From 9370e5e4d02aac58892befdddda4de08701cf073 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Tue, 3 May 2022 13:36:27 +0200 Subject: [PATCH] platform_drv: add PCI device support * Parse PCI specific information from devices ROM * Enable DMA, I/O memory and I/O port access dependent on BARs in config space * Introduce device PD for Nova + IOMMU support * Enable MSIs if available * Add PCI specific policy rules Fixes genodelabs/genode#4502 --- repos/os/src/drivers/platform/README | 15 ++ repos/os/src/drivers/platform/device.cc | 11 ++ repos/os/src/drivers/platform/device.h | 102 ++++++++++- .../src/drivers/platform/device_component.cc | 36 ++-- .../src/drivers/platform/device_component.h | 15 +- .../drivers/platform/device_model_policy.cc | 10 ++ repos/os/src/drivers/platform/device_pd.cc | 135 ++++++++++++++ repos/os/src/drivers/platform/device_pd.h | 83 +++++++++ repos/os/src/drivers/platform/pci.cc | 165 ++++++++++++++++++ repos/os/src/drivers/platform/pci.h | 33 ++++ repos/os/src/drivers/platform/root.h | 6 +- .../src/drivers/platform/session_component.cc | 14 +- .../src/drivers/platform/session_component.h | 11 +- repos/os/src/drivers/platform/target.mk | 9 +- 14 files changed, 613 insertions(+), 32 deletions(-) create mode 100644 repos/os/src/drivers/platform/device_pd.cc create mode 100644 repos/os/src/drivers/platform/device_pd.h create mode 100644 repos/os/src/drivers/platform/pci.cc create mode 100644 repos/os/src/drivers/platform/pci.h diff --git a/repos/os/src/drivers/platform/README b/repos/os/src/drivers/platform/README index 777fac775b..71e0aac21c 100644 --- a/repos/os/src/drivers/platform/README +++ b/repos/os/src/drivers/platform/README @@ -47,6 +47,21 @@ ROM will contain detailed information about physical resources of the devices of its virtual bus. This is only useful when using ported legacy drivers, which operate with global names of physical resources. +Policy for PCI devices +---------------------- + +Policies for PCI devices do not necessarily need to state the name of +the device, but can either state a class of devices, or a vendor/device +pair of identifiers inside a pci sub-node: + +! +! +! +! +! +! +! + Report facilities ----------------- diff --git a/repos/os/src/drivers/platform/device.cc b/repos/os/src/drivers/platform/device.cc index 3f530e3e0b..1581795e47 100644 --- a/repos/os/src/drivers/platform/device.cc +++ b/repos/os/src/drivers/platform/device.cc @@ -12,6 +12,7 @@ */ #include +#include #include #include @@ -78,6 +79,7 @@ void Driver::Device::acquire(Session_component & sc) } }); + pci_enable(sc.env(), sc.device_pd(), *this); sc.update_devices_rom(); sc.devices().update_report(); } @@ -88,6 +90,8 @@ void Driver::Device::release(Session_component & sc) if (!(_owner == sc)) return; + pci_disable(sc.env(), *this); + _reset_domain_list.for_each([&] (Reset_domain & r) { sc.devices().resets().apply(r.name, [&] (Driver::Reset &reset) { @@ -156,6 +160,13 @@ void Driver::Device::report(Xml_generator & xml, Device_model & devices, }); }); }); + _pci_config_list.for_each([&] (Pci_config &pci) { + xml.node("pci-config", [&] () { + xml.attribute("vendor_id", String<16>(Hex(pci.vendor_id))); + xml.attribute("device_id", String<16>(Hex(pci.device_id))); + xml.attribute("class", String<16>(Hex(pci.class_code))); + }); + }); _report_platform_specifics(xml, devices); }); diff --git a/repos/os/src/drivers/platform/device.h b/repos/os/src/drivers/platform/device.h index ff59c19d2a..9981675f24 100644 --- a/repos/os/src/drivers/platform/device.h +++ b/repos/os/src/drivers/platform/device.h @@ -11,12 +11,13 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_ -#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_ +#ifndef _SRC__DRIVERS__PLATFORM__DEVICE_H_ +#define _SRC__DRIVERS__PLATFORM__DEVICE_H_ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ namespace Driver { struct Clock_update_policy; struct Reset_domain_update_policy; struct Power_domain_update_policy; + struct Pci_config_update_policy; } @@ -141,6 +143,36 @@ class Driver::Device : private List_model::Element Reset_domain(Name name) : name(name) {} }; + struct Pci_config : List_model::Element + { + addr_t addr; + Pci::bus_t bus_num; + Pci::dev_t dev_num; + Pci::func_t func_num; + Pci::vendor_t vendor_id; + Pci::device_t device_id; + Pci::class_t class_code; + bool bridge; + + Pci_config(addr_t addr, + Pci::bus_t bus_num, + Pci::dev_t dev_num, + Pci::func_t func_num, + Pci::vendor_t vendor_id, + Pci::device_t device_id, + Pci::class_t class_code, + bool bridge) + : + addr(addr), + bus_num(bus_num), + dev_num(dev_num), + func_num(func_num), + vendor_id(vendor_id), + device_id(device_id), + class_code(class_code), + bridge(bridge) {} + }; + Device(Name name, Type type); virtual ~Device(); @@ -155,7 +187,7 @@ class Driver::Device : private List_model::Element { unsigned idx = 0; _irq_list.for_each([&] (Irq const & irq) { - fn(idx++, irq.number, irq.type, irq.polarity, irq.mode, 0); }); + fn(idx++, irq.number, irq.type, irq.polarity, irq.mode); }); } template void for_each_io_mem(FN const & fn) @@ -172,6 +204,23 @@ class Driver::Device : private List_model::Element fn(idx++, ipr.addr, ipr.size); }); } + template void for_pci_config(FN const & fn) + { + /* + * we allow only one PCI config per device, + * even if more were declared + */ + bool found = false; + _pci_config_list.for_each([&] (Pci_config const & cfg) { + if (found) { + warning("Only one pci-config is supported per device!"); + return; + } + found = true; + fn(cfg); + }); + } + void report(Xml_generator &, Device_model &, bool); protected: @@ -193,6 +242,7 @@ class Driver::Device : private List_model::Element List_model _clock_list {}; List_model _power_domain_list {}; List_model _reset_domain_list {}; + List_model _pci_config_list {}; /* * Noncopyable @@ -487,4 +537,48 @@ struct Driver::Reset_domain_update_policy } }; -#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_ */ + +struct Driver::Pci_config_update_policy +: Genode::List_model::Update_policy +{ + Genode::Allocator & alloc; + + Pci_config_update_policy(Genode::Allocator & alloc) : alloc(alloc) {} + + void destroy_element(Element & pd) { + Genode::destroy(alloc, &pd); } + + Element & create_element(Genode::Xml_node node) + { + using namespace Pci; + + addr_t addr = node.attribute_value("address", ~0UL); + bus_t bus_num = node.attribute_value("bus", 0); + dev_t dev_num = node.attribute_value("device", 0); + func_t func_num = node.attribute_value("function", 0); + vendor_t vendor_id = node.attribute_value("vendor_id", + 0xffff); + device_t device_id = node.attribute_value("device_id", + 0xffff); + class_t class_code = node.attribute_value("class", 0xff); + bool bridge = node.attribute_value("bridge", false); + + return *(new (alloc) Element(addr, bus_num, dev_num, func_num, + vendor_id, device_id, class_code, bridge)); + } + + void update_element(Element &, Genode::Xml_node) {} + + static bool element_matches_xml_node(Element const & e, Genode::Xml_node node) + { + addr_t addr = node.attribute_value("address", ~0UL); + return addr == e.addr; + } + + static bool node_is_element(Genode::Xml_node node) + { + return node.has_type("pci-config"); + } +}; + +#endif /* _SRC__DRIVERS__PLATFORM__DEVICE_H_ */ diff --git a/repos/os/src/drivers/platform/device_component.cc b/repos/os/src/drivers/platform/device_component.cc index 5df487a3c8..282278fcd9 100644 --- a/repos/os/src/drivers/platform/device_component.cc +++ b/repos/os/src/drivers/platform/device_component.cc @@ -13,6 +13,7 @@ #include #include +#include #include using Driver::Device_component; @@ -72,19 +73,17 @@ Genode::Irq_session_capability Device_component::irq(unsigned idx) return; if (!irq.irq.constructed()) { - - /* - * Unfortunately, we have to deliver the PCI config space address - * to the IRQ session for working MSI(-x) on NOVA. It is used - * for IOMMU configuration as some kind of access control - * - * Once, the IOMMU support is solved kernel-independent, this - * attribute has to be removed from the IRQs - */ - addr_t pci_cfg_addr = (irq.type != Device::Irq::LEGACY) - ? irq.pci_config_addr : 0; + addr_t pci_cfg_addr = 0; + if (irq.type != Device::Irq::LEGACY) { + if (_pci_config.constructed()) pci_cfg_addr = _pci_config->addr; + else + error("MSI(-x) detected for device without pci-config!"); + } irq.irq.construct(_session.env(), irq.number, irq.mode, irq.polarity, pci_cfg_addr); + Irq_session::Info info = irq.irq->info(); + if (info.type == Irq_session::Info::MSI) + pci_msi_enable(_session.env(), pci_cfg_addr, info); } cap = irq.irq->cap(); @@ -137,15 +136,13 @@ Device_component::Device_component(Registry & registry, unsigned nr, Device::Irq::Type type, Irq_session::Polarity polarity, - Irq_session::Trigger mode, - addr_t pci_cfg_addr) + Irq_session::Trigger mode) { session.ram_quota_guard().withdraw(Ram_quota{Irq_session::RAM_QUOTA}); _ram_quota += Irq_session::RAM_QUOTA; session.cap_quota_guard().withdraw(Cap_quota{Irq_session::CAP_QUOTA}); _cap_quota += Irq_session::CAP_QUOTA; - new (session.heap()) Irq(_irq_registry, idx, nr, type, - polarity, mode, pci_cfg_addr); + new (session.heap()) Irq(_irq_registry, idx, nr, type, polarity, mode); }); device.for_each_io_mem([&] (unsigned idx, Range range) @@ -167,6 +164,15 @@ Device_component::Device_component(Registry & registry, new (session.heap()) Io_port_range(_io_port_range_registry, idx, addr, size); }); + + device.for_pci_config([&] (Device::Pci_config const & cfg) + { + session.ram_quota_guard().withdraw(Ram_quota{Io_mem_session::RAM_QUOTA}); + _ram_quota += Io_mem_session::RAM_QUOTA; + session.cap_quota_guard().withdraw(Cap_quota{Io_mem_session::CAP_QUOTA}); + _cap_quota += Io_mem_session::CAP_QUOTA; + _pci_config.construct(cfg.addr); + }); } catch(...) { _release_resources(); throw; diff --git a/repos/os/src/drivers/platform/device_component.h b/repos/os/src/drivers/platform/device_component.h index 1e3d4c5b79..c890e267d3 100644 --- a/repos/os/src/drivers/platform/device_component.h +++ b/repos/os/src/drivers/platform/device_component.h @@ -43,7 +43,6 @@ class Driver::Device_component : public Rpc_object irq {}; Irq(Registry & registry, @@ -51,13 +50,11 @@ class Driver::Device_component : public Rpc_object::Element(registry, *this), idx(idx), number(number), type(type), - polarity(polarity), mode(mode), - pci_config_addr(pci_config_addr) {} + polarity(polarity), mode(mode) {} }; struct Io_mem : Registry::Element @@ -90,6 +87,13 @@ class Driver::Device_component : public Rpc_object & registry, Session_component & session, Driver::Device & device); @@ -117,6 +121,7 @@ class Driver::Device_component : public Rpc_object _irq_registry {}; Registry _io_mem_registry {}; Registry _io_port_range_registry {}; + Constructible _pci_config {}; void _release_resources(); diff --git a/repos/os/src/drivers/platform/device_model_policy.cc b/repos/os/src/drivers/platform/device_model_policy.cc index a3e7dfac3c..cda8df53cc 100644 --- a/repos/os/src/drivers/platform/device_model_policy.cc +++ b/repos/os/src/drivers/platform/device_model_policy.cc @@ -53,6 +53,11 @@ void Device_model::destroy_element(Device & device) device._reset_domain_list.destroy_all_elements(policy); } + { + Pci_config_update_policy policy(_heap); + device._pci_config_list.destroy_all_elements(policy); + } + Genode::destroy(_heap, &device); } @@ -102,4 +107,9 @@ void Device_model::update_element(Device & device, Reset_domain_update_policy policy(_heap); device._reset_domain_list.update_from_xml(policy, node); } + + { + Pci_config_update_policy policy(_heap); + device._pci_config_list.update_from_xml(policy, node); + } } diff --git a/repos/os/src/drivers/platform/device_pd.cc b/repos/os/src/drivers/platform/device_pd.cc new file mode 100644 index 0000000000..6b7cb0ce65 --- /dev/null +++ b/repos/os/src/drivers/platform/device_pd.cc @@ -0,0 +1,135 @@ +/* + * \brief Pci device protection for platform driver + * \author Alexander Boettcher + * \author Stefan Kalkowski + * \date 2013-02-10 + */ + +/* + * Copyright (C) 2013-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 +#include + +#include + +#include + +using namespace Driver; + +Device_pd::Region_map_client::Local_addr +Device_pd::Region_map_client::attach(Dataspace_capability ds, + size_t size, + off_t offset, + bool use_local_addr, + Local_addr local_addr, + bool executable, + bool writeable) +{ + return retry( + [&] () { + return retry( + [&] () { + return Genode::Region_map_client::attach(ds, size, offset, + use_local_addr, + local_addr, + executable, + writeable); }, + [&] () { + upgrade_caps(); + } + ); + }, + [&] () { upgrade_ram(); } + ); +} + + +void Device_pd::Region_map_client::upgrade_ram() +{ + Ram_quota const ram { 4096 }; + _ram_guard.withdraw(ram); + _env.pd().transfer_quota(_pd.rpc_cap(), ram); +} + + +void Device_pd::Region_map_client::upgrade_caps() +{ + Cap_quota const caps { 2 }; + _cap_guard.withdraw(caps); + _env.pd().transfer_quota(_pd.rpc_cap(), caps); +} + + +void Device_pd::attach_dma_mem(Dataspace_capability ds_cap, + addr_t const dma_addr) +{ + using namespace Genode; + + bool retry = false; + Dataspace_client ds_client(ds_cap); + + do { + _pd.attach_dma(ds_cap, dma_addr).with_result( + [&] (Pd_session::Attach_dma_ok) { + /* trigger eager mapping of memory */ + _pd.map(dma_addr, ds_client.size()); + retry = false; + }, + [&] (Pd_session::Attach_dma_error e) { + switch (e) { + case Pd_session::Attach_dma_error::OUT_OF_RAM: + _address_space.upgrade_ram(); + retry = true; + break; + case Pd_session::Attach_dma_error::OUT_OF_CAPS: + _address_space.upgrade_caps(); + retry = true; + break; + case Pd_session::Attach_dma_error::DENIED: + _address_space.detach(dma_addr); + error("Device PD: attach_dma denied!"); + break; + } + } + ); + } while (retry); +} + + +void Device_pd::assign_pci(Io_mem_dataspace_capability const io_mem_cap, + Pci::Bdf const bdf) +{ + addr_t addr = _address_space.attach(io_mem_cap, 0x1000); + + /* sanity check */ + if (!addr) + throw Region_map::Region_conflict(); + + /* trigger eager mapping of memory */ + _pd.map(addr, 0x1000); + + /* try to assign pci device to this protection domain */ + if (!_pd.assign_pci(addr, Pci::Bdf::rid(bdf))) + error("Assignment of PCI device ", bdf, " to device PD failed!"); + + /* we don't need the mapping anymore */ + _address_space.detach(addr); +} + + +Device_pd::Device_pd(Env & env, + Ram_quota_guard & ram_guard, + Cap_quota_guard & cap_guard) +: + _pd(env, Pd_connection::Device_pd()), + _address_space(env, _pd, ram_guard, cap_guard) +{ + _pd.ref_account(env.pd_session_cap()); +} diff --git a/repos/os/src/drivers/platform/device_pd.h b/repos/os/src/drivers/platform/device_pd.h new file mode 100644 index 0000000000..f8e8f2a0ae --- /dev/null +++ b/repos/os/src/drivers/platform/device_pd.h @@ -0,0 +1,83 @@ +/* + * \brief Device PD handling for the platform driver + * \author Alexander Boettcher + * \date 2015-11-05 + */ + +/* + * Copyright (C) 2015-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 _SRC__DRIVERS__PLATFORM__DEVICE_PD_H_ +#define _SRC__DRIVERS__PLATFORM__DEVICE_PD_H_ + +/* base */ +#include +#include +#include +#include +#include +#include + +namespace Driver { + using namespace Genode; + class Device_pd; +} + +class Driver::Device_pd +{ + private: + + Pd_connection _pd; + + /** + * Custom handling of PD-session depletion during attach operations + * + * The default implementation of 'env.rm()' automatically issues a resource + * request if the PD session quota gets exhausted. For the device PD, we don't + * want to issue resource requests but let the platform driver reflect this + * condition to its client. + */ + struct Region_map_client : Genode::Region_map_client + { + Env & _env; + Pd_connection & _pd; + Ram_quota_guard & _ram_guard; + Cap_quota_guard & _cap_guard; + + Region_map_client(Env & env, + Pd_connection & pd, + Ram_quota_guard & ram_guard, + Cap_quota_guard & cap_guard) + : + Genode::Region_map_client(pd.address_space()), + _env(env), _pd(pd), + _ram_guard(ram_guard), _cap_guard(cap_guard) + { } + + Local_addr attach(Dataspace_capability ds, + size_t size = 0, + off_t offset = 0, + bool use_local_addr = false, + Local_addr local_addr = (void *)0, + bool executable = false, + bool writeable = true) override; + + void upgrade_ram(); + void upgrade_caps(); + } _address_space; + + public: + + Device_pd(Env &env, + Ram_quota_guard &ram_guard, + Cap_quota_guard &cap_guard); + + void attach_dma_mem(Dataspace_capability, addr_t dma_addr); + void assign_pci(Io_mem_dataspace_capability const, Pci::Bdf const); +}; + +#endif /* _SRC__DRIVERS__PLATFORM__DEVICE_PD_H_ */ diff --git a/repos/os/src/drivers/platform/pci.cc b/repos/os/src/drivers/platform/pci.cc new file mode 100644 index 0000000000..f37394f2e6 --- /dev/null +++ b/repos/os/src/drivers/platform/pci.cc @@ -0,0 +1,165 @@ +/* + * \brief Platform driver - PCI helper utilities + * \author Stefan Kalkowski + * \date 2022-05-02 + */ + +/* + * 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 + +#include +#include +#include + +using namespace Genode; +using namespace Pci; + +struct Config_helper +{ + Driver::Device & _dev; + Driver::Device::Pci_config const & _cfg; + + Attached_io_mem_dataspace _io_mem; + Config _config { (addr_t)_io_mem.local_addr() }; + + Config_helper(Env & env, + Driver::Device & dev, + Driver::Device::Pci_config const & cfg) + : _dev(dev), _cfg(cfg), _io_mem(env, cfg.addr, 0x1000) { } + + void enable(Driver::Device_pd & pd) + { + pd.assign_pci(_io_mem.cap(), + { _cfg.bus_num, _cfg.dev_num, _cfg.func_num }); + + Config::Command::access_t cmd = + _config.read(); + + /* always allow DMA operations */ + 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::Range) { + Config::Command::Memory_space_enable::set(cmd, 1); }); + + /* enable i/o space when I/O ports are defined */ + _dev.for_each_io_port_range([&] (unsigned, uint16_t, uint16_t) { + Config::Command::Io_space_enable::set(cmd, 1); }); + + _config.write(cmd); + } + + void disable() + { + Config::Command::access_t cmd = + _config.read(); + Config::Command::Io_space_enable::set(cmd, 0); + Config::Command::Memory_space_enable::set(cmd, 0); + Config::Command::Bus_master_enable::set(cmd, 0); + Config::Command::Interrupt_enable::set(cmd, 0); + _config.write(cmd); + } +}; + + +void Driver::pci_enable(Env & env, Device_pd & pd, Device & dev) +{ + dev.for_pci_config([&] (Device::Pci_config const & pc) { + Config_helper(env, dev, pc).enable(pd); }); +} + + +void Driver::pci_disable(Env & env, Device & dev) +{ + dev.for_pci_config([&] (Device::Pci_config const & pc) { + Config_helper(env, dev, pc).disable(); }); +} + + +void Driver::pci_msi_enable(Env & env, addr_t cfg_space, Irq_session::Info info) +{ + Attached_io_mem_dataspace io_mem { env, cfg_space, 0x1000 }; + Config config { (addr_t)io_mem.local_addr() }; + config.scan(); + if (config.msi_cap.constructed()) + config.msi_cap->enable(info.address, (uint16_t)info.value); + else error("Device does not support MSI(-x)!"); +} + + +static inline String<16> +pci_class_code_alias(uint32_t class_code) +{ + enum { WILDCARD = 0xff }; + + uint8_t const b = (class_code >> 16) & 0xff; + uint8_t const s = (class_code >> 8) & 0xff; + uint8_t const i = class_code & 0xff; + + static struct Alias + { + String<16> name; + uint8_t base; + uint8_t sub; + uint8_t iface; + + bool matches(uint8_t b, uint8_t s, uint8_t i) const + { + return (base == WILDCARD || base == b) && + (sub == WILDCARD || sub == s) && + (iface == WILDCARD || iface == i); + } + } const aliases [] = { + { "NVME" , 0x01, 0x08, 0x02 }, + { "USB" , 0x0c, 0x03, 0x00 }, /* UHCI */ + { "USB" , 0x0c, 0x03, 0x10 }, /* OHCI */ + { "USB" , 0x0c, 0x03, 0x20 }, /* EHCI */ + { "USB" , 0x0c, 0x03, 0x30 }, /* XHCI */ + { "VGA" , 0x03, 0x00, 0x00 }, + { "AHCI" , 0x01, 0x06, WILDCARD }, + { "AUDIO" , 0x04, 0x01, WILDCARD }, + { "ETHERNET" , 0x02, 0x00, WILDCARD }, + { "HDAUDIO" , 0x04, 0x03, WILDCARD }, + { "ISABRIDGE", 0x06, 0x01, WILDCARD }, + { "WIFI" , 0x02, 0x80, WILDCARD }, + }; + + for (Alias const & alias : aliases) + if (alias.matches(b, s, i)) + return alias.name; + + return "ALL"; +} + + +bool Driver::pci_device_matches(Session_policy const & policy, Device & dev) +{ + bool ret = false; + + policy.for_each_sub_node("pci", [&] (Xml_node node) + { + if (dev.type() != "pci") + return; + + String<16> class_code = node.attribute_value("class", String<16>()); + vendor_t vendor_id = node.attribute_value("vendor_id", 0); + device_t device_id = node.attribute_value("device_id", 0); + + dev.for_pci_config([&] (Device::Pci_config cfg) + { + if ((pci_class_code_alias(cfg.class_code) == class_code) || + (vendor_id == cfg.vendor_id && device_id == cfg.device_id)) + ret = true; + }); + }); + + return ret; +} diff --git a/repos/os/src/drivers/platform/pci.h b/repos/os/src/drivers/platform/pci.h new file mode 100644 index 0000000000..a5d88975c5 --- /dev/null +++ b/repos/os/src/drivers/platform/pci.h @@ -0,0 +1,33 @@ +/* + * \brief Platform driver - PCI helper utilities + * \author Stefan Kalkowski + * \date 2022-05-02 + */ + +/* + * 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 _SRC__DRIVERS__PLATFORM__PCI_H_ +#define _SRC__DRIVERS__PLATFORM__PCI_H_ + +#include +#include +#include + +namespace Driver { + class Device; + class Device_pd; + + void pci_enable(Genode::Env & env, Device_pd & pd, Device & dev); + void pci_disable(Genode::Env & env, Device & dev); + void pci_msi_enable(Genode::Env & env, addr_t cfg_space, + Genode::Irq_session::Info info); + bool pci_device_matches(Genode::Session_policy const & policy, + Device & dev); +} + +#endif /* _SRC__DRIVERS__PLATFORM__PCI_H_ */ diff --git a/repos/os/src/drivers/platform/root.h b/repos/os/src/drivers/platform/root.h index a5f964e713..a2db38f0cc 100644 --- a/repos/os/src/drivers/platform/root.h +++ b/repos/os/src/drivers/platform/root.h @@ -11,8 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__ROOT_H_ -#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__ROOT_H_ +#ifndef _SRC__DRIVERS__PLATFORM__ROOT_H_ +#define _SRC__DRIVERS__PLATFORM__ROOT_H_ #include #include @@ -46,4 +46,4 @@ class Driver::Root : public Root_component Registry _sessions {}; }; -#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__ROOT_H_ */ +#endif /* _SRC__DRIVERS__PLATFORM__ROOT_H_ */ diff --git a/repos/os/src/drivers/platform/session_component.cc b/repos/os/src/drivers/platform/session_component.cc index 447832c277..5f70d56e02 100644 --- a/repos/os/src/drivers/platform/session_component.cc +++ b/repos/os/src/drivers/platform/session_component.cc @@ -14,6 +14,7 @@ #include #include +#include #include using Driver::Session_component; @@ -54,6 +55,12 @@ bool Session_component::matches(Device & dev) const try { Session_policy const policy { label(), _config.xml() }; + + /* check PCI devices */ + if (pci_device_matches(policy, dev)) + return true; + + /* check for dedicated device name */ policy.for_each_sub_node("device", [&] (Xml_node node) { if (dev.name() == node.attribute_value("name", Device::Name())) ret = true; @@ -114,6 +121,9 @@ Driver::Device_model & Session_component::devices() { return _devices; } Genode::Heap & Session_component::heap() { return _md_alloc; } +Driver::Device_pd & Session_component::device_pd() { return _device_pd; } + + void Session_component::update_devices_rom() { _rom_session.trigger_update(); @@ -175,7 +185,9 @@ Session_component::alloc_dma_buffer(size_t const size, Cache cache) if (!ram_cap.valid()) return ram_cap; try { - new (heap()) Dma_buffer(_buffer_registry, ram_cap); + Dma_buffer & buf = + *(new (heap()) Dma_buffer(_buffer_registry, ram_cap)); + _device_pd.attach_dma_mem(ram_cap, _env.pd().dma_addr(buf.cap)); } catch (Out_of_ram) { _env_ram.free(ram_cap); throw; diff --git a/repos/os/src/drivers/platform/session_component.h b/repos/os/src/drivers/platform/session_component.h index c4e6185011..dc197e29bf 100644 --- a/repos/os/src/drivers/platform/session_component.h +++ b/repos/os/src/drivers/platform/session_component.h @@ -11,8 +11,8 @@ * under the terms of the GNU Affero General Public License version 3. */ -#ifndef _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_ -#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_ +#ifndef _SRC__DRIVERS__PLATFORM__SESSION_COMPONENT_H_ +#define _SRC__DRIVERS__PLATFORM__SESSION_COMPONENT_H_ #include #include @@ -25,6 +25,7 @@ #include #include +#include namespace Driver { class Session_component; @@ -58,6 +59,7 @@ class Driver::Session_component Env & env(); Heap & heap(); Device_model & devices(); + Device_pd & device_pd(); bool matches(Device &) const; void update_devices_rom(); @@ -110,6 +112,9 @@ class Driver::Session_component _env.rm(), *this }; bool _info; Policy_version _version; + Device_pd _device_pd { _env, + _ram_quota_guard(), + _cap_quota_guard() }; Device_capability _acquire(Device & device); void _release_device(Device_component & dc); @@ -129,4 +134,4 @@ class Driver::Session_component void produce_xml(Xml_generator &xml) override; }; -#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_ */ +#endif /* _SRC__DRIVERS__PLATFORM__SESSION_COMPONENT_H_ */ diff --git a/repos/os/src/drivers/platform/target.mk b/repos/os/src/drivers/platform/target.mk index 023b7f379a..61b5510e6b 100644 --- a/repos/os/src/drivers/platform/target.mk +++ b/repos/os/src/drivers/platform/target.mk @@ -1,4 +1,11 @@ TARGET = platform_drv -SRC_CC = device.cc device_component.cc device_model_policy.cc main.cc session_component.cc root.cc +SRC_CC += device.cc +SRC_CC += device_component.cc +SRC_CC += device_model_policy.cc +SRC_CC += device_pd.cc +SRC_CC += main.cc +SRC_CC += pci.cc +SRC_CC += root.cc +SRC_CC += session_component.cc INC_DIR = $(PRG_DIR) LIBS = base