diff --git a/repos/os/recipes/pkg/black_hole/runtime b/repos/os/recipes/pkg/black_hole/runtime index 5b2ab031bb..2c41dfc4cc 100644 --- a/repos/os/recipes/pkg/black_hole/runtime +++ b/repos/os/recipes/pkg/black_hole/runtime @@ -6,6 +6,7 @@ + @@ -14,6 +15,7 @@ + diff --git a/repos/os/recipes/pkg/test-black_hole/runtime b/repos/os/recipes/pkg/test-black_hole/runtime index 597e59ac8e..3711cd5408 100644 --- a/repos/os/recipes/pkg/test-black_hole/runtime +++ b/repos/os/recipes/pkg/test-black_hole/runtime @@ -30,6 +30,7 @@ + @@ -37,6 +38,7 @@ + @@ -55,6 +57,7 @@ + diff --git a/repos/os/recipes/src/black_hole/used_apis b/repos/os/recipes/src/black_hole/used_apis index a40b53f092..d9b80bac1d 100644 --- a/repos/os/recipes/src/black_hole/used_apis +++ b/repos/os/recipes/src/black_hole/used_apis @@ -4,4 +4,5 @@ audio_out_session capture_session event_session nic_session +uplink_session os diff --git a/repos/os/recipes/src/test-black_hole/used_apis b/repos/os/recipes/src/test-black_hole/used_apis index 1474ce00c2..53873ce068 100644 --- a/repos/os/recipes/src/test-black_hole/used_apis +++ b/repos/os/recipes/src/test-black_hole/used_apis @@ -6,3 +6,4 @@ audio_out_session event_session capture_session nic_session +uplink_session diff --git a/repos/os/src/server/black_hole/README b/repos/os/src/server/black_hole/README index 66f07dd720..d08e5a6737 100644 --- a/repos/os/src/server/black_hole/README +++ b/repos/os/src/server/black_hole/README @@ -9,6 +9,7 @@ in the configuration of the component: * Capture * Event * Nic +* Uplink @@ -16,4 +17,5 @@ in the configuration of the component: + diff --git a/repos/os/src/server/black_hole/config.xsd b/repos/os/src/server/black_hole/config.xsd index 3919c4653e..df2da3f308 100644 --- a/repos/os/src/server/black_hole/config.xsd +++ b/repos/os/src/server/black_hole/config.xsd @@ -4,6 +4,7 @@ + diff --git a/repos/os/src/server/black_hole/main.cc b/repos/os/src/server/black_hole/main.cc index c1f78bbb05..b732e95e72 100644 --- a/repos/os/src/server/black_hole/main.cc +++ b/repos/os/src/server/black_hole/main.cc @@ -26,6 +26,7 @@ #include "capture.h" #include "event.h" #include "nic.h" +#include "uplink.h" /*************** @@ -45,6 +46,7 @@ struct Black_hole::Main Genode::Constructible capture_root { }; Genode::Constructible event_root { }; Genode::Constructible nic_root { }; + Genode::Constructible uplink_root { }; Main(Genode::Env &env) : env(env) { @@ -73,6 +75,11 @@ struct Black_hole::Main nic_root.construct(env, heap); env.parent().announce(env.ep().manage(*nic_root)); } + + if (_config_rom.xml().has_sub_node("uplink")) { + uplink_root.construct(env, heap); + env.parent().announce(env.ep().manage(*uplink_root)); + } } }; diff --git a/repos/os/src/server/black_hole/uplink.h b/repos/os/src/server/black_hole/uplink.h new file mode 100644 index 0000000000..6cb65d6548 --- /dev/null +++ b/repos/os/src/server/black_hole/uplink.h @@ -0,0 +1,171 @@ +/* + * \brief Uplink session component and root + * \author Martin Stein + * \date 2022-02-12 + */ + +/* + * Copyright (C) 2022 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _UPLINK_H_ +#define _UPLINK_H_ + +/* base includes */ +#include +#include + +/* os includes */ +#include +#include + +namespace Black_hole { + + using namespace Genode; + + class Uplink_session_base; + class Uplink_session; + class Uplink_root; +} + + +class Black_hole::Uplink_session_base +{ + friend class Uplink_session; + + private: + + class Buffer + { + private: + + Ram_allocator &_ram_alloc; + Ram_dataspace_capability _ram_ds; + + public: + + Buffer(Ram_allocator &ram_alloc, + size_t const size) + : + _ram_alloc { ram_alloc }, + _ram_ds { ram_alloc.alloc(size) } + { } + + ~Buffer() { _ram_alloc.free(_ram_ds); } + + Dataspace_capability ds() const { return _ram_ds; } + }; + + Env &_env; + Allocator &_alloc; + Nic::Packet_allocator _packet_alloc; + Buffer _tx_buf; + Buffer _rx_buf; + + public: + + Uplink_session_base(Env &env, + size_t tx_buf_size, + size_t rx_buf_size, + Allocator &alloc) + : + _env { env }, + _alloc { alloc }, + _packet_alloc { &_alloc }, + _tx_buf { _env.ram(), tx_buf_size }, + _rx_buf { _env.ram(), rx_buf_size } + { } +}; + + +class Black_hole::Uplink_session : private Uplink_session_base, + public Uplink::Session_rpc_object +{ + private: + + Signal_handler _packet_stream_handler; + + void _handle_packet_stream() + { + while (_tx.sink()->packet_avail()) { + + if (!_tx.sink()->ready_to_ack()) { + return; + } + Packet_descriptor const pkt { _tx.sink()->get_packet() }; + if (!pkt.size() || !_tx.sink()->packet_valid(pkt)) { + continue; + } + _tx.sink()->acknowledge_packet(pkt); + } + } + + public: + + Uplink_session(Env &env, + size_t tx_buf_size, + size_t rx_buf_size, + Allocator &alloc) + : + Uplink_session_base { env, tx_buf_size,rx_buf_size, alloc }, + Session_rpc_object { + _env.rm(), _tx_buf.ds(), _rx_buf.ds() ,&_packet_alloc, + _env.ep().rpc_ep() }, + + _packet_stream_handler { + env.ep(), *this, &Uplink_session::_handle_packet_stream } + { + _tx.sigh_ready_to_ack (_packet_stream_handler); + _tx.sigh_packet_avail (_packet_stream_handler); + _rx.sigh_ack_avail (_packet_stream_handler); + _rx.sigh_ready_to_submit(_packet_stream_handler); + } +}; + + +class Black_hole::Uplink_root : public Root_component +{ + private: + + Env &_env; + + Uplink_session *_create_session(char const *args) override + { + size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0); + + /* deplete ram quota by the memory needed for the session structure */ + size_t session_size = max(4096UL, (size_t)sizeof(Uplink_session)); + if (ram_quota < session_size) + throw Insufficient_ram_quota(); + + /* + * Check if donated ram quota suffices for both communication + * buffers and check for overflow + */ + if (tx_buf_size + rx_buf_size < tx_buf_size || + tx_buf_size + rx_buf_size > ram_quota - session_size) { + error("insufficient 'ram_quota', got ", ram_quota, ", " + "need ", tx_buf_size + rx_buf_size + session_size); + throw Insufficient_ram_quota(); + } + + return new (md_alloc()) + Uplink_session(_env, tx_buf_size, rx_buf_size, *md_alloc()); + } + + public: + + Uplink_root(Env &env, + Allocator &alloc) + : + Root_component { &env.ep().rpc_ep(), &alloc }, + _env { env } + { } +}; + +#endif /* _UPLINK_H_ */ diff --git a/repos/os/src/test/black_hole/main.cc b/repos/os/src/test/black_hole/main.cc index 0e73b4c0a9..e20fe9714c 100644 --- a/repos/os/src/test/black_hole/main.cc +++ b/repos/os/src/test/black_hole/main.cc @@ -14,12 +14,14 @@ /* base includes */ #include #include +#include /* os includes */ #include #include #include #include +#include #include #include #include @@ -40,30 +42,99 @@ class Test::Main enum { NIC_BUF_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE * 128, NIC_PKT_SIZE = 100, + UPLINK_BUF_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE * 128, + UPLINK_PKT_SIZE = 100, }; - Env &_env; - Heap _heap { _env.ram(), _env.rm() }; - Event::Connection _event { _env }; - Capture::Connection _capture { _env }; - Capture::Area _capture_screen_size { 1, 1 }; - Capture::Pixel _capture_pixels[1]; - Surface _capture_surface { _capture_pixels, _capture_screen_size }; - Capture::Connection::Screen _capture_screen { _capture, _env.rm(), _capture_screen_size }; - Audio_in::Connection _audio_in { _env, "left" }; - Audio_out::Connection _audio_out { _env, "left" }; - Allocator_avl _nic_tx_blk_alloc { &_heap }; - Nic::Connection _nic { _env, &_nic_tx_blk_alloc, NIC_BUF_SIZE, NIC_BUF_SIZE }; - Signal_handler
_nic_handler { _env.ep(), *this, &Main::_handle_nic }; - unsigned long _nic_pkt_count { 0 }; + Env &_env; + Heap _heap { _env.ram(), _env.rm() }; + Event::Connection _event { _env }; + Capture::Connection _capture { _env }; + Capture::Area _capture_screen_size { 1, 1 }; + Capture::Pixel _capture_pixels[1]; + Surface _capture_surface { _capture_pixels, _capture_screen_size }; + Capture::Connection::Screen _capture_screen { _capture, _env.rm(), _capture_screen_size }; + Audio_in::Connection _audio_in { _env, "left" }; + Audio_out::Connection _audio_out { _env, "left" }; + Allocator_avl _nic_tx_blk_alloc { &_heap }; + Nic::Connection _nic { _env, &_nic_tx_blk_alloc, NIC_BUF_SIZE, NIC_BUF_SIZE }; + Signal_handler
_nic_handler { _env.ep(), *this, &Main::_handle_nic }; + unsigned long _nic_pkt_count { 0 }; + Allocator_avl _uplink_tx_blk_alloc { &_heap }; + Constructible _uplink { }; + Signal_handler
_uplink_handler { _env.ep(), *this, &Main::_handle_uplink }; + unsigned long _uplink_pkt_count { 0 }; void _check_if_test_has_finished() { - if (_nic_pkt_count > 100) { + if (_nic_pkt_count > 100 && + _uplink_pkt_count > 100) { + log("Finished"); } } + void _reconstruct_uplink() + { + _uplink.destruct(); + _uplink.construct( + _env, &_uplink_tx_blk_alloc, UPLINK_BUF_SIZE, + UPLINK_BUF_SIZE, Net::Mac_address { 2 }); + + _uplink->tx_channel()->sigh_ready_to_submit(_uplink_handler); + _uplink->tx_channel()->sigh_ack_avail(_uplink_handler); + _uplink->rx_channel()->sigh_ready_to_ack(_uplink_handler); + _uplink->rx_channel()->sigh_packet_avail(_uplink_handler); + } + + void _handle_uplink() + { + if (!_uplink.constructed()) { + return; + } + if (_uplink->rx()->packet_avail()) { + class Uplink_rx_packet_avail { }; + throw Uplink_rx_packet_avail { }; + } + if (!_uplink->rx()->ack_slots_free()) { + class Uplink_no_rx_ack_slots_free { }; + throw Uplink_no_rx_ack_slots_free { }; + } + while (_uplink->tx()->ack_avail()) { + + Packet_descriptor const pkt { _uplink->tx()->get_acked_packet() }; + if (pkt.size() != UPLINK_PKT_SIZE) { + class Uplink_packet_size_unexpected { }; + throw Uplink_packet_size_unexpected { }; + } + _uplink->tx()->release_packet(pkt); + _uplink_pkt_count++; + } + _submit_uplink_pkts(); + _check_if_test_has_finished(); + } + + void _submit_uplink_pkts() + { + for (unsigned idx { 0 }; idx < 40; idx++) { + + if (idx == 10) { + _reconstruct_uplink(); + } + if (!_uplink->tx()->ready_to_submit()) { + class Uplink_submit_queue_full { }; + throw Uplink_submit_queue_full { }; + } + Packet_descriptor pkt; + try { pkt = _uplink->tx()->alloc_packet(UPLINK_PKT_SIZE); } + catch (...) { + class Uplink_packet_alloc_failed { }; + throw Uplink_packet_alloc_failed { }; + } + _uplink->tx()->submit_packet(pkt); + } + } + void _handle_nic() { if (_nic.rx()->packet_avail()) { @@ -110,6 +181,10 @@ class Test::Main Main(Env &env) : _env { env } { + /* test-drive uplink connection */ + _reconstruct_uplink(); + _submit_uplink_pkts(); + /* test-drive nic connection */ _nic.tx_channel()->sigh_ready_to_submit(_nic_handler); _nic.tx_channel()->sigh_ack_avail(_nic_handler);