diff --git a/repos/os/include/virtio/pci_device.h b/repos/os/include/virtio/pci_device.h index 57e4c99a1d..088e494ace 100644 --- a/repos/os/include/virtio/pci_device.h +++ b/repos/os/include/virtio/pci_device.h @@ -14,10 +14,7 @@ #ifndef _INCLUDE__VIRTIO__PCI_DEVICE_H_ #define _INCLUDE__VIRTIO__PCI_DEVICE_H_ -#include -#include -#include -#include +#include #include namespace Virtio { @@ -26,7 +23,7 @@ namespace Virtio { class Device; } -struct Virtio::Device_mmio : public Attached_mmio +struct Virtio::Device_mmio : public Genode::Mmio { struct DeviceFeatureSelect : Register<0x00, 32> { }; struct DeviceFeature : Register<0x04, 32> { }; @@ -54,10 +51,7 @@ struct Virtio::Device_mmio : public Attached_mmio struct IrqReason : Register<0x0, 32> { }; - Device_mmio(Genode::Env &env, - Genode::addr_t base, - Genode::size_t size) - : Attached_mmio(env, base, size, false) { } + using Mmio::Mmio; }; class Virtio::Device @@ -93,133 +87,112 @@ class Virtio::Device enum { VIRTIO_PCI_BASE_ID = 0x1040, - VIRTIO_MSI_NO_VECTOR = 0xffff + VIRTIO_MSI_NO_VECTOR = 0xffff, + MMIO_MAX = 6U }; - Genode::Env &_env; - Platform::Device_client &_device; - Genode::Irq_session_client _irq { _device.irq(0) }; - uint32_t _notify_offset_multiplier = 0; - Genode::Constructible _cfg_common { }; - Genode::Constructible _dev_config { }; - Genode::Constructible _notify { }; - Genode::Constructible _isr { }; + Env & _env; + Platform::Connection & _plat; + Platform::Device _device { _plat }; + Platform::Device::Irq _irq { _device, { 0 } }; + Constructible _mmio[MMIO_MAX] { }; - void _configure() + Mmio _cfg_common { _bar_offset("common") }; + Mmio _dev_config { _bar_offset("device") }; + Mmio _notify { _bar_offset("notify") }; + Mmio _isr { _bar_offset("irq_status") }; + size_t _notify_offset_multiplier { 0 }; + + template + void with_virtio_range(String<16> type, FN const & fn) { - typedef Platform::Device Pdev; + _plat.update(); + _plat.with_xml([&] (Xml_node xml) { + xml.with_optional_sub_node("device", [&] (Xml_node xml) { + xml.with_optional_sub_node("pci-config", + [&] (Xml_node xml) { + xml.for_each_sub_node("virtio_range", + [&] (Xml_node xml) { + if (xml.attribute_value("type", String<16>()) == + type) + fn(xml); + }); + }); + }); + }); + } - enum { PCI_STATUS = 0x6, PCI_CAPABILITIES = 0x34, }; + addr_t _bar_offset(String<16> type) + { + unsigned idx = MMIO_MAX; + addr_t off = ~0UL; + with_virtio_range(type, [&] (Xml_node xml) { + idx = xml.attribute_value("index", MMIO_MAX); + off = xml.attribute_value("offset", ~0UL); + }); - auto status = _device.config_read(PCI_STATUS, Pdev::ACCESS_16BIT); - if (!(status & 0x10)) { - error("PCI capabilities missing according to device status!"); - throw Configuration_failed(); - } - - auto addr = _device.config_read(PCI_CAPABILITIES, Pdev::ACCESS_8BIT); - addr &= 0xFC; - - while (addr) { - enum { ID_VNDR = 0x09 }; - enum { CAP_ID = 0, CAP_LIST_NEXT = 1 }; - - auto const cap_id = _device.config_read(addr + CAP_ID, Pdev::ACCESS_8BIT); - auto const cap_next = _device.config_read(addr + CAP_LIST_NEXT, Pdev::ACCESS_8BIT); - - if (cap_id == ID_VNDR) { - enum { CFG_TYPE = 0x3, BAR = 0x4, OFFSET = 0x8, - LENGTH = 0xC, NOTIFY_OFFSET_MULT = 0x10 }; - enum { COMMON_CFG = 1, NOTIFY_CFG = 2, ISR_CFG = 3, - DEVICE_CFG = 4, PCI_CFG = 5 }; - - auto const cfg_type = _device.config_read(addr + CFG_TYPE, Pdev::ACCESS_8BIT); - auto const bar = _device.config_read(addr + BAR, Pdev::ACCESS_8BIT); - auto const off = _device.config_read(addr + OFFSET, Pdev::ACCESS_32BIT); - auto const len = _device.config_read(addr + LENGTH, Pdev::ACCESS_32BIT); - - if (cfg_type == COMMON_CFG) { - auto const r = _device.resource(bar); - _cfg_common.construct(_env, r.base() + off, len); - } else if (cfg_type == DEVICE_CFG) { - auto const r = _device.resource(bar); - _dev_config.construct(_env, r.base() + off, len); - } else if (cfg_type == NOTIFY_CFG) { - _notify_offset_multiplier = _device.config_read( - addr + NOTIFY_OFFSET_MULT, Pdev::ACCESS_32BIT); - auto const r = _device.resource(bar); - _notify.construct(_env, r.base() + off, len); - } else if (cfg_type == ISR_CFG) { - auto const r = _device.resource(bar); - _isr.construct(_env, r.base() + off, len); - } - } - - addr = cap_next; - } - - if (!_cfg_common.constructed() || !_dev_config.constructed() || - !_notify.constructed() || !_isr.constructed()) { - error("Required VirtIO PCI capabilities not found!"); + if (idx >= MMIO_MAX || off == ~0UL) throw Configuration_failed(); - } - _cfg_common->write(VIRTIO_MSI_NO_VECTOR); + if (!_mmio[idx].constructed()) + _mmio[idx].construct(_device, + Platform::Device::Mmio::Index{idx}); + return _mmio[idx]->base() + off; } public: - Device(Genode::Env &env, - Platform::Device_client device) - : _env(env), _device(device) + Device(Genode::Env & env, + Platform::Connection & plat) + : _env(env), _plat(plat) { - _configure(); + with_virtio_range("notify", [&] (Xml_node xml) { + _notify_offset_multiplier = xml.attribute_value("factor", 0UL); + }); + + _cfg_common.write(VIRTIO_MSI_NO_VECTOR); } - uint32_t vendor_id() { return _device.vendor_id(); } - uint32_t device_id() { - return _device.device_id() - VIRTIO_PCI_BASE_ID; } - uint8_t get_status() { - return _cfg_common->read(); } + return _cfg_common.read(); } bool set_status(uint8_t status) { - _cfg_common->write(status); - return _cfg_common->read() == status; + _cfg_common.write(status); + return _cfg_common.read() == status; } uint32_t get_features(uint32_t selection) { - _cfg_common->write(selection); - return _cfg_common->read(); + _cfg_common.write(selection); + return _cfg_common.read(); } void set_features(uint32_t selection, uint32_t features) { - _cfg_common->write(selection); - _cfg_common->write(features); + _cfg_common.write(selection); + _cfg_common.write(features); } uint8_t get_config_generation() { - return _cfg_common->read(); } + return _cfg_common.read(); } uint16_t get_max_queue_size(uint16_t queue_index) { - _cfg_common->write(queue_index); - return _cfg_common->read(); + _cfg_common.write(queue_index); + return _cfg_common.read(); } uint32_t read_config(uint8_t offset, Access_size size) { switch (size) { case Device::ACCESS_8BIT: - return _dev_config->read(offset); + return _dev_config.read(offset); case Device::ACCESS_16BIT: - return _dev_config->read(offset >> 1); + return _dev_config.read(offset >> 1); case Device::ACCESS_32BIT: - return _dev_config->read(offset >> 2); + return _dev_config.read(offset >> 2); } return 0; } @@ -228,63 +201,63 @@ class Virtio::Device { switch (size) { case Device::ACCESS_8BIT: - _dev_config->write(value, offset); + _dev_config.write(value, offset); break; case Device::ACCESS_16BIT: - _dev_config->write(value, offset >> 1); + _dev_config.write(value, offset >> 1); break; case Device::ACCESS_32BIT: - _dev_config->write(value, offset >> 2); + _dev_config.write(value, offset >> 2); break; } } bool configure_queue(uint16_t queue_index, Virtio::Queue_description desc) { - _cfg_common->write(queue_index); + _cfg_common.write(queue_index); - if (_cfg_common->read()) { + if (_cfg_common.read()) { warning("VirtIO queues can't be re-configured after being enabled!"); return false; } - _cfg_common->write(VIRTIO_MSI_NO_VECTOR); - if (_cfg_common->read() != VIRTIO_MSI_NO_VECTOR) { + _cfg_common.write(VIRTIO_MSI_NO_VECTOR); + if (_cfg_common.read() != VIRTIO_MSI_NO_VECTOR) { error("Failed to disable MSI-X for queue ", queue_index); return false; } - _cfg_common->write(desc.size); + _cfg_common.write(desc.size); uint64_t addr = desc.desc; - _cfg_common->write((uint32_t)addr); - _cfg_common->write((uint32_t)(addr >> 32)); + _cfg_common.write((uint32_t)addr); + _cfg_common.write((uint32_t)(addr >> 32)); addr = desc.avail; - _cfg_common->write((uint32_t)addr); - _cfg_common->write((uint32_t)(addr >> 32)); + _cfg_common.write((uint32_t)addr); + _cfg_common.write((uint32_t)(addr >> 32)); addr = desc.used; - _cfg_common->write((uint32_t)addr); - _cfg_common->write((uint32_t)(addr >> 32)); - _cfg_common->write(1); - return _cfg_common->read() != 0; + _cfg_common.write((uint32_t)addr); + _cfg_common.write((uint32_t)(addr >> 32)); + _cfg_common.write(1); + return _cfg_common.read() != 0; } void notify_buffers_available(uint16_t queue_index) { - _cfg_common->write(queue_index); - auto const offset = _cfg_common->read(); + _cfg_common.write(queue_index); + auto const offset = _cfg_common.read(); auto const addr = (offset * _notify_offset_multiplier >> 1) + 1; - _notify->local_addr()[addr] = queue_index; + *(uint16_t*)(_notify.base() + addr) = queue_index; } uint32_t read_isr() { - return _isr->read(); } + return _isr.read(); } void irq_sigh(Signal_context_capability cap) { _irq.sigh(cap); } - void irq_ack() { _irq.ack_irq(); } + void irq_ack() { _irq.ack(); } }; #endif /* _INCLUDE__VIRTIO__PCI_DEVICE_H_ */ diff --git a/repos/os/include/virtio/queue.h b/repos/os/include/virtio/queue.h index f37b792110..529dee2ddf 100644 --- a/repos/os/include/virtio/queue.h +++ b/repos/os/include/virtio/queue.h @@ -14,9 +14,8 @@ #ifndef _INCLUDE__VIRTIO__QUEUE_H_ #define _INCLUDE__VIRTIO__QUEUE_H_ -#include +#include #include -#include #include namespace Virtio @@ -138,7 +137,7 @@ class Virtio::Queue Buffer_pool(Buffer_pool const &) = delete; Buffer_pool &operator = (Buffer_pool const &) = delete; - Attached_dataspace _ds; + Platform::Dma_buffer _ds; uint16_t const _buffer_count; uint16_t const _buffer_size; addr_t const _phys_base; @@ -156,16 +155,14 @@ class Virtio::Queue }; Buffer_pool(Platform::Connection & plat, - Region_map & rm, uint16_t const buffer_count, uint16_t const buffer_size) : - _ds(rm, plat.alloc_dma_buffer(buffer_count * - align_natural(buffer_size), - CACHED)), + _ds(plat, buffer_count * align_natural(buffer_size), + CACHED), _buffer_count(buffer_count), _buffer_size(buffer_size), - _phys_base(_dma_addr(plat, _ds.cap())) {} + _phys_base(_ds.dma_addr()) {} const Buffer get(uint16_t descriptor_idx) const { @@ -211,7 +208,7 @@ class Virtio::Queue uint16_t const _queue_size; - Attached_dataspace _ds; + Platform::Dma_buffer _ds; Buffer_pool _buffers; Avail volatile * const _avail; Used volatile * const _used; @@ -565,18 +562,16 @@ class Virtio::Queue print(output, _queue_size); } - Queue(Region_map & rm, - Platform::Connection & plat, + Queue(Platform::Connection & plat, uint16_t queue_size, uint16_t buffer_size) : _queue_size(queue_size), - _ds(rm, plat.alloc_dma_buffer(_ds_size(queue_size), UNCACHED)), - _buffers(plat, rm, queue_size, _check_buffer_size(buffer_size)), + _ds(plat, _ds_size(queue_size), UNCACHED), + _buffers(plat, queue_size, _check_buffer_size(buffer_size)), _avail(_init_avail(_ds.local_addr(), queue_size)), _used(_init_used(_ds.local_addr(), queue_size)), _descriptors(_ds.local_addr(), queue_size), - _description(_init_description(queue_size, - _dma_addr(plat, _ds.cap()))) + _description(_init_description(queue_size, _ds.dma_addr())) { _fill_descriptor_table(); } diff --git a/repos/os/src/drivers/framebuffer/virtio/component.h b/repos/os/src/drivers/framebuffer/virtio/component.h index 35d0b920dc..93194bf005 100644 --- a/repos/os/src/drivers/framebuffer/virtio/component.h +++ b/repos/os/src/drivers/framebuffer/virtio/component.h @@ -203,7 +203,7 @@ class Virtio_fb::Driver Env &_env; Platform::Connection &_platform; Virtio::Device &_device; - Control_queue _ctrl_vq { _env.rm(), _platform, 4, 512 }; + Control_queue _ctrl_vq { _platform, 4, 512 }; uint32_t const _num_scanouts; Signal_handler _irq_handler { _env.ep(), *this, &Driver::_handle_irq }; diff --git a/repos/os/src/drivers/input/virtio/component.h b/repos/os/src/drivers/input/virtio/component.h index 5387fc5c98..d799733d29 100644 --- a/repos/os/src/drivers/input/virtio/component.h +++ b/repos/os/src/drivers/input/virtio/component.h @@ -137,10 +137,8 @@ class Virtio_input::Driver Input::Absolute_motion _abs_motion { -1, -1 }; Abs_config _abs_config { { 0, 0 }, { 0, 0 }, 0, 0 }; Signal_handler _irq_handler {_env.ep(), *this, &Driver::_handle_irq}; - Events_virtqueue _events_vq { _env.rm(), _plat, - QUEUE_SIZE, QUEUE_ELM_SIZE }; - Status_virtqueue _status_vq { _env.rm(), _plat, - QUEUE_SIZE, QUEUE_ELM_SIZE }; + Events_virtqueue _events_vq { _plat, QUEUE_SIZE, QUEUE_ELM_SIZE }; + Status_virtqueue _status_vq { _plat, QUEUE_SIZE, QUEUE_ELM_SIZE }; void _handle_event(::Event::Session_client::Batch &batch, const Event &evt) diff --git a/repos/os/src/drivers/nic/virtio/component.h b/repos/os/src/drivers/nic/virtio/component.h index 5a7d5300c2..003ae5dc54 100644 --- a/repos/os/src/drivers/nic/virtio/component.h +++ b/repos/os/src/drivers/nic/virtio/component.h @@ -288,18 +288,17 @@ class Virtio_nic::Device : Noncopyable public: - Device(Genode::Env &env, - Virtio::Device &device, + Device(Virtio::Device &device, Platform::Connection &plat, Genode::Xml_node const &xml) try : _verbose { xml.attribute_value("verbose", false) }, _device { device }, _hw_features { _init_hw_features(xml) }, - _rx_vq { env.rm(), plat, + _rx_vq { plat, _vq_size(RX_VQ, xml, "rx_queue_size"), _buf_size(RX_VQ, xml, "rx_buffer_size") }, - _tx_vq { env.rm(), plat, + _tx_vq { plat, _vq_size(TX_VQ, xml, "tx_queue_size"), _buf_size(TX_VQ, xml, "tx_buffer_size") } { } @@ -496,7 +495,7 @@ class Virtio_nic::Uplink_client : public Virtio_nic::Device, Platform::Connection &plat, Genode::Xml_node const &xml) : - Device { env, device, plat, xml }, + Device { device, plat, xml }, Uplink_client_base { env, alloc, read_mac_address() }, _irq_handler { env.ep(), *this, &Uplink_client::_handle_irq } { diff --git a/repos/os/src/drivers/nic/virtio/pci_device.cc b/repos/os/src/drivers/nic/virtio/pci_device.cc index 1b5aa9e4d4..561a4e5c51 100644 --- a/repos/os/src/drivers/nic/virtio/pci_device.cc +++ b/repos/os/src/drivers/nic/virtio/pci_device.cc @@ -14,7 +14,7 @@ /* Genode includes */ #include #include -#include +#include #include /* local includes */ @@ -30,29 +30,15 @@ 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 }; - Attached_rom_dataspace config_rom { env, "config" }; + Genode::Heap heap { env.ram(), env.rm() }; + Platform::Connection pci { env }; + Virtio::Device virtio_device { env, pci }; + Attached_rom_dataspace config_rom { env, "config" }; Virtio_nic::Uplink_client uplink_client { env, heap, virtio_device, pci, config_rom.xml() }; - 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) - : env(env), platform_device(find_platform_device()) - { - log("--- VirtIO PCI driver started ---"); - } + Main(Env &env) : env(env) { + log("--- VirtIO PCI driver started ---"); } };