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
This commit is contained in:
Alexander Boettcher 2013-08-21 08:56:21 +02:00 committed by Norman Feske
parent b142939d14
commit 35a96e1101
1 changed files with 73 additions and 2 deletions

View File

@ -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<uint8_t *>(this); }
/* MADT acpi structures */
/* MADT ACPI structure */
Apic_struct *apic_struct() { return reinterpret_cast<Apic_struct *>(&creator_rev + 3); }
Apic_struct *end() { return reinterpret_cast<Apic_struct *>(signature + size); }
/* MCFG ACPI stucture */
/* MCFG ACPI structure */
Mcfg_struct *mcfg_struct() { return reinterpret_cast<Mcfg_struct *>(&creator_rev + 3); }
Mcfg_struct *mcfg_end() { return reinterpret_cast<Mcfg_struct *>(signature + size); }
/* DMAR Intel VT-d structures */
Dmar_struct_header *dmar_header() { return reinterpret_cast<Dmar_struct_header *>(this); }
Dmar_struct *dmar_struct() { return reinterpret_cast<Dmar_struct *>(&creator_rev + 4); }
Dmar_struct *dmar_end() { return reinterpret_cast<Dmar_struct *>(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<Dmar_struct *>((uint8_t *)this + length); }
Rmrr_struct *rmrr() { return reinterpret_cast<Rmrr_struct *>(&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) {