From fdba7259ab07a45240dc0c08eafee7d3e0544907 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Tue, 20 Sep 2022 12:01:21 +0200 Subject: [PATCH] platform_drv: provide Virtio PCI information Ref genodelabs/genode#4578 --- repos/os/src/drivers/platform/device.h | 2 +- .../src/drivers/platform/device_component.cc | 2 +- repos/os/src/drivers/platform/pci.cc | 11 +- repos/os/src/drivers/platform/pci_virtio.h | 119 ++++++++++++++++++ 4 files changed, 129 insertions(+), 5 deletions(-) create mode 100644 repos/os/src/drivers/platform/pci_virtio.h diff --git a/repos/os/src/drivers/platform/device.h b/repos/os/src/drivers/platform/device.h index 979bafb7cb..6bf0d57680 100644 --- a/repos/os/src/drivers/platform/device.h +++ b/repos/os/src/drivers/platform/device.h @@ -228,7 +228,7 @@ class Driver::Device : private List_model::Element { unsigned idx = 0; _io_mem_list.for_each([&] (Io_mem const & iomem) { - fn(idx++, iomem.range); }); + fn(idx++, iomem.range, iomem.bar); }); } template void for_each_io_port_range(FN const & fn) const diff --git a/repos/os/src/drivers/platform/device_component.cc b/repos/os/src/drivers/platform/device_component.cc index bed1211299..985aaabcc6 100644 --- a/repos/os/src/drivers/platform/device_component.cc +++ b/repos/os/src/drivers/platform/device_component.cc @@ -159,7 +159,7 @@ Device_component::Device_component(Registry & registry, new (session.heap()) Irq(_irq_registry, idx, nr, type, polarity, mode); }); - device.for_each_io_mem([&] (unsigned idx, Range range) + device.for_each_io_mem([&] (unsigned idx, Range range, Device::Pci_bar) { session.ram_quota_guard().withdraw(Ram_quota{Io_mem_session::RAM_QUOTA}); _ram_quota += Io_mem_session::RAM_QUOTA; diff --git a/repos/os/src/drivers/platform/pci.cc b/repos/os/src/drivers/platform/pci.cc index eb0a5b92b0..5911667d3c 100644 --- a/repos/os/src/drivers/platform/pci.cc +++ b/repos/os/src/drivers/platform/pci.cc @@ -21,6 +21,7 @@ #include #include #include +#include using namespace Genode; using namespace Pci; @@ -51,7 +52,8 @@ struct Config_helper Config::Command::Bus_master_enable::set(cmd, 1); /* enable memory space when I/O mem is defined */ - _dev.for_each_io_mem([&] (unsigned, Driver::Device::Io_mem::Range) { + _dev.for_each_io_mem([&] (unsigned, Driver::Device::Io_mem::Range, + Driver::Device::Pci_bar) { Config::Command::Memory_space_enable::set(cmd, 1); }); /* enable i/o space when I/O ports are defined */ @@ -182,6 +184,9 @@ void Driver::pci_device_specific_info(Device const & dev, Device_model & model, Xml_generator & xml) { - dev.for_pci_config([&] (Device::Pci_config const cfg) { - Driver::pci_intel_graphics_info(cfg, env, model, xml); }); + dev.for_pci_config([&] (Device::Pci_config const cfg) + { + Driver::pci_intel_graphics_info(cfg, env, model, xml); + Driver::pci_virtio_info(dev, cfg, env, xml); + }); } diff --git a/repos/os/src/drivers/platform/pci_virtio.h b/repos/os/src/drivers/platform/pci_virtio.h new file mode 100644 index 0000000000..d8bcc3b66e --- /dev/null +++ b/repos/os/src/drivers/platform/pci_virtio.h @@ -0,0 +1,119 @@ +/* + * \brief Platform driver - PCI Virtio utilities + * \author Stefan Kalkowski + * \date 2022-09-19 + */ + +/* + * 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. + */ + +#include +#include +#include + +namespace Driver { + void pci_virtio_info(Device const & dev, + Device::Pci_config cfg, + Env & env, + Xml_generator & xml); +} + + +void Driver::pci_virtio_info(Device const & dev, + Device::Pci_config cfg, + Env & env, + Xml_generator & xml) +{ + enum { VENDOR_RED_HAT = 0x1af4 }; + + if (cfg.vendor_id != VENDOR_RED_HAT) + return; + + struct Virtio : Pci::Config + { + struct Capability : Pci::Config::Pci_capability + { + enum { COMMON = 1, NOTIFY = 2, ISR = 3, DEVICE = 4 }; + + struct Type : Register<0x3, 8> {}; + struct Bar : Register<0x4, 8> {}; + struct Offset : Register<0x8, 32> {}; + struct Length : Register<0xc, 32> {}; + struct Offset_factor : Register<0x10, 32> {}; + + using Pci::Config::Pci_capability::Pci_capability; + + bool valid() + { + switch (read()) { + case COMMON: + case NOTIFY: + case ISR: + case DEVICE: + return true; + }; + return false; + } + + String<16> name() + { + switch (read()) { + case COMMON: return "common"; + case NOTIFY: return "notify"; + case ISR: return "irq_status"; + case DEVICE: return "device"; + }; + return "unknown"; + } + }; + + using Pci::Config::Config; + + void capability(Capability & cap, + Driver::Device const & dev, + Xml_generator & xml) + { + unsigned idx = ~0U; + dev.for_each_io_mem([&] (unsigned i, + Driver::Device::Io_mem::Range, + Driver::Device::Pci_bar bar) { + if (bar.number == cap.read()) idx = i; }); + + xml.node("virtio_range", [&] () { + xml.attribute("type", cap.name()); + xml.attribute("index", idx); + xml.attribute("offset", cap.read()); + xml.attribute("size", cap.read()); + if (cap.read() == Capability::NOTIFY) + xml.attribute("factor", + cap.read()); + }); + } + + void for_each_capability(Driver::Device const & dev, + Xml_generator & xml) + { + if (!read()) + return; + + uint16_t off = read(); + while (off) { + Capability cap(base() + off); + if (cap.read() == + Pci_capability::Id::VENDOR && + cap.valid()) + capability(cap, dev, xml); + off = cap.read(); + } + } + }; + + Attached_io_mem_dataspace io_mem(env, cfg.addr, 0x1000); + Virtio config((addr_t)io_mem.local_addr()); + config.for_each_capability(dev, xml); +} +