From 74e89727ee6c442b5f612d4d7e669b7ea998d1a3 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Thu, 5 Nov 2015 11:12:38 +0100 Subject: [PATCH] acpi - report rmrr via acpi report rom Issue #1764 --- repos/os/src/drivers/acpi/acpi.cc | 178 ++++++++++++++++++++++++------ 1 file changed, 143 insertions(+), 35 deletions(-) diff --git a/repos/os/src/drivers/acpi/acpi.cc b/repos/os/src/drivers/acpi/acpi.cc index 4938da4f3..326d6e07c 100644 --- a/repos/os/src/drivers/acpi/acpi.cc +++ b/repos/os/src/drivers/acpi/acpi.cc @@ -19,6 +19,7 @@ /* base includes */ #include +#include /* os includes */ #include @@ -72,7 +73,6 @@ struct Apic_override : Apic_struct } __attribute__((packed)); struct Dmar_struct_header; -struct Dmar_struct; /* ACPI spec 5.2.6 */ struct Generic @@ -97,16 +97,21 @@ struct Generic Mcfg_struct *mcfg_struct() { return reinterpret_cast(&creator_rev + 3); } Mcfg_struct *mcfg_end() { return reinterpret_cast(signature + size); } - /* DMAR Intel VT-d structures */ Dmar_struct_header *dmar_header() { return reinterpret_cast(this); } - Dmar_struct *dmar_struct() { return reinterpret_cast(&creator_rev + 4); } - Dmar_struct *dmar_end() { return reinterpret_cast(signature + size); } } __attribute__((packed)); -/** - * DMA Remapping structures - */ +struct Dmar_common : Genode::Mmio +{ + struct Type : Register<0x0, 16> { + enum { DRHD= 0U, RMRR = 0x1U, ATSR = 0x2U, RHSA = 0x3U }; }; + struct Length : Register<0x2, 16> { }; + + Dmar_common(addr_t mmio) : Genode::Mmio(mmio) { } +}; + + +/* DMA Remapping Reporting Structure - Intel VT-d IO Spec - 8.1. */ struct Dmar_struct_header : Generic { enum { INTR_REMAP_MASK = 0x1U }; @@ -114,37 +119,96 @@ struct Dmar_struct_header : Generic uint8_t width; uint8_t flags; uint8_t reserved[10]; + + /* DMAR Intel VT-d structures */ + addr_t dmar_entry_start() { return reinterpret_cast(&creator_rev + 4); } + addr_t dmar_entry_end() { return reinterpret_cast(signature + size); } + + template + void apply(FUNC const &func = [] () { } ) + { + addr_t addr = dmar_entry_start(); + do { + Dmar_common dmar(addr); + + func(dmar); + + addr = dmar.base + dmar.read(); + } while (addr < dmar_entry_end()); + } + + struct Dmar_struct_header * clone() + { + size_t const size = dmar_entry_end() - reinterpret_cast(this); + char * clone = new (env()->heap()) char[size]; + memcpy(clone, this, size); + + return reinterpret_cast(clone); + } } __attribute__((packed)); -/* Reserved Memory Region Reporting structure - Intel VT-d IO Spec - 8.4. */ -struct Rmrr_struct + +/* Intel VT-d IO Spec - 8.3.1. */ +struct Device_scope : Genode::Mmio { - uint16_t type; - uint16_t length; - uint16_t reserved; - uint16_t pci_segment; - uint64_t start; - uint64_t end; -} __attribute__((packed)); + Device_scope(addr_t a) : Genode::Mmio(a) { } -/* DMA Remapping Reporting structure - Intel VT-d IO Spec - 8.1. */ -struct Dmar_struct + struct Type : Register<0x0, 8> { enum { PCI_END_POINT = 0x1 }; }; + struct Length : Register<0x1, 8> { }; + struct Bus : Register<0x5, 8> { }; + + struct Path : Register_array<0x6, 8, 1, 16> { + struct Dev : Bitfield<0,8> { }; + struct Func : Bitfield<8,8> { }; + }; + + unsigned count() const { return (read() - 6) / 2; } +}; + + +/* DMA Remapping Reporting structure - Intel VT-d IO Spec - 8.3. */ +struct Dmar_rmrr : Genode::Mmio { - enum { DRHD= 0U, RMRR = 0x1U, ATSR = 0x2U, RHSA = 0x3U }; - uint16_t type; - uint16_t length; - uint8_t flags; - uint8_t reserved; - uint16_t pci_segment; - uint64_t base; - uint64_t limit; + struct Length : Register<0x02, 16> { }; + struct Base : Register<0x08, 64> { }; + struct Limit : Register<0x10, 64> { }; - Dmar_struct *next() { - return reinterpret_cast((uint8_t *)this + length); } + Dmar_rmrr(addr_t a) : Genode::Mmio(a) { } - Rmrr_struct *rmrr() { return reinterpret_cast(&base + 1); } -} __attribute__((packed)); + template + void apply(FUNC const &func = [] () { } ) + { + addr_t addr = base + 24; + do { + Device_scope scope(addr); + func(scope); + + addr = scope.base + scope.read(); + } while (addr < base + read()); + } +}; + + +class Dmar_entry : public List::Element +{ + private: + + Dmar_struct_header *_header; + + public: + + Dmar_entry(Dmar_struct_header * h) : _header(h) { } + + template + void apply(FUNC const &func = [] () { } ) { _header->apply(func); } + + static List *list() + { + static List _list; + return &_list; + } +}; /** * List that holds interrupt override information @@ -319,11 +383,11 @@ class Table_wrapper head->flags & Dmar_struct_header::INTR_REMAP_MASK ? " , IRQ remapping supported" : ""); - Dmar_struct *dmar = _table->dmar_struct(); - for (; dmar < _table->dmar_end(); dmar = dmar->next()) - if (dmar->type == Dmar_struct::RMRR) - PLOG("RMRR: [0x%llx,0x%llx] - DMA region reported by BIOS", - dmar->base, dmar->limit); + head->apply([&] (Dmar_common const &dmar) { + PLOG("DMA remapping structure type=%u", dmar.read()); + }); + + Dmar_entry::list()->insert(new (env()->heap()) Dmar_entry(head->clone())); } Table_wrapper(addr_t base) : _base(base), _table(0) @@ -1228,6 +1292,50 @@ void Acpi::generate_report() }); } + /* lambda definition for scope evaluation in rmrr */ + auto func_scope = [&] (Device_scope const &scope) + { + xml.node("scope", [&] () { + char number[8]; + Genode::snprintf(number, sizeof(number), "%u", + scope.read()); + xml.attribute("bus_start", number); + for (unsigned j = 0 ; j < scope.count(); j++) { + xml.node("path", [&] () { + char number[8]; + Genode::snprintf(number, sizeof(number), "0x%x", + scope.read(j)); + xml.attribute("dev", number); + Genode::snprintf(number, sizeof(number), "0x%x", + scope.read(j)); + xml.attribute("func", number); + }); + } + }); + }; + + for (Dmar_entry *entry = Dmar_entry::list()->first(); + entry; entry = entry->next()) { + + entry->apply([&] (Dmar_common const &dmar) { + if (dmar.read() != Dmar_common::Type::RMRR) + return; + + Dmar_rmrr rmrr(dmar.base); + + xml.node("rmrr", [&] () { + char number[20]; + Genode::snprintf(number, sizeof(number), "0x%llx", + rmrr.read()); + xml.attribute("start", number); + Genode::snprintf(number, sizeof(number), "0x%llx", + rmrr.read()); + xml.attribute("end", number); + + rmrr.apply(func_scope); + }); + }); + } { Element *e = Element::list()->first();