mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 09:46:20 +00:00
parent
874815ebf6
commit
0efa67893e
@ -22,8 +22,11 @@ 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);
|
||||
void init(Genode::Env &, Genode::Allocator &, Wait_acpi_ready,
|
||||
Act_as_acpi_drv);
|
||||
void use_platform_drv();
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__ACPICA__ACPICA_H_ */
|
||||
|
@ -43,24 +43,32 @@ the machine immediately.
|
||||
|
||||
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. E.g. for 'reset' on some machines the platform driver posses the
|
||||
required I/O ports and the acpica application don't get access to. On such
|
||||
systems the platform driver can be configured to react on the 'state="reset"'
|
||||
system state change. The platform_drv can be configured to monitor
|
||||
the 'system' ROM by adding a config attribute named 'system' and set to 'yes'.
|
||||
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.
|
||||
|
||||
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"/>
|
||||
! <config reset="no" poweroff="no" report="yes" acpi_ready="yes" act_as_acpi_drv="no"/>
|
||||
! <route>
|
||||
! <service name="ROM" label="system"> <child name="..."/> </service>
|
||||
! <service name="Report"> <child name="..."/> </service>
|
||||
|
139
repos/libports/src/app/acpica/bridge.h
Normal file
139
repos/libports/src/app/acpica/bridge.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* \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);
|
||||
}
|
||||
};
|
@ -117,7 +117,7 @@ struct Acpica::Main
|
||||
void *context;
|
||||
} irq_handler;
|
||||
|
||||
void init_acpica(Acpica::Wait_acpi_ready);
|
||||
void init_acpica(Acpica::Wait_acpi_ready, Acpica::Act_as_acpi_drv);
|
||||
|
||||
Main(Genode::Env &env)
|
||||
:
|
||||
@ -128,11 +128,13 @@ struct Acpica::Main
|
||||
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});
|
||||
init_acpica(Wait_acpi_ready{enable_ready},
|
||||
Act_as_acpi_drv{act_as_acpi_drv});
|
||||
|
||||
if (enable_report)
|
||||
report->enable();
|
||||
@ -187,10 +189,45 @@ struct Acpica::Main
|
||||
#include "lid.h"
|
||||
#include "sb.h"
|
||||
#include "ec.h"
|
||||
#include "bridge.h"
|
||||
|
||||
void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready)
|
||||
ACPI_STATUS init_pic_mode()
|
||||
{
|
||||
Acpica::init(env, heap, wait_acpi_ready);
|
||||
ACPI_OBJECT_LIST arguments;
|
||||
ACPI_OBJECT argument;
|
||||
|
||||
arguments.Count = 1;
|
||||
arguments.Pointer = &argument;
|
||||
|
||||
enum { PIC = 0, APIC = 1, SAPIC = 2};
|
||||
|
||||
argument.Type = ACPI_TYPE_INTEGER;
|
||||
argument.Integer.Value = APIC;
|
||||
|
||||
return AcpiEvaluateObject(ACPI_ROOT_OBJECT, ACPI_STRING("_PIC"),
|
||||
&arguments, nullptr);
|
||||
}
|
||||
|
||||
ACPI_STATUS Bridge::detect(ACPI_HANDLE bridge, UINT32, void * m,
|
||||
void **return_bridge)
|
||||
{
|
||||
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);
|
||||
|
||||
/* enable debugging: */
|
||||
/* AcpiDbgLevel |= ACPI_LV_IO | ACPI_LV_INTERRUPTS | ACPI_LV_INIT_NAMES; */
|
||||
@ -225,6 +262,13 @@ void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready)
|
||||
return;
|
||||
}
|
||||
|
||||
/* set APIC mode */
|
||||
status = init_pic_mode();
|
||||
if (status != AE_OK) {
|
||||
Genode::error("Setting PIC mode failed, status=", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Embedded controller */
|
||||
status = AcpiGetDevices(ACPI_STRING("PNP0C09"), Ec::detect, this, nullptr);
|
||||
if (status != AE_OK) {
|
||||
@ -286,6 +330,35 @@ void Acpica::Main::init_acpica(Wait_acpi_ready wait_acpi_ready)
|
||||
Genode::error("AcpiGetDevices (PNP0C0D) 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);
|
||||
}
|
||||
|
||||
/* Tell PCI backend to use platform_drv for PCI device access from now on */
|
||||
Acpica::use_platform_drv();
|
||||
}
|
||||
|
||||
|
||||
|
167
repos/libports/src/app/acpica/report.cc
Normal file
167
repos/libports/src/app/acpica/report.cc
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* \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 Genode::Reporter;
|
||||
|
||||
extern void AcpiGenodeFreeIOMem(ACPI_PHYSICAL_ADDRESS const phys, ACPI_SIZE const size);
|
||||
|
||||
template <typename H, typename S, typename F, typename FSIZE>
|
||||
void for_each_element(H const head, S *, F const &fn, FSIZE const &fn_size)
|
||||
{
|
||||
for(S const * e = reinterpret_cast<S const * const>(head + 1);
|
||||
e < reinterpret_cast<S const *>(reinterpret_cast<char const *>(head) + head->Header.Length);
|
||||
e = reinterpret_cast<S const *>(reinterpret_cast<char const *>(e) + fn_size(e)))
|
||||
{
|
||||
fn(e);
|
||||
}
|
||||
}
|
||||
|
||||
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; });
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (pci_root_bridge)
|
||||
pci_root_bridge->generate(xml);
|
||||
});
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
TARGET := acpica
|
||||
SRC_CC := os.cc printf.cc
|
||||
SRC_CC := os.cc printf.cc report.cc
|
||||
REQUIRES := x86
|
||||
LIBS += base acpica
|
||||
|
||||
|
@ -1,6 +1,25 @@
|
||||
/*
|
||||
* \brief Some utils
|
||||
* \author Alexander Boettcher
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016-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.
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include "acpi.h"
|
||||
}
|
||||
|
||||
class Bridge;
|
||||
|
||||
namespace Acpica {
|
||||
template<typename> class Buffer;
|
||||
template<typename> class Callback;
|
||||
void generate_report(Genode::Env &, Bridge *);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -28,6 +28,7 @@ struct Acpica::Env
|
||||
Genode::Allocator &heap;
|
||||
|
||||
Wait_acpi_ready const wait_acpi_ready;
|
||||
bool use_platform_drv;
|
||||
|
||||
Genode::Parent::Service_name announce_for_acpica {
|
||||
wait_acpi_ready.enabled ? "Acpi" : Platform::Session::service_name() };
|
||||
@ -37,16 +38,15 @@ struct Acpica::Env
|
||||
Genode::Id_space<Genode::Parent::Client>::Element id_space_element {
|
||||
parent_client, env.id_space() };
|
||||
|
||||
Genode::Capability<Platform::Session> cap {
|
||||
Genode::reinterpret_cap_cast<Platform::Session>(
|
||||
env.session(announce_for_acpica,
|
||||
id_space_element.id(),
|
||||
"ram_quota=36K", Genode::Affinity())) };
|
||||
Genode::Constructible<Genode::Capability<Platform::Session>> cap;
|
||||
Genode::Constructible<Platform::Client> platform;
|
||||
|
||||
Platform::Client platform { cap };
|
||||
|
||||
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,
|
||||
Wait_acpi_ready wait_acpi_ready)
|
||||
:
|
||||
env(env), heap(heap), wait_acpi_ready(wait_acpi_ready),
|
||||
use_platform_drv(!wait_acpi_ready.enabled)
|
||||
{ }
|
||||
};
|
||||
|
||||
static Genode::Constructible<Acpica::Env> instance;
|
||||
@ -54,11 +54,29 @@ static Genode::Constructible<Acpica::Env> instance;
|
||||
|
||||
Genode::Allocator & Acpica::heap() { return instance->heap; }
|
||||
Genode::Env & Acpica::env() { return instance->env; }
|
||||
Platform::Client & Acpica::platform() { return instance->platform; }
|
||||
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=36K", Genode::Affinity())));
|
||||
|
||||
instance->platform.construct(*instance->cap);
|
||||
}
|
||||
return *instance->platform;
|
||||
}
|
||||
bool Acpica::platform_drv() { return instance->use_platform_drv; }
|
||||
void Acpica::use_platform_drv() { instance->use_platform_drv = true; }
|
||||
|
||||
|
||||
void Acpica::init(Genode::Env &env, Genode::Allocator &heap,
|
||||
Wait_acpi_ready wait_acpi_ready)
|
||||
Wait_acpi_ready const wait_acpi_ready,
|
||||
Act_as_acpi_drv const act_as_acpi_drv)
|
||||
{
|
||||
instance.construct(env, heap, wait_acpi_ready);
|
||||
|
||||
/* if not running as acpi_drv, block until original acpi_drv is done */
|
||||
if (!act_as_acpi_drv.enabled)
|
||||
platform();
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ namespace Acpica {
|
||||
Genode::Env & env();
|
||||
Genode::Allocator & heap();
|
||||
Platform::Client & platform();
|
||||
bool platform_drv();
|
||||
}
|
||||
|
||||
#endif /* _ACPICA__ENV_H_ */
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <util/misc_math.h>
|
||||
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <region_map/client.h>
|
||||
#include <rm_session/connection.h>
|
||||
|
||||
#include "env.h"
|
||||
@ -124,6 +125,7 @@ class Acpica::Io_mem
|
||||
Genode::Io_mem_connection *_io_mem = nullptr;
|
||||
unsigned _ref = 0;
|
||||
|
||||
static Genode::Rm_connection *rm_conn;
|
||||
static Acpica::Io_mem _ios[32];
|
||||
|
||||
public:
|
||||
@ -144,6 +146,55 @@ class Acpica::Io_mem
|
||||
return reinterpret_cast<Genode::addr_t>(_virt + (p - _phys));
|
||||
}
|
||||
|
||||
static void force_free_overlap(ACPI_PHYSICAL_ADDRESS const phys,
|
||||
ACPI_SIZE const size)
|
||||
{
|
||||
Acpica::Io_mem::apply_u([&] (Acpica::Io_mem &io_mem) {
|
||||
if (io_mem.unused() && !io_mem.stale())
|
||||
return 0;
|
||||
|
||||
/* skip non overlapping ranges */
|
||||
if ((phys + size <= io_mem._phys) ||
|
||||
(io_mem._phys + io_mem._size <= phys))
|
||||
return 0;
|
||||
|
||||
while (io_mem._ref > 1) {
|
||||
io_mem.ref_dec();
|
||||
}
|
||||
|
||||
Genode::warning(" force freeing I/O memory",
|
||||
" unused=", io_mem.unused(),
|
||||
" stale=" , io_mem.stale(),
|
||||
" phys=" , Genode::Hex(io_mem._phys),
|
||||
" size=" , Genode::Hex(io_mem._size),
|
||||
" virt=" , io_mem._virt,
|
||||
" io_ptr=", io_mem._io_mem,
|
||||
" refcnt=", io_mem._ref);
|
||||
|
||||
/* allocate region on heap and don't free, otherwise in destructor the connection will be closed */
|
||||
if (!rm_conn)
|
||||
rm_conn = new (Acpica::heap()) Genode::Rm_connection(Acpica::env());
|
||||
|
||||
/* create managed dataspace to let virt region reserved */
|
||||
Genode::Region_map_client managed_region(rm_conn->create(io_mem._size));
|
||||
/* remember virt, since it get invalid during invalidate() */
|
||||
Genode::addr_t const re_attach_virt = reinterpret_cast<Genode::addr_t>(io_mem._virt);
|
||||
|
||||
/* drop I/O mem and virt region get's freed */
|
||||
io_mem.invalidate();
|
||||
|
||||
/* re-attach dummy managed dataspace to virt region */
|
||||
Genode::addr_t const re_attached_virt = Acpica::env().rm().attach_at(managed_region.dataspace(), re_attach_virt);
|
||||
if (re_attach_virt != re_attached_virt)
|
||||
FAIL(0);
|
||||
|
||||
if (!io_mem.unused() || io_mem.stale())
|
||||
FAIL(0);
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
bool ref_dec() { return --_ref; }
|
||||
|
||||
template <typename FUNC>
|
||||
@ -310,6 +361,7 @@ class Acpica::Io_mem
|
||||
};
|
||||
|
||||
Acpica::Io_mem Acpica::Io_mem::_ios[32];
|
||||
Genode::Rm_connection * Acpica::Io_mem::rm_conn { nullptr };
|
||||
|
||||
static ACPI_TABLE_RSDP faked_rsdp;
|
||||
enum { FAKED_PHYS_RSDP_ADDR = 1 };
|
||||
@ -390,3 +442,8 @@ void AcpiOsUnmapMemory (void * ptr, ACPI_SIZE size)
|
||||
|
||||
FAIL()
|
||||
}
|
||||
|
||||
void AcpiGenodeFreeIOMem(ACPI_PHYSICAL_ADDRESS const phys, ACPI_SIZE const size)
|
||||
{
|
||||
Acpica::Io_mem::force_free_overlap(phys, size);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <base/log.h>
|
||||
#include <io_port_session/connection.h>
|
||||
|
||||
#include "env.h"
|
||||
|
||||
@ -34,18 +35,125 @@ struct Bdf
|
||||
void print(Genode::Output &out) const
|
||||
{
|
||||
using Genode::Hex;
|
||||
Genode::print(out, Hex(bus, Hex::OMIT_PREFIX), ":",
|
||||
Hex(dev, Hex::OMIT_PREFIX), ".",
|
||||
Genode::print(out, Hex(bus, Hex::OMIT_PREFIX, Hex::PAD), ":",
|
||||
Hex(dev, Hex::OMIT_PREFIX, Hex::PAD), ".",
|
||||
Hex(fn, Hex::OMIT_PREFIX), " ");
|
||||
}
|
||||
};
|
||||
|
||||
static void dump_read(char const * const func, ACPI_PCI_ID *pcidev,
|
||||
UINT32 reg, UINT64 value, UINT32 width)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
log(func, ": ", Bdf(pcidev->Bus, pcidev->Device, pcidev->Function), " "
|
||||
"reg=", Hex(reg, Hex::PREFIX, Hex::PAD), " "
|
||||
"width=", width, width < 10 ? " " : "", " -> "
|
||||
"value=", Genode::Hex(value));
|
||||
}
|
||||
|
||||
static void dump_write(char const * const func, ACPI_PCI_ID *pcidev,
|
||||
UINT32 reg, UINT64 value, UINT32 width)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
warning(func, ": ", Bdf(pcidev->Bus, pcidev->Device, pcidev->Function), " "
|
||||
"reg=", Hex(reg, Hex::PREFIX, Hex::PAD), " "
|
||||
"width=", width, width < 10 ? " " : "", " -> "
|
||||
"value=", Genode::Hex(value));
|
||||
}
|
||||
|
||||
static void dump_error(char const * const func, ACPI_PCI_ID *pcidev,
|
||||
UINT32 reg, UINT32 width)
|
||||
{
|
||||
error(func, " unknown device - segment=", pcidev->Segment, " ",
|
||||
"bdf=", Bdf(pcidev->Bus, pcidev->Device, pcidev->Function), " ",
|
||||
"reg=", Genode::Hex(reg), " "
|
||||
"width=", Genode::Hex(width));
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
* Accessing PCI via I/O ports *
|
||||
*******************************/
|
||||
|
||||
enum { REG_ADDR = 0xcf8, REG_DATA = 0xcfc, REG_SIZE = 4 };
|
||||
|
||||
static Genode::Io_port_connection &pci_io_port() {
|
||||
static Genode::Io_port_connection conn(Acpica::env(), REG_ADDR, REG_SIZE);
|
||||
return conn;
|
||||
}
|
||||
|
||||
static unsigned pci_io_cfg_addr(unsigned const bus, unsigned const device,
|
||||
unsigned const function, unsigned const addr)
|
||||
{
|
||||
return (1U << 31) |
|
||||
(bus << 16) |
|
||||
((device & 0x1fU) << 11) |
|
||||
((function & 0x07U) << 8) |
|
||||
(addr & ~3U);
|
||||
}
|
||||
|
||||
static unsigned pci_io_read(unsigned const bus, unsigned const device,
|
||||
unsigned const function, unsigned const addr,
|
||||
unsigned const width)
|
||||
{
|
||||
/* write target address */
|
||||
pci_io_port().outl(REG_ADDR, pci_io_cfg_addr(bus, device, function, addr));
|
||||
|
||||
switch (width) {
|
||||
case 8:
|
||||
return pci_io_port().inb(REG_DATA + (addr & 3));
|
||||
case 16:
|
||||
return pci_io_port().inw(REG_DATA + (addr & 2));
|
||||
case 32:
|
||||
return pci_io_port().inl(REG_DATA);
|
||||
default:
|
||||
return ~0U;
|
||||
}
|
||||
}
|
||||
|
||||
static void pci_io_write(unsigned const bus, unsigned const device,
|
||||
unsigned const function, unsigned const addr,
|
||||
unsigned const width, unsigned value)
|
||||
{
|
||||
/* write target address */
|
||||
pci_io_port().outl(REG_ADDR, pci_io_cfg_addr(bus, device, function, addr));
|
||||
|
||||
switch (width) {
|
||||
case 8:
|
||||
pci_io_port().outb(REG_DATA + (addr & 3), value);
|
||||
return;
|
||||
case 16:
|
||||
pci_io_port().outw(REG_DATA + (addr & 2), value);
|
||||
return;
|
||||
case 32:
|
||||
pci_io_port().outl(REG_DATA, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Acpica PCI OS backend *
|
||||
*************************/
|
||||
|
||||
ACPI_STATUS AcpiOsInitialize (void) { return AE_OK; }
|
||||
|
||||
ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
UINT64 *value, UINT32 width)
|
||||
{
|
||||
if (!Acpica::platform_drv()) {
|
||||
try {
|
||||
*value = pci_io_read(pcidev->Bus, pcidev->Device, pcidev->Function,
|
||||
reg, width);
|
||||
dump_read(__func__, pcidev, reg, *value, width);
|
||||
} catch (...) {
|
||||
dump_error(__func__, pcidev, reg, width);
|
||||
return AE_ERROR;
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
Platform::Device_capability cap = Acpica::platform().first_device();
|
||||
|
||||
while (cap.valid()) {
|
||||
@ -76,10 +184,7 @@ ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
|
||||
*value = client.config_read(reg, access_size);
|
||||
|
||||
Genode::log(__func__, ": ", Bdf(bus, dev, fn),
|
||||
"reg=", Genode::Hex(reg), " "
|
||||
"width=", width, " -> "
|
||||
"value=", Genode::Hex(*value));
|
||||
dump_read(__func__, pcidev, reg, *value, width);
|
||||
|
||||
Acpica::platform().release_device(client);
|
||||
return AE_OK;
|
||||
@ -90,10 +195,7 @@ ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
Acpica::platform().release_device(client);
|
||||
}
|
||||
|
||||
Genode::error(__func__, " unknown device - segment=", pcidev->Segment, " "
|
||||
"bdf=", Bdf(pcidev->Bus, pcidev->Device, pcidev->Function), " "
|
||||
"reg=", Genode::Hex(reg), " "
|
||||
"width=", Genode::Hex(width));
|
||||
dump_error(__func__, pcidev, reg, width);
|
||||
|
||||
return AE_ERROR;
|
||||
}
|
||||
@ -101,6 +203,18 @@ ACPI_STATUS AcpiOsReadPciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
UINT64 value, UINT32 width)
|
||||
{
|
||||
if (!Acpica::platform_drv()) {
|
||||
try {
|
||||
dump_write(__func__, pcidev, reg, value, width);
|
||||
pci_io_write(pcidev->Bus, pcidev->Device, pcidev->Function, reg,
|
||||
width, value);
|
||||
return AE_OK;
|
||||
} catch (...) {
|
||||
dump_error(__func__, pcidev, reg, width);
|
||||
return AE_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
Platform::Device_capability cap = Acpica::platform().first_device();
|
||||
|
||||
while (cap.valid()) {
|
||||
@ -131,10 +245,7 @@ ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
|
||||
client.config_write(reg, value, access_size);
|
||||
|
||||
Genode::warning(__func__, ": ", Bdf(bus, dev, fn), " "
|
||||
"reg=", Genode::Hex(reg), " "
|
||||
"width=", width, " "
|
||||
"value=", Genode::Hex(value));
|
||||
dump_write(__func__, pcidev, reg, value, width);
|
||||
|
||||
Acpica::platform().release_device(client);
|
||||
return AE_OK;
|
||||
@ -145,10 +256,7 @@ ACPI_STATUS AcpiOsWritePciConfiguration (ACPI_PCI_ID *pcidev, UINT32 reg,
|
||||
Acpica::platform().release_device(client);
|
||||
}
|
||||
|
||||
Genode::error(__func__, " unknown device - segment=", pcidev->Segment, " ",
|
||||
"bdf=", Bdf(pcidev->Bus, pcidev->Device, pcidev->Function), " ",
|
||||
"reg=", Genode::Hex(reg), " "
|
||||
"width=", Genode::Hex(width));
|
||||
dump_error(__func__, pcidev, reg, width);
|
||||
|
||||
return AE_ERROR;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user