/** @file
AcpiVTD.c - VT-d DMAR ACPI Table Construction Driver
This DXE driver constructs the DMA-Remapping (DMAR) ACPI table used by
the OS IOMMU driver for Intel Virtualization Technology for Directed I/O
(VT-d) initialization. It reads platform configuration via UEFI variables,
builds DRHD/RMRR/ATSR/RHSA sub-tables, sorts them, and installs the final
DMAR table into the ACPI table list.
Source Path: PurleyPlatPkg/Acpi/Dxe/AcpiVtd/AcpiVTD.c
Build: HR6N0XMLK DEBUG_VS2015 X64
Module: AcpiVTD.efi (MD5: 357aef305256b04c9a30d7dbbce72ae7)
Reverse-engineered from the binary; the source file above was used as
reference for function names and structure layout. The actual binary
is compiled from the original C source, meaning all static functions
have been inlined and the assembly is the authoritative representation.
**/
#include "AcpiVTD.h"
//=============================================================================
// Global data (BSS, initialized at driver load)
//=============================================================================
//
// UEFI handle and table pointers
//
EFI_HANDLE gImageHandle = NULL; // 0x2450
EFI_SYSTEM_TABLE *gSystemTable = NULL; // 0x2440
EFI_BOOT_SERVICES *gBootServices = NULL; // 0x2448
EFI_RUNTIME_SERVICES *gRuntimeServices = NULL;// 0x2458
VOID *gDsServicesTable = NULL; // 0x2478 (DXE Services Table)
VOID *gHobList = NULL; // 0x2470 (HOB List)
//
// Protocol pointers (lazy-located)
//
VOID *gPcdProtocol = NULL; // 0x2460 (PCD protocol)
VOID *gAcpiTableProtocol = NULL;// 0x2490 (ACPI table protocol)
BOOLEAN gAcpiTableProtocolReady = FALSE;// 0x2488
VOID *gSetupProtocol = NULL; // 0x2480 (Setup protocol)
//
// DMAR table construction globals
//
DMA_REMAP_CONTAINER *mDmarContainer = NULL; // 0x24C8 (primary container pointer)
UINT8 mDmarSortBuffer[6144]; // 0x24D0->(sorted output, offset 2048)
DMA_REMAP_CONTAINER *mDmarSortedTable = NULL; // 0x24D0 (= mDmarContainer + 2048)
UINT64 mDmarSignature = DMAR_SIGNATURE; // 0x24A0 = 'DMAR' (0x52414D44)
//
// Platform configuration values (read from setup/PCD)
//
UINT16 mDmarFlags; // 0x24B0 (DMAR flags word: HAW + INTR_REMAP)
UINT8 mDmarReserved; // 0x24B2
//
// Function pointer table for DMAR sub-table construction callbacks
// (referenced via off_2320 -- each entry is a triple of
// [GuidPtr, VariableDataPtr, VariableSize])
//
// These entries come from the setup variable configuration describing
// platform-specific VT-d topology.
//
typedef struct {
CONST GUID *VariableGuid; // GUID identifying the variable (or sub-table type)
VOID *VariableData; // Pointer to platform data for this sub-table
UINTN VariableSize; // Size in bytes of the variable data
} DMAR_CONFIG_ENTRY;
DMAR_CONFIG_ENTRY mDmarConfig[] = {
// Index 0: DRHD hardware unit definitions
{ &gSetupVariableGuid, (VOID *)0x1E78, 0xE0 }, // 0x2320-0x2337
// Index 1: RMRR region definitions
{ &gSetupVariableGuid, (VOID *)0x2300, 0x1A0C }, // 0x2338-0x234F
// Index 2: ATSR device definitions
{ &gSetupVariableGuid, (VOID *)0x1EC8, 0x0155 }, // 0x2350-0x2367
{ &gSetupVariableGuid, (VOID *)0x2270, 0x0102 }, // 0x2368-0x237F
{ &gSetupVariableGuid, (VOID *)0x1EF0, 0x0202 }, // 0x2380-0x2397
{ &gSetupVariableGuid, (VOID *)0x2290, 0x01CE }, // 0x2398-0x23AF
{ &gSetupVariableGuid, (VOID *)0x2280, 0x012D }, // 0x23B0-0x23C7 -- RHSA definitions
{ &gSetupVariableGuid, (VOID *)0x1F88, 0x02A4 }, // 0x23C8-0x23DF
{ &gSetupVariableGuid, (VOID *)0x2240, 0x0567 }, // 0x23E0-0x23F7
{ &gSetupVariableGuid, (VOID *)0x2220, 0x06D7 }, // 0x23F8-0x240F
{ &gSetupVariableGuid, (VOID *)0x1FC8, 0x001B }, // 0x2410-0x2427
{ NULL, NULL, 0 } // Terminator
};
//=============================================================================
// Helper functions (library-level, inlined in original binary)
//=============================================================================
/**
Copies memory between buffers, handling overlap by comparing source and
destination addresses.
@param Destination Pointer to the destination buffer.
@param Source Pointer to the source buffer.
@param Length Number of bytes to copy.
@return Destination pointer.
**/
VOID *
EFIAPI
InternalCopyMem (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
UINT8 *Dst8;
const UINT8 *Src8;
UINTN Count;
if (Source >= Destination ||
(const UINT8 *)Source + Length - 1 < (const UINT8 *)Destination) {
//
// Forward copy (non-overlapping or src > dst)
//
Count = Length >> 3;
if (Count > 0) {
CopyMem (Destination, Source, Count << 3);
}
Dst8 = (UINT8 *)Destination + (Count << 3);
Src8 = (const UINT8 *)Source + (Count << 3);
for (Count = Length & 7; Count > 0; Count--) {
*Dst8++ = *Src8++;
}
} else {
//
// Backward copy to handle overlapping regions
//
Dst8 = (UINT8 *)Destination + Length - 1;
Src8 = (const UINT8 *)Source + Length - 1;
for (Count = Length; Count > 0; Count--) {
*Dst8-- = *Src8--;
}
}
return Destination;
}
/**
Zeroes a memory buffer using 8-byte writes when aligned.
@param Buffer Pointer to the buffer to zero.
@param Length Size of the buffer in bytes.
@return Pointer to the buffer.
**/
VOID *
EFIAPI
InternalZeroMem (
OUT VOID *Buffer,
IN UINTN Length
)
{
UINTN Count;
Count = Length >> 3;
if (Count > 0) {
ZeroMem (Buffer, Count << 3);
}
Count = Length & 7;
if (Count > 0) {
ZeroMem ((UINT8 *)Buffer + (Length & ~7), Count);
}
return Buffer;
}
/**
Fills a memory buffer with a specific byte value.
@param Buffer Pointer to the buffer.
@param Length Size of the buffer in bytes.
@param Value The byte value to fill with.
@return Pointer to the buffer.
**/
VOID *
EFIAPI
InternalSetMem (
OUT VOID *Buffer,
IN UINTN Length,
IN UINT8 Value
)
{
return SetMem (Buffer, Length, Value);
}
/**
ZeroMem wrapper with buffer range validation.
ASSERTs that Buffer is non-NULL and Length does not wrap around.
**/
VOID *
EFIAPI
InternalZeroMemChecked (
OUT VOID *Buffer,
IN UINTN Length
)
{
ASSERT (Buffer != NULL);
ASSERT (Length <= (MAX_ADDRESS - (UINTN)Buffer + 1));
return InternalZeroMem (Buffer, Length);
}
/**
CopyMem wrapper with buffer range validation.
ASSERTs that both buffers have sufficient space for the copy operation.
**/
VOID *
EFIAPI
InternalCopyMemChecked (
OUT VOID *Destination,
IN CONST VOID *Source,
IN UINTN Length
)
{
ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Destination));
ASSERT ((Length - 1) <= (MAX_ADDRESS - (UINTN)Source));
if (Destination == Source) {
return Destination;
}
return InternalCopyMem (Destination, Source, Length);
}
/**
SetMem wrapper with buffer range validation.
**/
VOID *
EFIAPI
InternalSetMemChecked (
OUT VOID *Buffer,
IN UINTN Length,
IN UINT8 Value
)
{
UINTN Result;
Result = (UINTN)Buffer;
if (Length > 0) {
if ((Length - 1) > (MAX_ADDRESS - (UINTN)Buffer)) {
ASSERT (FALSE);
}
}
return InternalSetMem (Buffer, Length, Value);
}
//=============================================================================
// Protocol / table location helpers
//=============================================================================
/**
Locates the PCD protocol from the UEFI protocol database.
The protocol GUID is {11B34006-D85B-4D0A-A290-D5A7310EF70B}.
@return Pointer to the PCD protocol interface, or NULL on failure.
**/
VOID *
EFIAPI
GetPcdProtocol (
VOID
)
{
EFI_STATUS Status;
if (gPcdProtocol == NULL) {
Status = gBootServices->LocateProtocol (
&gPcdProtocolGuid,
NULL,
&gPcdProtocol
);
if (EFI_ERROR (Status)) {
gPcdProtocol = NULL;
}
}
return gPcdProtocol;
}
/**
Locates the ACPI table protocol from the UEFI protocol database.
@return Pointer to the ACPI table protocol, or NULL on failure.
**/
EFI_ACPI_TABLE_PROTOCOL *
EFIAPI
GetAcpiTableProtocol (
VOID
)
{
EFI_STATUS Status;
if (gAcpiTableProtocol == NULL) {
Status = gBootServices->LocateProtocol (
&gEfiAcpiTableProtocolGuid,
NULL,
&gAcpiTableProtocol
);
if (EFI_ERROR (Status)) {
gAcpiTableProtocol = NULL;
}
}
return gAcpiTableProtocol;
}
/**
Locates the DXE Services Table by GUID from the system configuration table.
@param DxeServicesTable [out] Receives a pointer to the DXE Services Table.
@retval EFI_SUCCESS Table found.
@retval others Table not found or error.
**/
EFI_STATUS
EFIAPI
GetDxeServicesTable (
OUT VOID **DxeServicesTable
)
{
UINTN Index;
EFI_STATUS Status;
ASSERT (DxeServicesTable != NULL);
*DxeServicesTable = NULL;
if (gSystemTable->NumberOfTableEntries == 0) {
return EFI_NOT_FOUND;
}
Status = EFI_NOT_FOUND;
for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
if (CompareGuid (
&gSystemTable->ConfigurationTable[Index].VendorGuid,
&gDxeServicesTableGuid
)) {
*DxeServicesTable = gSystemTable->ConfigurationTable[Index].VendorTable;
Status = EFI_SUCCESS;
break;
}
}
return Status;
}
/**
Locates the HOB list from the DXE configuration table.
The HOB list is located by GUID: {7739F477-93D4-11D4-9A3A-0090273FC14D}.
@param HobList [out] Receives a pointer to the HOB list header.
@retval EFI_SUCCESS HOB list located.
@retval others HOB list not found.
**/
EFI_STATUS
EFIAPI
GetHobList (
OUT VOID **HobList
)
{
UINTN Index;
EFI_STATUS Status;
ASSERT (HobList != NULL);
*HobList = NULL;
if (gSystemTable->NumberOfTableEntries == 0) {
return EFI_NOT_FOUND;
}
Status = EFI_NOT_FOUND;
for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
if (CompareGuid (
&gSystemTable->ConfigurationTable[Index].VendorGuid,
&gEfiHobListGuid
)) {
*HobList = gSystemTable->ConfigurationTable[Index].VendorTable;
Status = EFI_SUCCESS;
break;
}
}
return Status;
}
/**
Compares two GUIDs using 64-bit wide comparison.
@param Guid1 Pointer to first GUID.
@param Guid2 Pointer to second GUID.
@retval TRUE GUIDs are identical.
@retval FALSE GUIDs differ.
**/
BOOLEAN
EFIAPI
CompareGuid (
IN CONST GUID *Guid1,
IN CONST GUID *Guid2
)
{
return (ReadUnaligned64 (Guid1) == ReadUnaligned64 (Guid2) &&
ReadUnaligned64 ((UINT8 *)Guid1 + 8) ==
ReadUnaligned64 ((UINT8 *)Guid2 + 8));
}
//=============================================================================
// UEFI setup variable reading
//=============================================================================
/**
Returns the current debug error level based on platform type.
Reads CMOS register 0x4B to check firmware type and debug level.
The debug output level determines whether ASSERT/RETURN_ERROR messages
are displayed.
@param ErrorLevel The error level bits to check.
@param Format Print format string.
@param ... Variable arguments for format.
@retval TRUE The message was output.
@retval FALSE The message was suppressed.
**/
BOOLEAN
EFIAPI
DebugPrintErrorLevel (
IN UINTN ErrorLevel,
IN CONST CHAR8 *Format,
...
)
{
BOOLEAN Result;
UINT8 CmosData;
UINTN LocalErrorLevel;
va_list Marker;
//
// Read CMOS register 0x4B to determine debug configuration
//
CmosData = IoRead8 (0x70);
IoWrite8 (0x70, CmosData & 0x80 | 0x4B);
CmosData = IoRead8 (0x71);
if ((UINT8)CmosData > 3) {
if (CmosData == 0) {
CmosData = (UINT8)(MmioRead8 (0xFEDAF0490) & 2) | 1;
}
}
if (CmosData - 1 <= 0xFD) {
LocalErrorLevel = 0x80000000; // EFI_D_ERROR
if (CmosData == 1) {
LocalErrorLevel = 0x80000004; // EFI_D_INFO
}
} else {
CmosData = 4;
}
Result = FALSE;
if ((LocalErrorLevel & ErrorLevel) != 0) {
//
// Forward to the debug protocol if installed
//
Result = (BOOLEAN)DEBUG (ErrorLevel, Format);
}
return Result;
}
/**
Locates a protocol by GUID.
@param Guid Pointer to the protocol GUID.
@param Interface [out] Receives the protocol interface.
@return EFI_STATUS.
**/
EFI_STATUS
EFIAPI
LocateProtocol (
IN CONST GUID *Guid,
OUT VOID **Interface
)
{
EFI_STATUS Status;
Status = gBootServices->LocateProtocol (Guid, NULL, Interface);
if (EFI_ERROR (Status)) {
ASSERT_EFI_ERROR (Status);
ASSERT (FALSE);
return Status;
}
return EFI_SUCCESS;
}
//=============================================================================
// DMAR sub-table type parsing
//=============================================================================
/**
Parses a DMAR sub-table to determine its type and length.
Examines the first WORD of the sub-table to determine the type:
0 = DRHD (DMA-Remapping Hardware Unit Definition)
1 = RMRR (Reserved Memory Region Reporting)
2 = ATSR (Address Translation Services Reporting)
3 = RHSA (Remapping Hardware Status Affinity)
@param SubTable Pointer to the DMAR sub-table.
@param Type [out] Sub-table type (0-3, 0xFF on error).
@param IsDmarUnit [out] TRUE if type is DRHD (0).
@param Length [out] Length of this sub-table (from offset +2).
**/
VOID
EFIAPI
ParseDmarSubTableType (
IN UINT8 *SubTable,
OUT UINT8 *Type,
OUT BOOLEAN *IsDmarUnit,
OUT UINT16 *Length
)
{
UINT16 SubType;
ASSERT (SubTable != NULL);
SubType = ReadUnaligned16 (SubTable);
*Length = ReadUnaligned16 (SubTable + 2);
*IsDmarUnit = FALSE;
*Type = (UINT8)-1;
switch (SubType) {
case 0:
*Type = 0;
*IsDmarUnit = TRUE; // SubType 0 + No flag = DRHD entry
break;
case 1:
*Type = 1;
break;
case 2:
*Type = 2;
break;
case 3:
*Type = 3;
break;
default:
break;
}
if (*Type == 0 && !*IsDmarUnit) {
// This is actually subtype 1 (RMRR) because SubType=0 but IsDmarUnit=TRUE
// means the first byte was 0x00 and the second byte 0x01 = LE value 0x0100 = 256.
// Real DMAR sub-tables don't have type 256, this is RMRR.
// Actually: In the binary the sub_4DC writes:
// Type 0: *(UINT32 *)v8 = 0x100000 -> bytes 00 00 10
// Type 1: *(UINT32 *)v8 = 0x180001 -> byte 01 00 18
// So for sorting: type 0 has WORD=0, type 1 has WORD=1 (but is checked
// in the binary via the n2 flag, not the actual WORD).
//
// The ReadDmarSubTableType function in the original checks:
// *p_n2 = 1 if WORD == 1 (type 1)
// *p_n2 = 2 if WORD == 2 (type 2)
// *p_n2 = 3 if WORD == 3 (type 3)
// *p_n2 = 0 if WORD == 0 (DRHD)
// *a3 = (byte at +4 == 1) -- this flag distinguishes DRHD from RMRR
}
}
//=============================================================================
// DMAR sub-table construction (InsertDmaRemap)
//=============================================================================
/**
Inserts a DMAR sub-table (DRHD/RMRR/ATSR/RHSA) at the current write
offset within the DMAR container. Each type writes its specific header,
then appends device scope entries.
The sub-table data is passed through the SubTableData pointer, which
must contain the signature in its first DWORD:
DRHD: 0x44524844 ('DRHD')
RMRR: 0x52524D52 ('RMRR')
ATSR: 0x52535441 ('ATSR')
RHSA: 0x52485341 ('RHSA') [actually ASHR in original code]
@param DmaRemap Pointer to the DMAR container buffer.
@param SubTableType 0=DRHD, 1=RMRR, 2=ATSR, 3=RHSA.
@param SubTableData Pointer to the sub-table source data.
@retval EFI_SUCCESS Sub-table inserted.
@retval EFI_INVALID_PARAMETER DmaRemap is NULL or signature mismatch.
**/
UINT64
EFIAPI
InsertDmaRemap (
IN DMA_REMAP_CONTAINER *DmaRemap,
IN UINT32 SubTableType,
IN VOID *SubTableData
)
{
UINT8 *WriteCursor;
UINTN DeviceScopeIndex;
UINTN ScopeDataOffset;
UINTN Count;
UINT16 CurrentLength;
UINT64 DeviceScopeCount;
UINT64 ScopeCount;
//
// Validate container pointer
//
if (DmaRemap == NULL) {
DEBUG ((EFI_D_ERROR, "InsertDmaRemap Error. Invalid pointer.\n"));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
//
// Write cursor: points to the current end of the container data
//
WriteCursor = (UINT8 *)DmaRemap + DmaRemap->Length;
if (WriteCursor == NULL) {
DEBUG ((EFI_D_ERROR, "InsertDmaRemap Error. Invalid pointer.\n"));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
switch (SubTableType) {
case 0: // DRHD - DMA-Remapping Hardware Unit Definition
{
DMA_REMAP_HARDWARE_UNIT_DEFINITION *Drhd;
Drhd = (DMA_REMAP_HARDWARE_UNIT_DEFINITION *)SubTableData;
ASSERT (*(UINT32 *)Drhd == DMA_REMAP_HARDWARE_UNIT_SIGNATURE);
//
// Write DRHD header: Type=0, Flags, Segment, BaseAddress
//
*(UINT32 *)WriteCursor = 0x100000; // Type/Reserved/Length placeholder
WriteCursor[4] = Drhd->Flags; // INCLUDE_PCI_ALL flag
*(UINT16 *)(WriteCursor + 6) = Drhd->Segment;
*(UINT64 *)(WriteCursor + 8) = Drhd->BaseAddress;
//
// Append device scope entries
//
CurrentLength = *(UINT16 *)(WriteCursor + 2);
DeviceScopeCount = *(UINT64 *)((UINT8 *)SubTableData + 16); // +16 = device scope count
for (DeviceScopeIndex = 0, ScopeDataOffset = 0;
DeviceScopeIndex < DeviceScopeCount;
DeviceScopeIndex++, ScopeDataOffset += 16)
{
UINT8 *ScopeEntry;
UINT8 *ScopeSource;
UINT8 *ScopePath;
UINTN Index;
ScopeEntry = WriteCursor + CurrentLength;
if (ScopeEntry == NULL) {
DEBUG ((EFI_D_ERROR, "InsertDmaRemap Error. Invalid pointer.\n"));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
ScopeSource = (UINT8 *)SubTableData + *(UINT64 *)((UINT8 *)SubTableData + 24)
+ ScopeDataOffset + 8;
//
// Write device scope type and bus number
//
ScopeEntry[0] = *ScopeSource; // Device type
ScopeEntry[1] = 6; // Minimum length (header)
//
// Copy initial 2 bytes of PCI path data
//
for (Index = 0; Index < 2; Index++) {
ScopeEntry[4 + Index] = ScopeSource[Index + 1];
}
//
// Append additional PCI path entries until terminator (0xFF)
//
ScopeSource = (UINT8 *)SubTableData + *(UINT64 *)((UINT8 *)SubTableData + 24)
+ ScopeDataOffset + 16;
ScopeCount = Count;
if (*ScopeSource != 0xFF) {
ScopePath = ScopeEntry + (UINT8)ScopeEntry[1];
while (*ScopeSource != 0xFF) {
InternalCopyMemChecked (ScopePath, ScopeSource, 2);
ScopeEntry[1] += 2;
ScopeSource += 2;
ScopePath += 2;
}
}
CurrentLength += (UINT8)ScopeEntry[1];
*(UINT16 *)(WriteCursor + 2) = CurrentLength;
}
DmaRemap->Length += CurrentLength;
break;
}
case 1: // RMRR - Reserved Memory Region Reporting
{
RESERVED_MEMORY_REGION_REPORTING *Rmrr;
Rmrr = (RESERVED_MEMORY_REGION_REPORTING *)SubTableData;
ASSERT (*(UINT32 *)Rmrr == RESERVED_MEMORY_REGION_SIGNATURE);
//
// Write RMRR header: Type=1, Segment, BaseAddress, EndAddress
//
*(UINT32 *)WriteCursor = 0x180001; // Type=1, Len=0, Reserved=0x01 00 18
*(UINT16 *)(WriteCursor + 6) = Rmrr->Segment;
*(UINT64 *)(WriteCursor + 8) = Rmrr->BaseAddress;
*(UINT64 *)(WriteCursor + 16) = Rmrr->EndAddress;
//
// Append device scope entries
//
CurrentLength = *(UINT16 *)(WriteCursor + 2);
DeviceScopeCount = *(UINT64 *)((UINT8 *)SubTableData + 24);
for (DeviceScopeIndex = 0, ScopeDataOffset = 0;
DeviceScopeIndex < DeviceScopeCount;
DeviceScopeIndex++, ScopeDataOffset += 16)
{
UINT8 *ScopeEntry;
UINT8 *ScopeSource;
UINT8 *ScopePath;
ScopeEntry = WriteCursor + CurrentLength;
if (ScopeEntry == (UINT8 *)-6) {
DEBUG ((EFI_D_ERROR, "InsertDmaRemap Error. Invalid pointer.\n"));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
ScopeSource = (UINT8 *)SubTableData + *(UINT64 *)((UINT8 *)SubTableData + 32)
+ ScopeDataOffset;
//
// Write device scope header data
//
ScopeEntry[0] = ScopeSource[0]; // Type
ScopeEntry[5] = ScopeSource[2]; // Enumeration data
ScopeEntry[1] = 6; // Minimum length
//
// Append PCI path entries
//
ScopeSource = (UINT8 *)SubTableData + *(UINT64 *)((UINT8 *)SubTableData + 32)
+ ScopeDataOffset + 16;
if (*ScopeSource != 0xFF) {
ScopePath = ScopeEntry + 6;
while (*ScopeSource != 0xFF) {
InternalCopyMemChecked (ScopePath, ScopeSource, 2);
ScopeEntry[1] += 2;
ScopeSource += 2;
ScopePath += 2;
}
}
CurrentLength += (UINT8)ScopeEntry[1];
*(UINT16 *)(WriteCursor + 2) = CurrentLength;
}
DmaRemap->Length += CurrentLength;
break;
}
case 2: // ATSR - Address Translation Services Reporting
{
ADDRESS_TRANSLATION_SERVICES_REPORTING *Atsr;
Atsr = (ADDRESS_TRANSLATION_SERVICES_REPORTING *)SubTableData;
ASSERT (*(UINT32 *)Atsr == ADDRESS_TRANSLATION_SERVICES_SIGNATURE);
//
// Write ATSR header: Type=2, Flags, Segment
//
*(UINT16 *)WriteCursor = 2; // Type
WriteCursor[4] = Atsr->Flags;
*(UINT16 *)(WriteCursor + 6) = Atsr->Segment;
*(UINT16 *)(WriteCursor + 2) = 8; // Minimum length of 8 bytes
CurrentLength = 8;
DeviceScopeCount = *(UINT64 *)((UINT8 *)SubTableData + 8);
//
// Append device scope entries (only for ATS-capable devices)
//
for (DeviceScopeIndex = 0, ScopeDataOffset = 0;
DeviceScopeIndex < DeviceScopeCount;
DeviceScopeIndex++, ScopeDataOffset += 16)
{
UINT8 *ScopeEntry;
UINT8 *ScopeSource;
UINT8 *ScopePath;
//
// Check ATS capability mask at SubTableData[16] (UINT32)
//
if (((*(UINT32 *)((UINT8 *)SubTableData + 16) >> DeviceScopeIndex) & 1) == 0) {
continue;
}
ScopeEntry = WriteCursor + CurrentLength;
if (ScopeEntry == (UINT8 *)-6) {
DEBUG ((EFI_D_ERROR, "InsertDmaRemap Error. Invalid pointer.\n"));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
ScopeSource = (UINT8 *)SubTableData + *(UINT64 *)((UINT8 *)SubTableData + 24)
+ ScopeDataOffset;
//
// Write device scope header
//
ScopeEntry[0] = ScopeSource[0]; // Type
ScopeEntry[5] = ScopeSource[2]; // Enumeration data
ScopeEntry[1] = 6; // Minimum length
//
// Append PCI path entries
//
ScopeSource += 16;
if (*ScopeSource != 0xFF) {
ScopePath = ScopeEntry + 6;
while (*ScopeSource != 0xFF) {
InternalCopyMemChecked (ScopePath, ScopeSource, 2);
ScopeEntry[1] += 2;
ScopeSource += 2;
ScopePath += 2;
}
}
CurrentLength += (UINT8)ScopeEntry[1];
*(UINT16 *)(WriteCursor + 2) = (UINT16)CurrentLength;
}
*(UINT16 *)(WriteCursor + 2) = (UINT16)CurrentLength;
DmaRemap->Length += CurrentLength;
break;
}
case 3: // RHSA - Remapping Hardware Status Affinity
{
REMAPPING_HARDWARE_STATUS_AFFINITY *Rhsa;
Rhsa = (REMAPPING_HARDWARE_STATUS_AFFINITY *)SubTableData;
ASSERT (*(UINT32 *)Rhsa == RHS_REGION_SIGNATURE);
if (WriteCursor == NULL) {
DEBUG ((EFI_D_ERROR, "InsertDmaRemap Error. Invalid pointer.\n"));
ASSERT (FALSE);
return EFI_INVALID_PARAMETER;
}
//
// Write RHSA header: Type=3, ProximityDomain, BaseAddress
//
*(UINT16 *)WriteCursor = 3; // Type
WriteCursor[16] = (UINT8)(Rhsa->ProximityDomain & 0xFF);
WriteCursor[17] = (UINT8)((Rhsa->ProximityDomain >> 8) & 0xFF);
WriteCursor[18] = (UINT8)((Rhsa->ProximityDomain >> 16) & 0xFF);
WriteCursor[19] = (UINT8)((Rhsa->ProximityDomain >> 24) & 0xFF);
*(UINT64 *)(WriteCursor + 8) = Rhsa->BaseAddress;
*(UINT16 *)(WriteCursor + 2) = 20; // Total length: 20 bytes
CurrentLength = 20;
DmaRemap->Length += CurrentLength;
break;
}
default:
return EFI_INVALID_PARAMETER;
}
//
// Validate DMAR table size does not exceed 2KB limit
//
if (DmaRemap->Length >= 2 * 1024) {
ASSERT (DmaRemap->Length < 2 * 1024);
}
return EFI_SUCCESS;
}
//=============================================================================
// DMAR sub-table sorting (SortDmarSubTables)
//=============================================================================
/**
Sorts DMAR sub-tables into the canonical ACPI order:
DRHD (type 0) first, then RMRR (type 1), ATSR (type 2), RHSA (type 3).
The original container may have sub-tables in any order (as they were
added by InsertDmaRemap). This function reorders them into the sorted
buffer (mDmarSortBuffer + 2048).
Note: ATSR entries have their own sorting criteria -- those with the
device scope type field != 1 AND type != 2 are also filtered.
**/
UINT64
EFIAPI
SortDmarSubTables (
VOID
)
{
UINT8 Type;
BOOLEAN IsDmarUnit;
UINT16 EntryLength;
UINT32 SrcLength;
UINT32 SrcOffset;
UINT32 DstOffset;
UINT8 *SrcBase;
UINT8 *DstBase;
DstOffset = DMAR_HEADER_LENGTH + DMAR_HEADER_LENGTH; // Skip DMAR header copy
SrcOffset = DMAR_HEADER_LENGTH; // Start after header
DstBase = mDmarSortBuffer + 2048; // Sorted output area
SrcBase = (UINT8 *)mDmarContainer;
SrcLength = *(UINT32 *)(mDmarContainer + 4); // Total container length
//
// Pass 1: Copy DRHD entries (type 0 where IsDmarUnit is set)
//
while (SrcOffset < SrcLength) {
ParseDmarSubTableType (
SrcBase + SrcOffset,
&Type,
&IsDmarUnit,
&EntryLength
);
if (Type == 0 && IsDmarUnit) {
InternalCopyMemChecked (
DstBase + DstOffset,
SrcBase + SrcOffset,
EntryLength
);
DstOffset += EntryLength;
}
SrcOffset += EntryLength;
}
//
// Pass 2: Copy RMRR entries (type 0 where IsDmarUnit is NOT set)
// In the binary, these are the "type 0 entries with !n2 && n21" flag
//
SrcOffset = DMAR_HEADER_LENGTH;
while (SrcOffset < SrcLength) {
ParseDmarSubTableType (
SrcBase + SrcOffset,
&Type,
&IsDmarUnit,
&EntryLength
);
if (Type == 0 && !IsDmarUnit) {
InternalCopyMemChecked (
DstBase + DstOffset,
SrcBase + SrcOffset,
EntryLength
);
DstOffset += EntryLength;
}
SrcOffset += EntryLength;
}
//
// Pass 3: Copy RMRR entries (type 1 where IsDmarUnit is NOT set)
// This handles the type-1 entries (actual RMRR)
//
SrcOffset = DMAR_HEADER_LENGTH;
while (SrcOffset < SrcLength) {
ParseDmarSubTableType (
SrcBase + SrcOffset,
&Type,
&IsDmarUnit,
&EntryLength
);
if (Type == 1 && !IsDmarUnit) {
InternalCopyMemChecked (
DstBase + DstOffset,
SrcBase + SrcOffset,
EntryLength
);
DstOffset += EntryLength;
}
SrcOffset += EntryLength;
}
//
// Pass 4: Copy ATSR entries (type 2 where IsDmarUnit is NOT set)
//
SrcOffset = DMAR_HEADER_LENGTH;
while (SrcOffset < SrcLength) {
ParseDmarSubTableType (
SrcBase + SrcOffset,
&Type,
&IsDmarUnit,
&EntryLength
);
if (Type == 2 && !IsDmarUnit) {
InternalCopyMemChecked (
DstBase + DstOffset,
SrcBase + SrcOffset,
EntryLength
);
DstOffset += EntryLength;
}
SrcOffset += EntryLength;
}
//
// Pass 5: Copy RHSA entries (type 3)
//
SrcOffset = DMAR_HEADER_LENGTH;
while (SrcOffset < SrcLength) {
ParseDmarSubTableType (
SrcBase + SrcOffset,
&Type,
&IsDmarUnit,
&EntryLength
);
if (Type == 3) {
InternalCopyMemChecked (
DstBase + DstOffset,
SrcBase + SrcOffset,
EntryLength
);
DstOffset += EntryLength;
}
SrcOffset += EntryLength;
}
return EFI_SUCCESS;
}
//=============================================================================
// Get DMAR Table (GetDmarTable)
//=============================================================================
/**
Returns the finalized, sorted DMAR table to the caller.
Validates the container has data beyond the 48-byte header, sorts the
sub-tables into canonical order, and returns a pointer to the sorted table.
@param Table [out] Receives a pointer to the sorted DMAR table.
@retval EFI_SUCCESS Table built successfully.
@retval EFI_INVALID_PARAMETER Table pointer is NULL.
@retval EFI_UNSUPPORTED No sub-tables present.
**/
UINT64
EFIAPI
GetDmarTable (
OUT DMA_REMAP_CONTAINER **Table
)
{
if (Table == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check if container has sub-table data
//
if (*(UINT32 *)((UINT8 *)mDmarContainer + 4) <= DMAR_HEADER_LENGTH) {
return EFI_UNSUPPORTED;
}
//
// Sort sub-tables and return pointer to sorted output
//
SortDmarSubTables ();
*Table = (DMA_REMAP_CONTAINER *)mDmarSortBuffer;
return EFI_SUCCESS;
}
//=============================================================================
// DMAR table installation (InstallDmarTable)
//=============================================================================
/**
Installs the DMAR ACPI table.
This is the main DMAR table construction function. It:
1. Allocates a 6KB zero-filled buffer for the DMAR container
2. Initializes the DMAR table header:
- Signature = 'DMAR' (0x52414D44)
- HeaderLength = 48
- Revision = 1
- DmarUnitCount = 1 (initial)
- DeviceScopeCount = 1 (initial)
- Internal device scope count = 45 (0x2D)
3. Reads platform configuration from PCD protocol:
- Host address width (PCD at +32)
- Interrupt remap capability (PCD at +40)
4. Encodes host address width and INTR_REMAP flag into the table
5. Installs via gBS->InstallAcpiTable with:
- Handle: &mAcpiTableRegistration
- Table: &mDmarAcpiTableHeader
- Key: 0
- Flags: &mDmarFlags
@return EFI_STATUS.
**/
UINT64
EFIAPI
InstallDmarTable (
VOID
)
{
UINT8 *DmarBuffer;
UINT32 DmarSignature;
UINT32 PcdValue32;
UINTN PcdValueN;
UINT64 DmarAddressWidth;
UINT64 Status;
//
// Allocate DMAR table buffer (6 KB = 0x1800)
//
DmarBuffer = AllocateZeroPool (DMAR_TABLE_BUFFER_SIZE);
if (DmarBuffer == NULL) {
DEBUG ((EFI_D_ERROR, "Asserting the AllocateZeroPool returns NULL\n"));
ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
ASSERT (FALSE);
return EFI_OUT_OF_RESOURCES;
}
mDmarContainer = (DMA_REMAP_CONTAINER *)DmarBuffer;
//
// Initialize the DMAR table header:
// - Signature = 'DMAR' (0x52414D44 = 1380011332)
// - HeaderLength = 48 (0x30)
// - Revision = 1
// - DmarUnitCount = 1 (initial placeholder)
// - DeviceScopeCount = 1 (initial placeholder)
// - Internal device scope count = 45 (0x2D)
//
DmarSignature = DMAR_SIGNATURE;
*(UINT32 *)DmarBuffer = DMAR_SIGNATURE; // 'DMAR' at offset 0
*(UINT32 *)(DmarBuffer + 4) = DMAR_HEADER_LENGTH; // 48 at offset 4
DmarBuffer[8] = 1; // Revision at offset 8
*(UINT32 *)(DmarBuffer + 24) = 1; // DmarUnitCount at offset 24
*(UINT32 *)(DmarBuffer + 28) = 1; // DeviceScopeCount at offset 28
DmarBuffer[36] = 45; // Internal scope count at offset 36
//
// Read host address width from PCD protocol
//
if (GetPcdProtocol () != NULL) {
//
// PCD protocol offset +32 = Get32 method
// PCD protocol offset +40 = GetN method (returns UINTN)
// These are used to query platform VT-d capability:
// PcdVTdHostAddressWidth -> determines address width field in DMAR
// PcdVTdInterruptRemap -> determines INTR_REMAP flag
//
PcdValue32 = ((PCD_PROTOCOL *)gPcdProtocol)->Get32 (PcdVTdHostAddressWidth);
PcdValueN = ((PCD_PROTOCOL *)gPcdProtocol)->GetN (PcdVTdInterruptRemap);
PcdValueN = PcdValueN & 0xFFFFFFFF;
//
// Encode the address width and interrupt remap capability
// into the DMAR table header fields at offset 10-24
//
InternalCopyMemChecked (
DmarBuffer + 10,
&PcdValueN,
6
);
InternalCopyMemChecked (
DmarBuffer + 16,
&PcdValue32,
8
);
}
//
// Install the DMAR ACPI table via gBS->InstallAcpiTable
// This corresponds to BootServices[128] (InstallAcpiTable)
// with the registered protocol handle via LocateProtocol(&gAcpiTableGuid)
//
// Signature used for registration:
// &mDmarTableRegistration (at 0x24A8)
// &mDmarAcpiTableHeader (at 0x22D0) - ACPI table OemId/TableId template
// Key: 0
// Flags: &mDmarFlags (at 0x24B0) - contains host address width + INTR_REMAP
//
Status = gBootServices->InstallAcpiTable (
&gDmarTableRegistration,
&gDmarAcpiTableHeader,
0,
&mDmarFlags
);
return Status;
}
//=============================================================================
// Platform configuration reading (sub_1620 / variable read)
//=============================================================================
/**
Finds the index of the setup variable entry that matches the given
(GUID *) -> qword_22B0 criteria.
Iterates the mDmarConfig table and finds the entry whose GUID matches
the reference GUID at qword_22B0 (the SETUP_VARIABLE_GUID).
@return Index into mDmarConfig array, or -1 if not found.
**/
INTN
EFIAPI
FindSetupVariableIndex (
VOID
)
{
INTN Index;
Index = 0;
if (mDmarConfig[0].VariableGuid != NULL) {
do {
if (CompareGuid (
mDmarConfig[Index].VariableGuid,
&gSetupVariableGuid
)) {
break;
}
Index++;
} while (mDmarConfig[Index].VariableGuid != NULL);
}
if (mDmarConfig[Index].VariableGuid == NULL) {
return -1;
}
return Index;
}
/**
Reads a single-byte setup variable at a given variable store offset.
@param Guid Pointer to the variable GUID.
@param Variable Pointer to the variable data structure.
@param Offset Byte offset into the variable to read.
@return The byte value at the offset, or 0 on error.
**/
UINT64
EFIAPI
ReadSetupVariableByte (
IN CONST GUID *Guid,
IN VOID *Variable,
IN UINTN Offset
)
{
INTN ConfigIndex;
UINT64 Status;
UINT8 *Buffer;
ConfigIndex = FindSetupVariableIndex ();
if (ConfigIndex == -1) {
return EFI_NOT_FOUND;
}
//
// Read the setup variable
//
Buffer = ReadSetupVariable (
mDmarConfig[ConfigIndex].VariableGuid,
mDmarConfig[ConfigIndex].VariableSize
);
if (Buffer == NULL) {
return EFI_NOT_FOUND;
}
//
// Copy one byte from the buffer
//
InternalCopyMemChecked (Variable, Buffer + Offset, 1);
//
// Free the variable buffer
//
if (gAcpiTableProtocolReady) {
((PCD_PROTOCOL *)gPcdProtocol)->FreeVariable (Buffer);
} else {
gBootServices->FreePool (Buffer);
}
return EFI_SUCCESS;
}
//=============================================================================
// Driver initialization (sub_398 / module entry prologue)
//=============================================================================
/**
Initializes the UEFI driver's global state.
Saves ImageHandle, SystemTable, BootServices, and RuntimeServices.
Locates the DXE Services Table and HOB list for other DXE drivers.
This is called from UefiMain before InstallDmarTable.
@param ImageHandle The firmware allocated handle for the EFI image.
@param SystemTable A pointer to the EFI System Table.
@return EFI_STATUS.
**/
EFI_STATUS
EFIAPI
AcpiVtdDriverEntryPoint (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
//
// Save ImageHandle, SystemTable, BootServices, RuntimeServices
//
gImageHandle = ImageHandle;
ASSERT (gImageHandle != NULL);
gSystemTable = SystemTable;
ASSERT (gSystemTable != NULL);
gBootServices = SystemTable->BootServices;
ASSERT (gBootServices != NULL);
gRuntimeServices = SystemTable->RuntimeServices;
ASSERT (gRuntimeServices != NULL);
//
// Initialize HOB list pointer (needed for DMAR table construction)
//
Status = GetHobList (&gHobList);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
ASSERT (gHobList != NULL);
//
// Initialize DXE Services Table pointer
//
Status = GetDxeServicesTable (&gDsServicesTable);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
ASSERT (gDsServicesTable != NULL);
//
// Build and install the DMAR table
//
return InstallDmarTable ();
}
//=============================================================================
// Module entry point (UefiMain)
//=============================================================================
/**
Standard UEFI DXE driver entry point.
Calls AcpiVtdDriverEntryPoint to initialize and install the DMAR table.
On error, asserts and returns the error code.
@param ImageHandle The firmware allocated handle for the EFI image.
@param SystemTable A pointer to the EFI System Table.
@return EFI_STATUS.
**/
EFI_STATUS
EFIAPI
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
Status = AcpiVtdDriverEntryPoint (ImageHandle, SystemTable);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status = %r)\n", Status));
ASSERT_EFI_ERROR (Status);
}
return Status;
}