acpica: adjust to new platform driver

genodelabs/genode#4578
This commit is contained in:
Alexander Boettcher 2022-10-04 13:21:01 +02:00 committed by Christian Helmuth
parent 3e8ffe179b
commit 8f0a012345
10 changed files with 206 additions and 644 deletions

View File

@ -21,11 +21,7 @@ namespace Genode {
namespace Acpica {
struct Wait_acpi_ready { bool enabled; };
struct Act_as_acpi_drv { bool enabled; };
void init(Genode::Env &, Genode::Allocator &, Wait_acpi_ready,
Act_as_acpi_drv);
void init(Genode::Env &, Genode::Allocator &);
void use_platform_drv();
}

View File

@ -9,47 +9,25 @@ if {
set build_components {
core init timer
drivers/ps2
server/dynamic_rom
server/event_filter
server/report_rom
drivers/platform
server/event_dump
app/pci_decode
app/acpica
app/acpi_event
}
set use_acpica_as_acpi_drv 0
source ${genode_dir}/repos/base/run/platform_drv.inc
if {!$use_acpica_as_acpi_drv} {
# override default platform driver policy
proc platform_drv_policy {} {
return {
<policy label_prefix="ps2_drv"> <device name="PS2"/> </policy>
<policy label_prefix="acpica"> <pci class="ALL"/> </policy>}
}
# add routing information
proc platform_drv_add_routing {} {
return {
<service name="ROM" label="acpi_ready"> <child name="acpi_state"/> </service>}
}
# override default config to react on 'acpi_ready' ROM change
proc platform_drv_config_config {} {
return {
<config acpi_ready="yes">}
}
}
append_platform_drv_build_components
build $build_components
create_boot_directory
import_from_depot [depot_user]/src/dynamic_rom \
[depot_user]/src/event_filter \
[depot_user]/src/pc_usb_host_drv \
[depot_user]/src/ps2_drv \
[depot_user]/src/rom_filter \
[depot_user]/src/report_rom \
[depot_user]/src/usb_hid_drv
set config {
<config>
<parent-provides>
@ -65,91 +43,80 @@ set config {
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="timer">
<start name="timer" caps="100">
<resource name="RAM" quantum="2M"/>
<provides><service name="Timer"/></provides>
</start>}
</start>
append_if [expr !$use_acpica_as_acpi_drv] config {
<start name="acpica" caps="200">
<resource name="RAM" quantum="8M"/>
<config ld_verbose="yes" reset="no" poweroff="no" report="yes" acpi_ready="yes">
<start name="drivers_reports" caps="100">
<binary name="report_rom"/>
<resource name="RAM" quantum="1M"/>
<provides>
<service name="Report"/>
<service name="ROM"/>
</provides>
<config verbose="no">
<policy label="pci_decode -> system" report="acpi_drv -> acpi"/>
<policy label="rom_filter -> pci_devices" report="pci_decode -> devices"/>
<policy label="usb_hid_drv -> report" report="usb_drv -> devices"/>
</config>
</start>
<start name="acpi_drv" caps="350">
<resource name="RAM" quantum="4M"/>
<route>
<service name="ROM" label="system"> <child name="dynamic_rom"/> </service>
<service name="Report"> <child name="acpi_state"/> </service>
<service name="Report"> <child name="drivers_reports"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
</start>
append config {
<start name="acpi_state">
<binary name="report_rom"/>
<resource name="RAM" quantum="2M"/>
<provides>
<service name="ROM" />
<service name="Report" />
</provides>
<config verbose="yes">
<policy label="platform_drv -> acpi_ready" report="acpica -> acpi_ready"/>
<policy label="acpi_event -> acpi_ac" report="acpica -> acpi_ac"/>
<policy label="acpi_event -> acpi_battery" report="acpica -> acpi_battery"/>
<policy label="acpi_event -> acpi_ec" report="acpica -> acpi_ec"/>
<policy label="acpi_event -> acpi_fixed" report="acpica -> acpi_fixed"/>
<policy label="acpi_event -> acpi_lid" report="acpica -> acpi_lid"/>
<policy label="acpi_event -> acpi_hid" report="acpica -> acpi_hid"/>
</config>
<start name="pci_decode" caps="350">
<resource name="RAM" quantum="1M"/>
<route>
<any-service> <parent/> </any-service>
<service name="ROM" label="system"> <child name="drivers_reports"/> </service>
<service name="Report"> <child name="drivers_reports"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
</start>
append config {
<start name="dynamic_rom">
<resource name="RAM" quantum="4M"/>
<provides><service name="ROM"/></provides>
<config verbose="yes">
<rom name="system">
<inline description="set system state to 'normal'">
<system state="normal"/>
</inline>
<sleep milliseconds="5000" />
<inline description="set system state to 'reset'">
<system state="reset"/>
</inline>
<!--
<inline description="set system state to 'poweroff'">
<system state="poweroff"/>
</inline>
-->
<sleep milliseconds="500" />
</rom>
</config>
</start>}
append config {
<start name="event_filter">
<resource name="RAM" quantum="1M" />
<provides> <service name="Event" /> </provides>
<config>
<output>
<merge>
<input name="ps2"/>
<input name="acpi"/>
</merge>
<start name="rom_filter" caps="70">
<resource name="RAM" quantum="1M"/>
<provides> <service name="ROM"/> </provides>
<config buffer="32K">
<input name="devices"/>
<input name="pci_devices"/>
<output node="devices">
<input name="devices" skip_toplevel="yes"/>
<input name="pci_devices" skip_toplevel="yes"/>
</output>
<policy label="ps2" input="ps2"/>
<policy label="acpi" input="acpi"/>
</config>
<route>
<service name="Event"> <child name="event_dump" /> </service>
<any-service> <parent/> </any-service>
<service name="ROM" label="pci_devices"> <child name="drivers_reports"/> </service>
<service name="LOG"> <parent/> </service>
<service name="PD"> <parent/> </service>
<service name="CPU"> <parent/> </service>
<service name="ROM"> <parent/> </service>
</route>
</start>}
</start>
append config {
<start name="ps2_drv">
<start name="platform_drv" caps="400" managing_system="yes">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Platform"/>
</provides>
<config>
<policy label_prefix="ps2_drv"> <device name="ps2"/> </policy>
<policy label_prefix="usb_drv" info="yes"> <pci class="USB"/> </policy>
<policy label_prefix="acpica"/>
</config>
<route>
<service name="ROM" label="devices"> <child name="rom_filter"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="ps2_drv" caps="100">
<resource name="RAM" quantum="2M"/>
<config verbose_keyboard="no" verbose_mouse="no" verbose_scancodes="no"/>
<route>
@ -160,17 +127,93 @@ append config {
</route>
</start>
<start name="event_dump">
<start name="usb_drv" caps="200">
<binary name="pc_usb_host_drv"/>
<resource name="RAM" quantum="20M"/>
<provides> <service name="Usb"/> </provides>
<config bios_handoff="no">
<report devices="yes"/>
<policy label_prefix="usb_hid_drv" class="0x3"/>
</config>
<route>
<service name="Report"> <child name="drivers_reports"/> </service>
<any-service><parent/><any-child/></any-service>
</route>
</start>
<start name="usb_hid_drv" caps="140">
<resource name="RAM" quantum="10M"/>
<config use_report="yes"/>
<route>
<service name="ROM" label="report"> <child name="drivers_reports"/> </service>
<service name="Event"> <child name="event_filter" label="usb"/> </service>
<service name="Usb"> <child name="usb_drv"/> </service>
<any-service><parent/><any-child/></any-service>
</route>
</start>
<start name="event_filter" caps="100">
<resource name="RAM" quantum="1M" />
<provides> <service name="Event" /> </provides>
<config>
<output>
<merge>
<input name="ps2"/>
<input name="acpi"/>
<input name="usb"/>
</merge>
</output>
<policy label="ps2" input="ps2"/>
<policy label="acpi" input="acpi"/>
<policy label="usb" input="usb"/>
</config>
<route>
<service name="Event"> <child name="event_dump" /> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="event_dump" caps="100">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Event"/> </provides>
<route>
<service name="Timer"> <child name="timer"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>}
</start>
append config {
<start name="acpi_event">
<start name="acpica" caps="200">
<resource name="RAM" quantum="8M"/>
<config ld_verbose="yes" reset="yes" poweroff="yes" report="yes">
</config>
<route>
<service name="ROM" label="system"> <child name="dynamic_rom"/> </service>
<service name="Report"> <child name="acpi_state"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="acpi_state" caps="100">
<binary name="report_rom"/>
<resource name="RAM" quantum="2M"/>
<provides>
<service name="ROM" />
<service name="Report" />
</provides>
<config verbose="yes">
<policy label="acpi_event -> acpi_ac" report="acpica -> acpi_ac"/>
<policy label="acpi_event -> acpi_battery" report="acpica -> acpi_battery"/>
<policy label="acpi_event -> acpi_ec" report="acpica -> acpi_ec"/>
<policy label="acpi_event -> acpi_fixed" report="acpica -> acpi_fixed"/>
<policy label="acpi_event -> acpi_lid" report="acpica -> acpi_lid"/>
<policy label="acpi_event -> acpi_hid" report="acpica -> acpi_hid"/>
</config>
<route>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="acpi_event" caps="100">
<resource name="RAM" quantum="1M"/>
<config>
<!-- example mapping - adapt to your target notebook !!! -->
@ -196,42 +239,57 @@ append config {
<service name="Event"> <child name="event_filter" label="acpi"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>}
</start>
append_platform_drv_config
<start name="dynamic_rom" caps="100">
<resource name="RAM" quantum="4M"/>
<provides><service name="ROM"/></provides>
<config verbose="yes">
<rom name="system">
<inline description="set system state to 'normal'">
<system state="normal"/>
</inline>
<sleep milliseconds="5000" />
<!--
<inline description="set system state to 'reset'">
<system state="reset"/>
</inline>
<sleep milliseconds="5000" />
<inline description="set system state to 'poweroff'">
<system state="poweroff"/>
</inline>
<sleep milliseconds="500" />
-->
</rom>
</config>
</start>
append config {
</config>
</config>
}
install_config $config
# non PCI devices for platform_drv, e.g. ps2/pit
file copy [select_from_repositories board/[board]/devices] [run_dir]/genode/devices
set boot_modules {
core init
ld.lib.so
timer
ps2_drv
event_filter
report_rom
dynamic_rom
core init ld.lib.so
timer platform_drv pci_decode acpi_drv
acpica
acpi_event
event_dump
}
append_platform_drv_boot_modules
build_boot_image $boot_modules
append qemu_args "-nographic "
run_genode_until {\[init -\> acpi.*SCI IRQ:.*\n} 30
if {![have_include "power_on/qemu"]} {
run_genode_until {\[init -\> acpi.*SCI IRQ:.*\n} 30
exit 0
}
run_genode_until {.*PS2 uses IRQ, vector 0xc.*} 30
set spawn_id $qemu_spawn_id
sleep 1

View File

@ -27,15 +27,6 @@ changes of the 'state' attribute:
!<system state="something"/>
Additionally, if the config attributes 'acpi_ready' is set to yes, the
application generates a reports named 'acpi_ready' and set the state to
!<system state="acpi_ready"/>
after finishing the ACPI bring up. This is used by platform_drv to finally
announce the Platform session, so that drivers can start after acpica has
finished.
If the ROM changes to 'state="reset"' the application tries to reset the
machine immediately.
If the ROM changes to 'state="poweroff"' the application tries to poweroff
@ -45,22 +36,9 @@ The attempt to reset or to poweroff may fail. One reason, we have seen so far,
is that the required resources are already owned by other components in the
system.
Furthermore the ACPICA library triggers depended on the ACPI table content
I/O operations on various PCI devices and partly re-configure it. Because of
this a policy rule at the platform driver is required, that permits access
to the required devices.
Acpica as acpi_drv replacement
------------------------------
The application acpica may also be run as replacement of the original acpi_drv
when the 'act_as_acpi_drv' attribute is set to yes:
! <config ... acpi_ready="yes" act_as_acpi_drv="yes"/>
The acpica driver will parse in this mode the ACPI tables and will generate
the same content in the ACPI report, which is transformed by a report_rom
service into a ACPI ROM expected initially by the platform driver.
Furthermore the ACPICA library may trigger, dependent on the ACPI ASL code,
various I/O port and I/O mem accesses to hardware. Accesses to PCI devices are
ignored and dropped by this component.
Excerpt of important parts of the acpica configuration
------------------------------------------------------
@ -68,7 +46,7 @@ Excerpt of important parts of the acpica configuration
!<start name="acpica">
! <!-- <binary name="debug-acpica"/> -->
! ...
! <config reset="no" poweroff="no" report="yes" acpi_ready="yes" act_as_acpi_drv="no"/>
! <config reset="no" poweroff="no" report="yes"/>
! <route>
! <service name="ROM" label="system"> <child name="..."/> </service>
! <service name="Report"> <child name="..."/> </service>

View File

@ -1,139 +0,0 @@
/*
* \brief Handle PCI Root bridge
* \author Alexander Boettcher
*
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
class Bridge {
private:
ACPI_HANDLE _bridge;
unsigned bdf_bridge(ACPI_HANDLE bridge)
{
/* address (high word = device, low word = function) (6.1.1) */
unsigned bridge_adr = 0;
/* Base bus number (6.5.5) */
unsigned bridge_bbn = 0;
/* Segment object located under host bridge (6.5.6) */
unsigned bridge_seg = 0;
Acpica::Buffer<ACPI_OBJECT> adr;
ACPI_STATUS res = AcpiEvaluateObjectTyped(bridge,
ACPI_STRING("_ADR"),
nullptr, &adr,
ACPI_TYPE_INTEGER);
if (res != AE_OK) {
Genode::error("could not detect address of bridge - ", res);
return 0;
} else
bridge_adr = adr.object.Integer.Value;
Acpica::Buffer<ACPI_OBJECT> bbn;
res = AcpiEvaluateObjectTyped(bridge, ACPI_STRING("_BBN"),
nullptr, &bbn, ACPI_TYPE_INTEGER);
if (res != AE_OK) {
Genode::warning("_BBN missing for bridge");
} else
bridge_bbn = bbn.object.Integer.Value;
Acpica::Buffer<ACPI_OBJECT> seg;
res = AcpiEvaluateObjectTyped(bridge, ACPI_STRING("_SEG"),
nullptr, &seg, ACPI_TYPE_INTEGER);
/* according to ACPI spec assume segment 0 if method unavailable */
if (res == AE_OK)
bridge_seg = seg.object.Integer.Value;
unsigned const bridge_bdf = ((0xffffU & bridge_seg) << 16) |
((0x00ffU & bridge_bbn) << 8) |
(0xffU & ((bridge_adr >> 16) << 3)) |
(bridge_adr & 0x7);
return bridge_bdf;
}
void _gen_bridge(ACPI_HANDLE bridge, Genode::Xml_generator &xml,
unsigned const bridge_bdf)
{
Acpica::Buffer<char [2 * 4096]> irqs;
ACPI_STATUS res = AcpiGetIrqRoutingTable (bridge, &irqs);
if (res != AE_OK) {
Genode::error("buffer for PCI IRQ routing information to "
"small - ", irqs.Length, " required");
return;
}
ACPI_PCI_ROUTING_TABLE *s = reinterpret_cast<ACPI_PCI_ROUTING_TABLE *>(irqs.Pointer);
ACPI_PCI_ROUTING_TABLE *e = reinterpret_cast<ACPI_PCI_ROUTING_TABLE *>(reinterpret_cast<unsigned long>(&irqs) + irqs.Length);
for (ACPI_PCI_ROUTING_TABLE *c = s; c < e && c->Length; ) {
using Genode::Hex;
using Genode::String;
xml.node("routing", [&] () {
xml.attribute("gsi", String<16>(Hex(c->SourceIndex)));
xml.attribute("bridge_bdf", String<16>(Hex(bridge_bdf)));
xml.attribute("device", String<16>(Hex((c->Address >> 16) & 0x1f)));
xml.attribute("device_pin", String<16>(Hex(c->Pin)));
});
c = reinterpret_cast<ACPI_PCI_ROUTING_TABLE *>(reinterpret_cast<unsigned long>(c) + c->Length);
}
}
void _sub_bridges(ACPI_HANDLE handle, Genode::Xml_generator &xml)
{
ACPI_STATUS res = AcpiEvaluateObject(handle, ACPI_STRING("_PRT"),
nullptr, nullptr);
if (res != AE_OK)
return;
/* got another bridge, generate irq routing information to xml */
Bridge::_gen_bridge(handle, xml, bdf_bridge(handle));
ACPI_HANDLE child = nullptr;
/* lookup next bridge behind the bridge */
while (AE_OK == (res = AcpiGetNextObject(ACPI_TYPE_DEVICE, handle,
child, &child)))
{
_sub_bridges(child, xml);
}
}
public:
Bridge(void *, ACPI_HANDLE bridge)
:
_bridge(bridge)
{ }
static ACPI_STATUS detect(ACPI_HANDLE bridge, UINT32, void * m,
void **return_bridge);
void generate(Genode::Xml_generator &xml)
{
unsigned const root_bridge_bdf = bdf_bridge(_bridge);
xml.node("root_bridge", [&] () {
xml.attribute("bdf", Genode::String<8>(Genode::Hex(root_bridge_bdf)));
});
/* irq routing information of this (pci root) bridge */
_gen_bridge(_bridge, xml, root_bridge_bdf);
/* lookup all pci-to-pci bridges and add irq routing information */
_sub_bridges(_bridge, xml);
}
};

View File

@ -123,7 +123,7 @@ struct Acpica::Main
void *context;
} irq_handler;
void init_acpica(Acpica::Wait_acpi_ready, Acpica::Act_as_acpi_drv);
void init_acpica();
Main(Genode::Env &env)
:
@ -134,14 +134,11 @@ struct Acpica::Main
bool const enable_reset = config.xml().attribute_value("reset", false);
bool const enable_poweroff = config.xml().attribute_value("poweroff", false);
bool const enable_report = config.xml().attribute_value("report", false);
bool const enable_ready = config.xml().attribute_value("acpi_ready", false);
bool const act_as_acpi_drv = config.xml().attribute_value("act_as_acpi_drv", false);
if (enable_report)
report = new (heap) Acpica::Reportstate(env);
init_acpica(Wait_acpi_ready{enable_ready},
Act_as_acpi_drv{act_as_acpi_drv});
init_acpica();
if (enable_report)
report->enable();
@ -162,16 +159,6 @@ struct Acpica::Main
sci_conn->sigh(sci_irq);
sci_conn->ack_irq();
if (!enable_ready)
return;
/* we are ready - signal it via changing system state */
static Genode::Reporter _system_rom(env, "system", "acpi_ready");
_system_rom.enabled(true);
Genode::Reporter::Xml_generator xml(_system_rom, [&] () {
xml.attribute("state", "acpi_ready");
});
}
void acpi_irq()
@ -213,7 +200,6 @@ struct Acpica::Main
#include "lid.h"
#include "sb.h"
#include "ec.h"
#include "bridge.h"
#include "fujitsu.h"
ACPI_STATUS init_pic_mode()
@ -233,26 +219,10 @@ ACPI_STATUS init_pic_mode()
&arguments, nullptr);
}
ACPI_STATUS Bridge::detect(ACPI_HANDLE bridge, UINT32, void * m,
void **return_bridge)
void Acpica::Main::init_acpica()
{
Acpica::Main * main = reinterpret_cast<Acpica::Main *>(m);
Bridge * dev_obj = new (main->heap) Bridge(main->report, bridge);
if (*return_bridge == (void *)PCI_ROOT_HID_STRING)
Genode::log("detected - bridge - PCI root bridge");
if (*return_bridge == (void *)PCI_EXPRESS_ROOT_HID_STRING)
Genode::log("detected - bridge - PCIE root bridge");
*return_bridge = dev_obj;
return AE_OK;
}
void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready,
Act_as_acpi_drv act_as_acpi_drv)
{
Acpica::init(env, heap, wait_acpi_ready, act_as_acpi_drv);
Acpica::init(env, heap);
/* enable debugging: */
if (false) {
@ -428,32 +398,6 @@ void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready,
Genode::error("AcpiGetDevices (FUJ02E3) failed, status=", status);
return;
}
if (act_as_acpi_drv.enabled) {
/* lookup PCI root bridge */
void * pci_bridge = (void *)PCI_ROOT_HID_STRING;
status = AcpiGetDevices(ACPI_STRING(PCI_ROOT_HID_STRING), Bridge::detect,
this, &pci_bridge);
if (status != AE_OK || pci_bridge == (void *)PCI_ROOT_HID_STRING)
pci_bridge = nullptr;
/* lookup PCI Express root bridge */
void * pcie_bridge = (void *)PCI_EXPRESS_ROOT_HID_STRING;
status = AcpiGetDevices(ACPI_STRING(PCI_EXPRESS_ROOT_HID_STRING),
Bridge::detect, this, &pcie_bridge);
if (status != AE_OK || pcie_bridge == (void *)PCI_EXPRESS_ROOT_HID_STRING)
pcie_bridge = nullptr;
if (pcie_bridge && pci_bridge)
Genode::log("PCI and PCIE root bridge found - using PCIE for IRQ "
"routing information");
Bridge *bridge = pcie_bridge ? reinterpret_cast<Bridge *>(pcie_bridge)
: reinterpret_cast<Bridge *>(pci_bridge);
/* Generate report for platform driver */
Acpica::generate_report(env, bridge);
}
}

View File

@ -1,174 +0,0 @@
/*
* \brief Generate XML report
* \author Alexander Boettcher
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <base/env.h>
#include <os/reporter.h>
#include "util.h"
#include "bridge.h"
using namespace Acpica;
using Genode::Reporter;
extern void AcpiGenodeFreeIOMem(ACPI_PHYSICAL_ADDRESS const phys, ACPI_SIZE const size);
static void add_madt(ACPI_TABLE_MADT const * const madt,
Reporter::Xml_generator &xml)
{
typedef ACPI_SUBTABLE_HEADER Madt_sub;
using Genode::String;
for_each_element(madt, (Madt_sub *) nullptr, [&](Madt_sub const * const s) {
if (s->Type != ACPI_MADT_TYPE_INTERRUPT_OVERRIDE)
return;
typedef ACPI_MADT_INTERRUPT_OVERRIDE Irq;
Irq const * const irq = reinterpret_cast<Irq const * const>(s);
xml.node("irq_override", [&] () {
xml.attribute("irq", irq->SourceIrq);
xml.attribute("gsi", irq->GlobalIrq);
xml.attribute("flags", String<16>(Genode::Hex(irq->IntiFlags)));
xml.attribute("bus", irq->Bus);
});
}, [](Madt_sub const * const s) { return s->Length; });
}
static void add_mcfg(ACPI_TABLE_MCFG const * const mcfg,
Reporter::Xml_generator &xml)
{
using namespace Genode;
typedef ACPI_MCFG_ALLOCATION Mcfg_sub;
for_each_element(mcfg, (Mcfg_sub *) nullptr, [&](Mcfg_sub const * const e) {
/* bus_count * up to 32 devices * 8 function per device * 4k */
uint32_t const bus_count = e->EndBusNumber - e->StartBusNumber + 1;
uint32_t const func_count = bus_count * 32 * 8;
uint32_t const bus_start = e->StartBusNumber * 32 * 8;
xml.node("bdf", [&] () {
xml.attribute("start", bus_start);
xml.attribute("count", func_count);
xml.attribute("base", String<24>(Hex(e->Address)));
});
/* force freeing I/O mem so that platform driver can use it XXX */
AcpiGenodeFreeIOMem(e->Address, 0x1000UL * func_count);
}, [](Mcfg_sub const * const e) { return sizeof(*e); });
}
static void add_dmar(ACPI_TABLE_DMAR const * const dmar_table,
Reporter::Xml_generator &xml)
{
using Genode::String;
using Genode::Hex;
auto scope_length = [](ACPI_DMAR_DEVICE_SCOPE const * const e) {
return e->Length; };
auto scope_lambda = [&](ACPI_DMAR_DEVICE_SCOPE const * const e) {
xml.node("scope", [&] () {
xml.attribute("bus_start", e->Bus);
xml.attribute("type", e->EntryType);
unsigned const count = (e->Length < 6) ? 0 : ((e->Length - 6) / 2);
ACPI_DMAR_PCI_PATH * path = ACPI_CAST_PTR(ACPI_DMAR_PCI_PATH, e + 1);
for (unsigned i = 0; i < count; i++) {
xml.node("path", [&] () {
xml.attribute("dev", String<8>(Hex(path->Device)));
xml.attribute("func", String<8>(Hex(path->Function)));
});
}
});
};
for_each_element(dmar_table, (ACPI_DMAR_HEADER *) nullptr, [&](ACPI_DMAR_HEADER const * const e) {
if (e->Type == ACPI_DMAR_TYPE_RESERVED_MEMORY) {
ACPI_DMAR_RESERVED_MEMORY const * const dmar = ACPI_CAST_PTR (ACPI_DMAR_RESERVED_MEMORY, e);
xml.node("rmrr", [&] () {
xml.attribute("start", String<24>(Hex(dmar->BaseAddress)));
xml.attribute("end" , String<24>(Hex(dmar->EndAddress)));
for_each_element(dmar, (ACPI_DMAR_DEVICE_SCOPE *) nullptr,
scope_lambda, scope_length);
});
} else
if (e->Type == ACPI_DMAR_TYPE_HARDWARE_UNIT) {
ACPI_DMAR_HARDWARE_UNIT const * const drhd = ACPI_CAST_PTR (ACPI_DMAR_HARDWARE_UNIT, e);
xml.node("drhd", [&] () {
xml.attribute("phys", String<24>(Hex(drhd->Address)));
xml.attribute("flags", String<4>(Hex(drhd->Flags)));
xml.attribute("segment", String<8>(Hex(drhd->Segment)));
for_each_element(drhd, (ACPI_DMAR_DEVICE_SCOPE *) nullptr,
scope_lambda, scope_length);
});
}
}, [](ACPI_DMAR_HEADER const * const e) { return e->Length; });
}
static void add_ivdb(ACPI_TABLE_IVRS const * const ivrs_table,
Reporter::Xml_generator &xml)
{
typedef ACPI_IVRS_HEADER Ivdb;
for_each_element(ivrs_table, (Ivdb *) nullptr, [&](Ivdb const * const e) {
xml.node("ivdb", [&] () {
xml.attribute("type", e->Type);
});
}, [](Ivdb const * const e) { return e->Length; });
}
void Acpica::generate_report(Genode::Env &env, Bridge *pci_root_bridge)
{
enum { REPORT_SIZE = 5 * 4096 };
static Reporter acpi(env, "acpi", "acpi", REPORT_SIZE);
acpi.enabled(true);
Reporter::Xml_generator xml(acpi, [&] () {
ACPI_TABLE_HEADER *header = nullptr;
ACPI_STATUS status = AcpiGetTable((char *)ACPI_SIG_MADT, 0, &header);
if (status == AE_OK)
add_madt(reinterpret_cast<ACPI_TABLE_MADT *>(header), xml);
status = AcpiGetTable((char *)ACPI_SIG_MCFG, 0, &header);
if (status == AE_OK)
add_mcfg(reinterpret_cast<ACPI_TABLE_MCFG *>(header), xml);
for (unsigned instance = 1; ; instance ++) {
status = AcpiGetTable(ACPI_STRING(ACPI_SIG_DMAR), instance,
&header);
if (status != AE_OK)
break;
add_dmar(reinterpret_cast<ACPI_TABLE_DMAR *>(header), xml);
}
status = AcpiGetTable((char *)ACPI_SIG_IVRS, 0, &header);
if (status == AE_OK)
add_ivdb(reinterpret_cast<ACPI_TABLE_IVRS *>(header), xml);
if (pci_root_bridge)
pci_root_bridge->generate(xml);
});
}

View File

@ -1,5 +1,5 @@
TARGET := acpica
SRC_CC := os.cc printf.cc report.cc
SRC_CC := os.cc printf.cc
REQUIRES := x86
LIBS += base acpica

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
* Copyright (C) 2016-2022 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -14,7 +14,7 @@
/* Genode includes */
#include <util/reconstructible.h>
#include <acpica/acpica.h>
#include <legacy/x86/platform_session/client.h>
#include <platform_session/connection.h>
#include "env.h"
@ -27,24 +27,9 @@ struct Acpica::Env
Genode::Env &env;
Genode::Allocator &heap;
Wait_acpi_ready const wait_acpi_ready;
Genode::Constructible<Platform::Connection> platform;
Genode::Parent::Service_name announce_for_acpica {
wait_acpi_ready.enabled ? "Acpi" : Platform::Session::service_name() };
Genode::Parent::Client parent_client;
Genode::Id_space<Genode::Parent::Client>::Element id_space_element {
parent_client, env.id_space() };
Genode::Constructible<Genode::Capability<Platform::Session>> cap;
Genode::Constructible<Platform::Client> platform;
Env(Genode::Env &env, Genode::Allocator &heap,
Wait_acpi_ready wait_acpi_ready)
:
env(env), heap(heap), wait_acpi_ready(wait_acpi_ready)
{ }
Env(Genode::Env &env, Genode::Allocator &heap) : env(env), heap(heap) { }
};
static Genode::Constructible<Acpica::Env> instance;
@ -54,25 +39,16 @@ Genode::Allocator & Acpica::heap() { return instance->heap; }
Genode::Env & Acpica::env() { return instance->env; }
Platform::Client & Acpica::platform()
{
if (!instance->cap.constructed()) {
instance->cap.construct(Genode::reinterpret_cap_cast<Platform::Session>(
instance->env.session(instance->announce_for_acpica,
instance->id_space_element.id(),
"ram_quota=48K", Genode::Affinity())));
if (!instance->platform.constructed())
instance->platform.construct(instance->env);
instance->platform.construct(*instance->cap);
}
return *instance->platform;
}
void Acpica::init(Genode::Env &env, Genode::Allocator &heap,
Wait_acpi_ready const wait_acpi_ready,
Act_as_acpi_drv const act_as_acpi_drv)
void Acpica::init(Genode::Env &env, Genode::Allocator &heap)
{
instance.construct(env, heap, wait_acpi_ready);
instance.construct(env, heap);
/* if not running as acpi_drv, block until original acpi_drv is done */
if (!act_as_acpi_drv.enabled)
platform();
platform();
}

View File

@ -16,7 +16,7 @@
#include <base/env.h>
#include <base/allocator.h>
#include <legacy/x86/platform_session/client.h>
#include <platform_session/client.h>
namespace Acpica {
Genode::Env & env();

View File

@ -12,7 +12,6 @@
*/
#include <base/log.h>
#include <io_port_session/connection.h>
#include "env.h"
@ -51,49 +50,11 @@ ACPI_STATUS AcpiOsInitialize (void) { return AE_OK; }
ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
UINT64 *value, UINT32 width)
{
Platform::Device_capability cap = Acpica::platform().first_device();
using namespace Genode;
while (cap.valid()) {
Platform::Device_client client(cap);
Bdf bdf(pcidev->Bus, pcidev->Device, pcidev->Function);
unsigned char bus, dev, fn;
client.bus_address(&bus, &dev, &fn);
if (pcidev->Bus == bus && pcidev->Device == dev &&
pcidev->Function == fn) {
Platform::Device_client::Access_size access_size;
switch (width) {
case 8:
access_size = Platform::Device_client::Access_size::ACCESS_8BIT;
break;
case 16:
access_size = Platform::Device_client::Access_size::ACCESS_16BIT;
break;
case 32:
access_size = Platform::Device_client::Access_size::ACCESS_32BIT;
break;
default:
Genode::error(__func__, " : unsupported access size ", width);
Acpica::platform().release_device(client.rpc_cap());
return AE_ERROR;
};
if (reg >= 0x100)
Genode::warning(__func__, " ", Genode::Hex(reg),
" out of supported config space range ",
" -> wrong location will be read");
*value = client.config_read(reg, access_size);
Acpica::platform().release_device(client.rpc_cap());
return AE_OK;
}
cap = Acpica::platform().next_device(cap);
Acpica::platform().release_device(client.rpc_cap());
}
error(__func__, " ", bdf, " ", Hex(reg), " width=", width);
*value = ~0U;
return AE_OK;
@ -102,49 +63,11 @@ ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
UINT64 value, UINT32 width)
{
Platform::Device_capability cap = Acpica::platform().first_device();
using namespace Genode;
while (cap.valid()) {
Platform::Device_client client(cap);
Bdf bdf(pcidev->Bus, pcidev->Device, pcidev->Function);
unsigned char bus, dev, fn;
client.bus_address(&bus, &dev, &fn);
if (pcidev->Bus == bus && pcidev->Device == dev &&
pcidev->Function == fn) {
Platform::Device_client::Access_size access_size;
switch (width) {
case 8:
access_size = Platform::Device_client::Access_size::ACCESS_8BIT;
break;
case 16:
access_size = Platform::Device_client::Access_size::ACCESS_16BIT;
break;
case 32:
access_size = Platform::Device_client::Access_size::ACCESS_32BIT;
break;
default:
Genode::error(__func__, " : unsupported access size ", width);
Acpica::platform().release_device(client.rpc_cap());
return AE_ERROR;
};
client.config_write(reg, value, access_size);
if (reg >= 0x100)
Genode::warning(__func__, " ", Genode::Hex(reg),
" out of supported config space range ",
" -> wrong location will be written");
Acpica::platform().release_device(client.rpc_cap());
return AE_OK;
}
cap = Acpica::platform().next_device(cap);
Acpica::platform().release_device(client.rpc_cap());
}
error(__func__, " ", bdf, " ", Hex(reg), "=", Hex(value), " width=", width);
return AE_OK;
}