/* * \brief platform session component * \author Norman Feske * \date 2008-01-28 */ /* * Copyright (C) 2008-2017 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. */ #pragma once /* base */ #include #include #include #include #include #include #include #include #include #include /* os */ #include #include #include #include #include /* local */ #include "pci_device_component.h" #include "pci_config_access.h" #include "device_pd.h" typedef Genode::Ram_dataspace_capability Ram_capability; namespace Platform { unsigned short bridge_bdf(unsigned char bus); class Pci_buses; class Ram_dataspace; class Rmrr; class Root; class Session_component; } class Platform::Ram_dataspace : public Genode::List::Element { private: Ram_capability const _cap; public: Ram_dataspace(Ram_capability c) : _cap(c) { } bool match(const Ram_capability &cap) const { return cap.local_name() == _cap.local_name(); } Ram_capability cap() const { return _cap; } }; class Platform::Rmrr : public Genode::List::Element { public: class Bdf : public Genode::List::Element { private: Genode::uint8_t _bus, _dev, _func; public: Bdf(Genode::uint8_t bus, Genode::uint8_t dev, Genode::uint8_t func) : _bus(bus), _dev(dev), _func(func) { } bool match(Genode::uint8_t bus, Genode::uint8_t dev, Genode::uint8_t func) { return bus == _bus && dev == _dev && func == _func; } }; private: Genode::uint64_t const _start, _end; Genode::Io_mem_dataspace_capability _cap; Genode::List _bdf_list; Genode::Constructible _io_mem; public: Rmrr(Genode::uint64_t start, Genode::uint64_t end) : _start(start), _end(end) { } Genode::Io_mem_dataspace_capability match(Genode::Env &env, Device_config config) { Genode::uint8_t bus = config.bus_number(); Genode::uint8_t device = config.device_number(); Genode::uint8_t function = config.function_number(); for (Bdf *bdf = _bdf_list.first(); bdf; bdf = bdf->next()) { if (!bdf->match(bus, device, function)) continue; if (_cap.valid()) return _cap; _io_mem.construct(env, _start, _end - _start + 1); _cap = _io_mem->dataspace(); return _cap; } return Genode::Io_mem_dataspace_capability(); } void add(Bdf * bdf) { _bdf_list.insert(bdf); } static Genode::List *list() { static Genode::List _list; return &_list; } }; class Platform::Pci_buses { private: Genode::Bit_array _valid; void scan_bus(Config_access &config_access, Genode::Allocator &heap, unsigned char bus = 0); bool _bus_valid(int bus) { if (bus >= Device_config::MAX_BUSES) return false; return _valid.get(bus, 1); } public: Pci_buses(Genode::Env &env, Genode::Allocator &heap) { Config_access c(env); scan_bus(c, heap); } /** * Scan PCI buses for a device * * \param bus start scanning at bus number * \param device start scanning at device number * \param function start scanning at function number * \param out_device_config device config information of the * found device * \param config_access interface for accessing the PCI * configuration * space * * \retval true device was found * \retval false no device was found */ bool find_next(int bus, int device, int function, Device_config *out_device_config, Config_access *config_access) { for (; bus < Device_config::MAX_BUSES; bus++) { if (!_bus_valid(bus)) continue; for (; device < Device_config::MAX_DEVICES; device++) { for (; function < Device_config::MAX_FUNCTIONS; function++) { /* read config space */ Device_config config(bus, device, function, config_access); if (config.valid()) { *out_device_config = config; return true; } } function = 0; /* init value for next device */ } device = 0; /* init value for next bus */ } return false; } }; class Platform::Session_component : public Genode::Rpc_object { private: Genode::Env &_env; Genode::Attached_rom_dataspace &_config; Genode::Ram_session_guard _env_ram; Genode::Heap _md_alloc; Genode::Session_label const _label; Genode::Session_policy const _policy { _label, _config.xml() }; Genode::List _device_list; Platform::Pci_buses &_pci_bus; Genode::Heap &_global_heap; bool _no_device_pd = false; /** * Registry of RAM dataspaces allocated by the session */ Genode::List _ram_caps; void _insert(Ram_capability cap) { _ram_caps.insert(new (_md_alloc) Platform::Ram_dataspace(cap)); } bool _remove(Ram_capability cap) { for (Platform::Ram_dataspace *ds = _ram_caps.first(); ds; ds = ds->next()) { if (!ds->match(cap)) continue; _ram_caps.remove(ds); destroy(_md_alloc, ds); return true; } return false; } Platform::Device_pd _device_pd { _env, _label, _env_ram }; enum { MAX_PCI_DEVICES = Device_config::MAX_BUSES * Device_config::MAX_DEVICES * Device_config::MAX_FUNCTIONS }; static Genode::Bit_array bdf_in_use; /** * List containing extended PCI config space information */ static Genode::List &config_space_list() { static Genode::List config_space; return config_space; } /** * Find for a given PCI device described by the bus:dev:func triple * the corresponding extended 4K PCI config space address. * A io mem dataspace is created and returned. */ Genode::addr_t lookup_config_space(Genode::uint16_t const bdf) { using namespace Genode; addr_t config_space = ~0UL; /* invalid */ Config_space *e = config_space_list().first(); for (; e && (config_space == ~0UL); e = e->next()) config_space = e->lookup_config_space(bdf); return config_space; } /* * List of aliases for PCI Class/Subclas/Prog I/F triple used * by xml config for this platform driver */ unsigned class_subclass_prog(const char * name) { using namespace Genode; static struct { const char * alias; uint8_t pci_class, pci_subclass, pci_progif; } const aliases [] = { { "AHCI" , 0x1, 0x06, 0x0}, { "ALL" , 0x0, 0x00, 0x0}, { "AUDIO" , 0x4, 0x01, 0x0}, { "ETHERNET" , 0x2, 0x00, 0x0}, { "HDAUDIO" , 0x4, 0x03, 0x0}, { "USB" , 0xc, 0x03, 0x0}, { "VGA" , 0x3, 0x00, 0x0}, { "WIFI" , 0x2, 0x80, 0x0}, { "ISABRIDGE", 0x6, 0x01, 0x0} }; for (unsigned i = 0; i < sizeof(aliases) / sizeof(aliases[0]); i++) { if (strcmp(aliases[i].alias, name)) continue; return 0U | aliases[i].pci_class << 16 | aliases[i].pci_subclass << 8 | aliases[i].pci_progif; } return ~0U; } /** * Check device usage according to session policy */ bool permit_device(const char * name) { using namespace Genode; try { _policy.for_each_sub_node("device", [&] (Xml_node dev) { try { /* enforce restriction based on name name */ char policy_name[8]; dev.attribute("name").value(policy_name, sizeof(policy_name)); if (!strcmp(policy_name, name)) /* found identical match - permit access */ throw true; } catch (Xml_attribute::Nonexistent_attribute) { } }); } catch (bool result) { return result; } return false; } /** * Check according session policy device usage */ bool permit_device(Genode::uint8_t b, Genode::uint8_t d, Genode::uint8_t f, unsigned class_code) { using namespace Genode; try { _policy.for_each_sub_node("pci", [&] (Xml_node node) { try { unsigned bus, device, function; node.attribute("bus").value(&bus); node.attribute("device").value(&device); node.attribute("function").value(&function); if (b == bus && d == device && f == function) throw true; return; } catch (Xml_attribute::Nonexistent_attribute) { } /* enforce restriction based upon classes */ unsigned class_sub_prog = 0; try { char alias_class[32]; node.attribute("class").value(alias_class, sizeof(alias_class)); class_sub_prog = class_subclass_prog(alias_class); } catch (Xml_attribute::Nonexistent_attribute) { return; } enum { DONT_CHECK_PROGIF = 8 }; /* if class/subclass don't match - deny */ if (class_sub_prog && (class_sub_prog ^ class_code) >> DONT_CHECK_PROGIF) return; /* if this bdf is used by some policy - deny */ if (find_dev_in_policy(b, d, f)) return; throw true; }); } catch (bool result) { return result; } return false; } /** * Lookup a given device name. */ bool find_dev_in_policy(const char * dev_name, bool once = true) { using namespace Genode; try { _config.xml().for_each_sub_node("policy", [&] (Xml_node policy) { policy.for_each_sub_node("device", [&] (Xml_node device) { try { /* device attribute from policy node */ char policy_device[8]; device.attribute("name").value(policy_device, sizeof(policy_device)); if (!strcmp(policy_device, dev_name)) { if (once) throw true; once = true; } } catch (Xml_node::Nonexistent_attribute) { } }); }); } catch (bool result) { return result; } return false; } /** * Lookup a given device name. */ bool find_dev_in_policy(Genode::uint8_t b, Genode::uint8_t d, Genode::uint8_t f, bool once = true) { using namespace Genode; try { Xml_node xml = _config.xml(); xml.for_each_sub_node("policy", [&] (Xml_node policy) { policy.for_each_sub_node("pci", [&] (Xml_node node) { try { unsigned bus, device, function; node.attribute("bus").value(&bus); node.attribute("device").value(&device); node.attribute("function").value(&function); if (b == bus && d == device && f == function) { if (once) throw true; once = true; } } catch (Xml_node::Nonexistent_attribute) { } }); }); } catch (bool result) { return result; } return false; } public: /** * Constructor */ Session_component(Genode::Env &env, Genode::Attached_rom_dataspace &config, Platform::Pci_buses &buses, Genode::Heap &global_heap, char const *args) : _env(env), _config(config), _env_ram(env.ram(), Genode::ram_quota_from_args(args).value), _md_alloc(_env_ram, env.rm()), _label(Genode::label_from_args(args)), _pci_bus(buses), _global_heap(global_heap) { /* non-pci devices */ _policy.for_each_sub_node("device", [&] (Genode::Xml_node device_node) { try { char policy_device[8]; device_node.attribute("name").value(policy_device, sizeof(policy_device)); enum { DOUBLET = false }; if (!find_dev_in_policy(policy_device, DOUBLET)) return; Genode::error("'", _label, "' - device " "'", Genode::Cstring(policy_device), "' " "is part of more than one policy"); } catch (Genode::Xml_node::Nonexistent_attribute) { Genode::error("'", _label, "' - device node " "misses a 'name' attribute"); } throw Genode::Service_denied(); }); /* pci devices */ _policy.for_each_sub_node("pci", [&] (Genode::Xml_node node) { enum { INVALID_CLASS = 0x1000000U }; unsigned class_sub_prog = INVALID_CLASS; using Genode::Xml_attribute; /** * Valid input is either a triple of 'bus', 'device', * 'function' attributes or a single 'class' attribute. * All other attribute names are traded as wrong. */ try { char alias_class[32]; node.attribute("class").value(alias_class, sizeof(alias_class)); class_sub_prog = class_subclass_prog(alias_class); if (class_sub_prog >= INVALID_CLASS) { Genode::error("'", _label, "' - invalid 'class' ", "attribute '", Genode::Cstring(alias_class), "'"); throw Genode::Service_denied(); } } catch (Xml_attribute::Nonexistent_attribute) { } /* if we read a class attribute all is fine */ if (class_sub_prog < INVALID_CLASS) { /* sanity check that 'class' is the only attribute */ try { node.attribute(1); Genode::error("'", _label, "' - attributes beside 'class' detected"); throw Genode::Service_denied(); } catch (Xml_attribute::Nonexistent_attribute) { } /* we have a class and it is the only attribute */ return; } /* no 'class' attribute - now check for valid bdf triple */ try { node.attribute(3); Genode::error("'", _label, "' - " "invalid number of pci node attributes"); throw Genode::Service_denied(); } catch (Xml_attribute::Nonexistent_attribute) { } try { unsigned bus, device, function; node.attribute("bus").value(&bus); node.attribute("device").value(&device); node.attribute("function").value(&function); if ((bus >= Device_config::MAX_BUSES) || (device >= Device_config::MAX_DEVICES) || (function >= Device_config::MAX_FUNCTIONS)) throw Xml_attribute::Nonexistent_attribute(); enum { DOUBLET = false }; if (!find_dev_in_policy(bus, device, function, DOUBLET)) return; Genode::error("'", _label, "' - device '", Genode::Hex(bus), ":", Genode::Hex(device), ".", function, "' " "is part of more than one policy"); } catch (Xml_attribute::Nonexistent_attribute) { Genode::error("'", _label, "' - " "invalid pci node attributes for bdf"); } throw Genode::Service_denied(); }); } /** * Destructor */ ~Session_component() { /* release all elements of the session's device list */ while (_device_list.first()) release_device(_device_list.first()->cap()); while (Platform::Ram_dataspace *ds = _ram_caps.first()) { _ram_caps.remove(ds); _env_ram.free(ds->cap()); destroy(_md_alloc, ds); } } void upgrade_ram_quota(long quota) { _env_ram.upgrade(quota); } static void add_config_space(Genode::uint32_t bdf_start, Genode::uint32_t func_count, Genode::addr_t base, Genode::Allocator &heap) { using namespace Genode; Config_space * space = new (heap) Config_space(bdf_start, func_count, base); config_space_list().insert(space); } /** * Check whether msi usage was explicitly switched off */ bool msi_usage() { try { char mode[8]; _policy.attribute("irq_mode").value(mode, sizeof(mode)); if (!Genode::strcmp("nomsi", mode)) return false; } catch (Genode::Xml_node::Nonexistent_attribute) { } return true; } /*************************** ** PCI session interface ** ***************************/ Device_capability first_device(unsigned device_class, unsigned class_mask) override { return next_device(Device_capability(), device_class, class_mask); } Device_capability next_device(Device_capability prev_device, unsigned device_class, unsigned class_mask) override { /* * Create the interface to the PCI config space. * This involves the creation of I/O port sessions. */ Config_access config_access(_env); /* lookup device component for previous device */ auto lambda = [&] (Device_component *prev) { /* * Start bus scanning after the previous device's location. * If no valid device was specified for 'prev_device', * start at the beginning. */ int bus = 0, device = 0, function = -1; if (prev) { Device_config config = prev->config(); bus = config.bus_number(); device = config.device_number(); function = config.function_number(); } /* * Scan buses for devices. * If no device is found, return an invalid capability. */ Device_config config; while (true) { function += 1; if (!_pci_bus.find_next(bus, device, function, &config, &config_access)) return Device_capability(); /* get new bdf values */ bus = config.bus_number(); device = config.device_number(); function = config.function_number(); /* if filter of driver don't match skip and continue */ if ((config.class_code() ^ device_class) & class_mask) continue; /* check that policy permit access to the matched device */ if (permit_device(bus, device, function, config.class_code())) break; } /* lookup if we have a extended pci config space */ Genode::addr_t config_space = lookup_config_space(config.bdf()); /* * A device was found. Create a new device component for the * device and return its capability. */ try { Device_component * dev = new (_md_alloc) Device_component(_env, config, config_space, *this, _md_alloc, _global_heap); /* if more than one driver uses the device - warn about */ if (bdf_in_use.get(Device_config::MAX_BUSES * bus + Device_config::MAX_DEVICES * device + function, 1)) Genode::error("Device ", config, " is used by more than one driver - " "session '", _label, "'."); else bdf_in_use.set(Device_config::MAX_BUSES * bus + Device_config::MAX_DEVICES * device + function, 1); _device_list.insert(dev); return _env.ep().rpc_ep().manage(dev); } catch (Genode::Out_of_ram) { throw; } catch (Genode::Out_of_caps) { Genode::warning("Out_of_caps during Device_component construction"); throw; } }; return _env.ep().rpc_ep().apply(prev_device, lambda); } void release_device(Device_capability device_cap) override { Device_component * device; auto lambda = [&] (Device_component *d) { device = d; if (!device) return; unsigned const bus = device->config().bus_number(); unsigned const dev = device->config().device_number(); unsigned const func = device->config().function_number(); if (bdf_in_use.get(Device_config::MAX_BUSES * bus + Device_config::MAX_DEVICES * dev + func, 1)) bdf_in_use.clear(Device_config::MAX_BUSES * bus + Device_config::MAX_DEVICES * dev + func, 1); _device_list.remove(device); _env.ep().rpc_ep().dissolve(device); }; /* lookup device component for previous device */ _env.ep().rpc_ep().apply(device_cap, lambda); if (!device) return; if (device->config().valid()) destroy(_md_alloc, device); else destroy(_md_alloc, device); } void assign_device(Device_component * device) { using namespace Genode; if (!device || !device->get_config_space().valid()) return; Io_mem_dataspace_capability io_mem = device->get_config_space(); try { _device_pd.assign_pci(io_mem, device->config().bdf()); for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) { Io_mem_dataspace_capability rmrr_cap = r->match(_env, device->config()); if (rmrr_cap.valid()) _device_pd.attach_dma_mem(rmrr_cap); } } catch (...) { Genode::error("assignment to device pd or of RMRR region failed"); } } /** * De-/Allocation of dma capable dataspaces */ Ram_capability alloc_dma_buffer(Genode::size_t const size) override { Ram_capability ram_cap = _env_ram.alloc(size, Genode::UNCACHED); if (!ram_cap.valid()) return ram_cap; try { _device_pd.attach_dma_mem(ram_cap); _insert(ram_cap); } catch (Out_of_ram) { _env_ram.free(ram_cap); throw Genode::Out_of_ram(); } catch (Out_of_caps) { _env_ram.free(ram_cap); throw Genode::Out_of_caps(); } return ram_cap; } void free_dma_buffer(Ram_capability ram_cap) override { if (!ram_cap.valid() || !_remove(ram_cap)) return; _env_ram.free(ram_cap); } Device_capability device(String const &name) override; }; class Platform::Root : public Genode::Root_component { private: struct Fadt { Genode::uint32_t features = 0, reset_type = 0, reset_value = 0; Genode::uint64_t reset_addr = 0; /* Table 5-35 Fixed ACPI Description Table Fixed Feature Flags */ struct Features : Genode::Register<32> { struct Reset : Bitfield<10, 1> { }; }; /* ACPI spec - 5.2.3.2 Generic Address Structure */ struct Gas : Genode::Register<32> { struct Address_space : Bitfield <0, 8> { enum { SYSTEM_IO = 1 }; }; struct Access_size : Bitfield<24,8> { enum { UNDEFINED = 0, BYTE = 1, WORD = 2, DWORD = 3, QWORD = 4}; }; }; } fadt; Genode::Env &_env; Genode::Attached_rom_dataspace &_config; Genode::Reporter _pci_reporter { _env, "pci" }; Genode::Heap _heap { _env.ram(), _env.rm() }; Platform::Pci_buses _buses { _env, _heap }; void _parse_report_rom(Genode::Env &env, const char * acpi_rom) { using namespace Genode; Config_access config_access(env); Xml_node xml_acpi(acpi_rom); if (!xml_acpi.has_type("acpi")) throw 1; for (unsigned i = 0; i < xml_acpi.num_sub_nodes(); i++) { Xml_node node = xml_acpi.sub_node(i); if (node.has_type("bdf")) { uint32_t bdf_start = 0; uint32_t func_count = 0; addr_t base = 0; node.attribute("start").value(&bdf_start); node.attribute("count").value(&func_count); node.attribute("base").value(&base); Session_component::add_config_space(bdf_start, func_count, base, _heap); } if (node.has_type("irq_override")) { unsigned irq = 0xff; unsigned gsi = 0xff; unsigned flags = 0xff; node.attribute("irq").value(&irq); node.attribute("gsi").value(&gsi); node.attribute("flags").value(&flags); using Platform::Irq_override; Irq_override * o = new (_heap) Irq_override(irq, gsi, flags); Irq_override::list()->insert(o); } if (node.has_type("rmrr")) { uint64_t mem_start = 0, mem_end = 0; node.attribute("start").value(&mem_start); node.attribute("end").value(&mem_end); if (node.num_sub_nodes() == 0) throw 2; Rmrr * rmrr = new (_heap) Rmrr(mem_start, mem_end); Rmrr::list()->insert(rmrr); for (unsigned s = 0; s < node.num_sub_nodes(); s++) { Xml_node scope = node.sub_node(s); if (!scope.num_sub_nodes() || !scope.has_type("scope")) throw 3; unsigned bus = 0, dev = 0, func = 0; scope.attribute("bus_start").value(&bus); for (unsigned p = 0; p < scope.num_sub_nodes(); p++) { Xml_node path = scope.sub_node(p); if (!path.has_type("path")) throw 4; path.attribute("dev").value(&dev); path.attribute("func").value(&func); Device_config bridge(bus, dev, func, &config_access); if (bridge.pci_bridge()) /* PCI bridge spec 3.2.5.3, 3.2.5.4 */ bus = bridge.read(&config_access, 0x19, Device::ACCESS_8BIT); } rmrr->add(new (_heap) Rmrr::Bdf(bus, dev, func)); } } if (node.has_type("fadt")) { node.attribute("features").value(&fadt.features); node.attribute("reset_type").value(&fadt.reset_type); node.attribute("reset_addr").value(&fadt.reset_addr); node.attribute("reset_value").value(&fadt.reset_value); } if (!node.has_type("routing")) continue; unsigned gsi; unsigned bridge_bdf; unsigned device; unsigned device_pin; node.attribute("gsi").value(&gsi); node.attribute("bridge_bdf").value(&bridge_bdf); node.attribute("device").value(&device); node.attribute("device_pin").value(&device_pin); /* check that bridge bdf is actually a valid device */ Device_config config((bridge_bdf >> 8 & 0xff), (bridge_bdf >> 3) & 0x1f, bridge_bdf & 0x7, &config_access); if (!config.valid()) continue; if (!config.pci_bridge() && bridge_bdf != 0) /** * If the bridge bdf has not a type header of a bridge in * the pci config space, then it should be the host bridge * device. The host bridge device need not to be * necessarily at 0:0.0, it may be on another location. The * irq routing information for the host bridge however * contain entries for the bridge bdf to be 0:0.0 - * therefore we override it here for the irq rerouting * information of host bridge devices. */ bridge_bdf = 0; Irq_routing * r = new (_heap) Irq_routing(gsi, bridge_bdf, device, device_pin); Irq_routing::list()->insert(r); } } protected: Session_component *_create_session(const char *args) { try { return new (md_alloc()) Session_component(_env, _config, _buses, _heap, args); } catch (Genode::Session_policy::No_policy_defined) { Genode::error("Invalid session request, no matching policy for ", "'", Genode::label_from_args(args).string(), "'"); throw Genode::Service_denied(); } } void _upgrade_session(Session_component *s, const char *args) override { long ram_quota = Genode::Arg_string::find_arg(args, "ram_quota").long_value(0); s->upgrade_ram_quota(ram_quota); } public: /** * Constructor * * \param ep entry point to be used for serving the PCI session * and PCI device interface * \param md_alloc meta-data allocator for allocating PCI-session * components and PCI-device components */ Root(Genode::Env &env, Genode::Allocator &md_alloc, Genode::Attached_rom_dataspace &config, const char *acpi_rom) : Genode::Root_component(&env.ep().rpc_ep(), &md_alloc), _env(env), _config(config) { if (acpi_rom) { try { _parse_report_rom(env, acpi_rom); } catch (...) { Genode::error("PCI config space data could not be parsed."); } } _pci_reporter.enabled(config.xml().has_sub_node("report") && config.xml().sub_node("report") .attribute_value("pci", true)); if (_pci_reporter.enabled()) { Config_access config_access(env); Device_config config; int bus = 0, device = 0, function = -1; Genode::Reporter::Xml_generator xml(_pci_reporter, [&] () { /* iterate over pci devices */ while (true) { function += 1; if (!_buses.find_next(bus, device, function, &config, &config_access)) return; bus = config.bus_number(); device = config.device_number(); function = config.function_number(); using Genode::String; using Genode::Hex; xml.node("device", [&] () { xml.attribute("bdf" , String<8>(Hex(bus, Hex::Prefix::OMIT_PREFIX), ":", Hex(device, Hex::Prefix::OMIT_PREFIX), ".", function)); xml.attribute("vendor_id" , String<8>(Hex(config.vendor_id()))); xml.attribute("device_id" , String<8>(Hex(config.device_id()))); xml.attribute("class_code", String<12>(Hex(config.class_code()))); xml.attribute("bridge" , config.pci_bridge() ? "yes" : "no"); }); } }); } } void system_reset() { const bool io_port_space = (Fadt::Gas::Address_space::get(fadt.reset_type) == Fadt::Gas::Address_space::SYSTEM_IO); if (!io_port_space) return; Config_access config_access(_env); const unsigned raw_access_size = Fadt::Gas::Access_size::get(fadt.reset_type); const bool reset_support = config_access.reset_support(fadt.reset_addr, raw_access_size); if (!reset_support) return; const bool feature_reset = Fadt::Features::Reset::get(fadt.features); if (!feature_reset) { Genode::warning("system reset failed - feature not supported"); return; } Device::Access_size access_size = Device::ACCESS_8BIT; unsigned raw_size = Fadt::Gas::Access_size::get(fadt.reset_type); switch (raw_size) { case Fadt::Gas::Access_size::WORD: access_size = Device::ACCESS_16BIT; break; case Fadt::Gas::Access_size::DWORD: access_size = Device::ACCESS_32BIT; break; case Fadt::Gas::Access_size::QWORD: Genode::error("system reset failed - unsupported access size"); return; default: break; } config_access.system_reset(fadt.reset_addr, fadt.reset_value, access_size); /* if we are getting here - the reset failed */ Genode::warning("system reset failed"); } };