platform_drv/x86: Switch to ECAM/MMCONF

Switch port I/O based PCI config space access to memory-mapped IO.  The
base address of the PCI configuration space is acquired by mapping the
ACPI ROM and reading the first <bdf> node. An exception is thrown if the
first <bdf> node is not for PCI domain zero or if multiple <bdf> nodes
exist. This is to reduce complexity and also because multiple PCI
domains are rare.

The PCI configuration space is accessed via I/O mem dataspace which is
created in the platform_drv root and then passed on to the PCI session,
device components and finally to the actual PCI config access instances.

The 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 works also for Linux)
always returns 0xffff in EAX to indicate a non-existing device.
Therefore, EAX is enforced in the assembly templates.

Fixes #2547
This commit is contained in:
Reto Buerki 2017-10-19 10:13:35 +02:00 committed by Christian Helmuth
parent 661be648d5
commit 47724c68c2
13 changed files with 319 additions and 323 deletions

View File

@ -54,8 +54,8 @@ proc audio_drv_binary { } {
proc platform_drv_build_components {} { proc platform_drv_build_components {} {
set drv_build_components "" set drv_build_components ""
lappend_if [have_platform_drv] drv_build_components drivers/platform lappend_if [have_platform_drv] drv_build_components drivers/platform
lappend_if [have_spec acpi] drv_build_components drivers/acpi lappend_if [have_spec x86] drv_build_components drivers/acpi
lappend_if [have_spec acpi] drv_build_components server/report_rom lappend_if [have_spec x86] drv_build_components server/report_rom
return $drv_build_components return $drv_build_components
} }
@ -68,9 +68,16 @@ proc append_platform_drv_build_components {} {
proc platform_drv_boot_modules {} { proc platform_drv_boot_modules {} {
set drv_boot_modules "" set drv_boot_modules ""
lappend_if [have_platform_drv] drv_boot_modules platform_drv lappend_if [have_platform_drv] drv_boot_modules platform_drv
lappend_if [have_spec acpi] drv_boot_modules acpi_drv lappend_if [have_spec x86] drv_boot_modules report_rom
lappend_if [have_spec acpi] drv_boot_modules report_rom
lappend_if [have_spec muen] drv_boot_modules acpi if {[have_spec x86]} {
if {[have_spec muen]} {
lappend drv_boot_modules acpi
} else {
lappend drv_boot_modules acpi_drv
}
}
return $drv_boot_modules return $drv_boot_modules
} }
@ -104,7 +111,7 @@ proc platform_drv_policy {} {
proc platform_drv_priority {} { return "" } proc platform_drv_priority {} { return "" }
proc platform_drv_add_routing {} { proc platform_drv_add_routing {} {
if {[have_spec acpi]} { if {[have_spec x86]} {
return { return {
<service name="ROM" label="system"> <child name="acpi_report_rom"/> </service>} <service name="ROM" label="system"> <child name="acpi_report_rom"/> </service>}
} }
@ -127,7 +134,7 @@ proc platform_drv_config_config {} {
proc platform_drv_config {} { proc platform_drv_config {} {
set drv_config "" set drv_config ""
if {[have_spec acpi]} { if {[have_spec x86] && ![have_spec muen] && ![have_spec linux]} {
append drv_config { append drv_config {
<start name="acpi_drv" } [platform_drv_priority] { caps="400" > <start name="acpi_drv" } [platform_drv_priority] { caps="400" >
@ -175,7 +182,7 @@ proc platform_drv_config {} {
<provides> <provides>
<service name="Platform"/>} <service name="Platform"/>}
append_if [have_spec acpi] drv_config { append_if [have_spec x86] drv_config {
<service name="Acpi"/>} <service name="Acpi"/>}
append_if [have_spec arm] 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 drv_config "[platform_drv_add_routing]"
append_if [have_spec acpi] drv_config { append_if [expr [have_spec x86] && ![have_spec muen]] drv_config {
<service name="ROM" label="acpi"> <child name="acpi_report_rom"/> </service>} <service name="ROM" label="acpi"> <child name="acpi_report_rom"/> </service>}
append_if [have_spec rpi] drv_config { append_if [have_spec rpi] drv_config {

View File

@ -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 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). (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, The platform driver waits on startup on the first valid ACPI report, typically
which conatins further information about the platform the platform driver can provided dynamically by the acpi driver.
not discover (e.g. IRQ re-routing information, pci config extended space The report contains further information about the hardware the platform driver can
information). 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 A specific route to a report_rom service named 'acpi_report_rom' looks as
in the following: in the following:
@ -105,17 +105,6 @@ in the following:
! </route> ! </route>
! ... ! ...
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:
!<start name="platform_drv">
! ...
! <config acpi="no" system="no">
! ...
! </config>
! ...
Synchronize ACPI startup and platform driver 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'. monitors a ROM in XML format named 'acpi_ready'.
!<start name="platform_drv"> !<start name="platform_drv">
! <config acpi="yes" acpi_ready="yes"> ! <config acpi_ready="yes">
The platform driver will announce its service not as 'Platform', but instead The platform driver will announce its service not as 'Platform', but instead
as 'Acpi' first. 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 the platform driver will announce the platform session as 'Platform', so
that drivers may start to operate with the platform driver. 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'.
!<start name="platform_drv">
! <config acpi="yes" system="yes">
If the attribute 'state' in the system XML ROM turns to 'reset'
!<system state="reset"/>
the platform driver will try to reset the machine, if the required I/O ports
are owned by it.
Supported PCI class aliases Supported PCI class aliases
--------------------------- ---------------------------

View File

@ -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, void Platform::Device_pd::assign_pci(Genode::Io_mem_dataspace_capability const io_mem_cap,
Genode::uint16_t rid) Genode::addr_t const offset,
Genode::uint16_t const rid)
{ {
using namespace Genode; using namespace Genode;
Dataspace_client ds_client(io_mem_cap); 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 */ /* sanity check */
if (!page) if (!page)
throw Region_map::Region_conflict(); throw Region_map::Region_conflict();
/* trigger eager mapping of memory */ /* trigger eager mapping of memory */
_pd.map(page, ds_client.size()); _pd.map(page, 0x1000);
/* utility to print rid value */ /* utility to print rid value */
struct Rid 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 */ /* try to assign pci device to this protection domain */
if (!_pd.assign_pci(page, rid)) if (!_pd.assign_pci(page, rid))
Genode::error(_label, ": assignment of PCI device ", Rid(rid), " failed ", 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)); "virt=", Genode::Hex(page));
else else
Genode::log(_label,": assignment of PCI device ", Rid(rid), " succeeded"); Genode::log(_label,": assignment of PCI device ", Rid(rid), " succeeded");

View File

@ -109,5 +109,6 @@ class Platform::Device_pd
} }
void attach_dma_mem(Genode::Dataspace_capability); 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);
}; };

View File

@ -57,8 +57,9 @@ struct Platform::Main
return; return;
const char * report_addr = acpi_rom->local_addr<const char>(); const char * report_addr = acpi_rom->local_addr<const char>();
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); root_cap = _env.ep().manage(*root);
@ -71,26 +72,12 @@ struct Platform::Main
void system_update() void system_update()
{ {
if (system_state.is_constructed())
system_state->update();
if (acpi_ready.is_constructed()) if (acpi_ready.is_constructed())
acpi_ready->update(); acpi_ready->update();
if (!root.is_constructed()) if (!root.is_constructed())
return; return;
if (system_state.is_constructed() && system_state->is_valid()) {
Genode::Xml_node system(system_state->local_addr<char>(),
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()) { if (acpi_ready.is_constructed() && acpi_ready->is_valid()) {
Genode::Xml_node system(acpi_ready->local_addr<char>(), Genode::Xml_node system(acpi_ready->local_addr<char>(),
acpi_ready->size()); acpi_ready->size());
@ -112,34 +99,20 @@ struct Platform::Main
_system_report(_env.ep(), *this, &Main::system_update) _system_report(_env.ep(), *this, &Main::system_update)
{ {
const Genode::Xml_node config = _config.xml(); 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) { _acpi_ready = config.attribute_value("acpi_ready", false);
/* wait for system state changes, e.g. reset and acpi_ready */
system_state.construct(env, "system");
system_state->sigh(_system_report);
}
if (_acpi_ready) { if (_acpi_ready) {
acpi_ready.construct(env, "acpi_ready"); acpi_ready.construct(env, "acpi_ready");
acpi_ready->sigh(_system_report); acpi_ready->sigh(_system_report);
} }
if (wait_for_acpi) { /* wait for the first valid acpi report */
/* for ACPI support, wait for the first valid acpi report */ acpi_rom.construct(env, "acpi");
acpi_rom.construct(env, "acpi"); acpi_rom->sigh(_acpi_report);
acpi_rom->sigh(_acpi_report); /* check if already valid */
/* check if already valid */ acpi_update();
acpi_update(); system_update();
system_update();
return;
}
/* non ACPI platform case */
root.construct(_env, sliced_heap, _config, nullptr);
_env.parent().announce(_env.ep().manage(*root));
} }
}; };

View File

@ -36,10 +36,12 @@ class Nonpci::Ps2 : public Platform::Device_component
public: 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) 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()), _ep(env.ep().rpc_ep()),
_irq_mouse(IRQ_MOUSE, ~0UL, env, heap_for_irq), _irq_mouse(IRQ_MOUSE, ~0UL, env, heap_for_irq),
_data(env, REG_DATA, ACCESS_WIDTH), _data(env, REG_DATA, ACCESS_WIDTH),
@ -99,10 +101,12 @@ class Nonpci::Pit : public Platform::Device_component
public: 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) 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) _ports(env, PIT_PORT, PORTS_WIDTH)
{ } { }
@ -150,10 +154,10 @@ Platform::Device_capability Platform::Session_component::device(String const &na
switch(devices_i) { switch(devices_i) {
case 0: case 0:
dev = new (_md_alloc) Nonpci::Ps2(_env, *this, _global_heap); dev = new (_md_alloc) Nonpci::Ps2(_env, _pciconf, *this, _global_heap);
break; break;
case 1: case 1:
dev = new (_md_alloc) Nonpci::Pit(_env, *this, _global_heap); dev = new (_md_alloc) Nonpci::Pit(_env, _pciconf, *this, _global_heap);
break; break;
default: default:
return Device_capability(); return Device_capability();

View File

@ -1,6 +1,7 @@
/* /*
* \brief Interface for accessing PCI configuration registers * \brief Interface for accessing PCI configuration registers
* \author Norman Feske * \author Norman Feske
* \author Reto Buerki
* \date 2008-01-29 * \date 2008-01-29
*/ */
@ -15,60 +16,36 @@
#define _X86_PCI_CONFIG_ACCESS_H_ #define _X86_PCI_CONFIG_ACCESS_H_
#include <util/bit_array.h> #include <util/bit_array.h>
#include <io_port_session/connection.h> #include <base/attached_io_mem_dataspace.h>
#include <base/attached_rom_dataspace.h>
#include <platform_device/platform_device.h> #include <platform_device/platform_device.h>
using namespace Genode;
namespace Platform { namespace Platform {
class Config_access class Config_access
{ {
private: private:
Genode::Env &_env; Attached_io_mem_dataspace &_pciconf;
Genode::size_t const _pciconf_size;
enum { REG_ADDR = 0xcf8, REG_DATA = 0xcfc, REG_SIZE = 4 };
/** /**
* Request interface to access an I/O port * Calculate device offset from BDF
*/
template <unsigned port>
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
* *
* \param bus target PCI bus ID (0..255) * \param bus target PCI bus ID (0..255)
* \param device target device ID (0..31) * \param device target device ID (0..31)
* \param function target function ID (0..7) * \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) { unsigned _dev_base(int bus, int device, int function)
return ( (1 << 31) | {
(bus << 16) | return ((bus << 20) |
(device << 11) | (device << 15) |
(function << 8) | (function << 12));
(addr & ~3) ); } }
Genode::Bit_array<256> _used { }; Genode::Bit_array<256> _used { };
@ -81,7 +58,16 @@ namespace Platform {
public: 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 * Read value from config space of specified device/function
@ -100,26 +86,41 @@ namespace Platform {
unsigned char addr, Device::Access_size size, unsigned char addr, Device::Access_size size,
bool track = true) bool track = true)
{ {
/* write target address */ unsigned ret;
_io_port<REG_ADDR>()->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<char>() + 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) { switch (size) {
case Device::ACCESS_8BIT: case Device::ACCESS_8BIT:
if (track) if (track)
_use_register(addr, 1); _use_register(addr, 1);
asm volatile("movb %1,%%al" :"=a" (ret) :"m" (*((volatile unsigned char *)field)) :"memory");
return _io_port<REG_DATA>()->inb(REG_DATA + (addr & 3)); return ret & 0xff;
case Device::ACCESS_16BIT: case Device::ACCESS_16BIT:
if (track) if (track)
_use_register(addr, 2); _use_register(addr, 2);
return _io_port<REG_DATA>()->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: case Device::ACCESS_32BIT:
if (track) if (track)
_use_register(addr, 4); _use_register(addr, 4);
return _io_port<REG_DATA>()->inl(REG_DATA); asm volatile("movl %1,%%eax" :"=a" (ret) :"m" (*(volatile unsigned int *)field) :"memory");
return ret;
default: default:
return ~0U; return ~0U;
} }
@ -141,29 +142,34 @@ namespace Platform {
unsigned value, Device::Access_size size, unsigned value, Device::Access_size size,
bool track = true) bool track = true)
{ {
/* write target address */ unsigned const offset = _dev_base(bus, device, function) + addr;
_io_port<REG_ADDR>()->outl(REG_ADDR, _cfg_addr(bus, device, char const * const field = _pciconf.local_addr<char>() + offset;
function, addr));
/* 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) { switch (size) {
case Device::ACCESS_8BIT: case Device::ACCESS_8BIT:
if (track) if (track)
_use_register(addr, 1); _use_register(addr, 1);
_io_port<REG_DATA>()->outb(REG_DATA + (addr & 3), value); asm volatile("movb %%al,%1" : :"a" (value), "m" (*(volatile unsigned char *)field) :"memory");
break; break;
case Device::ACCESS_16BIT: case Device::ACCESS_16BIT:
if (track) if (track)
_use_register(addr, 2); _use_register(addr, 2);
_io_port<REG_DATA>()->outw(REG_DATA + (addr & 2), value); asm volatile("movw %%ax,%1" : :"a" (value), "m" (*(volatile unsigned char *)field) :"memory");
break; break;
case Device::ACCESS_32BIT: case Device::ACCESS_32BIT:
if (track) if (track)
_use_register(addr, 4); _use_register(addr, 4);
_io_port<REG_DATA>()->outl(REG_DATA, value); asm volatile("movl %%eax,%1" : :"a" (value), "m" (*(volatile unsigned char *)field) :"memory");
break; break;
} }
} }
@ -181,32 +187,6 @@ namespace Platform {
return true; 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<REG_ADDR>()->outb(reg, value);
break;
case Device::ACCESS_16BIT:
_io_port<REG_ADDR>()->outw(reg, value);
break;
case Device::ACCESS_32BIT:
_io_port<REG_ADDR>()->outl(reg, value);
break;
default:
return false;
}
return true;
}
}; };
} }

View File

@ -99,7 +99,7 @@ void Platform::Device_component::config_write(unsigned char address,
switch (address) { switch (address) {
case 0x40 ... 0xff: case 0x40 ... 0xff:
/* allow access to device-specific registers if not used by us */ /* 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; break;
Genode::error(_device_config, " write access to " 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); _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::addr_t msi_address = _irq_session->msi_address();
Genode::uint32_t msi_value = _irq_session->msi_data(); 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, msi_cap + 2,
Platform::Device::ACCESS_16BIT); 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); Platform::Device::ACCESS_32BIT);
if (msi & CAP_MSI_64) { 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 ? (Genode::uint64_t)msi_address >> 32
: 0UL; : 0UL;
_device_config.write(&_config_access, msi_cap + 0x8, _device_config.write(_config_access, msi_cap + 0x8,
upper_address, upper_address,
Platform::Device::ACCESS_32BIT); Platform::Device::ACCESS_32BIT);
_device_config.write(&_config_access, msi_cap + 0xc, _device_config.write(_config_access, msi_cap + 0xc,
msi_value, msi_value,
Platform::Device::ACCESS_16BIT); Platform::Device::ACCESS_16BIT);
} }
else 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); Platform::Device::ACCESS_16BIT);
/* enable MSI */ /* enable MSI */
_device_config.write(&_config_access, msi_cap + 2, _device_config.write(_config_access, msi_cap + 2,
msi ^ MSI_ENABLED, msi ^ MSI_ENABLED,
Platform::Device::ACCESS_8BIT); 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_64 = false;
bool msi_mask = false; bool msi_mask = false;
if (msi_cap) { if (msi_cap) {
Genode::uint16_t msi = _device_config.read(&_config_access, Genode::uint16_t msi = _device_config.read(_config_access,
msi_cap + 2, msi_cap + 2,
Platform::Device::ACCESS_16BIT); Platform::Device::ACCESS_16BIT);
msi_64 = msi & CAP_MSI_64; msi_64 = msi & CAP_MSI_64;

View File

@ -15,6 +15,7 @@
/* base */ /* base */
#include <base/rpc_server.h> #include <base/rpc_server.h>
#include <io_port_session/connection.h>
#include <io_mem_session/connection.h> #include <io_mem_session/connection.h>
#include <util/list.h> #include <util/list.h>
#include <util/mmio.h> #include <util/mmio.h>
@ -45,13 +46,11 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
Genode::Env &_env; Genode::Env &_env;
Device_config _device_config { }; Device_config _device_config { };
Genode::addr_t _config_space; Genode::addr_t _config_space;
Config_access _config_access { _env }; Config_access _config_access;
Platform::Session_component &_session; Platform::Session_component &_session;
unsigned short _irq_line; unsigned short _irq_line;
Irq_session_component *_irq_session = nullptr; Irq_session_component *_irq_session = nullptr;
Genode::Constructible<Genode::Io_mem_connection> _io_mem_config_extended { };
Genode::Allocator &_global_heap; Genode::Allocator &_global_heap;
class Io_mem : public Genode::Io_mem_connection, class Io_mem : public Genode::Io_mem_connection,
@ -108,18 +107,18 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
{ {
enum { PCI_STATUS = 0x6, PCI_CAP_OFFSET = 0x34, CAP_MSI = 0x5 }; 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, PCI_STATUS,
Platform::Device::ACCESS_16BIT)); Platform::Device::ACCESS_16BIT));
if (!Status::Capabilities::get(status)) if (!Status::Capabilities::get(status))
return 0; return 0;
Genode::uint8_t cap = _device_config.read(&_config_access, Genode::uint8_t cap = _device_config.read(_config_access,
PCI_CAP_OFFSET, PCI_CAP_OFFSET,
Platform::Device::ACCESS_8BIT); Platform::Device::ACCESS_8BIT);
for (Genode::uint16_t val = 0; cap; cap = val >> 8) { 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); Platform::Device::ACCESS_16BIT);
if ((val & 0xff) != CAP_MSI) if ((val & 0xff) != CAP_MSI)
continue; continue;
@ -139,7 +138,7 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
using Genode::uint16_t; using Genode::uint16_t;
using Genode::uint8_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); Platform::Device::ACCESS_8BIT);
if (!pin) if (!pin)
return Irq_session_component::INVALID_IRQ; return Irq_session_component::INVALID_IRQ;
@ -160,12 +159,12 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
if (!cap) if (!cap)
return irq; 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); Platform::Device::ACCESS_16BIT);
if (msi & MSI_ENABLED) if (msi & MSI_ENABLED)
/* disable MSI */ /* disable MSI */
_device_config.write(&_config_access, cap + 2, _device_config.write(_config_access, cap + 2,
msi ^ MSI_ENABLED, msi ^ MSI_ENABLED,
Platform::Device::ACCESS_8BIT); Platform::Device::ACCESS_8BIT);
@ -185,10 +184,10 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
if (_device_config.pci_bridge()) if (_device_config.pci_bridge())
return; 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); Platform::Device::ACCESS_16BIT);
if (cmd & PCI_CMD_DMA) 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, cmd ^ PCI_CMD_DMA,
Platform::Device::ACCESS_16BIT); Platform::Device::ACCESS_16BIT);
} }
@ -200,14 +199,16 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
*/ */
Device_component(Genode::Env &env, Device_component(Genode::Env &env,
Device_config device_config, Genode::addr_t addr, Device_config device_config, Genode::addr_t addr,
Config_access &config_access,
Platform::Session_component &session, Platform::Session_component &session,
Genode::Allocator &md_alloc, Genode::Allocator &md_alloc,
Genode::Allocator &global_heap) Genode::Allocator &global_heap)
: :
_env(env), _env(env),
_device_config(device_config), _config_space(addr), _device_config(device_config), _config_space(addr),
_config_access(config_access),
_session(session), _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)), Platform::Device::ACCESS_8BIT)),
_global_heap(global_heap), _global_heap(global_heap),
_slab_ioport(&md_alloc, &_slab_ioport_block_data), _slab_ioport(&md_alloc, &_slab_ioport_block_data),
@ -224,11 +225,13 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
* Constructor for non PCI devices * Constructor for non PCI devices
*/ */
Device_component(Genode::Env &env, Device_component(Genode::Env &env,
Genode::Attached_io_mem_dataspace &pciconf,
Platform::Session_component &session, unsigned irq, Platform::Session_component &session, unsigned irq,
Genode::Allocator &global_heap) Genode::Allocator &global_heap)
: :
_env(env), _env(env),
_config_space(~0UL), _config_space(~0UL),
_config_access(pciconf),
_session(session), _session(session),
_irq_line(irq), _irq_line(irq),
_global_heap(global_heap), _global_heap(global_heap),
@ -239,6 +242,7 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
_io_port_conn[i] = nullptr; _io_port_conn[i] = nullptr;
} }
/** /**
* De-constructor * De-constructor
*/ */
@ -267,26 +271,8 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
** Methods used solely by pci session ** ** Methods used solely by pci session **
****************************************/ ****************************************/
Device_config config() { return _device_config; } Device_config config() const { return _device_config; }
Genode::addr_t config_space() const { return _config_space; }
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();
}
/************************** /**************************
** PCI-device interface ** ** PCI-device interface **
@ -317,7 +303,7 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
unsigned config_read(unsigned char address, Access_size size) override 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); _device_config.DONT_TRACK_ACCESS);
} }

View File

@ -24,7 +24,9 @@ namespace Platform {
{ {
private: 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 * Information provided by the PCI config space
@ -68,6 +70,13 @@ namespace Platform {
*/ */
Device_config() : _vendor_id(INVALID_VENDOR) { } 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, Device_config(int bus, int device, int function,
Config_access *pci_config): Config_access *pci_config):
_bus(bus), _device(device), _function(function) _bus(bus), _device(device), _function(function)
@ -149,8 +158,8 @@ namespace Platform {
{ {
using Genode::print; using Genode::print;
using Genode::Hex; using Genode::Hex;
print(out, Hex(_bus, Hex::Prefix::OMIT_PREFIX), print(out, Hex(_bus, Hex::Prefix::OMIT_PREFIX, Hex::Pad::PAD),
":", Hex(_device, Hex::Prefix::OMIT_PREFIX), ":", Hex(_device, Hex::Prefix::OMIT_PREFIX, Hex::Pad::PAD),
".", Hex(_function, Hex::Prefix::OMIT_PREFIX)); ".", Hex(_function, Hex::Prefix::OMIT_PREFIX));
} }
@ -190,27 +199,27 @@ namespace Platform {
* Read configuration space * Read configuration space
*/ */
enum { DONT_TRACK_ACCESS = false }; 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) Device::Access_size size, bool track = true)
{ {
return pci_config->read(_bus, _device, _function, address, return pci_config.read(_bus, _device, _function, address,
size, track); size, track);
} }
/** /**
* Write configuration space * 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, unsigned long value, Device::Access_size size,
bool track = true) bool track = true)
{ {
pci_config->write(_bus, _device, _function, address, value, pci_config.write(_bus, _device, _function, address, value,
size, track); 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) { 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<Config_space>::Element class Config_space : private Genode::List<Config_space>::Element

View File

@ -1,5 +1,5 @@
/* /*
* \brief platform session component * \brief Platform session component
* \author Norman Feske * \author Norman Feske
* \date 2008-01-28 * \date 2008-01-28
*/ */
@ -152,9 +152,9 @@ class Platform::Pci_buses
public: 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); scan_bus(c, heap);
} }
@ -207,6 +207,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
Genode::Env &_env; Genode::Env &_env;
Genode::Attached_rom_dataspace &_config; Genode::Attached_rom_dataspace &_config;
Genode::Attached_io_mem_dataspace &_pciconf;
Genode::Ram_quota_guard _ram_guard; Genode::Ram_quota_guard _ram_guard;
Genode::Cap_quota_guard _cap_guard; Genode::Cap_quota_guard _cap_guard;
Genode::Constrained_ram_allocator _env_ram { Genode::Constrained_ram_allocator _env_ram {
@ -455,14 +456,16 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
/** /**
* Constructor * Constructor
*/ */
Session_component(Genode::Env &env, Session_component(Genode::Env &env,
Genode::Attached_rom_dataspace &config, Genode::Attached_rom_dataspace &config,
Platform::Pci_buses &buses, Genode::Attached_io_mem_dataspace &pciconf,
Genode::Heap &global_heap, Platform::Pci_buses &buses,
char const *args) Genode::Heap &global_heap,
char const *args)
: :
_env(env), _env(env),
_config(config), _config(config),
_pciconf(pciconf),
_ram_guard(Genode::ram_quota_from_args(args)), _ram_guard(Genode::ram_quota_from_args(args)),
_cap_guard(Genode::cap_quota_from_args(args)), _cap_guard(Genode::cap_quota_from_args(args)),
_md_alloc(_env_ram, env.rm()), _md_alloc(_env_ram, env.rm()),
@ -637,9 +640,8 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
{ {
/* /*
* Create the interface to the PCI config space. * 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 */ /* lookup device component for previous device */
auto lambda = [&] (Device_component *prev) auto lambda = [&] (Device_component *prev)
@ -696,7 +698,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
*/ */
try { try {
Device_component * dev = new (_md_alloc) 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); _md_alloc, _global_heap);
/* if more than one driver uses the device - warn about */ /* if more than one driver uses the device - warn about */
@ -751,11 +753,7 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
/* lookup device component for previous device */ /* lookup device component for previous device */
_env.ep().rpc_ep().apply(device_cap, lambda); _env.ep().rpc_ep().apply(device_cap, lambda);
if (!device) return; if (device && device->config().valid())
if (device->config().valid())
destroy(_md_alloc, device);
else
destroy(_md_alloc, device); destroy(_md_alloc, device);
} }
@ -763,13 +761,20 @@ class Platform::Session_component : public Genode::Rpc_object<Session>
{ {
using namespace Genode; using namespace Genode;
if (!device || !device->get_config_space().valid()) if (!device || device->config_space() == ~0UL)
return; return;
Io_mem_dataspace_capability io_mem = device->get_config_space();
try { 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()) { for (Rmrr *r = Rmrr::list()->first(); r; r = r->next()) {
Io_mem_dataspace_capability rmrr_cap = r->match(_env, device->config()); Io_mem_dataspace_capability rmrr_cap = r->match(_env, device->config());
@ -846,37 +851,65 @@ class Platform::Root : public Genode::Root_component<Session_component>
Genode::Env &_env; Genode::Env &_env;
Genode::Attached_rom_dataspace &_config; Genode::Attached_rom_dataspace &_config;
Genode::Constructible<Genode::Attached_io_mem_dataspace> _pci_confspace { };
Genode::Reporter _pci_reporter { _env, "pci" }; Genode::Reporter _pci_reporter { _env, "pci" };
Genode::Heap _heap { _env.ram(), _env.rm() }; Genode::Heap _heap { _env.ram(), _env.rm() };
Platform::Pci_buses _buses { _env, _heap };
void _parse_report_rom(Genode::Env &env, const char * acpi_rom) Genode::Constructible<Platform::Pci_buses> _buses { };
void _parse_report_rom(Genode::Env &env, const char * acpi_rom,
bool acpi_platform)
{ {
using namespace Genode; using namespace Genode;
Config_access config_access(env);
Xml_node xml_acpi(acpi_rom); Xml_node xml_acpi(acpi_rom);
if (!xml_acpi.has_type("acpi")) if (!xml_acpi.has_type("acpi"))
throw 1; 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<addr_t>(base, memory_size), " ignored");
return;
}
log("ECAM/MMCONF range ", bdf_first, "-", bdf_last, " - addr ",
Hex_range<addr_t>(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++) { for (unsigned i = 0; i < xml_acpi.num_sub_nodes(); i++) {
Xml_node node = xml_acpi.sub_node(i); Xml_node node = xml_acpi.sub_node(i);
if (node.has_type("bdf")) { if (node.has_type("bdf"))
continue;
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")) { if (node.has_type("irq_override")) {
unsigned irq = 0xff; unsigned irq = 0xff;
@ -887,10 +920,17 @@ class Platform::Root : public Genode::Root_component<Session_component>
node.attribute("gsi").value(&gsi); node.attribute("gsi").value(&gsi);
node.attribute("flags").value(&flags); node.attribute("flags").value(&flags);
if (!acpi_platform) {
warning("MADT IRQ ", irq, "-> GSI ", gsi, " flags ",
flags, " ignored");
continue;
}
using Platform::Irq_override; using Platform::Irq_override;
Irq_override * o = new (_heap) Irq_override(irq, gsi, Irq_override * o = new (_heap) Irq_override(irq, gsi,
flags); flags);
Irq_override::list()->insert(o); Irq_override::list()->insert(o);
continue;
} }
if (node.has_type("rmrr")) { if (node.has_type("rmrr")) {
@ -899,7 +939,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
node.attribute("end").value(&mem_end); node.attribute("end").value(&mem_end);
if (node.num_sub_nodes() == 0) if (node.num_sub_nodes() == 0)
throw 2; throw 3;
Rmrr * rmrr = new (_heap) Rmrr(mem_start, mem_end); Rmrr * rmrr = new (_heap) Rmrr(mem_start, mem_end);
Rmrr::list()->insert(rmrr); Rmrr::list()->insert(rmrr);
@ -907,7 +947,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
for (unsigned s = 0; s < node.num_sub_nodes(); s++) { for (unsigned s = 0; s < node.num_sub_nodes(); s++) {
Xml_node scope = node.sub_node(s); Xml_node scope = node.sub_node(s);
if (!scope.num_sub_nodes() || !scope.has_type("scope")) if (!scope.num_sub_nodes() || !scope.has_type("scope"))
throw 3; throw 4;
unsigned bus = 0, dev = 0, func = 0; unsigned bus = 0, dev = 0, func = 0;
scope.attribute("bus_start").value(&bus); scope.attribute("bus_start").value(&bus);
@ -915,7 +955,7 @@ class Platform::Root : public Genode::Root_component<Session_component>
for (unsigned p = 0; p < scope.num_sub_nodes(); p++) { for (unsigned p = 0; p < scope.num_sub_nodes(); p++) {
Xml_node path = scope.sub_node(p); Xml_node path = scope.sub_node(p);
if (!path.has_type("path")) if (!path.has_type("path"))
throw 4; throw 5;
path.attribute("dev").value(&dev); path.attribute("dev").value(&dev);
path.attribute("func").value(&func); path.attribute("func").value(&func);
@ -924,12 +964,13 @@ class Platform::Root : public Genode::Root_component<Session_component>
&config_access); &config_access);
if (bridge.pci_bridge()) if (bridge.pci_bridge())
/* PCI bridge spec 3.2.5.3, 3.2.5.4 */ /* 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); Device::ACCESS_8BIT);
} }
rmrr->add(new (_heap) Rmrr::Bdf(bus, dev, func)); rmrr->add(new (_heap) Rmrr::Bdf(bus, dev, func));
} }
continue;
} }
if (node.has_type("fadt")) { if (node.has_type("fadt")) {
@ -937,10 +978,13 @@ class Platform::Root : public Genode::Root_component<Session_component>
node.attribute("reset_type").value(&fadt.reset_type); node.attribute("reset_type").value(&fadt.reset_type);
node.attribute("reset_addr").value(&fadt.reset_addr); node.attribute("reset_addr").value(&fadt.reset_addr);
node.attribute("reset_value").value(&fadt.reset_value); node.attribute("reset_value").value(&fadt.reset_value);
continue;
} }
if (!node.has_type("routing")) if (!node.has_type("routing")) {
continue; error ("unsupported node '", node.type(), "'");
throw __LINE__;
}
unsigned gsi; unsigned gsi;
unsigned bridge_bdf; unsigned bridge_bdf;
@ -960,6 +1004,20 @@ class Platform::Root : public Genode::Root_component<Session_component>
if (!config.valid()) if (!config.valid())
continue; 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 (!config.pci_bridge() && bridge_bdf != 0)
/** /**
* If the bridge bdf has not a type header of a bridge in * If the bridge bdf has not a type header of a bridge in
@ -979,13 +1037,52 @@ class Platform::Root : public Genode::Root_component<Session_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: protected:
Session_component *_create_session(const char *args) Session_component *_create_session(const char *args)
{ {
try { try {
return new (md_alloc()) 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) { catch (Genode::Session_policy::No_policy_defined) {
Genode::error("Invalid session request, no matching policy for ", Genode::error("Invalid session request, no matching policy for ",
@ -1010,27 +1107,30 @@ class Platform::Root : public Genode::Root_component<Session_component>
*/ */
Root(Genode::Env &env, Genode::Allocator &md_alloc, Root(Genode::Env &env, Genode::Allocator &md_alloc,
Genode::Attached_rom_dataspace &config, Genode::Attached_rom_dataspace &config,
const char *acpi_rom) const char *acpi_rom,
bool acpi_platform)
: :
Genode::Root_component<Session_component>(&env.ep().rpc_ep(), Genode::Root_component<Session_component>(&env.ep().rpc_ep(),
&md_alloc), &md_alloc),
_env(env), _config(config) _env(env), _config(config)
{ {
if (acpi_rom) {
try { try {
_parse_report_rom(env, acpi_rom); _parse_report_rom(env, acpi_rom, acpi_platform);
} catch (...) { } catch (...) {
Genode::error("PCI config space data could not be parsed."); Genode::error("ACPI report parsing error.");
} throw;
} }
_construct_buses();
_pci_reporter.enabled(config.xml().has_sub_node("report") && _pci_reporter.enabled(config.xml().has_sub_node("report") &&
config.xml().sub_node("report") config.xml().sub_node("report")
.attribute_value("pci", true)); .attribute_value("pci", true));
if (_pci_reporter.enabled()) { if (_pci_reporter.enabled()) {
Config_access config_access(env); Config_access config_access(*_pci_confspace);
Device_config config; Device_config config;
int bus = 0, device = 0, function = -1; int bus = 0, device = 0, function = -1;
@ -1038,8 +1138,8 @@ class Platform::Root : public Genode::Root_component<Session_component>
/* iterate over pci devices */ /* iterate over pci devices */
while (true) { while (true) {
function += 1; function += 1;
if (!_buses.find_next(bus, device, function, &config, if (!(*_buses).find_next(bus, device, function, &config,
&config_access)) &config_access))
return; return;
bus = config.bus_number(); bus = config.bus_number();
@ -1060,47 +1160,4 @@ class Platform::Root : public Genode::Root_component<Session_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");
}
}; };

View File

@ -55,9 +55,9 @@ void Platform::Pci_buses::scan_bus(Config_access &config_access,
/* scan behind bridge */ /* scan behind bridge */
if (config.pci_bridge()) { if (config.pci_bridge()) {
/* PCI bridge spec 3.2.5.3, 3.2.5.4 */ /* 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); Device::ACCESS_8BIT);
unsigned char sub_bus = config.read(&config_access, 0x20, unsigned char sub_bus = config.read(config_access, 0x20,
Device::ACCESS_8BIT); Device::ACCESS_8BIT);
bridges()->insert(new (heap) Bridge(bus, dev, fun, sec_bus, 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 */ 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); Platform::Device::ACCESS_16BIT);
if ((cmd & PCI_CMD_MASK) != PCI_CMD_MASK) { 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, cmd | PCI_CMD_MASK,
Platform::Device::ACCESS_16BIT); 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" ((cmd & PCI_CMD_MASK) != PCI_CMD_MASK) ? " enabled"
: ""); : "");

View File

@ -124,6 +124,8 @@ proc run_power_on { } {
puts "Aborting, cannot execute Qemu without a ISO or disk image" puts "Aborting, cannot execute Qemu without a ISO or disk image"
exit -4 exit -4
} } } } } } } }
append qemu_args " -machine q35 "
} }
# on ARM, we supply the boot image as kernel # on ARM, we supply the boot image as kernel