From 35a96e1101ea8f3853605410fe5bacf9060b2835 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 21 Aug 2013 08:56:21 +0200 Subject: [PATCH] acpi: parse RMRR structures and print DMA regions The regions reported by the RMRR structure are used by legacy devices for DMA requests. Theses would need to be added to the device_pd to avoid DMAR faults when used in legacy mode. For now parse and print them, so that one has a clue about why we get DMAR faults. Issue #683 --- os/src/drivers/acpi/acpi.cc | 75 ++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/os/src/drivers/acpi/acpi.cc b/os/src/drivers/acpi/acpi.cc index 9b64e415c..20998e2b6 100644 --- a/os/src/drivers/acpi/acpi.cc +++ b/os/src/drivers/acpi/acpi.cc @@ -65,6 +65,8 @@ struct Apic_override : Apic_struct uint16_t flags; } __attribute__((packed)); +struct Dmar_struct_header; +struct Dmar_struct; /* ACPI spec 5.2.6 */ struct Generic @@ -81,13 +83,59 @@ struct Generic uint8_t const *data() { return reinterpret_cast(this); } - /* MADT acpi structures */ + /* MADT ACPI structure */ Apic_struct *apic_struct() { return reinterpret_cast(&creator_rev + 3); } Apic_struct *end() { return reinterpret_cast(signature + size); } - /* MCFG ACPI stucture */ + /* MCFG ACPI structure */ 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_struct_header : Generic +{ + enum { INTR_REMAP_MASK = 0x1U }; + + uint8_t width; + uint8_t flags; + uint8_t reserved[10]; +} __attribute__((packed)); + +/* Reserved Memory Region Reporting structure - Intel VT-d IO Spec - 8.4. */ +struct Rmrr_struct +{ + uint16_t type; + uint16_t length; + uint16_t reserved; + uint16_t pci_segment; + uint64_t start; + uint64_t end; +} __attribute__((packed)); + +/* DMA Remapping Reporting structure - Intel VT-d IO Spec - 8.1. */ +struct Dmar_struct +{ + 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; + + Dmar_struct *next() { + return reinterpret_cast((uint8_t *)this + length); } + + Rmrr_struct *rmrr() { return reinterpret_cast(&base + 1); } } __attribute__((packed)); @@ -240,6 +288,11 @@ class Table_wrapper */ bool is_searched() const { return _cmp("DSDT") || _cmp("SSDT"); } + /** + * Is this a DMAR table + */ + bool is_dmar() { return _cmp("DMAR"); } + /** * Parse override structures */ @@ -276,6 +329,19 @@ class Table_wrapper } } + void parse_dmar() const + { + Dmar_struct_header *head = _table->dmar_header(); + PLOG("%u bit DMA physical addressable %s\n", head->width + 1, + 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 - DMA region reported by BIOS", dmar->base); + } + Table_wrapper(addr_t base) : _base(base), _io_mem(0), _table(0) { /* @@ -1054,6 +1120,11 @@ class Acpi_table table.parse_mcfg(); } + if (table.is_dmar()) { + PDBG("Found DMAR"); + + table.parse_dmar(); + } } if (dsdt) {