committed by
Norman Feske
parent
04c42f34bc
commit
2687de2376
40
include/remote_rom/backend_base.h
Normal file
40
include/remote_rom/backend_base.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* \brief Backend interface used by the Remote_rom client and server
|
||||
* \author Johannes Schlatow
|
||||
* \date 2016-02-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE__REMOTE_ROM__BACKEND_BASE_H_
|
||||
#define __INCLUDE__REMOTE_ROM__BACKEND_BASE_H_
|
||||
|
||||
#include <rom_forwarder.h>
|
||||
#include <rom_receiver.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
struct Backend_server_base;
|
||||
struct Backend_client_base;
|
||||
|
||||
class Exception : public ::Genode::Exception { };
|
||||
Backend_server_base &backend_init_server();
|
||||
Backend_client_base &backend_init_client();
|
||||
};
|
||||
|
||||
struct Remote_rom::Backend_server_base
|
||||
{
|
||||
virtual void send_update() = 0;
|
||||
virtual void register_forwarder(Rom_forwarder_base *forwarder) = 0;
|
||||
};
|
||||
|
||||
struct Remote_rom::Backend_client_base
|
||||
{
|
||||
virtual void register_receiver(Rom_receiver_base *receiver) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
31
include/remote_rom/rom_forwarder.h
Normal file
31
include/remote_rom/rom_forwarder.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* \brief Interface used by the backend to transfer ROM content to the remote clients.
|
||||
* \author Johannes Schlatow
|
||||
* \date 2016-02-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE__REMOTE_ROM__ROM_FORWARDER_H_
|
||||
#define __INCLUDE__REMOTE_ROM__ROM_FORWARDER_H_
|
||||
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::size_t;
|
||||
struct Rom_forwarder_base;
|
||||
}
|
||||
|
||||
struct Remote_rom::Rom_forwarder_base
|
||||
{
|
||||
virtual const char *module_name() const = 0;
|
||||
virtual size_t content_size() const = 0;
|
||||
virtual size_t transfer_content(char *dst, size_t dst_len, size_t offset=0) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
31
include/remote_rom/rom_receiver.h
Normal file
31
include/remote_rom/rom_receiver.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* \brief Interface used by the backend to write the ROM data received from the remote server
|
||||
* \author Johannes Schlatow
|
||||
* \date 2016-02-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE__REMOTE_ROM__ROM_RECEIVER_H_
|
||||
#define __INCLUDE__REMOTE_ROM__ROM_RECEIVER_H_
|
||||
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::size_t;
|
||||
struct Rom_receiver_base;
|
||||
}
|
||||
|
||||
struct Remote_rom::Rom_receiver_base
|
||||
{
|
||||
virtual const char *module_name() const = 0;
|
||||
virtual char* start_new_content(size_t len) = 0;
|
||||
virtual void commit_new_content(bool abort=false) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
3
lib/mk/remote_rom_backend.inc
Normal file
3
lib/mk/remote_rom_backend.inc
Normal file
@@ -0,0 +1,3 @@
|
||||
INC_DIR += $(REP_DIR)/include/remote_rom
|
||||
|
||||
vpath % $(REP_DIR)/src/lib/remote_rom
|
||||
9
lib/mk/remote_rom_backend_nic_ip.mk
Normal file
9
lib/mk/remote_rom_backend_nic_ip.mk
Normal file
@@ -0,0 +1,9 @@
|
||||
# \author Johannes Schlatow
|
||||
# \date 2016-03-19
|
||||
|
||||
SRC_CC += backend/nic_ip/backend.cc
|
||||
|
||||
LIBS += base config net
|
||||
|
||||
# include less specific configuration
|
||||
include $(REP_DIR)/lib/mk/remote_rom_backend.inc
|
||||
147
run/remote_rom_backend_nic_ip.run
Normal file
147
run/remote_rom_backend_nic_ip.run
Normal file
@@ -0,0 +1,147 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
build { core init drivers/timer
|
||||
server/dynamic_rom
|
||||
proxy/remote_rom/backend/nic_ip
|
||||
app/rom_logger
|
||||
drivers/nic
|
||||
server/nic_bridge
|
||||
}
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
install_config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="CAP"/>
|
||||
<service name="LOG"/>
|
||||
<service name="RM"/>
|
||||
<service name="SIGNAL"/>
|
||||
<service name="ROM" />
|
||||
<service name="RAM" />
|
||||
<service name="CPU" />
|
||||
<service name="PD" />
|
||||
<service name="IO_MEM" />
|
||||
<service name="IRQ" />
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="dynamic_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config verbose="yes">
|
||||
<rom name="test">
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="disable">
|
||||
<test enabled="no"/>
|
||||
</inline>
|
||||
<sleep milliseconds="5000" />
|
||||
<inline description="enable">
|
||||
<test enabled="yes"/>
|
||||
</inline>
|
||||
<sleep milliseconds="10000" />
|
||||
<inline description="finished"/>
|
||||
</rom>
|
||||
</config>
|
||||
</start>
|
||||
<start name="remote_rom_server">
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<route>
|
||||
<service name="ROM"> <child name="dynamic_rom"/> </service>
|
||||
<service name="Nic"> <child name="nic_bridge"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
<config>
|
||||
<remote_rom localname="test" name="remote" src="192.168.42.10" dst="192.168.42.11">
|
||||
<default>
|
||||
<default />
|
||||
</default>
|
||||
</remote_rom>
|
||||
</config>
|
||||
</start>
|
||||
<start name="remote_rom_client">
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<route>
|
||||
<service name="Nic"> <child name="nic_bridge"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config>
|
||||
<remote_rom name="remote" src="192.168.42.11" dst="192.168.42.10">
|
||||
<default>
|
||||
<default />
|
||||
</default>
|
||||
</remote_rom>
|
||||
</config>
|
||||
</start>
|
||||
<start name="nic_bridge">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Nic"/></provides>
|
||||
<route>
|
||||
<service name="Nic"> <child name="nic_drv"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
<config>
|
||||
<nic tap="tap1"/>
|
||||
</config>
|
||||
</start>
|
||||
<start name="nic_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Nic"/></provides>
|
||||
<config>
|
||||
<nic tap="tap1"/>
|
||||
</config>
|
||||
</start>
|
||||
<start name="rom_logger">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config rom="remote" />
|
||||
<route>
|
||||
<service name="ROM"> <child name="remote_rom_client"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
#
|
||||
# Boot image
|
||||
#
|
||||
|
||||
build_boot_image { core init timer
|
||||
remote_rom_server
|
||||
remote_rom_client
|
||||
dynamic_rom
|
||||
rom_logger
|
||||
nic_drv
|
||||
nic_bridge
|
||||
}
|
||||
|
||||
append qemu_args " -nographic "
|
||||
|
||||
run_genode_until {.*change \(finished\).*} 30
|
||||
|
||||
grep_output {init -> rom_logger}
|
||||
compare_output_to {
|
||||
[init -> rom_logger] ROM 'remote':
|
||||
[init -> rom_logger] <default />
|
||||
[init -> rom_logger]
|
||||
[init -> rom_logger] ROM 'remote':
|
||||
[init -> rom_logger] <default />
|
||||
[init -> rom_logger]
|
||||
[init -> rom_logger] ROM 'remote':
|
||||
[init -> rom_logger] <test enabled="no"/>
|
||||
[init -> rom_logger]
|
||||
[init -> rom_logger] ROM 'remote':
|
||||
[init -> rom_logger] <test enabled="yes"/>
|
||||
[init -> rom_logger]
|
||||
}
|
||||
75
run/remote_rom_backend_nic_ip_client.run
Normal file
75
run/remote_rom_backend_nic_ip_client.run
Normal file
@@ -0,0 +1,75 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
build { core init drivers/timer
|
||||
app/rom_logger
|
||||
proxy/remote_rom/backend/nic_ip/client
|
||||
drivers/nic
|
||||
}
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
install_config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="CAP"/>
|
||||
<service name="LOG"/>
|
||||
<service name="RM"/>
|
||||
<service name="SIGNAL"/>
|
||||
<service name="ROM" />
|
||||
<service name="RAM" />
|
||||
<service name="CPU" />
|
||||
<service name="PD" />
|
||||
<service name="IO_MEM" />
|
||||
<service name="IRQ" />
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="rom_logger">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config rom="remote" />
|
||||
<route>
|
||||
<service name="ROM"> <child name="remote_rom_client"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="remote_rom_client">
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config>
|
||||
<remote_rom name="remote" src="192.168.42.11" dst="192.168.42.10" />
|
||||
</config>
|
||||
</start>
|
||||
<start name="nic_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Nic"/></provides>
|
||||
<config>
|
||||
<nic tap="tap1"/>
|
||||
</config>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
#
|
||||
# Boot image
|
||||
#
|
||||
|
||||
build_boot_image { core init timer
|
||||
remote_rom_client
|
||||
rom_logger
|
||||
nic_drv
|
||||
}
|
||||
|
||||
append qemu_args " -nographic "
|
||||
append qemu_args " -net tap,ifname=tap2 "
|
||||
|
||||
run_genode_until forever
|
||||
89
run/remote_rom_backend_nic_ip_server.run
Normal file
89
run/remote_rom_backend_nic_ip_server.run
Normal file
@@ -0,0 +1,89 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
build { core init drivers/timer
|
||||
server/dynamic_rom
|
||||
proxy/remote_rom/backend/nic_ip/server
|
||||
drivers/nic
|
||||
}
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
install_config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="CAP"/>
|
||||
<service name="LOG"/>
|
||||
<service name="RM"/>
|
||||
<service name="SIGNAL"/>
|
||||
<service name="ROM" />
|
||||
<service name="RAM" />
|
||||
<service name="CPU" />
|
||||
<service name="PD" />
|
||||
<service name="IO_MEM" />
|
||||
<service name="IRQ" />
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="dynamic_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config verbose="yes">
|
||||
<rom name="test">
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="disable">
|
||||
<test enabled="no"/>
|
||||
</inline>
|
||||
<sleep milliseconds="5000" />
|
||||
<inline description="enable">
|
||||
<test enabled="yes"/>
|
||||
</inline>
|
||||
<sleep milliseconds="10000" />
|
||||
<inline description="finished"/>
|
||||
</rom>
|
||||
</config>
|
||||
</start>
|
||||
<start name="remote_rom_server">
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<route>
|
||||
<service name="ROM"> <child name="dynamic_rom"/> </service>
|
||||
<service name="Nic"> <child name="nic_drv"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
<config>
|
||||
<remote_rom localname="test" name="remote" src="192.168.42.10" dst="192.168.42.11" />
|
||||
</config>
|
||||
</start>
|
||||
<start name="nic_drv">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="Nic"/></provides>
|
||||
<config>
|
||||
<nic tap="tap1"/>
|
||||
</config>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
#
|
||||
# Boot image
|
||||
#
|
||||
|
||||
build_boot_image { core init timer
|
||||
remote_rom_server
|
||||
dynamic_rom
|
||||
nic_drv
|
||||
}
|
||||
|
||||
append qemu_args " -nographic "
|
||||
append qemu_args " -net tap,ifname=tap2 "
|
||||
|
||||
run_genode_until forever
|
||||
563
src/lib/remote_rom/backend/nic_ip/backend.cc
Normal file
563
src/lib/remote_rom/backend/nic_ip/backend.cc
Normal file
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* \brief TODO
|
||||
* \author Johannes Schlatow
|
||||
* \date 2016-02-18
|
||||
*/
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/exception.h>
|
||||
|
||||
#include <backend_base.h>
|
||||
|
||||
#include <nic/packet_allocator.h>
|
||||
#include <nic_session/connection.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/ipv4.h>
|
||||
|
||||
#include <os/config.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
bool verbose = false;
|
||||
using Genode::size_t;
|
||||
using Genode::uint16_t;
|
||||
using Genode::uint32_t;
|
||||
using Genode::Packet_descriptor;
|
||||
using Genode::env;
|
||||
using Net::Ethernet_frame;
|
||||
using Net::Ipv4_packet;
|
||||
|
||||
template <class>
|
||||
class Backend_base;
|
||||
class Backend_server;
|
||||
class Backend_client;
|
||||
|
||||
struct Packet_base;
|
||||
struct SignalPacket;
|
||||
struct UpdatePacket;
|
||||
struct DataPacket;
|
||||
};
|
||||
|
||||
/* Packet format we use for inter-system communication */
|
||||
class Remote_rom::Packet_base : public Ethernet_frame, public Ipv4_packet
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
MAX_NAME_LEN = 64 /* maximum length of the module name */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SIGNAL = 1, /* signal that ROM content has changed */
|
||||
UPDATE = 2, /* request transmission of updated content */
|
||||
DATA = 3, /* first data packet */
|
||||
DATA_CONT = 4, /* following data packets */
|
||||
} Type;
|
||||
|
||||
protected:
|
||||
char _module_name[MAX_NAME_LEN]; /* the ROM module name */
|
||||
Type _type; /* packet type */
|
||||
uint32_t _content_size; /* ROM content size in bytes */
|
||||
uint16_t _offset; /* offset in bytes */
|
||||
uint16_t _payload_size; /* payload size in bytes */
|
||||
|
||||
/*****************************************************
|
||||
** 'payload' must be the last member of this class **
|
||||
*****************************************************/
|
||||
|
||||
char payload[0];
|
||||
|
||||
public:
|
||||
|
||||
Packet_base(size_t size) : Ethernet_frame(sizeof(Packet_base) + size), Ipv4_packet(sizeof(Packet_base) + size - sizeof(Ethernet_frame)), _payload_size(size) { }
|
||||
|
||||
void const * base() const { return &payload; }
|
||||
|
||||
/**
|
||||
* Return type of the packet
|
||||
*/
|
||||
Type type() const { return _type; }
|
||||
|
||||
/**
|
||||
* Return size of the packet
|
||||
*/
|
||||
size_t size() const { return _payload_size + sizeof(Packet_base); }
|
||||
|
||||
/**
|
||||
* Return content_size of the packet
|
||||
*/
|
||||
size_t content_size() const { return _content_size; }
|
||||
|
||||
/**
|
||||
* Return offset of the packet
|
||||
*/
|
||||
size_t offset() const { return _offset; }
|
||||
|
||||
/**
|
||||
* Return module_name of the packet
|
||||
*/
|
||||
char* module_name() { return _module_name; }
|
||||
|
||||
/**
|
||||
* Set payload size of the packet
|
||||
*/
|
||||
void payload_size(Genode::size_t payload_size)
|
||||
{
|
||||
_payload_size = payload_size;
|
||||
Ipv4_packet::total_length(size() - sizeof(Ethernet_frame));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return payload size of the packet
|
||||
*/
|
||||
size_t payload_size() const { return _payload_size; }
|
||||
|
||||
/**
|
||||
* Return address of the payload
|
||||
*/
|
||||
void *addr() { return payload; }
|
||||
|
||||
void prepare_ethernet(const Mac_address &src, const Mac_address &dst=Ethernet_frame::BROADCAST)
|
||||
{
|
||||
Ethernet_frame::src(src);
|
||||
Ethernet_frame::dst(dst);
|
||||
Ethernet_frame::type(IPV4);
|
||||
}
|
||||
|
||||
void prepare_ipv4(const Ipv4_address &src, const Ipv4_address &dst=Ipv4_packet::BROADCAST)
|
||||
{
|
||||
Ipv4_packet::version(4);
|
||||
Ipv4_packet::header_length(5);
|
||||
Ipv4_packet::time_to_live(10);
|
||||
Ipv4_packet::src(src);
|
||||
Ipv4_packet::dst(dst);
|
||||
Ipv4_packet::total_length(size() - sizeof(Ethernet_frame));
|
||||
}
|
||||
|
||||
void set_checksums()
|
||||
{
|
||||
Ipv4_packet::checksum(Ipv4_packet::calculate_checksum(*this));
|
||||
}
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
class Remote_rom::SignalPacket : public Packet_base
|
||||
{
|
||||
public:
|
||||
SignalPacket() : Packet_base(0)
|
||||
{ }
|
||||
|
||||
void prepare(const char *module)
|
||||
{
|
||||
Genode::strncpy(_module_name, module, MAX_NAME_LEN);
|
||||
_type = SIGNAL;
|
||||
_payload_size = 0;
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
class Remote_rom::UpdatePacket : public Packet_base
|
||||
{
|
||||
public:
|
||||
UpdatePacket() : Packet_base(0)
|
||||
{ }
|
||||
|
||||
void prepare(const char *module)
|
||||
{
|
||||
Genode::strncpy(_module_name, module, MAX_NAME_LEN);
|
||||
_type = UPDATE;
|
||||
_payload_size = 0;
|
||||
}
|
||||
} __attribute__((packed));
|
||||
|
||||
class Remote_rom::DataPacket : public Packet_base
|
||||
{
|
||||
public:
|
||||
enum { MAX_PAYLOAD_SIZE = 1024 };
|
||||
|
||||
char payload[MAX_PAYLOAD_SIZE];
|
||||
|
||||
DataPacket() : Packet_base(MAX_PAYLOAD_SIZE)
|
||||
{ }
|
||||
|
||||
void prepare(const char* module, size_t offset, size_t content_size)
|
||||
{
|
||||
Genode::strncpy(_module_name, module, MAX_NAME_LEN);
|
||||
|
||||
_payload_size = MAX_PAYLOAD_SIZE;
|
||||
_offset = offset;
|
||||
_content_size = content_size;
|
||||
|
||||
if (offset == 0)
|
||||
_type = DATA;
|
||||
else
|
||||
_type = DATA_CONT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return packet size for given payload
|
||||
*/
|
||||
static size_t packet_size(size_t payload) { return sizeof(Packet_base) + Genode::min(payload, MAX_PAYLOAD_SIZE); }
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
template <class HANDLER>
|
||||
class Remote_rom::Backend_base
|
||||
{
|
||||
protected:
|
||||
enum {
|
||||
PACKET_SIZE = 1024,
|
||||
BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE
|
||||
};
|
||||
|
||||
class Rx_thread : public Genode::Thread
|
||||
{
|
||||
protected:
|
||||
Ipv4_packet::Ipv4_address &_accept_ip;
|
||||
Nic::Connection &_nic;
|
||||
HANDLER &_handler;
|
||||
|
||||
Genode::Signal_receiver _sig_rec;
|
||||
Genode::Signal_dispatcher<Rx_thread> _link_state_dispatcher;
|
||||
Genode::Signal_dispatcher<Rx_thread> _rx_packet_avail_dispatcher;
|
||||
Genode::Signal_dispatcher<Rx_thread> _rx_ready_to_ack_dispatcher;
|
||||
|
||||
void _handle_rx_packet_avail(unsigned)
|
||||
{
|
||||
while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) {
|
||||
Packet_descriptor _rx_packet = _nic.rx()->get_packet();
|
||||
|
||||
char *content = _nic.rx()->packet_content(_rx_packet);
|
||||
|
||||
/* check IP */
|
||||
Ipv4_packet &ip_packet = *(Packet_base*)content;
|
||||
if (_accept_ip == Ipv4_packet::BROADCAST || _accept_ip == ip_packet.dst())
|
||||
_handler.receive(*(Packet_base*)content);
|
||||
|
||||
_nic.rx()->acknowledge_packet(_rx_packet);
|
||||
}
|
||||
}
|
||||
|
||||
void _handle_rx_ready_to_ack(unsigned) { _handle_rx_packet_avail(0); }
|
||||
|
||||
void _handle_link_state(unsigned)
|
||||
{
|
||||
PINF("link state changed");
|
||||
}
|
||||
|
||||
public:
|
||||
Rx_thread(Nic::Connection &nic, HANDLER &handler, Ipv4_packet::Ipv4_address &ip)
|
||||
: Genode::Thread(Weight::DEFAULT_WEIGHT, "backend_nic_rx", 8192),
|
||||
_accept_ip(ip),
|
||||
_nic(nic), _handler(handler),
|
||||
_link_state_dispatcher(_sig_rec, *this, &Rx_thread::_handle_link_state),
|
||||
_rx_packet_avail_dispatcher(_sig_rec, *this, &Rx_thread::_handle_rx_packet_avail),
|
||||
_rx_ready_to_ack_dispatcher(_sig_rec, *this, &Rx_thread::_handle_rx_ready_to_ack)
|
||||
{
|
||||
_nic.link_state_sigh(_link_state_dispatcher);
|
||||
_nic.rx_channel()->sigh_packet_avail(_rx_packet_avail_dispatcher);
|
||||
_nic.rx_channel()->sigh_ready_to_ack(_rx_ready_to_ack_dispatcher);
|
||||
}
|
||||
|
||||
void entry()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
Genode::Signal sig = _sig_rec.wait_for_signal();
|
||||
int num = sig.num();
|
||||
|
||||
Genode::Signal_dispatcher_base *dispatcher;
|
||||
dispatcher = dynamic_cast<Genode::Signal_dispatcher_base *>(sig.context());
|
||||
dispatcher->dispatch(num);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Nic::Packet_allocator _tx_block_alloc;
|
||||
Nic::Connection _nic;
|
||||
Rx_thread _rx_thread;
|
||||
Ethernet_frame::Mac_address _mac_address;
|
||||
Ipv4_packet::Ipv4_address _src_ip;
|
||||
Ipv4_packet::Ipv4_address _accept_ip;
|
||||
Ipv4_packet::Ipv4_address _dst_ip;
|
||||
|
||||
protected:
|
||||
void _tx_ack(bool block = false)
|
||||
{
|
||||
/* check for acknowledgements */
|
||||
while (_nic.tx()->ack_avail() || block) {
|
||||
Nic::Packet_descriptor acked_packet = _nic.tx()->get_acked_packet();
|
||||
_nic.tx()->release_packet(acked_packet);
|
||||
block = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit Backend_base(Genode::Allocator &alloc, HANDLER &handler) : _tx_block_alloc(&alloc), _nic(&_tx_block_alloc, BUF_SIZE, BUF_SIZE), _rx_thread(_nic, handler, _accept_ip)
|
||||
{
|
||||
/* start dispatcher thread */
|
||||
_rx_thread.start();
|
||||
|
||||
/* convert and store mac address */
|
||||
Nic::Mac_address mac = _nic.mac_address();
|
||||
_mac_address.addr[0] = mac.addr[0];
|
||||
_mac_address.addr[1] = mac.addr[1];
|
||||
_mac_address.addr[2] = mac.addr[2];
|
||||
_mac_address.addr[3] = mac.addr[3];
|
||||
_mac_address.addr[4] = mac.addr[4];
|
||||
_mac_address.addr[5] = mac.addr[5];
|
||||
|
||||
try {
|
||||
char ip_string[15];
|
||||
Genode::Xml_node remoterom = Genode::config()->xml_node().sub_node("remote_rom");
|
||||
remoterom.attribute("src").value(ip_string, sizeof(ip_string));
|
||||
_src_ip = Ipv4_packet::ip_from_string(ip_string);
|
||||
|
||||
remoterom.attribute("dst").value(ip_string, sizeof(ip_string));
|
||||
_dst_ip = Ipv4_packet::ip_from_string(ip_string);
|
||||
|
||||
_accept_ip = _src_ip;
|
||||
} catch (...) {
|
||||
PWRN("No IP configured, falling back to broadcast mode!");
|
||||
_src_ip = Ipv4_packet::CURRENT;
|
||||
_dst_ip = Ipv4_packet::BROADCAST;
|
||||
_accept_ip = Ipv4_packet::BROADCAST;
|
||||
}
|
||||
}
|
||||
|
||||
Nic::Packet_descriptor alloc_tx_packet(Genode::size_t size)
|
||||
{
|
||||
while (true) {
|
||||
try {
|
||||
Nic::Packet_descriptor packet = _nic.tx()->alloc_packet(size);
|
||||
return packet;
|
||||
} catch(Nic::Session::Tx::Source::Packet_alloc_failed) {
|
||||
/* packet allocator exhausted, wait for acknowledgements */
|
||||
_tx_ack(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void submit_tx_packet(Nic::Packet_descriptor packet)
|
||||
{
|
||||
_nic.tx()->submit_packet(packet);
|
||||
/* check for acknowledgements */
|
||||
_tx_ack();
|
||||
}
|
||||
};
|
||||
|
||||
class Remote_rom::Backend_server : public Backend_server_base, public Backend_base<Backend_server>
|
||||
{
|
||||
private:
|
||||
static Backend_server_base* _instance;
|
||||
Rom_forwarder_base *_forwarder;
|
||||
|
||||
Backend_server(Genode::Allocator &alloc) : Backend_base(alloc, *this), _forwarder(nullptr)
|
||||
{ }
|
||||
|
||||
void send_data()
|
||||
{
|
||||
if (!_forwarder) return;
|
||||
|
||||
size_t offset = 0;
|
||||
size_t size = _forwarder->content_size();
|
||||
while (offset < size)
|
||||
{
|
||||
/* create and transmit packet via NIC session */
|
||||
Nic::Packet_descriptor pd = alloc_tx_packet(DataPacket::packet_size(size));
|
||||
DataPacket *packet = (DataPacket*)_nic.tx()->packet_content(pd);
|
||||
|
||||
packet->prepare_ethernet(_mac_address, Ethernet_frame::BROADCAST);
|
||||
packet->prepare_ipv4(_src_ip, _dst_ip);
|
||||
packet->prepare(_forwarder->module_name(), offset, size);
|
||||
|
||||
packet->payload_size(_forwarder->transfer_content((char*)packet->addr(), DataPacket::MAX_PAYLOAD_SIZE, offset));
|
||||
packet->set_checksums();
|
||||
|
||||
submit_tx_packet(pd);
|
||||
|
||||
offset += packet->payload_size();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static Backend_server_base &instance()
|
||||
{
|
||||
if (!_instance) {
|
||||
_instance = new (env()->heap()) Backend_server(*env()->heap());
|
||||
|
||||
if (!_instance)
|
||||
throw Exception();
|
||||
}
|
||||
|
||||
return *_instance;
|
||||
}
|
||||
|
||||
void register_forwarder(Rom_forwarder_base *forwarder)
|
||||
{
|
||||
_forwarder = forwarder;
|
||||
}
|
||||
|
||||
void send_update()
|
||||
{
|
||||
if (!_forwarder) return;
|
||||
|
||||
/* create and transmit packet via NIC session */
|
||||
Nic::Packet_descriptor pd = alloc_tx_packet(sizeof(SignalPacket));
|
||||
SignalPacket *packet = (SignalPacket*)_nic.tx()->packet_content(pd);
|
||||
|
||||
packet->prepare_ethernet(_mac_address);
|
||||
packet->prepare_ipv4(_src_ip, _dst_ip);
|
||||
packet->prepare(_forwarder->module_name());
|
||||
packet->set_checksums();
|
||||
|
||||
submit_tx_packet(pd);
|
||||
}
|
||||
|
||||
void receive(Packet_base &packet)
|
||||
{
|
||||
switch (packet.type())
|
||||
{
|
||||
case Packet_base::UPDATE:
|
||||
if (verbose) PINF("receiving UPDATE (%s) packet", packet.module_name());
|
||||
|
||||
if (!_forwarder)
|
||||
return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(packet.module_name(), _forwarder->module_name()))
|
||||
return;
|
||||
|
||||
/* TODO (optional) dont send data within Rx_Thread's context */
|
||||
send_data();
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Remote_rom::Backend_client : public Backend_client_base, public Backend_base<Backend_client>
|
||||
{
|
||||
private:
|
||||
static Backend_client_base *_instance;
|
||||
Rom_receiver_base *_receiver;
|
||||
char *_write_ptr;
|
||||
size_t _buf_size;
|
||||
|
||||
Backend_client(Genode::Allocator &alloc) : Backend_base(alloc, *this), _receiver(nullptr), _write_ptr(nullptr), _buf_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
void write(char *data, size_t offset, size_t size)
|
||||
{
|
||||
if (!_write_ptr) return;
|
||||
|
||||
size_t const len = Genode::min(size, _buf_size-offset);
|
||||
Genode::memcpy(_write_ptr+offset, data, len);
|
||||
|
||||
if (offset + len >= _buf_size)
|
||||
_receiver->commit_new_content();
|
||||
}
|
||||
|
||||
public:
|
||||
static Backend_client_base &instance()
|
||||
{
|
||||
if (!_instance) {
|
||||
_instance = new (env()->heap()) Backend_client(*env()->heap());
|
||||
|
||||
if (!_instance)
|
||||
throw Exception();
|
||||
}
|
||||
|
||||
return *_instance;
|
||||
}
|
||||
|
||||
void register_receiver(Rom_receiver_base *receiver)
|
||||
{
|
||||
/* TODO support multiple receivers (ROM names) */
|
||||
_receiver = receiver;
|
||||
|
||||
/* FIXME request update on startup (occasionally triggers invalid signal-context capability) */
|
||||
// if (_receiver)
|
||||
// update(_receiver->module_name());
|
||||
}
|
||||
|
||||
|
||||
void update(const char* module_name)
|
||||
{
|
||||
if (!_receiver) return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(module_name, _receiver->module_name()))
|
||||
return;
|
||||
|
||||
/* create and transmit packet via NIC session */
|
||||
Nic::Packet_descriptor pd = alloc_tx_packet(sizeof(UpdatePacket));
|
||||
UpdatePacket *packet = (UpdatePacket*)_nic.tx()->packet_content(pd);
|
||||
|
||||
packet->prepare_ethernet(_mac_address);
|
||||
packet->prepare_ipv4(_src_ip, _dst_ip);
|
||||
packet->prepare(_receiver->module_name());
|
||||
packet->set_checksums();
|
||||
|
||||
submit_tx_packet(pd);
|
||||
}
|
||||
|
||||
void receive(Packet_base &packet)
|
||||
{
|
||||
switch (packet.type())
|
||||
{
|
||||
case Packet_base::SIGNAL:
|
||||
if (verbose) PINF("receiving SIGNAL(%s) packet", packet.module_name());
|
||||
|
||||
/* send update request */
|
||||
update(packet.module_name());
|
||||
|
||||
break;
|
||||
case Packet_base::DATA:
|
||||
if (verbose) PINF("receiving DATA(%s) packet", packet.module_name());
|
||||
|
||||
/* write into buffer */
|
||||
if (!_receiver) return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(packet.module_name(), _receiver->module_name()))
|
||||
return;
|
||||
|
||||
_write_ptr = _receiver->start_new_content(packet.content_size());
|
||||
_buf_size = (_write_ptr) ? packet.content_size() : 0;
|
||||
|
||||
write((char*)packet.addr(), packet.offset(), packet.payload_size());
|
||||
|
||||
break;
|
||||
case Packet_base::DATA_CONT:
|
||||
if (verbose) PINF("receiving DATA_CONT(%s) packet", packet.module_name());
|
||||
|
||||
if (!_receiver) return;
|
||||
|
||||
/* check module name */
|
||||
if (Genode::strcmp(packet.module_name(), _receiver->module_name()))
|
||||
return;
|
||||
|
||||
/* write into buffer */
|
||||
write((char*)packet.addr(), packet.offset(), packet.payload_size());
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Remote_rom::Backend_server_base *Remote_rom::Backend_server::_instance = nullptr;
|
||||
Remote_rom::Backend_client_base *Remote_rom::Backend_client::_instance = nullptr;
|
||||
|
||||
Remote_rom::Backend_server_base &Remote_rom::backend_init_server()
|
||||
{
|
||||
return Backend_server::instance();
|
||||
}
|
||||
|
||||
Remote_rom::Backend_client_base &Remote_rom::backend_init_client()
|
||||
{
|
||||
return Backend_client::instance();
|
||||
}
|
||||
32
src/proxy/remote_rom/README
Normal file
32
src/proxy/remote_rom/README
Normal file
@@ -0,0 +1,32 @@
|
||||
The remote ROM allows providing ROM services over a network or similar communication
|
||||
medium and thus implements publisher/subscriber communication in a distributed system.
|
||||
|
||||
The remote_rom server connects to a local ROM service and provides a remote ROM service
|
||||
via the specified backend. The remote_rom client connects to a remote ROM service via
|
||||
the specified backend and provides a ROM service via local RPC.
|
||||
|
||||
Backends
|
||||
--------
|
||||
|
||||
The remote_rom can be compiled with one of multiple backends that use different session
|
||||
interfaces or libraries to forward and receive the packets. By exchanging the backend,
|
||||
we can also easily change the publication strategy (e.g. notification+polling vs. multicast).
|
||||
Furthermore, a backend is responsible for access control and optionally allows the
|
||||
specification of a policy for this.
|
||||
|
||||
:'nic_ip':
|
||||
This backend uses a Nic_session to transmit network packets with IPv4 headers.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Both, the client and the server evaluate the <remote_rom> node of their config.
|
||||
The _name_ attribute specifies the ROMs module name. The <remote_rom> node may
|
||||
further contain a <default> node that can be used to populate the ROM with a default
|
||||
content.
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
For an example that illustrates the use of these components, please refer to the
|
||||
_run/test-remote_rom_backend_nic.run_ script.
|
||||
2
src/proxy/remote_rom/backend/nic_ip/client/target.mk
Normal file
2
src/proxy/remote_rom/backend/nic_ip/client/target.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
include $(PRG_DIR)/../target.inc
|
||||
include $(PRG_DIR)/../../../client/target.inc
|
||||
2
src/proxy/remote_rom/backend/nic_ip/server/target.mk
Normal file
2
src/proxy/remote_rom/backend/nic_ip/server/target.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
include $(PRG_DIR)/../target.inc
|
||||
include $(PRG_DIR)/../../../server/target.inc
|
||||
1
src/proxy/remote_rom/backend/nic_ip/target.inc
Normal file
1
src/proxy/remote_rom/backend/nic_ip/target.inc
Normal file
@@ -0,0 +1 @@
|
||||
LIBS += remote_rom_backend_nic_ip
|
||||
259
src/proxy/remote_rom/client/main.cc
Normal file
259
src/proxy/remote_rom/client/main.cc
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* \brief Client-side proxy component translating a rom_session provided over a network into a local rom_session.
|
||||
* \author Johannes Schlatow
|
||||
* \date 2016-02-15
|
||||
*
|
||||
* Usage scenario:
|
||||
* __________ ________________ _________________ __________
|
||||
* | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client |
|
||||
* | | | server | | client | | |
|
||||
* ---------- ---------------- ----------------- ----------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/printf.h>
|
||||
#include <base/env.h>
|
||||
#include <util/volatile_object.h>
|
||||
#include <util/list.h>
|
||||
|
||||
#include <base/rpc_server.h>
|
||||
#include <root/component.h>
|
||||
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <rom_session/rom_session.h>
|
||||
|
||||
#include <base/component.h>
|
||||
#include <os/config.h>
|
||||
|
||||
#include <backend_base.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::size_t;
|
||||
using Genode::Lazy_volatile_object;
|
||||
using Genode::Signal_context_capability;
|
||||
|
||||
class Session_component;
|
||||
class Root;
|
||||
struct Main;
|
||||
struct Read_buffer;
|
||||
|
||||
static char remotename[255];
|
||||
|
||||
typedef Genode::List<Session_component> Session_list;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Interface used by the sessions to obtain the ROM data received from the remote server
|
||||
*/
|
||||
struct Remote_rom::Read_buffer
|
||||
{
|
||||
virtual size_t content_size() const = 0;
|
||||
virtual size_t export_content(char *dst, size_t dst_len) const = 0;
|
||||
};
|
||||
|
||||
class Remote_rom::Session_component : public Genode::Rpc_object<Genode::Rom_session, Remote_rom::Session_component>,
|
||||
public Session_list::Element
|
||||
{
|
||||
private:
|
||||
Genode::Env &_env;
|
||||
|
||||
Signal_context_capability _sigh;
|
||||
|
||||
Read_buffer const &_buffer;
|
||||
|
||||
Session_list &_sessions;
|
||||
|
||||
Lazy_volatile_object<Genode::Attached_ram_dataspace> _ram_ds;
|
||||
|
||||
public:
|
||||
|
||||
static int version() { return 1; }
|
||||
|
||||
Session_component(Genode::Env &env, Session_list &sessions, Read_buffer const &buffer)
|
||||
:
|
||||
_env(env), _buffer(buffer), _sessions(sessions)
|
||||
{
|
||||
_sessions.insert(this);
|
||||
}
|
||||
|
||||
~Session_component() { _sessions.remove(this); }
|
||||
|
||||
void notify_client()
|
||||
{
|
||||
if (!_sigh.valid())
|
||||
return;
|
||||
|
||||
Genode::Signal_transmitter(_sigh).submit();
|
||||
}
|
||||
|
||||
/* ROM session implementation */
|
||||
|
||||
Genode::Rom_dataspace_capability dataspace() override
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* replace dataspace by new one as needed */
|
||||
if (!_ram_ds.is_constructed()
|
||||
|| _buffer.content_size() > _ram_ds->size()) {
|
||||
|
||||
_ram_ds.construct(&_env.ram(), _buffer.content_size());
|
||||
}
|
||||
|
||||
char *dst = _ram_ds->local_addr<char>();
|
||||
size_t const dst_size = _ram_ds->size();
|
||||
|
||||
/* fill with content of current evaluation result */
|
||||
size_t const copied_len = _buffer.export_content(dst, dst_size);
|
||||
|
||||
/* clear remainder of dataspace */
|
||||
Genode::memset(dst + copied_len, 0, dst_size - copied_len);
|
||||
|
||||
/* cast RAM into ROM dataspace capability */
|
||||
Dataspace_capability ds_cap = static_cap_cast<Dataspace>(_ram_ds->cap());
|
||||
return static_cap_cast<Rom_dataspace>(ds_cap);
|
||||
}
|
||||
|
||||
void sigh(Genode::Signal_context_capability sigh) override
|
||||
{
|
||||
_sigh = sigh;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Remote_rom::Root : public Genode::Root_component<Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Env &_env;
|
||||
Read_buffer &_buffer;
|
||||
Session_list _sessions;
|
||||
|
||||
protected:
|
||||
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
/* TODO compare requested module name with provided module name (config) */
|
||||
|
||||
return new (Root::md_alloc())
|
||||
Session_component(_env, _sessions, _buffer);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Genode::Env &env, Genode::Allocator &md_alloc, Read_buffer &buffer)
|
||||
: Genode::Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc), _env(env), _buffer(buffer)
|
||||
{ }
|
||||
|
||||
void notify_clients()
|
||||
{
|
||||
for (Session_component *s = _sessions.first(); s; s = s->next())
|
||||
s->notify_client();
|
||||
}
|
||||
};
|
||||
|
||||
struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom_receiver_base
|
||||
{
|
||||
Genode::Env &env;
|
||||
Genode::Heap heap = { &env.ram(), &env.rm() };
|
||||
Root remote_rom_root = { env, heap, *this };
|
||||
|
||||
Genode::Lazy_volatile_object<Genode::Attached_ram_dataspace> _ds;
|
||||
size_t _ds_content_size;
|
||||
|
||||
Backend_client_base &_backend;
|
||||
|
||||
Main(Genode::Env &env) : env(env), _ds_content_size(1024), _backend(backend_init_client())
|
||||
{
|
||||
env.parent().announce(env.ep().manage(remote_rom_root));
|
||||
|
||||
/* initialise backend */
|
||||
_backend.register_receiver(this);
|
||||
|
||||
// _ds.construct(Genode::env()->ram_session(), _ds_content_size);
|
||||
}
|
||||
|
||||
const char* module_name() const { return remotename; }
|
||||
|
||||
char* start_new_content(size_t len)
|
||||
{
|
||||
/* Create buffer for new data */
|
||||
_ds_content_size = len;
|
||||
|
||||
// TODO (optional) implement double buffering
|
||||
if (!_ds.is_constructed() || _ds_content_size > _ds->size())
|
||||
_ds.construct(&env.ram(), _ds_content_size);
|
||||
|
||||
// TODO set write lock
|
||||
|
||||
return _ds->local_addr<char>();
|
||||
}
|
||||
|
||||
void commit_new_content(bool abort=false)
|
||||
{
|
||||
if (abort)
|
||||
PERR("abort not supported");
|
||||
|
||||
// TODO release write lock
|
||||
|
||||
remote_rom_root.notify_clients();
|
||||
}
|
||||
|
||||
size_t content_size() const
|
||||
{
|
||||
if (_ds.is_constructed()) {
|
||||
return _ds_content_size;
|
||||
}
|
||||
else {
|
||||
/* transfer default content if set */
|
||||
try {
|
||||
Genode::Xml_node default_content = Genode::config()->xml_node().sub_node("remote_rom").sub_node("default");
|
||||
return default_content.content_size();
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t export_content(char *dst, size_t dst_len) const
|
||||
{
|
||||
if (_ds.is_constructed()) {
|
||||
size_t const len = Genode::min(dst_len, _ds_content_size);
|
||||
Genode::memcpy(dst, _ds->local_addr<char>(), len);
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
/* transfer default content if set */
|
||||
try {
|
||||
Genode::Xml_node default_content = Genode::config()->xml_node().sub_node("remote_rom").sub_node("default");
|
||||
size_t const len = Genode::min(dst_len, default_content.content_size());
|
||||
Genode::memcpy(dst, default_content.content_base(), len);
|
||||
return len;
|
||||
} catch (...) { }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
namespace Component {
|
||||
Genode::size_t stack_size() { return 2*1024*sizeof(long); }
|
||||
void construct(Genode::Env &env)
|
||||
{
|
||||
try {
|
||||
Genode::Xml_node remote_rom = Genode::config()->xml_node().sub_node("remote_rom");
|
||||
remote_rom.attribute("name").value(Remote_rom::remotename, sizeof(Remote_rom::remotename));
|
||||
} catch (...) {
|
||||
PERR("No ROM module configured!");
|
||||
}
|
||||
|
||||
static Remote_rom::Main main(env);
|
||||
}
|
||||
}
|
||||
8
src/proxy/remote_rom/client/target.inc
Normal file
8
src/proxy/remote_rom/client/target.inc
Normal file
@@ -0,0 +1,8 @@
|
||||
SRC_CC = main.cc
|
||||
TARGET = remote_rom_client
|
||||
|
||||
LIBS += base config
|
||||
|
||||
INC_DIR += $(REP_DIR)/include/remote_rom
|
||||
|
||||
vpath main.cc $(REP_DIR)/src/proxy/remote_rom/client
|
||||
141
src/proxy/remote_rom/server/main.cc
Normal file
141
src/proxy/remote_rom/server/main.cc
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* \brief Server-side proxy component providing a rom_session over a network.
|
||||
* \author Johannes Schlatow
|
||||
* \date 2016-02-15
|
||||
*
|
||||
* Usage scenario:
|
||||
* __________ ________________ _________________ __________
|
||||
* | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client |
|
||||
* | | | server | | client | | |
|
||||
* ---------- ---------------- ----------------- ----------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/printf.h>
|
||||
#include <base/env.h>
|
||||
|
||||
#include <backend_base.h>
|
||||
|
||||
#include <base/component.h>
|
||||
#include <os/config.h>
|
||||
#include <os/attached_rom_dataspace.h>
|
||||
|
||||
namespace Remote_rom {
|
||||
using Genode::size_t;
|
||||
using Genode::Attached_rom_dataspace;
|
||||
|
||||
class Rom_forwarder;
|
||||
struct Main;
|
||||
|
||||
static char modulename[255];
|
||||
static char remotename[255];
|
||||
static bool binary = false;
|
||||
|
||||
};
|
||||
|
||||
struct Remote_rom::Rom_forwarder : Rom_forwarder_base
|
||||
{
|
||||
Attached_rom_dataspace &_rom;
|
||||
Backend_server_base &_backend;
|
||||
|
||||
Rom_forwarder(Attached_rom_dataspace &rom, Backend_server_base &backend) : _rom(rom), _backend(backend)
|
||||
{
|
||||
_backend.register_forwarder(this);
|
||||
|
||||
/* on startup, send an update message to remote client */
|
||||
update();
|
||||
}
|
||||
|
||||
const char *module_name() const { return remotename; }
|
||||
|
||||
void update()
|
||||
{
|
||||
/* TODO don't update ROM if a transfer is still in progress */
|
||||
|
||||
/* refresh dataspace if valid*/
|
||||
_rom.update();
|
||||
|
||||
/* trigger backend_server */
|
||||
_backend.send_update();
|
||||
}
|
||||
|
||||
size_t content_size() const
|
||||
{
|
||||
if (_rom.is_valid()) {
|
||||
if (binary)
|
||||
return _rom.size();
|
||||
else
|
||||
return Genode::min(1+Genode::strlen(_rom.local_addr<char>()), _rom.size());
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Genode::Xml_node default_content = Genode::config()->xml_node().sub_node("remote_rom").sub_node("default");
|
||||
return default_content.content_size();
|
||||
} catch (...) { }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t transfer_content(char *dst, size_t dst_len, size_t offset=0) const
|
||||
{
|
||||
if (_rom.is_valid()) {
|
||||
size_t const len = Genode::min(dst_len, content_size()-offset);
|
||||
Genode::memcpy(dst, _rom.local_addr<char>() + offset, len);
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
/* transfer default content if set */
|
||||
try {
|
||||
Genode::Xml_node default_content = Genode::config()->xml_node().sub_node("remote_rom").sub_node("default");
|
||||
size_t const len = Genode::min(dst_len, default_content.content_size()-offset);
|
||||
Genode::memcpy(dst, default_content.content_base() + offset, len);
|
||||
return len;
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct Remote_rom::Main
|
||||
{
|
||||
Genode::Entrypoint &_ep;
|
||||
Attached_rom_dataspace _rom;
|
||||
Rom_forwarder _forwarder;
|
||||
|
||||
Genode::Signal_handler<Rom_forwarder> _dispatcher = { _ep, _forwarder, &Rom_forwarder::update };
|
||||
|
||||
Main(Genode::Entrypoint &ep)
|
||||
: _ep(ep),
|
||||
_rom(modulename),
|
||||
_forwarder(_rom, backend_init_server())
|
||||
{
|
||||
/* register update dispatcher */
|
||||
_rom.sigh(_dispatcher);
|
||||
}
|
||||
};
|
||||
|
||||
namespace Component {
|
||||
Genode::size_t stack_size() { return 2*1024*sizeof(long); }
|
||||
void construct(Genode::Env &env)
|
||||
{
|
||||
try {
|
||||
Genode::Xml_node remote_rom = Genode::config()->xml_node().sub_node("remote_rom");
|
||||
remote_rom.attribute("localname").value(Remote_rom::modulename, sizeof(Remote_rom::modulename));
|
||||
remote_rom.attribute("name").value(Remote_rom::remotename, sizeof(Remote_rom::remotename));
|
||||
try {
|
||||
remote_rom.attribute("binary").value(&Remote_rom::binary);
|
||||
} catch (...) { }
|
||||
} catch (...) {
|
||||
PERR("No ROM module configured!");
|
||||
}
|
||||
|
||||
static Remote_rom::Main main(env.ep());
|
||||
}
|
||||
}
|
||||
8
src/proxy/remote_rom/server/target.inc
Normal file
8
src/proxy/remote_rom/server/target.inc
Normal file
@@ -0,0 +1,8 @@
|
||||
SRC_CC = main.cc
|
||||
TARGET = remote_rom_server
|
||||
|
||||
LIBS += base config
|
||||
|
||||
INC_DIR += $(REP_DIR)/include/remote_rom
|
||||
|
||||
vpath main.cc $(REP_DIR)/src/proxy/remote_rom/server
|
||||
Reference in New Issue
Block a user