diff --git a/repos/base/run/platform_drv.inc b/repos/base/run/platform_drv.inc index e5ad96607..edde5c9eb 100644 --- a/repos/base/run/platform_drv.inc +++ b/repos/base/run/platform_drv.inc @@ -54,8 +54,8 @@ proc audio_drv_binary { } { proc platform_drv_build_components {} { set drv_build_components "" lappend_if [have_platform_drv] drv_build_components drivers/platform - lappend_if [have_spec acpi] drv_build_components drivers/acpi - lappend_if [have_spec acpi] drv_build_components server/report_rom + lappend_if [have_spec x86] drv_build_components drivers/acpi + lappend_if [have_spec x86] drv_build_components server/report_rom return $drv_build_components } @@ -68,9 +68,16 @@ proc append_platform_drv_build_components {} { proc platform_drv_boot_modules {} { set drv_boot_modules "" lappend_if [have_platform_drv] drv_boot_modules platform_drv - lappend_if [have_spec acpi] drv_boot_modules acpi_drv - lappend_if [have_spec acpi] drv_boot_modules report_rom - lappend_if [have_spec muen] drv_boot_modules acpi + lappend_if [have_spec x86] drv_boot_modules report_rom + + if {[have_spec x86]} { + if {[have_spec muen]} { + lappend drv_boot_modules acpi + } else { + lappend drv_boot_modules acpi_drv + } + } + return $drv_boot_modules } @@ -104,7 +111,7 @@ proc platform_drv_policy {} { proc platform_drv_priority {} { return "" } proc platform_drv_add_routing {} { - if {[have_spec acpi]} { + if {[have_spec x86]} { return { } } @@ -127,7 +134,7 @@ proc platform_drv_config_config {} { proc platform_drv_config {} { set drv_config "" - if {[have_spec acpi]} { + if {[have_spec x86] && ![have_spec muen] && ![have_spec linux]} { append drv_config { @@ -175,7 +182,7 @@ proc platform_drv_config {} { } - append_if [have_spec acpi] drv_config { + append_if [have_spec x86] drv_config { } append_if [have_spec arm] drv_config { @@ -187,7 +194,7 @@ proc platform_drv_config {} { append drv_config "[platform_drv_add_routing]" - append_if [have_spec acpi] drv_config { + append_if [expr [have_spec x86] && ![have_spec muen]] drv_config { } append_if [have_spec rpi] drv_config { diff --git a/repos/os/src/drivers/platform/spec/x86/README b/repos/os/src/drivers/platform/spec/x86/README index e9a7edfe7..950990bc5 100644 --- a/repos/os/src/drivers/platform/spec/x86/README +++ b/repos/os/src/drivers/platform/spec/x86/README @@ -87,10 +87,10 @@ physical memory address below 4G. Another example is that on 32bit hosts physical to virtual identical mappings of DMA memory for the device_pd (required when IOMMU is used) must be below the kernel memory boundary (3G). -By default the platform driver waits on startup on a report of the acpi driver, -which conatins further information about the platform the platform driver can -not discover (e.g. IRQ re-routing information, pci config extended space -information). +The platform driver waits on startup on the first valid ACPI report, typically +provided dynamically by the acpi driver. +The report contains further information about the hardware the platform driver can +not discover (e.g. IRQ re-routing information, PCI ECAM/MMCONF information). A specific route to a report_rom service named 'acpi_report_rom' looks as in the following: @@ -105,17 +105,6 @@ in the following: ! ! ... -For platforms which don't support or require the ACPI information - -e.g. base-okl4, base-pistachio, base-fiasco - the platform driver can be -configured to not wait for the acpi report: - -! -! ... -! -! ... -! -! ... - Synchronize ACPI startup and platform driver -------------------------------------------- @@ -123,7 +112,7 @@ If the config attribute 'acpi_ready' is set to 'yes', the platform driver monitors a ROM in XML format named 'acpi_ready'. ! -! +! The platform driver will announce its service not as 'Platform', but instead as 'Acpi' first. @@ -137,21 +126,6 @@ system state changes to "acpi_ready in the XML ROM 'acpi_ready': the platform driver will announce the platform session as 'Platform', so that drivers may start to operate with the platform driver. -Hardware reset --------------- -If the config attribute 'system' is set to 'yes', the platform driver monitors -a ROM in XML format named 'system'. - -! -! - -If the attribute 'state' in the system XML ROM turns to 'reset' - -! - -the platform driver will try to reset the machine, if the required I/O ports -are owned by it. - Supported PCI class aliases --------------------------- diff --git a/repos/os/src/drivers/platform/spec/x86/device_pd.cc b/repos/os/src/drivers/platform/spec/x86/device_pd.cc index a1a97091f..924f59d14 100644 --- a/repos/os/src/drivers/platform/spec/x86/device_pd.cc +++ b/repos/os/src/drivers/platform/spec/x86/device_pd.cc @@ -58,21 +58,22 @@ void Platform::Device_pd::attach_dma_mem(Genode::Dataspace_capability ds_cap) } } -void Platform::Device_pd::assign_pci(Genode::Io_mem_dataspace_capability io_mem_cap, - Genode::uint16_t rid) +void Platform::Device_pd::assign_pci(Genode::Io_mem_dataspace_capability const io_mem_cap, + Genode::addr_t const offset, + Genode::uint16_t const rid) { using namespace Genode; Dataspace_client ds_client(io_mem_cap); - addr_t page = _address_space.attach(io_mem_cap); + addr_t page = _address_space.attach(io_mem_cap, 0x1000, offset); /* sanity check */ if (!page) throw Region_map::Region_conflict(); /* trigger eager mapping of memory */ - _pd.map(page, ds_client.size()); + _pd.map(page, 0x1000); /* utility to print rid value */ struct Rid @@ -92,7 +93,7 @@ void Platform::Device_pd::assign_pci(Genode::Io_mem_dataspace_capability io_mem_ /* try to assign pci device to this protection domain */ if (!_pd.assign_pci(page, rid)) Genode::error(_label, ": assignment of PCI device ", Rid(rid), " failed ", - "phys=", Genode::Hex(ds_client.phys_addr()), " " + "phys=", Genode::Hex(ds_client.phys_addr() + offset), " " "virt=", Genode::Hex(page)); else Genode::log(_label,": assignment of PCI device ", Rid(rid), " succeeded"); diff --git a/repos/os/src/drivers/platform/spec/x86/device_pd.h b/repos/os/src/drivers/platform/spec/x86/device_pd.h index 9c53d7bc7..a52cecf48 100644 --- a/repos/os/src/drivers/platform/spec/x86/device_pd.h +++ b/repos/os/src/drivers/platform/spec/x86/device_pd.h @@ -109,5 +109,6 @@ class Platform::Device_pd } void attach_dma_mem(Genode::Dataspace_capability); - void assign_pci(Genode::Io_mem_dataspace_capability, Genode::uint16_t); + void assign_pci(Genode::Io_mem_dataspace_capability const, + Genode::addr_t const, Genode::uint16_t const); }; diff --git a/repos/os/src/drivers/platform/spec/x86/main.cc b/repos/os/src/drivers/platform/spec/x86/main.cc index 1d41939c4..d4d4802b2 100644 --- a/repos/os/src/drivers/platform/spec/x86/main.cc +++ b/repos/os/src/drivers/platform/spec/x86/main.cc @@ -57,8 +57,9 @@ struct Platform::Main return; const char * report_addr = acpi_rom->local_addr(); + bool const acpi_platform = _config.xml().attribute_value("acpi", true); - root.construct(_env, sliced_heap, _config, report_addr); + root.construct(_env, sliced_heap, _config, report_addr, acpi_platform); root_cap = _env.ep().manage(*root); @@ -71,26 +72,12 @@ struct Platform::Main void system_update() { - if (system_state.is_constructed()) - system_state->update(); - if (acpi_ready.is_constructed()) acpi_ready->update(); if (!root.is_constructed()) return; - if (system_state.is_constructed() && system_state->is_valid()) { - Genode::Xml_node system(system_state->local_addr(), - system_state->size()); - - typedef Genode::String<16> Value; - const Value state = system.attribute_value("state", Value("unknown")); - - if (state == "reset") - root->system_reset(); - } - if (acpi_ready.is_constructed() && acpi_ready->is_valid()) { Genode::Xml_node system(acpi_ready->local_addr(), acpi_ready->size()); @@ -112,34 +99,20 @@ struct Platform::Main _system_report(_env.ep(), *this, &Main::system_update) { const Genode::Xml_node config = _config.xml(); - bool const system_rom = config.attribute_value("system", false); - bool const wait_for_acpi = config.attribute_value("acpi", true); - _acpi_ready = config.attribute_value("acpi_ready", false); - if (system_rom) { - /* wait for system state changes, e.g. reset and acpi_ready */ - system_state.construct(env, "system"); - system_state->sigh(_system_report); - } + _acpi_ready = config.attribute_value("acpi_ready", false); if (_acpi_ready) { acpi_ready.construct(env, "acpi_ready"); acpi_ready->sigh(_system_report); } - if (wait_for_acpi) { - /* for ACPI support, wait for the first valid acpi report */ - acpi_rom.construct(env, "acpi"); - acpi_rom->sigh(_acpi_report); - /* check if already valid */ - acpi_update(); - system_update(); - return; - } - - /* non ACPI platform case */ - root.construct(_env, sliced_heap, _config, nullptr); - _env.parent().announce(_env.ep().manage(*root)); + /* wait for the first valid acpi report */ + acpi_rom.construct(env, "acpi"); + acpi_rom->sigh(_acpi_report); + /* check if already valid */ + acpi_update(); + system_update(); } }; diff --git a/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc b/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc index 432b84f93..7179a20f4 100644 --- a/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc +++ b/repos/os/src/drivers/platform/spec/x86/nonpci_devices.cc @@ -36,10 +36,12 @@ class Nonpci::Ps2 : public Platform::Device_component public: - Ps2(Genode::Env &env, Platform::Session_component &session, + Ps2(Genode::Env &env, + Genode::Attached_io_mem_dataspace &pciconf, + Platform::Session_component &session, Genode::Allocator &heap_for_irq) : - Platform::Device_component(env, session, IRQ_KEYBOARD, heap_for_irq), + Platform::Device_component(env, pciconf, session, IRQ_KEYBOARD, heap_for_irq), _ep(env.ep().rpc_ep()), _irq_mouse(IRQ_MOUSE, ~0UL, env, heap_for_irq), _data(env, REG_DATA, ACCESS_WIDTH), @@ -99,10 +101,12 @@ class Nonpci::Pit : public Platform::Device_component public: - Pit(Genode::Env &env, Platform::Session_component &session, + Pit(Genode::Env &env, + Genode::Attached_io_mem_dataspace &pciconf, + Platform::Session_component &session, Genode::Allocator &heap_for_irq) : - Platform::Device_component(env, session, IRQ_PIT, heap_for_irq), + Platform::Device_component(env, pciconf, session, IRQ_PIT, heap_for_irq), _ports(env, PIT_PORT, PORTS_WIDTH) { } @@ -150,10 +154,10 @@ Platform::Device_capability Platform::Session_component::device(String const &na switch(devices_i) { case 0: - dev = new (_md_alloc) Nonpci::Ps2(_env, *this, _global_heap); + dev = new (_md_alloc) Nonpci::Ps2(_env, _pciconf, *this, _global_heap); break; case 1: - dev = new (_md_alloc) Nonpci::Pit(_env, *this, _global_heap); + dev = new (_md_alloc) Nonpci::Pit(_env, _pciconf, *this, _global_heap); break; default: return Device_capability(); diff --git a/repos/os/src/drivers/platform/spec/x86/pci_config_access.h b/repos/os/src/drivers/platform/spec/x86/pci_config_access.h index 94ba9dc72..ac282ee6b 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_config_access.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_config_access.h @@ -1,6 +1,7 @@ /* * \brief Interface for accessing PCI configuration registers * \author Norman Feske + * \author Reto Buerki * \date 2008-01-29 */ @@ -15,60 +16,36 @@ #define _X86_PCI_CONFIG_ACCESS_H_ #include -#include +#include +#include #include +using namespace Genode; + namespace Platform { class Config_access { private: - Genode::Env &_env; - - enum { REG_ADDR = 0xcf8, REG_DATA = 0xcfc, REG_SIZE = 4 }; + Attached_io_mem_dataspace &_pciconf; + Genode::size_t const _pciconf_size; /** - * Request interface to access an I/O port - */ - template - Genode::Io_port_session *_io_port() - { - /* - * Open I/O-port session when first called. - * The number of instances of the io_port_session_client - * variable depends on the number of instances of the - * template function. - * - * Thanks to this mechanism, the sessions to the PCI - * ports are created lazily when PCI service is first - * used. If the PCI bus driver is just started but not - * used yet, other processes are able to access the PCI - * config space. - * - * Once created, each I/O-port session persists until - * the PCI driver gets killed by its parent. - */ - static Genode::Io_port_connection io_port(_env, port, REG_SIZE); - return &io_port; - } - - /** - * Generate configuration address + * Calculate device offset from BDF * * \param bus target PCI bus ID (0..255) * \param device target device ID (0..31) * \param function target function ID (0..7) - * \param addr target byte within targeted PCI config space (0..255) * - * \return configuration address (written to REG_ADDR register) + * \return device base address */ - unsigned _cfg_addr(int bus, int device, int function, int addr) { - return ( (1 << 31) | - (bus << 16) | - (device << 11) | - (function << 8) | - (addr & ~3) ); } + unsigned _dev_base(int bus, int device, int function) + { + return ((bus << 20) | + (device << 15) | + (function << 12)); + } Genode::Bit_array<256> _used { }; @@ -81,7 +58,16 @@ namespace Platform { public: - Config_access(Genode::Env &env) : _env(env) { } + class Invalid_mmio_access : Genode::Exception { }; + + Config_access(Attached_io_mem_dataspace &pciconf) + : + _pciconf(pciconf), + _pciconf_size(Dataspace_client(_pciconf.cap()).size()) + { } + + Config_access(Config_access &c) + : _pciconf(c._pciconf), _pciconf_size(c._pciconf_size) { } /** * Read value from config space of specified device/function @@ -100,26 +86,41 @@ namespace Platform { unsigned char addr, Device::Access_size size, bool track = true) { - /* write target address */ - _io_port()->outl(REG_ADDR, _cfg_addr(bus, device, function, addr)); + unsigned ret; + unsigned const offset = _dev_base(bus, device, function) + addr; + char const * const field = _pciconf.local_addr() + offset; - /* return read value */ + if (offset >= _pciconf_size) + throw Invalid_mmio_access(); + + /* + * Memory access code is implemented in a way to make it work + * with Muen subject monitor (SM) device emulation and also + * general x86 targets. On Muen, the simplified device + * emulation code (which also works for Linux) always returns + * 0xffff in EAX to indicate a non-existing device. Therefore, + * we enforce the usage of EAX in the following assembly + * templates. Also clear excess bits before return to guarantee + * the requested size. + */ switch (size) { case Device::ACCESS_8BIT: if (track) _use_register(addr, 1); - - return _io_port()->inb(REG_DATA + (addr & 3)); + asm volatile("movb %1,%%al" :"=a" (ret) :"m" (*((volatile unsigned char *)field)) :"memory"); + return ret & 0xff; case Device::ACCESS_16BIT: if (track) _use_register(addr, 2); - return _io_port()->inw(REG_DATA + (addr & 2)); + asm volatile("movw %1,%%ax" :"=a" (ret) :"m" (*(volatile unsigned short *)field) :"memory"); + return ret & 0xffff; case Device::ACCESS_32BIT: if (track) _use_register(addr, 4); - return _io_port()->inl(REG_DATA); + asm volatile("movl %1,%%eax" :"=a" (ret) :"m" (*(volatile unsigned int *)field) :"memory"); + return ret; default: return ~0U; } @@ -141,29 +142,34 @@ namespace Platform { unsigned value, Device::Access_size size, bool track = true) { - /* write target address */ - _io_port()->outl(REG_ADDR, _cfg_addr(bus, device, - function, addr)); + unsigned const offset = _dev_base(bus, device, function) + addr; + char const * const field = _pciconf.local_addr() + offset; - /* write value to targeted address */ + if (offset >= _pciconf_size) + throw Invalid_mmio_access(); + + /* + * Write value to targeted address, see read() comment above + * for an explanation of the assembly templates + */ switch (size) { case Device::ACCESS_8BIT: if (track) _use_register(addr, 1); - _io_port()->outb(REG_DATA + (addr & 3), value); + asm volatile("movb %%al,%1" : :"a" (value), "m" (*(volatile unsigned char *)field) :"memory"); break; case Device::ACCESS_16BIT: if (track) _use_register(addr, 2); - _io_port()->outw(REG_DATA + (addr & 2), value); + asm volatile("movw %%ax,%1" : :"a" (value), "m" (*(volatile unsigned char *)field) :"memory"); break; case Device::ACCESS_32BIT: if (track) _use_register(addr, 4); - _io_port()->outl(REG_DATA, value); + asm volatile("movl %%eax,%1" : :"a" (value), "m" (*(volatile unsigned char *)field) :"memory"); break; } } @@ -181,32 +187,6 @@ namespace Platform { return true; } } - - bool reset_support(unsigned reg, unsigned reg_size) const - { - return (REG_ADDR <= reg) && - reg + reg_size <= REG_ADDR + REG_SIZE; - } - - bool system_reset(unsigned reg, unsigned long long value, - const Device::Access_size &access_size) - { - switch (access_size) { - case Device::ACCESS_8BIT: - _io_port()->outb(reg, value); - break; - case Device::ACCESS_16BIT: - _io_port()->outw(reg, value); - break; - case Device::ACCESS_32BIT: - _io_port()->outl(reg, value); - break; - default: - return false; - } - - return true; - } }; } diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device.cc b/repos/os/src/drivers/platform/spec/x86/pci_device.cc index 2fed491fa..11a5e440d 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device.cc +++ b/repos/os/src/drivers/platform/spec/x86/pci_device.cc @@ -99,7 +99,7 @@ void Platform::Device_component::config_write(unsigned char address, switch (address) { case 0x40 ... 0xff: /* allow access to device-specific registers if not used by us */ - if (!_device_config.reg_in_use(&_config_access, address, size)) + if (!_device_config.reg_in_use(_config_access, address, size)) break; Genode::error(_device_config, " write access to " @@ -134,7 +134,7 @@ void Platform::Device_component::config_write(unsigned char address, } } - _device_config.write(&_config_access, address, value, size, + _device_config.write(_config_access, address, value, size, _device_config.DONT_TRACK_ACCESS); } @@ -172,11 +172,11 @@ Genode::Irq_session_capability Platform::Device_component::irq(Genode::uint8_t i Genode::addr_t msi_address = _irq_session->msi_address(); Genode::uint32_t msi_value = _irq_session->msi_data(); - Genode::uint16_t msi = _device_config.read(&_config_access, + Genode::uint16_t msi = _device_config.read(_config_access, msi_cap + 2, Platform::Device::ACCESS_16BIT); - _device_config.write(&_config_access, msi_cap + 0x4, msi_address, + _device_config.write(_config_access, msi_cap + 0x4, msi_address, Platform::Device::ACCESS_32BIT); if (msi & CAP_MSI_64) { @@ -184,19 +184,19 @@ Genode::Irq_session_capability Platform::Device_component::irq(Genode::uint8_t i ? (Genode::uint64_t)msi_address >> 32 : 0UL; - _device_config.write(&_config_access, msi_cap + 0x8, + _device_config.write(_config_access, msi_cap + 0x8, upper_address, Platform::Device::ACCESS_32BIT); - _device_config.write(&_config_access, msi_cap + 0xc, + _device_config.write(_config_access, msi_cap + 0xc, msi_value, Platform::Device::ACCESS_16BIT); } else - _device_config.write(&_config_access, msi_cap + 0x8, msi_value, + _device_config.write(_config_access, msi_cap + 0x8, msi_value, Platform::Device::ACCESS_16BIT); /* enable MSI */ - _device_config.write(&_config_access, msi_cap + 2, + _device_config.write(_config_access, msi_cap + 2, msi ^ MSI_ENABLED, Platform::Device::ACCESS_8BIT); } @@ -204,7 +204,7 @@ Genode::Irq_session_capability Platform::Device_component::irq(Genode::uint8_t i bool msi_64 = false; bool msi_mask = false; if (msi_cap) { - Genode::uint16_t msi = _device_config.read(&_config_access, + Genode::uint16_t msi = _device_config.read(_config_access, msi_cap + 2, Platform::Device::ACCESS_16BIT); msi_64 = msi & CAP_MSI_64; diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device_component.h b/repos/os/src/drivers/platform/spec/x86/pci_device_component.h index 7123be741..8d9089e8f 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_device_component.h @@ -15,6 +15,7 @@ /* base */ #include +#include #include #include #include @@ -45,13 +46,11 @@ class Platform::Device_component : public Genode::Rpc_object, Genode::Env &_env; Device_config _device_config { }; Genode::addr_t _config_space; - Config_access _config_access { _env }; + Config_access _config_access; Platform::Session_component &_session; unsigned short _irq_line; Irq_session_component *_irq_session = nullptr; - Genode::Constructible _io_mem_config_extended { }; - Genode::Allocator &_global_heap; class Io_mem : public Genode::Io_mem_connection, @@ -108,18 +107,18 @@ class Platform::Device_component : public Genode::Rpc_object, { enum { PCI_STATUS = 0x6, PCI_CAP_OFFSET = 0x34, CAP_MSI = 0x5 }; - Status::access_t status = Status::read(_device_config.read(&_config_access, + Status::access_t status = Status::read(_device_config.read(_config_access, PCI_STATUS, Platform::Device::ACCESS_16BIT)); if (!Status::Capabilities::get(status)) return 0; - Genode::uint8_t cap = _device_config.read(&_config_access, + Genode::uint8_t cap = _device_config.read(_config_access, PCI_CAP_OFFSET, Platform::Device::ACCESS_8BIT); for (Genode::uint16_t val = 0; cap; cap = val >> 8) { - val = _device_config.read(&_config_access, cap, + val = _device_config.read(_config_access, cap, Platform::Device::ACCESS_16BIT); if ((val & 0xff) != CAP_MSI) continue; @@ -139,7 +138,7 @@ class Platform::Device_component : public Genode::Rpc_object, using Genode::uint16_t; using Genode::uint8_t; - uint8_t pin = _device_config.read(&_config_access, PCI_IRQ_PIN, + uint8_t pin = _device_config.read(_config_access, PCI_IRQ_PIN, Platform::Device::ACCESS_8BIT); if (!pin) return Irq_session_component::INVALID_IRQ; @@ -160,12 +159,12 @@ class Platform::Device_component : public Genode::Rpc_object, if (!cap) return irq; - uint16_t msi = _device_config.read(&_config_access, cap + 2, + uint16_t msi = _device_config.read(_config_access, cap + 2, Platform::Device::ACCESS_16BIT); if (msi & MSI_ENABLED) /* disable MSI */ - _device_config.write(&_config_access, cap + 2, + _device_config.write(_config_access, cap + 2, msi ^ MSI_ENABLED, Platform::Device::ACCESS_8BIT); @@ -185,10 +184,10 @@ class Platform::Device_component : public Genode::Rpc_object, if (_device_config.pci_bridge()) return; - unsigned cmd = _device_config.read(&_config_access, PCI_CMD_REG, + unsigned cmd = _device_config.read(_config_access, PCI_CMD_REG, Platform::Device::ACCESS_16BIT); if (cmd & PCI_CMD_DMA) - _device_config.write(&_config_access, PCI_CMD_REG, + _device_config.write(_config_access, PCI_CMD_REG, cmd ^ PCI_CMD_DMA, Platform::Device::ACCESS_16BIT); } @@ -200,14 +199,16 @@ class Platform::Device_component : public Genode::Rpc_object, */ Device_component(Genode::Env &env, Device_config device_config, Genode::addr_t addr, + Config_access &config_access, Platform::Session_component &session, Genode::Allocator &md_alloc, Genode::Allocator &global_heap) : _env(env), _device_config(device_config), _config_space(addr), + _config_access(config_access), _session(session), - _irq_line(_device_config.read(&_config_access, PCI_IRQ_LINE, + _irq_line(_device_config.read(_config_access, PCI_IRQ_LINE, Platform::Device::ACCESS_8BIT)), _global_heap(global_heap), _slab_ioport(&md_alloc, &_slab_ioport_block_data), @@ -224,11 +225,13 @@ class Platform::Device_component : public Genode::Rpc_object, * Constructor for non PCI devices */ Device_component(Genode::Env &env, + Genode::Attached_io_mem_dataspace &pciconf, Platform::Session_component &session, unsigned irq, Genode::Allocator &global_heap) : _env(env), _config_space(~0UL), + _config_access(pciconf), _session(session), _irq_line(irq), _global_heap(global_heap), @@ -239,6 +242,7 @@ class Platform::Device_component : public Genode::Rpc_object, _io_port_conn[i] = nullptr; } + /** * De-constructor */ @@ -267,26 +271,8 @@ class Platform::Device_component : public Genode::Rpc_object, ** Methods used solely by pci session ** ****************************************/ - Device_config config() { return _device_config; } - - Genode::Io_mem_dataspace_capability get_config_space() - { - if (_config_space == ~0UL) - return Genode::Io_mem_dataspace_capability(); - - if (!_io_mem_config_extended.constructed()) { - try { - _io_mem_config_extended.construct(_env, _config_space, 0x1000); - } catch (...) { - _config_space = ~0UL; - } - } - - if (!_io_mem_config_extended.constructed()) - return Genode::Io_mem_dataspace_capability(); - - return _io_mem_config_extended->dataspace(); - } + Device_config config() const { return _device_config; } + Genode::addr_t config_space() const { return _config_space; } /************************** ** PCI-device interface ** @@ -317,7 +303,7 @@ class Platform::Device_component : public Genode::Rpc_object, unsigned config_read(unsigned char address, Access_size size) override { - return _device_config.read(&_config_access, address, size, + return _device_config.read(_config_access, address, size, _device_config.DONT_TRACK_ACCESS); } diff --git a/repos/os/src/drivers/platform/spec/x86/pci_device_config.h b/repos/os/src/drivers/platform/spec/x86/pci_device_config.h index 26206a405..71348cb3c 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_device_config.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_device_config.h @@ -24,7 +24,9 @@ namespace Platform { { private: - int _bus = 0, _device = 0, _function = 0; /* location at PCI bus */ + uint8_t _bus = 0; + uint8_t _device = 0; + uint8_t _function = 0; /* location at PCI bus */ /* * Information provided by the PCI config space @@ -68,6 +70,13 @@ namespace Platform { */ Device_config() : _vendor_id(INVALID_VENDOR) { } + Device_config(unsigned bdf) + : + _bus((bdf >> 8) & 0xff), + _device((bdf >> 3) & 0x1f), + _function(bdf & 0x7) + { } + Device_config(int bus, int device, int function, Config_access *pci_config): _bus(bus), _device(device), _function(function) @@ -149,8 +158,8 @@ namespace Platform { { using Genode::print; using Genode::Hex; - print(out, Hex(_bus, Hex::Prefix::OMIT_PREFIX), - ":", Hex(_device, Hex::Prefix::OMIT_PREFIX), + print(out, Hex(_bus, Hex::Prefix::OMIT_PREFIX, Hex::Pad::PAD), + ":", Hex(_device, Hex::Prefix::OMIT_PREFIX, Hex::Pad::PAD), ".", Hex(_function, Hex::Prefix::OMIT_PREFIX)); } @@ -190,27 +199,27 @@ namespace Platform { * Read configuration space */ enum { DONT_TRACK_ACCESS = false }; - unsigned read(Config_access *pci_config, unsigned char address, + unsigned read(Config_access &pci_config, unsigned char address, Device::Access_size size, bool track = true) { - return pci_config->read(_bus, _device, _function, address, - size, track); + return pci_config.read(_bus, _device, _function, address, + size, track); } /** * Write configuration space */ - void write(Config_access *pci_config, unsigned char address, + void write(Config_access &pci_config, unsigned char address, unsigned long value, Device::Access_size size, bool track = true) { - pci_config->write(_bus, _device, _function, address, value, - size, track); + pci_config.write(_bus, _device, _function, address, value, + size, track); } - bool reg_in_use(Config_access *pci_config, unsigned char address, + bool reg_in_use(Config_access &pci_config, unsigned char address, Device::Access_size size) { - return pci_config->reg_in_use(address, size); } + return pci_config.reg_in_use(address, size); } }; class Config_space : private Genode::List::Element diff --git a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h index 581e458e5..e858c55df 100644 --- a/repos/os/src/drivers/platform/spec/x86/pci_session_component.h +++ b/repos/os/src/drivers/platform/spec/x86/pci_session_component.h @@ -1,5 +1,5 @@ /* - * \brief platform session component + * \brief Platform session component * \author Norman Feske * \date 2008-01-28 */ @@ -152,9 +152,9 @@ class Platform::Pci_buses public: - Pci_buses(Genode::Env &env, Genode::Allocator &heap) + Pci_buses(Genode::Allocator &heap, Genode::Attached_io_mem_dataspace &pciconf) { - Config_access c(env); + Config_access c(pciconf); scan_bus(c, heap); } @@ -207,6 +207,7 @@ class Platform::Session_component : public Genode::Rpc_object Genode::Env &_env; Genode::Attached_rom_dataspace &_config; + Genode::Attached_io_mem_dataspace &_pciconf; Genode::Ram_quota_guard _ram_guard; Genode::Cap_quota_guard _cap_guard; Genode::Constrained_ram_allocator _env_ram { @@ -455,14 +456,16 @@ class Platform::Session_component : public Genode::Rpc_object /** * Constructor */ - Session_component(Genode::Env &env, - Genode::Attached_rom_dataspace &config, - Platform::Pci_buses &buses, - Genode::Heap &global_heap, - char const *args) + Session_component(Genode::Env &env, + Genode::Attached_rom_dataspace &config, + Genode::Attached_io_mem_dataspace &pciconf, + Platform::Pci_buses &buses, + Genode::Heap &global_heap, + char const *args) : _env(env), _config(config), + _pciconf(pciconf), _ram_guard(Genode::ram_quota_from_args(args)), _cap_guard(Genode::cap_quota_from_args(args)), _md_alloc(_env_ram, env.rm()), @@ -637,9 +640,8 @@ class Platform::Session_component : public Genode::Rpc_object { /* * Create the interface to the PCI config space. - * This involves the creation of I/O port sessions. */ - Config_access config_access(_env); + Config_access config_access(_pciconf); /* lookup device component for previous device */ auto lambda = [&] (Device_component *prev) @@ -696,7 +698,7 @@ class Platform::Session_component : public Genode::Rpc_object */ try { Device_component * dev = new (_md_alloc) - Device_component(_env, config, config_space, *this, + Device_component(_env, config, config_space, config_access, *this, _md_alloc, _global_heap); /* if more than one driver uses the device - warn about */ @@ -751,11 +753,7 @@ class Platform::Session_component : public Genode::Rpc_object /* 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 + if (device && device->config().valid()) destroy(_md_alloc, device); } @@ -763,13 +761,20 @@ class Platform::Session_component : public Genode::Rpc_object { using namespace Genode; - if (!device || !device->get_config_space().valid()) + if (!device || device->config_space() == ~0UL) return; - Io_mem_dataspace_capability io_mem = device->get_config_space(); - try { - _device_pd.assign_pci(io_mem, device->config().bdf()); + addr_t const function = device->config().bus_number() * 32 * 8 + + device->config().device_number() * 8 + + device->config().function_number(); + addr_t const base_ecam = Dataspace_client(_pciconf.cap()).phys_addr(); + addr_t const base_offset = 0x1000UL * function; + + if (base_ecam + base_offset != device->config_space()) + throw 1; + + _device_pd.assign_pci(_pciconf.cap(), base_offset, device->config().bdf()); for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) { Io_mem_dataspace_capability rmrr_cap = r->match(_env, device->config()); @@ -846,37 +851,65 @@ class Platform::Root : public Genode::Root_component Genode::Env &_env; Genode::Attached_rom_dataspace &_config; + Genode::Constructible _pci_confspace { }; + Genode::Reporter _pci_reporter { _env, "pci" }; - Genode::Heap _heap { _env.ram(), _env.rm() }; - Platform::Pci_buses _buses { _env, _heap }; + Genode::Heap _heap { _env.ram(), _env.rm() }; - void _parse_report_rom(Genode::Env &env, const char * acpi_rom) + Genode::Constructible _buses { }; + + void _parse_report_rom(Genode::Env &env, const char * acpi_rom, + bool acpi_platform) { using namespace Genode; - Config_access config_access(env); - Xml_node xml_acpi(acpi_rom); if (!xml_acpi.has_type("acpi")) throw 1; + xml_acpi.for_each_sub_node("bdf", [&] (Xml_node &node) { + + 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); + + Device_config const bdf_first(bdf_start); + Device_config const bdf_last(bdf_start + func_count - 1); + addr_t const memory_size = 0x1000UL * func_count; + + /* Simplification: Only consider first config space and + * check if it is for domain 0 */ + if (bdf_start || _pci_confspace.constructed()) { + warning("ECAM/MMCONF range ", + bdf_first, "-", bdf_last, " - addr ", + Hex_range(base, memory_size), " ignored"); + return; + } + + log("ECAM/MMCONF range ", bdf_first, "-", bdf_last, " - addr ", + Hex_range(base, memory_size)); + + _pci_confspace.construct(env, base, memory_size); + }); + + if (!_pci_confspace.constructed()) + throw 2; + + Config_access config_access(*_pci_confspace); + 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("bdf")) + continue; if (node.has_type("irq_override")) { unsigned irq = 0xff; @@ -887,10 +920,17 @@ class Platform::Root : public Genode::Root_component node.attribute("gsi").value(&gsi); node.attribute("flags").value(&flags); + if (!acpi_platform) { + warning("MADT IRQ ", irq, "-> GSI ", gsi, " flags ", + flags, " ignored"); + continue; + } + using Platform::Irq_override; Irq_override * o = new (_heap) Irq_override(irq, gsi, flags); Irq_override::list()->insert(o); + continue; } if (node.has_type("rmrr")) { @@ -899,7 +939,7 @@ class Platform::Root : public Genode::Root_component node.attribute("end").value(&mem_end); if (node.num_sub_nodes() == 0) - throw 2; + throw 3; Rmrr * rmrr = new (_heap) Rmrr(mem_start, mem_end); Rmrr::list()->insert(rmrr); @@ -907,7 +947,7 @@ class Platform::Root : public Genode::Root_component 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; + throw 4; unsigned bus = 0, dev = 0, func = 0; scope.attribute("bus_start").value(&bus); @@ -915,7 +955,7 @@ class Platform::Root : public Genode::Root_component for (unsigned p = 0; p < scope.num_sub_nodes(); p++) { Xml_node path = scope.sub_node(p); if (!path.has_type("path")) - throw 4; + throw 5; path.attribute("dev").value(&dev); path.attribute("func").value(&func); @@ -924,12 +964,13 @@ class Platform::Root : public Genode::Root_component &config_access); if (bridge.pci_bridge()) /* PCI bridge spec 3.2.5.3, 3.2.5.4 */ - bus = bridge.read(&config_access, 0x19, + bus = bridge.read(config_access, 0x19, Device::ACCESS_8BIT); } rmrr->add(new (_heap) Rmrr::Bdf(bus, dev, func)); } + continue; } if (node.has_type("fadt")) { @@ -937,10 +978,13 @@ class Platform::Root : public Genode::Root_component node.attribute("reset_type").value(&fadt.reset_type); node.attribute("reset_addr").value(&fadt.reset_addr); node.attribute("reset_value").value(&fadt.reset_value); + continue; } - if (!node.has_type("routing")) - continue; + if (!node.has_type("routing")) { + error ("unsupported node '", node.type(), "'"); + throw __LINE__; + } unsigned gsi; unsigned bridge_bdf; @@ -960,6 +1004,20 @@ class Platform::Root : public Genode::Root_component if (!config.valid()) continue; + /* drop routing information on non ACPI platform */ + if (!acpi_platform) { + if (config.pci_bridge()) + continue; + + Device_config dev(device << 3); + + enum { PCI_IRQ_LINE = 0x3c }; + uint8_t pin = dev.read(config_access, PCI_IRQ_LINE, + Platform::Device::ACCESS_8BIT); + warning(dev, " ignore ACPI IRQ routing: ", pin, "->", gsi); + continue; + } + if (!config.pci_bridge() && bridge_bdf != 0) /** * If the bridge bdf has not a type header of a bridge in @@ -979,13 +1037,52 @@ class Platform::Root : public Genode::Root_component } } + void _construct_buses() + { + Genode::Dataspace_client ds_pci_mmio(_pci_confspace->cap()); + uint64_t const phys_addr = ds_pci_mmio.phys_addr(); + uint64_t const phys_size = ds_pci_mmio.size(); + uint64_t mmio_size = 0x10000000UL; /* max MMCONF memory */ + + /* try surviving wrong ACPI ECAM/MMCONF table information */ + while (true) { + try { + _buses.construct(_heap, *_pci_confspace); + /* construction and scan succeeded */ + break; + } catch (Platform::Config_access::Invalid_mmio_access) { + + error("ECAM/MMCONF MMIO access out of bounds - " + "ACPI table information is wrong!"); + + _pci_confspace.destruct(); + + while (mmio_size > phys_size) { + try { + error(" adjust size from ", Hex(phys_size), + "->", Hex(mmio_size)); + _pci_confspace.construct(_env, phys_addr, mmio_size); + /* got memory - try again */ + break; + } catch (Genode::Service_denied) { + /* decrease by one bus memory size */ + mmio_size -= 0x1000UL * 32 * 8; + } + } + if (mmio_size <= phys_size) + /* broken machine - you're lost */ + throw; + } + } + } + protected: Session_component *_create_session(const char *args) { try { return new (md_alloc()) - Session_component(_env, _config, _buses, _heap, args); + Session_component(_env, _config, *_pci_confspace, *_buses, _heap, args); } catch (Genode::Session_policy::No_policy_defined) { Genode::error("Invalid session request, no matching policy for ", @@ -1010,27 +1107,30 @@ class Platform::Root : public Genode::Root_component */ Root(Genode::Env &env, Genode::Allocator &md_alloc, Genode::Attached_rom_dataspace &config, - const char *acpi_rom) + const char *acpi_rom, + bool acpi_platform) : 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."); - } + + try { + _parse_report_rom(env, acpi_rom, acpi_platform); + } catch (...) { + Genode::error("ACPI report parsing error."); + throw; } + _construct_buses(); + _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); + Config_access config_access(*_pci_confspace); Device_config config; int bus = 0, device = 0, function = -1; @@ -1038,8 +1138,8 @@ class Platform::Root : public Genode::Root_component /* iterate over pci devices */ while (true) { function += 1; - if (!_buses.find_next(bus, device, function, &config, - &config_access)) + if (!(*_buses).find_next(bus, device, function, &config, + &config_access)) return; bus = config.bus_number(); @@ -1060,47 +1160,4 @@ class Platform::Root : public Genode::Root_component }); } } - - 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"); - } }; diff --git a/repos/os/src/drivers/platform/spec/x86/session.cc b/repos/os/src/drivers/platform/spec/x86/session.cc index 57b008c80..301760cd6 100644 --- a/repos/os/src/drivers/platform/spec/x86/session.cc +++ b/repos/os/src/drivers/platform/spec/x86/session.cc @@ -55,9 +55,9 @@ void Platform::Pci_buses::scan_bus(Config_access &config_access, /* scan behind bridge */ if (config.pci_bridge()) { /* PCI bridge spec 3.2.5.3, 3.2.5.4 */ - unsigned char sec_bus = config.read(&config_access, 0x19, + unsigned char sec_bus = config.read(config_access, 0x19, Device::ACCESS_8BIT); - unsigned char sub_bus = config.read(&config_access, 0x20, + unsigned char sub_bus = config.read(config_access, 0x20, Device::ACCESS_8BIT); bridges()->insert(new (heap) Bridge(bus, dev, fun, sec_bus, @@ -68,16 +68,18 @@ void Platform::Pci_buses::scan_bus(Config_access &config_access, PCI_CMD_MASK = 0x7 /* IOPORT, MEM, DMA */ }; - unsigned short cmd = config.read(&config_access, PCI_CMD_REG, + unsigned short cmd = config.read(config_access, PCI_CMD_REG, Platform::Device::ACCESS_16BIT); if ((cmd & PCI_CMD_MASK) != PCI_CMD_MASK) { - config.write(&config_access, PCI_CMD_REG, + config.write(config_access, PCI_CMD_REG, cmd | PCI_CMD_MASK, Platform::Device::ACCESS_16BIT); } - Genode::log(config, " - bridge ", sec_bus, ":0.0", + Genode::log(config, " - bridge ", + Hex(sec_bus, Hex::Prefix::OMIT_PREFIX, Hex::Pad::PAD), + ":00.0", ((cmd & PCI_CMD_MASK) != PCI_CMD_MASK) ? " enabled" : ""); diff --git a/tool/run/power_on/qemu b/tool/run/power_on/qemu index e1748f6f5..e35a200f3 100644 --- a/tool/run/power_on/qemu +++ b/tool/run/power_on/qemu @@ -124,6 +124,8 @@ proc run_power_on { } { puts "Aborting, cannot execute Qemu without a ISO or disk image" exit -4 } } } } + + append qemu_args " -machine q35 " } # on ARM, we supply the boot image as kernel