diff --git a/repos/os/recipes/pkg/drivers_nic-virt_qemu/README b/repos/os/recipes/pkg/drivers_nic-virt_qemu/README new file mode 100644 index 0000000000..b9ad938515 --- /dev/null +++ b/repos/os/recipes/pkg/drivers_nic-virt_qemu/README @@ -0,0 +1,3 @@ + + Device drivers needed for scenarios + using one network interface diff --git a/repos/os/recipes/pkg/drivers_nic-virt_qemu/archives b/repos/os/recipes/pkg/drivers_nic-virt_qemu/archives new file mode 100644 index 0000000000..9aae66c752 --- /dev/null +++ b/repos/os/recipes/pkg/drivers_nic-virt_qemu/archives @@ -0,0 +1,4 @@ +_/raw/drivers_nic-virt_qemu +_/src/virtdev_rom +_/src/platform_drv +_/src/virtio_nic_drv diff --git a/repos/os/recipes/pkg/drivers_nic-virt_qemu/hash b/repos/os/recipes/pkg/drivers_nic-virt_qemu/hash new file mode 100644 index 0000000000..98a66e8f74 --- /dev/null +++ b/repos/os/recipes/pkg/drivers_nic-virt_qemu/hash @@ -0,0 +1 @@ +2020-07-01 45d2ce0a7e352afa423739b9c1de5435511f30b0 diff --git a/repos/os/recipes/raw/drivers_nic-virt_qemu/content.mk b/repos/os/recipes/raw/drivers_nic-virt_qemu/content.mk new file mode 100644 index 0000000000..78a408f9d6 --- /dev/null +++ b/repos/os/recipes/raw/drivers_nic-virt_qemu/content.mk @@ -0,0 +1,4 @@ +content: drivers.config + +drivers.config: + cp $(REP_DIR)/recipes/raw/drivers_nic-virt_qemu/$@ $@ diff --git a/repos/os/recipes/raw/drivers_nic-virt_qemu/drivers.config b/repos/os/recipes/raw/drivers_nic-virt_qemu/drivers.config new file mode 100644 index 0000000000..6ee156fa50 --- /dev/null +++ b/repos/os/recipes/raw/drivers_nic-virt_qemu/drivers.config @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/os/recipes/raw/drivers_nic-virt_qemu/hash b/repos/os/recipes/raw/drivers_nic-virt_qemu/hash new file mode 100644 index 0000000000..b420d1cb74 --- /dev/null +++ b/repos/os/recipes/raw/drivers_nic-virt_qemu/hash @@ -0,0 +1 @@ +2020-07-01 a13f65f854fef31aaca5c1183f4e80d47f7797ef diff --git a/repos/os/recipes/src/virtio_nic_drv/content.mk b/repos/os/recipes/src/virtio_nic_drv/content.mk new file mode 100644 index 0000000000..e61c9b01d1 --- /dev/null +++ b/repos/os/recipes/src/virtio_nic_drv/content.mk @@ -0,0 +1,2 @@ +SRC_DIR = src/drivers/nic/virtio +include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/os/recipes/src/virtio_nic_drv/hash b/repos/os/recipes/src/virtio_nic_drv/hash new file mode 100644 index 0000000000..9d7a1d664a --- /dev/null +++ b/repos/os/recipes/src/virtio_nic_drv/hash @@ -0,0 +1 @@ +2020-07-01-b 330640a1c3dddf5e18087e03155638fbd4bbd567 diff --git a/repos/os/recipes/src/virtio_nic_drv/used_apis b/repos/os/recipes/src/virtio_nic_drv/used_apis new file mode 100644 index 0000000000..626bf71970 --- /dev/null +++ b/repos/os/recipes/src/virtio_nic_drv/used_apis @@ -0,0 +1,5 @@ +base +os +virtio +nic_session +platform_session diff --git a/repos/os/src/drivers/nic/virtio/README b/repos/os/src/drivers/nic/virtio/README new file mode 100644 index 0000000000..558e915789 --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/README @@ -0,0 +1,44 @@ +This directory contains the implementation of Genode's VirtIO NIC driver. + +Brief +===== + +The driver implements virtual ethernet card driver as defined in section +5.1 of Virtial I/O Device (VIRTIO) Version 1.0 specification. The device +is exposed to the rest of the system via standard Genode NIC session +interface. + +This driver does not require, or utilize any advanced VirtIO ethernet +device features such as VLAN filtering, or checksum offloading. + +Configuration +============= + +The following config illustrates how the driver is configured: + +! +! +! +! +! + +The rx_queue_size and tx_queue_size parameters define the maximum number +buffers the transmit and receive virtio queues can hold. The buffers +used by both queues are pre-allocated on device initialization. The +rx_buffer_size and tx_buffer_size can be used to specify sizes of those +pre-allocated buffers. + +The default values of the presented configuration parameters the driver +uses were selected to minimize driver memory usage without negatively +affecting performance. Testing was done on Qemu arm_v8a, arm_v8a, and +x86_64 machines. These values might not be suitable for more advanted +usage scenarios. + +The mac configuration parameter can be used to override the default +device MAC address obtained from VirtIO configuration space. + +The driver does produce some additional logs when verbose parameter is set +to true. diff --git a/repos/os/src/drivers/nic/virtio/component.h b/repos/os/src/drivers/nic/virtio/component.h new file mode 100644 index 0000000000..1f1b53e55f --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/component.h @@ -0,0 +1,523 @@ +/* + * \brief VirtIO NIC driver component + * \author Piotr Tworek + * \date 2019-09-27 + */ + +/* + * Copyright (C) 2019 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. + */ + +/* Need to come before attached_rom_dataspace.h */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Virtio_nic { + using namespace Genode; + struct Main; + class Root; + class Session_component; +} + + +class Virtio_nic::Session_component : public Nic::Session_component +{ + private: + + /* + * Noncopyable + */ + Session_component(Session_component const &); + Session_component &operator = (Session_component const &); + + struct Unsupported_version : Genode::Exception { }; + struct Device_init_failed : Genode::Exception { }; + struct Features_init_failed : Genode::Exception { }; + struct Queue_init_failed : Genode::Exception { }; + + struct Hardware_features + { + Nic::Mac_address mac = { }; + bool link_status_available = false; + }; + + /** + * See section 5.1.6 of VirtIO 1.0 specification. + */ + struct Virtio_net_header + { + enum Flags : Genode::uint16_t + { + NEEDS_CSUM = 1, + }; + + enum GSO : Genode::uint16_t + { + NONE = 0, + TCPV4 = 1, + UDP = 3, + TCPV6 = 4, + ECN = 0x80, + }; + + uint8_t flags = 0; + uint8_t gso_type = GSO::NONE; + uint16_t hdr_len = 0; + uint16_t gso_size = 0; + uint16_t csum_start = 0; + uint16_t csum_offset = 0; + uint16_t num_buffers = 0; + }; + + /** + * VirtIO feature bits relevant to this VirtIO net driver implementation. + */ + struct Features : Genode::Register<64> + { + struct CSUM : Bitfield<0, 1> { }; + struct GUEST_CSUM : Bitfield<1, 1> { }; + struct MTU : Bitfield<3, 1> { }; + struct MAC : Bitfield<5, 1> { }; + struct GSO : Bitfield<6, 1> { }; + struct GUEST_TSO4 : Bitfield<7, 1> { }; + struct GUEST_TSO6 : Bitfield<8, 1> { }; + struct GUEST_ECN : Bitfield<9, 1> { }; + struct GUEST_UFO : Bitfield<10, 1> { }; + struct HOST_TSO4 : Bitfield<11, 1> { }; + struct HOST_TSO6 : Bitfield<12, 1> { }; + struct HOST_ECN : Bitfield<13, 1> { }; + struct HOST_UFO : Bitfield<14, 1> { }; + struct MRG_RXBUF : Bitfield<15, 1> { }; + struct STATUS : Bitfield<16, 1> { }; + struct CTRL_VQ : Bitfield<17, 1> { }; + struct CTRL_RX : Bitfield<18, 1> { }; + struct CTRL_VLAN : Bitfield<19, 1> { }; + struct GUEST_ANNOUNCE : Bitfield<21, 1> { }; + struct MQ : Bitfield<22, 1> { }; + struct CTRL_MAC_ADDR : Bitfield<23, 1> { }; + struct EVENT_IDX : Bitfield<29, 1> { }; + struct VERSION_1 : Bitfield<32, 1> { }; + }; + + /** + * See section 5.1.4 of VirtIO 1.0 specification. + */ + enum { CONFIG_MAC_BASE = 0, CONFIG_STATUS = 6 }; + enum { STATUS_LINK_UP = 1 << 0 }; + + /** + * Available VirtIO queue numbers, see section 5.1.2 of VirtIO 1.0 specification. + */ + enum Vq_id : Genode::uint16_t { RX_VQ = 0, TX_VQ = 1 }; + + /** + * Each VirtIO queue contains fixed number of buffers. The most common size of the buffer + * is 1526 bytes (size of ethernet frame + Virtio_net_header). VirtIO queue size must be + * a power of 2. Each VirtIO queue needs some additional space for the descriptor table, + * available and used rings. The default VirtIO queue parameter values defined here have + * been selected to make Ram_dataspace used by both TX and RX VirtIO queues consume around + * 32Kb of RAM. + */ + static const uint16_t DEFAULT_VQ_SIZE = 16; + static const uint16_t DEFAULT_VQ_BUF_SIZE = 2020; + + struct Rx_queue_traits + { + static const bool device_write_only = true; + static const bool has_data_payload = true; + }; + + struct Tx_queue_traits + { + static const bool device_write_only = false; + static const bool has_data_payload = true; + }; + + typedef Virtio::Queue Rx_queue_type; + typedef Virtio::Queue Tx_queue_type; + typedef Genode::Signal_handler Signal_handler; + + + bool const _verbose; + Virtio::Device &_device; + Hardware_features const _hw_features; + Rx_queue_type _rx_vq; + Tx_queue_type _tx_vq; + Irq_session_client _irq; + Signal_handler _irq_handler; + bool _link_up = false; + + + void _init_virtio_device() + { + using Status = Virtio::Device::Status; + + if (!_device.set_status(Status::RESET)) { + error("Failed to reset the device!"); + throw Device_init_failed(); + } + + if (!_device.set_status(Status::ACKNOWLEDGE)) { + error("Failed to acknowledge the device!"); + throw Device_init_failed(); + } + + if (!_device.set_status(Status::DRIVER)) { + _device.set_status(Status::FAILED); + error("Device initialization failed!"); + throw Device_init_failed(); + } + } + + static Nic::Mac_address _read_mac_address(Virtio::Device &device) + { + Nic::Mac_address mac = {}; + + /* See section 2.3.1 of VirtIO 1.0 spec for rationale. */ + uint32_t before = 0, after = 0; + do { + before = device.get_config_generation(); + for (size_t idx = 0; idx < sizeof(mac.addr); ++idx) { + mac.addr[idx] = device.read_config( + CONFIG_MAC_BASE + idx, Virtio::Device::ACCESS_8BIT); + } + after = device.get_config_generation(); + } while (after != before); + + return mac; + } + + Hardware_features _init_hw_features(Xml_node const &xml) + { + _init_virtio_device(); + + using Status = Virtio::Device::Status; + + const uint32_t low = _device.get_features(0); + const uint32_t high = _device.get_features(1); + const Features::access_t device_features = ((uint64_t)high << 32) | low; + Features::access_t driver_features = 0; + + /* This driver does not support legacy VirtIO versions. */ + if (!Features::VERSION_1::get(device_features)) { + error("Unsupprted VirtIO device version!"); + throw Features_init_failed(); + } + Features::VERSION_1::set(driver_features); + + Hardware_features hw_features; + + if (Features::MAC::get(device_features)) { + Features::MAC::set(driver_features); + hw_features.mac = _read_mac_address(_device); + } + + hw_features.mac = xml.attribute_value("mac", hw_features.mac); + + if (hw_features.mac == Nic::Mac_address()) { + error("HW mac address missing and not provided via config!"); + throw Features_init_failed(); + } + + if (Features::STATUS::get(device_features)) { + Features::STATUS::set(driver_features); + hw_features.link_status_available = true; + } + + _device.set_features(0, (uint32_t)driver_features); + _device.set_features(1, (uint32_t)(driver_features >> 32)); + + if (!_device.set_status(Status::FEATURES_OK)) { + _device.set_status(Status::FAILED); + error("Device feature negotiation failed!"); + throw Features_init_failed(); + } + + return hw_features; + } + + Genode::uint16_t _vq_size(Vq_id vq, Xml_node const &xml, char const *cfg_attr) + { + const uint16_t max_vq_size = _device.get_max_queue_size(vq); + + if (max_vq_size == 0) { + error("VirtIO queue ", (int)vq, " is not available!"); + throw Queue_init_failed(); + } + + const uint16_t vq_size = Genode::min(xml.attribute_value(cfg_attr, DEFAULT_VQ_SIZE), + max_vq_size); + + if (_verbose) + log("VirtIO queue ", (int)vq, " size: ", vq_size, " (max: ", max_vq_size, ")"); + + return vq_size; + } + + uint16_t _buf_size(Vq_id vq, Xml_node const &xml, char const *cfg_attr) + { + const uint16_t vq_buf_size = xml.attribute_value(cfg_attr, DEFAULT_VQ_BUF_SIZE ); + if (_verbose) + log("VirtIO queue ", (int)vq, " buffer size: ", Number_of_bytes(vq_buf_size), "b"); + return vq_buf_size; + } + + void _setup_virtio_queues() + { + if (!_device.configure_queue(RX_VQ, _rx_vq.description())) { + error("Failed to initialize rx VirtIO queue!"); + throw Queue_init_failed(); + } + + if (!_device.configure_queue(TX_VQ, _tx_vq.description())) { + error("Failed to initialize tx VirtIO queue!"); + throw Queue_init_failed(); + } + + using Status = Virtio::Device::Status; + if (!_device.set_status(Status::DRIVER_OK)) { + _device.set_status(Status::FAILED); + error("Failed to initialize VirtIO queues!"); + throw Queue_init_failed(); + } + } + + void _handle_irq() + { + const uint32_t reasons = _device.read_isr(); + + enum { IRQ_USED_RING_UPDATE = 1, IRQ_CONFIG_CHANGE = 2 }; + + if (_tx_vq.has_used_buffers()) + _tx_vq.ack_all_transfers(); + + if (reasons & IRQ_USED_RING_UPDATE) { + _receive(); + } + + if ((reasons & IRQ_CONFIG_CHANGE) && _hw_features.link_status_available && + (link_state() != _link_up)) { + _link_up = !_link_up; + if (_verbose) + log("Link status changed: ", (_link_up ? "on-line" : "off-line")); + _link_state_changed(); + } + + _irq.ack_irq(); + } + + bool _send() + { + if (!_tx.sink()->ready_to_ack()) + return false; + + if (!_tx.sink()->packet_avail()) + return false; + + auto packet = _tx.sink()->get_packet(); + if (!packet.size() || !_tx.sink()->packet_valid(packet)) { + warning("Invalid tx packet"); + return true; + } + + if (link_state()) { + Virtio_net_header hdr; + auto const *data = _tx.sink()->packet_content(packet); + if (!_tx_vq.write_data(hdr, data, packet.size(), false)) { + warning("Failed to push packet into tx VirtIO queue!"); + return false; + } + } + + _tx.sink()->acknowledge_packet(packet); + return true; + } + + void _receive() + { + auto rcv_func = [&] (Virtio_net_header const &, + char const *data, + size_t size) { + if (!_rx.source()->ready_to_submit()) { + Genode::warning("Not ready to submit!"); + return false; + } + + try { + auto p = _rx.source()->alloc_packet(size); + char *dst = _rx.source()->packet_content(p); + Genode::memcpy(dst, data, size); + _rx.source()->submit_packet(p); + } catch (Session::Rx::Source::Packet_alloc_failed) { + Genode::warning("Packet alloc failed!"); + return false; + } + + return true; + }; + + while (_rx_vq.has_used_buffers()) + _rx_vq.read_data(rcv_func); + + /** + * Inform the device the buffers we've just consumed are ready + * to used again + */ + _device.notify_buffers_available(RX_VQ); + } + + void _handle_packet_stream() override + { + while (_rx.source()->ack_avail()) + _rx.source()->release_packet(_rx.source()->get_acked_packet()); + + /* Reclaim all buffers processed by the device. */ + if (_tx_vq.has_used_buffers()) + _tx_vq.ack_all_transfers(); + + bool sent_packets = false; + while (_send()) + sent_packets = true; + + if (sent_packets) { + _device.notify_buffers_available(TX_VQ); + } + } + + public: + + bool link_state() override + { + /** + * According to docs when STATUS feature is not available or has not + * been negotiated the driver should assume the link is always active. + * See section 5.1.4.2 of VIRTIO 1.0 specification. + */ + if (!_hw_features.link_status_available) + return true; + + uint32_t before = 0, after = 0; + uint8_t status = 0; + do { + before = _device.get_config_generation(); + status = _device.read_config(CONFIG_STATUS, Virtio::Device::ACCESS_8BIT); + after = _device.get_config_generation(); + } while (after != before); + + return status & STATUS_LINK_UP; + } + + Nic::Mac_address mac_address() override { return _hw_features.mac; } + + Session_component(Genode::Env &env, + Genode::Allocator &rx_block_md_alloc, + Virtio::Device &device, + Irq_session_capability irq_cap, + Genode::Xml_node const &xml, + Genode::size_t const tx_buf_size, + Genode::size_t const rx_buf_size) + try : Nic::Session_component(tx_buf_size, rx_buf_size, Genode::CACHED, + rx_block_md_alloc, env), + _verbose(xml.attribute_value("verbose", false)), + _device(device), + _hw_features(_init_hw_features(xml)), + _rx_vq(env.ram(), env.rm(), + _vq_size(RX_VQ, xml, "rx_queue_size"), + _buf_size(RX_VQ, xml, "rx_buffer_size")), + _tx_vq(env.ram(), env.rm(), + _vq_size(TX_VQ, xml, "tx_queue_size"), + _buf_size(TX_VQ, xml, "tx_buffer_size")), + _irq(irq_cap), + _irq_handler(env.ep(), *this, &Session_component::_handle_irq), + _link_up(link_state()) + { + _setup_virtio_queues(); + _irq.sigh(_irq_handler); + _irq.ack_irq(); + + _link_state_changed(); + + if (_verbose) + Genode::log("Mac address: ", mac_address()); + } + catch (Tx_queue_type::Invalid_buffer_size) + { + error("Invalid TX VirtIO queue buffer size specified!"); + throw; + } + catch (Rx_queue_type::Invalid_buffer_size) + { + error("Invalid RX VirtIO queue buffer size specified!"); + throw; + } + + ~Session_component() { + _device.set_status(Virtio::Device::Status::RESET); + } +}; + + +class Virtio_nic::Root : public Genode::Root_component +{ + private: + + struct Device_not_found : Genode::Exception { }; + + /* + * Noncopyable + */ + Root(Root const &) = delete; + Root &operator = (Root const &) = delete; + + Genode::Env &_env; + Virtio::Device &_device; + Irq_session_capability _irq_cap; + + Session_component *_create_session(const char *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); + + /* + * 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) { + error("insufficient 'ram_quota', got ", ram_quota, ", " + "need ", tx_buf_size + rx_buf_size); + throw Genode::Insufficient_ram_quota(); + } + + Attached_rom_dataspace rom(_env, "config"); + + try { + return new (md_alloc()) Session_component( + _env, *md_alloc(), _device, _irq_cap, rom.xml(), + tx_buf_size, rx_buf_size); + } catch (...) { throw Service_denied(); } + } + + public: + + Root(Env &env, + Allocator &md_alloc, + Virtio::Device &device, + Irq_session_capability irq_cap) + : Root_component(env.ep(), md_alloc), + _env(env), _device(device), _irq_cap(irq_cap) + { } +}; diff --git a/repos/os/src/drivers/nic/virtio/config.xsd b/repos/os/src/drivers/nic/virtio/config.xsd new file mode 100644 index 0000000000..9deae92320 --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/config.xsd @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/os/src/drivers/nic/virtio/mmio_device.cc b/repos/os/src/drivers/nic/virtio/mmio_device.cc new file mode 100644 index 0000000000..f8f27b3db0 --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/mmio_device.cc @@ -0,0 +1,86 @@ +/* + * \brief VirtIO MMIO NIC driver + * \author Piotr Tworek + * \date 2019-09-27 + */ + +/* + * Copyright (C) 2019 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. + */ + +#include +#include +#include +#include + +#include "component.h" + +namespace Virtio_mmio_nic { + using namespace Genode; + struct Main; +} + +struct Virtio_mmio_nic::Main +{ + struct Device_not_found : Genode::Exception { }; + + struct Device_info { + using String = Genode::String<64>; + + String name {}; + size_t io_mem_offset = 0; + + Device_info(Platform::Connection & platform) { + bool found = false; + platform.with_xml([&] (Xml_node & xml) { + xml.for_each_sub_node("device", [&] (Xml_node node) { + if (found) return; + + node.for_each_sub_node("property", [&] (Xml_node node) { + if ((node.attribute_value("name", String()) == "type") && + (node.attribute_value("value", String()) == "nic")) { + found = true; } + }); + + if (!found) return; + + name = node.attribute_value("name", String()); + + node.for_each_sub_node("io_mem", [&] (Xml_node node) { + io_mem_offset = node.attribute_value("page_offset", 0); + }); + }); + }); + if (!found) { + error("No device was found"); + throw Device_not_found(); + } + } + }; + + Genode::Env &env; + Genode::Heap heap { env.ram(), env.rm() }; + Platform::Connection platform { env }; + Device_info info { platform }; + Platform::Device_client platform_device { platform.acquire_device(info.name.string()) }; + Virtio::Device virtio_device { env, platform_device.io_mem_dataspace(), + info.io_mem_offset }; + Virtio_nic::Root root { env, heap, virtio_device, platform_device.irq() }; + + Main(Env &env) + try : env(env) + { + log("--- VirtIO MMIO NIC driver started ---"); + env.parent().announce(env.ep().manage(root)); + } + catch (...) { env.parent().exit(-1); } +}; + + +void Component::construct(Genode::Env &env) +{ + static Virtio_mmio_nic::Main main(env); +} diff --git a/repos/os/src/drivers/nic/virtio/pci_device.cc b/repos/os/src/drivers/nic/virtio/pci_device.cc new file mode 100644 index 0000000000..abef1ca5ea --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/pci_device.cc @@ -0,0 +1,60 @@ +/* + * \brief VirtIO PCI NIC driver + * \author Piotr Tworek + * \date 2019-09-27 + */ + +/* + * Copyright (C) 2019 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. + */ + +#include +#include +#include +#include + +#include "component.h" + +namespace Virtio_pci_nic { + using namespace Genode; + struct Main; +} + +struct Virtio_pci_nic::Main +{ + struct Device_not_found : Genode::Exception { }; + + Genode::Env &env; + Genode::Heap heap{ env.ram(), env.rm() }; + Platform::Connection pci { env }; + Platform::Device_client platform_device; + Virtio::Device virtio_device { env, platform_device }; + Virtio_nic::Root root { env, heap, virtio_device, platform_device.irq(0) }; + + Platform::Device_capability find_platform_device() + { + Platform::Device_capability device_cap; + pci.with_upgrade([&] () { device_cap = pci.first_device(); }); + + if (!device_cap.valid()) throw Device_not_found(); + + return device_cap; + } + + Main(Env &env) + try : env(env), platform_device(find_platform_device()) + { + log("--- VirtIO PCI driver started ---"); + env.parent().announce(env.ep().manage(root)); + } + catch (...) { env.parent().exit(-1); } +}; + + +void Component::construct(Genode::Env &env) +{ + static Virtio_pci_nic::Main main(env); +} diff --git a/repos/os/src/drivers/nic/virtio/spec/arm/target.mk b/repos/os/src/drivers/nic/virtio/spec/arm/target.mk new file mode 100644 index 0000000000..73920eeb1e --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/spec/arm/target.mk @@ -0,0 +1,3 @@ +REQUIRES = arm + +include $(REP_DIR)/src/drivers/nic/virtio/target_mmio.inc diff --git a/repos/os/src/drivers/nic/virtio/spec/arm_64/target.mk b/repos/os/src/drivers/nic/virtio/spec/arm_64/target.mk new file mode 100644 index 0000000000..ba17e4f3b6 --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/spec/arm_64/target.mk @@ -0,0 +1,3 @@ +REQUIRES = arm_64 + +include $(REP_DIR)/src/drivers/nic/virtio/target_mmio.inc diff --git a/repos/os/src/drivers/nic/virtio/spec/x86/target.mk b/repos/os/src/drivers/nic/virtio/spec/x86/target.mk new file mode 100644 index 0000000000..e8445fab6e --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/spec/x86/target.mk @@ -0,0 +1,8 @@ +TARGET = virtio_pci_nic +REQUIRES = x86 +SRC_CC = pci_device.cc +LIBS = base +INC_DIR = $(REP_DIR)/src/drivers/nic/virtio +CONFIG_XSD = ../../config.xsd + +vpath % $(REP_DIR)/src/drivers/nic/virtio diff --git a/repos/os/src/drivers/nic/virtio/target_mmio.inc b/repos/os/src/drivers/nic/virtio/target_mmio.inc new file mode 100644 index 0000000000..0723a56c05 --- /dev/null +++ b/repos/os/src/drivers/nic/virtio/target_mmio.inc @@ -0,0 +1,7 @@ +TARGET = virtio_mmio_nic +SRC_CC = mmio_device.cc +LIBS = base +INC_DIR = $(REP_DIR)/src/drivers/nic/virtio +CONFIG_XSD = ../../config.xsd + +vpath % $(REP_DIR)/src/drivers/nic/virtio diff --git a/tool/run/depot.inc b/tool/run/depot.inc index 7a25196308..0a70438fa8 100644 --- a/tool/run/depot.inc +++ b/tool/run/depot.inc @@ -487,7 +487,7 @@ proc drivers_nic_pkg { } { if {[have_spec imx6q_sabrelite]} { return drivers_nic-imx6q_sabrelite } if {[have_spec imx7d_sabre]} { return drivers_nic-imx7d_sabre } if {[have_spec imx8q_evk]} { return drivers_nic-imx8q_evk } - + if {[have_spec virt_qemu]} { return drivers_nic-virt_qemu } puts stderr "drivers_nic package undefined for this build configuration" exit 1 diff --git a/tool/run/qemu.inc b/tool/run/qemu.inc index 7e20b37b0e..b67fca67c9 100644 --- a/tool/run/qemu.inc +++ b/tool/run/qemu.inc @@ -29,7 +29,12 @@ proc append_qemu_nic_args { { extra_netdev_args "" } } { append qemu_args ",$extra_netdev_args" } - append qemu_args " -net nic,model=[qemu_nic_model],netdev=net0 " + if {[have_spec virt_qemu]} { + append qemu_args " -global virtio-mmio.force-legacy=false " + append qemu_args " -device virtio-net-device,bus=virtio-mmio-bus.0,netdev=net0 " + } else { + append qemu_args " -net nic,model=[qemu_nic_model],netdev=net0 " + } }