acpi: report ACPI tables and SCI IRQ

Issue #4679
This commit is contained in:
Christian Helmuth 2022-12-13 12:37:05 +01:00
parent 661330a97a
commit 53c2cff331

View File

@ -20,6 +20,7 @@
/* base includes */
#include <base/attached_io_mem_dataspace.h>
#include <base/attached_rom_dataspace.h>
#include <base/registry.h>
#include <util/misc_math.h>
#include <util/mmio.h>
@ -311,6 +312,7 @@ struct Fadt : Genode::Mmio
Fadt(addr_t mmio, size_t size) : Genode::Mmio(mmio), size(size) { }
struct Dsdt : Register<0x28, 32> { };
struct Sci_int : Register<0x2e, 16> { };
struct Features : Register<0x70, 32> {
/* Table 5-35 Fixed ACPI Description Table Fixed Feature Flags */
struct Reset : Bitfield<10, 1> { };
@ -327,6 +329,9 @@ struct Fadt : Genode::Mmio
bool dsdt_valid() {
return size >= Dsdt::OFFSET + Dsdt::ACCESS_WIDTH / 8; }
bool sci_int_valid() {
return size >= Sci_int::OFFSET + Sci_int::ACCESS_WIDTH / 8; }
bool io_reset_supported()
{
if (size < Reset_value::OFFSET + Reset_value::ACCESS_WIDTH / 8)
@ -511,6 +516,21 @@ class Pci_config_space : public List<Pci_config_space>::Element
*/
class Table_wrapper
{
public:
struct Info : Registry<Info>::Element
{
String<5> name;
addr_t addr;
size_t size;
Info(Registry<Info> &registry,
char const *name, addr_t addr, size_t size)
:
Registry<Info>::Element(registry, *this),
name(name), addr(addr), size(size) { }
};
private:
addr_t _base; /* table base address */
@ -634,7 +654,8 @@ class Table_wrapper
Dmar_entry::list()->insert(new (&alloc) Dmar_entry(head->clone(alloc)));
}
Table_wrapper(Acpi::Memory &memory, addr_t base)
Table_wrapper(Acpi::Memory &memory, addr_t base,
Registry<Info> &registry, Allocator &heap)
: _base(base), _table(0)
{
/* make table header accessible */
@ -646,6 +667,8 @@ class Table_wrapper
memset(_name, 0, 5);
memcpy(_name, _table->signature, 4);
new (heap) Info(registry, name(), _base, _table->size);
if (verbose)
Genode::log("table mapped '", Genode::Cstring(_name), "' at ", _table, " "
"(from ", Genode::Hex(_base), ") "
@ -1318,7 +1341,7 @@ class Acpi_table
private:
Genode::Env &_env;
Genode::Allocator &_alloc;
Genode::Allocator &_heap;
Acpi::Memory _memory;
struct Reset_info
@ -1328,6 +1351,10 @@ class Acpi_table
};
Genode::Constructible<Reset_info> _reset_info { };
unsigned short _sci_int { };
bool _sci_int_valid { };
Registry<Table_wrapper::Info> _table_registry { };
/* BIOS range to scan for RSDP */
enum { BIOS_BASE = 0xe0000, BIOS_SIZE = 0x20000 };
@ -1380,13 +1407,13 @@ class Acpi_table
}
template <typename T>
void _parse_tables(Genode::Allocator &alloc, T * entries, uint32_t const count)
void _parse_tables(T * entries, uint32_t const count)
{
/* search for SSDT and DSDT tables */
for (uint32_t i = 0; i < count; i++) {
uint32_t dsdt = 0;
try {
Table_wrapper table(_memory, entries[i]);
Table_wrapper table(_memory, entries[i], _table_registry, _heap);
if (!table.valid()) {
Genode::error("ignoring table '", table.name(),
@ -1398,7 +1425,7 @@ class Acpi_table
log("Found IVRS");
Ivrs ivrs(reinterpret_cast<Genode::addr_t>(table->signature));
ivrs.parse(alloc);
ivrs.parse(_heap);
}
if (table.is_facp()) {
@ -1414,6 +1441,10 @@ class Acpi_table
_reset_info.construct(Reset_info { .io_port = reset_io_port,
.value = reset_value });
}
if (fadt.sci_int_valid()) {
_sci_int = fadt.read<Fadt::Sci_int>();
_sci_int_valid = true;
}
}
if (table.is_searched()) {
@ -1421,23 +1452,23 @@ class Acpi_table
if (verbose)
Genode::log("Found ", table.name());
Element::parse(alloc, table.table());
Element::parse(_heap, table.table());
}
if (table.is_madt()) {
Genode::log("Found MADT");
table.parse_madt(alloc);
table.parse_madt(_heap);
}
if (table.is_mcfg()) {
Genode::log("Found MCFG");
table.parse_mcfg(alloc);
table.parse_mcfg(_heap);
}
if (table.is_dmar()) {
Genode::log("Found DMAR");
table.parse_dmar(alloc);
table.parse_dmar(_heap);
}
} catch (Acpi::Memory::Unsupported_range &) { }
@ -1445,7 +1476,7 @@ class Acpi_table
continue;
try {
Table_wrapper table(_memory, dsdt);
Table_wrapper table(_memory, dsdt, _table_registry, _heap);
if (!table.valid()) {
Genode::error("ignoring table '", table.name(),
@ -1456,7 +1487,7 @@ class Acpi_table
if (verbose)
Genode::log("Found dsdt ", table.name());
Element::parse(alloc, table.table());
Element::parse(_heap, table.table());
}
} catch (Acpi::Memory::Unsupported_range &) { }
}
@ -1465,8 +1496,8 @@ class Acpi_table
public:
Acpi_table(Genode::Env &env, Genode::Allocator &alloc)
: _env(env), _alloc(alloc), _memory(_env, _alloc)
Acpi_table(Genode::Env &env, Genode::Allocator &heap)
: _env(env), _heap(heap), _memory(_env, _heap)
{
addr_t rsdt = 0, xsdt = 0;
uint8_t acpi_revision = 0;
@ -1514,33 +1545,43 @@ class Acpi_table
if (acpi_revision != 0 && xsdt && sizeof(addr_t) != sizeof(uint32_t)) {
/* running 64bit and xsdt is valid */
Table_wrapper table(_memory, xsdt);
Table_wrapper table(_memory, xsdt, _table_registry, _heap);
if (!table.valid()) throw -1;
uint64_t * entries = reinterpret_cast<uint64_t *>(table.table() + 1);
_parse_tables(alloc, entries, table.entry_count(entries));
_parse_tables(entries, table.entry_count(entries));
Genode::log("XSDT ", *table.table());
} else {
/* running (32bit) or (64bit and xsdt isn't valid) */
Table_wrapper table(_memory, rsdt);
Table_wrapper table(_memory, rsdt, _table_registry, _heap);
if (!table.valid()) throw -1;
uint32_t * entries = reinterpret_cast<uint32_t *>(table.table() + 1);
_parse_tables(alloc, entries, table.entry_count(entries));
_parse_tables(entries, table.entry_count(entries));
Genode::log("RSDT ", *table.table());
}
/* free up memory of elements not of any use */
Element::clean_list(alloc);
Element::clean_list(_heap);
/* free up io memory */
_memory.free_io_memory();
}
void generate_reset_info(Xml_generator &xml) const
~Acpi_table()
{
_table_registry.for_each([&] (Table_wrapper::Info &info) {
destroy(_heap, &info);
});
}
void generate_info(Xml_generator &xml) const
{
if (_sci_int_valid)
xml.node("sci_int", [&] () { xml.attribute("irq", _sci_int); });
if (!_reset_info.constructed())
return;
@ -1548,6 +1589,15 @@ class Acpi_table
xml.attribute("io_port", String<32>(Hex(_reset_info->io_port)));
xml.attribute("value", _reset_info->value);
});
Registry<Table_wrapper::Info> const &reg = _table_registry;
reg.for_each([&] (Table_wrapper::Info const &info) {
xml.node("table", [&] {
xml.attribute("name", info.name);
xml.attribute("addr", String<20>(Hex(info.addr)));
xml.attribute("size", info.size);
});
});
}
};
@ -1570,7 +1620,7 @@ void Acpi::generate_report(Genode::Env &env, Genode::Allocator &alloc)
acpi.generate([&] (Genode::Xml_generator &xml) {
acpi_table.generate_reset_info(xml);
acpi_table.generate_info(xml);
if (root_bridge_bdf != INVALID_ROOT_BRIDGE) {
xml.node("root_bridge", [&] () {