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