2#ifndef PEDIGREE_PC_ACPI_DMAR_H
3#define PEDIGREE_PC_ACPI_DMAR_H
10 static constexpr size_t MaxDirectEndpoints = 128;
11 static constexpr size_t MaxDirectBridges = 128;
13 uint8_t hostAddressWidth = 0;
14 bool interruptRemapping =
false;
15 bool x2ApicOptOut =
false;
16 bool dmaControlPlatformOptIn =
false;
17 bool reservedMemoryRegions =
false;
18 size_t hardwareUnitCount = 0;
19 size_t segmentZeroUnitCount = 0;
20 size_t segmentZeroIncludeAllCount = 0;
21 uint64_t firstSegmentZeroUnitAddress = 0;
22 uint8_t firstSegmentZeroUnitRegisterPagesLog2 = 0;
23 uint64_t firstSegmentZeroIncludeAllAddress = 0;
24 uint8_t firstSegmentZeroIncludeAllRegisterPagesLog2 = 0;
25 uint16_t directEndpoints[MaxDirectEndpoints] = {};
26 size_t directEndpointCount = 0;
27 uint16_t directBridges[MaxDirectBridges] = {};
28 size_t directBridgeCount = 0;
30 bool includesDirectEndpoint(uint8_t bus, uint8_t device, uint8_t function)
const {
31 const uint16_t sourceId = (uint16_t(bus) << 8) | (uint16_t(device) << 3) | function;
32 for (
size_t index = 0; index < directEndpointCount; ++index) {
33 if (directEndpoints[index] == sourceId) {
41inline uint16_t read16(
const uint8_t* bytes) {
42 return uint16_t(bytes[0]) | (uint16_t(bytes[1]) << 8);
45inline uint32_t read32(
const uint8_t* bytes) {
46 return uint32_t(read16(bytes)) | (uint32_t(read16(bytes + 2)) << 16);
49inline uint64_t read64(
const uint8_t* bytes) {
50 return uint64_t(read32(bytes)) | (uint64_t(read32(bytes + 4)) << 32);
54inline bool parse(
const uint8_t* table,
size_t available, Info& result) {
55 constexpr size_t HeaderBytes = 48;
56 if (!table || available < HeaderBytes || read32(table) != 0x52414d44U) {
59 const size_t length = read32(table + 4);
60 if (length < HeaderBytes || length > available || table[36] < 31 || table[36] > 63 ||
66 for (
size_t i = 0; i < length; ++i) {
74 found.hostAddressWidth = table[36] + 1;
75 found.interruptRemapping = table[37] & 1U;
76 found.x2ApicOptOut = table[37] & 2U;
77 found.dmaControlPlatformOptIn = table[37] & 4U;
78 for (
size_t offset = HeaderBytes; offset < length;) {
79 if (length - offset < 4) {
82 const uint16_t type = read16(table + offset);
83 const size_t bytes = read16(table + offset + 2);
84 if (bytes < 4 || bytes > length - offset) {
91 const uint8_t registerPagesLog2 = table[offset + 5] & 0x0fU;
92 if ((table[offset + 4] & ~1U) || (table[offset + 5] & ~0x0fU) ||
93 !read64(table + offset + 8) ||
94 (read64(table + offset + 8) & ((uint64_t(1) << (12 + registerPagesLog2)) - 1))) {
97 for (
size_t scope = offset + 16; scope < offset + bytes;) {
98 if (offset + bytes - scope < 8) {
101 const size_t scopeBytes = table[scope + 1];
102 if (!table[scope] || scopeBytes < 8 || (scopeBytes & 1U) ||
103 scopeBytes > offset + bytes - scope) {
106 if (!read16(table + offset + 6) && (table[scope] == 1 || table[scope] == 2) &&
107 scopeBytes == 8 && !table[scope + 2] && !table[scope + 3] && !table[scope + 4] &&
108 table[scope + 6] < 32 && table[scope + 7] < 8) {
109 const uint16_t sourceId = (uint16_t(table[scope + 5]) << 8) |
110 (uint16_t(table[scope + 6]) << 3) | table[scope + 7];
111 if (table[scope] == 1) {
112 if (found.directEndpointCount == Info::MaxDirectEndpoints) {
115 found.directEndpoints[found.directEndpointCount++] = sourceId;
117 if (found.directBridgeCount == Info::MaxDirectBridges) {
120 found.directBridges[found.directBridgeCount++] = sourceId;
125 ++found.hardwareUnitCount;
126 if (!read16(table + offset + 6)) {
127 ++found.segmentZeroUnitCount;
128 if (!found.firstSegmentZeroUnitAddress) {
129 found.firstSegmentZeroUnitAddress = read64(table + offset + 8);
130 found.firstSegmentZeroUnitRegisterPagesLog2 = registerPagesLog2;
132 if (table[offset + 4] & 1U) {
133 ++found.segmentZeroIncludeAllCount;
134 if (!found.firstSegmentZeroIncludeAllAddress) {
135 found.firstSegmentZeroIncludeAllAddress = read64(table + offset + 8);
136 found.firstSegmentZeroIncludeAllRegisterPagesLog2 = registerPagesLog2;
140 }
else if (type == 1) {
144 found.reservedMemoryRegions =
true;
148 if (!found.hardwareUnitCount) {