In order to support PEI graphic, we let VTdPmrPei driver
parse DMAR table RMRR entry and allow the UMA access.
If a system has no PEI IGD, no RMRR is needed. The behavior
is unchanged.
If a system has PEI IGD, it must report RMRR in PEI phase.
The PeiVTdPrm will program the IGD VTd engine to skip the
RMRR region, and program the reset PCI VTd engine to skip
the another DMA buffer allocated in PEI phase for other
device driver.
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
---
IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c | 52 +-
IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c | 581 +++++++++++++++++++-
IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h | 20 +-
3 files changed, 624 insertions(+), 29 deletions(-)
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
index ef08e29..be841aa 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
@@ -22,7 +22,7 @@
#include "IntelVTdPmrPei.h"
-extern EDKII_VTD_INFO_PPI *mVTdInfoPpi;
+extern VTD_INFO *mVTdInfo;
/**
Get protected low memory alignment.
@@ -60,7 +60,7 @@ GetPhmrAlignment (
UINT64 Data64;
UINT8 HostAddressWidth;
- HostAddressWidth = mVTdInfoPpi->HostAddressWidth;
+ HostAddressWidth = mVTdInfo->HostAddressWidth;
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);
Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);
@@ -73,11 +73,13 @@ GetPhmrAlignment (
/**
Get protected low memory alignment.
+ @param EngineMask The mask of the VTd engine to be accessed.
+
@return protected low memory alignment.
**/
UINT32
GetLowMemoryAlignment (
- VOID
+ IN UINT64 EngineMask
)
{
UINTN Index;
@@ -85,8 +87,11 @@ GetLowMemoryAlignment (
UINT32 FinalAlignment;
FinalAlignment = 0;
- for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {
- Alignment = GetPlmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
+ for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+ if ((EngineMask & LShiftU64(1, Index)) == 0) {
+ continue;
+ }
+ Alignment = GetPlmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
if (FinalAlignment < Alignment) {
FinalAlignment = Alignment;
}
@@ -97,11 +102,13 @@ GetLowMemoryAlignment (
/**
Get protected high memory alignment.
+ @param EngineMask The mask of the VTd engine to be accessed.
+
@return protected high memory alignment.
**/
UINT64
GetHighMemoryAlignment (
- VOID
+ IN UINT64 EngineMask
)
{
UINTN Index;
@@ -109,8 +116,11 @@ GetHighMemoryAlignment (
UINT64 FinalAlignment;
FinalAlignment = 0;
- for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {
- Alignment = GetPhmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
+ for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+ if ((EngineMask & LShiftU64(1, Index)) == 0) {
+ continue;
+ }
+ Alignment = GetPhmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
if (FinalAlignment < Alignment) {
FinalAlignment = Alignment;
}
@@ -246,6 +256,7 @@ SetPmrRegion (
/**
Set DMA protected region.
+ @param EngineMask The mask of the VTd engine to be accessed.
@param LowMemoryBase The protected low memory region base.
@param LowMemoryLength The protected low memory region length.
@param HighMemoryBase The protected high memory region base.
@@ -256,6 +267,7 @@ SetPmrRegion (
**/
EFI_STATUS
SetDmaProtectedRange (
+ IN UINT64 EngineMask,
IN UINT32 LowMemoryBase,
IN UINT32 LowMemoryLength,
IN UINT64 HighMemoryBase,
@@ -265,12 +277,15 @@ SetDmaProtectedRange (
UINTN Index;
EFI_STATUS Status;
- DEBUG ((DEBUG_INFO, "SetDmaProtectedRange - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));
+ DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));
- for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {
- DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
+ for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+ if ((EngineMask & LShiftU64(1, Index)) == 0) {
+ continue;
+ }
+ DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
Status = SetPmrRegion (
- (UINTN)mVTdInfoPpi->VTdEngineAddress[Index],
+ (UINTN)mVTdInfo->VTdEngineAddress[Index],
LowMemoryBase,
LowMemoryLength,
HighMemoryBase,
@@ -279,7 +294,7 @@ SetDmaProtectedRange (
if (EFI_ERROR(Status)) {
return Status;
}
- Status = EnablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
+ Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
if (EFI_ERROR(Status)) {
return Status;
}
@@ -291,11 +306,13 @@ SetDmaProtectedRange (
/**
Diable DMA protection.
+ @param EngineMask The mask of the VTd engine to be accessed.
+
@retval DMA protection is disabled.
**/
EFI_STATUS
DisableDmaProtection (
- VOID
+ IN UINT64 EngineMask
)
{
UINTN Index;
@@ -303,8 +320,11 @@ DisableDmaProtection (
DEBUG ((DEBUG_INFO, "DisableDmaProtection\n"));
- for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {
- Status = DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);
+ for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {
+ if ((EngineMask & LShiftU64(1, Index)) == 0) {
+ continue;
+ }
+ Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);
if (EFI_ERROR(Status)) {
return Status;
}
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
index d118b7e..063e8cd 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
@@ -29,7 +29,9 @@
#define TOTAL_DMA_BUFFER_SIZE SIZE_4MB
-EDKII_VTD_INFO_PPI *mVTdInfoPpi;
+EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;
+VTD_INFO *mVTdInfo;
+UINT64 mEngineMask;
UINTN mDmaBufferBase;
UINTN mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE;
UINTN mDmaBufferCurrentTop;
@@ -48,15 +50,19 @@ typedef struct {
PEI Memory Layout:
+ +------------------+ <=============== PHMR.Limit (Top of memory)
+ | Mem Resource |
+ | |
+
+------------------+ <------- EfiMemoryTop
| PEI allocated |
- =========== +==================+
+ =========== +==================+ <=============== PHMR.Base
^ | Commom Buf |
| | -------------- |
DMA Buffer | * DMA FREE * |
| | -------------- |
V | Read/Write Buf |
- =========== +==================+
+ =========== +==================+ <=============== PLMR.Limit
| PEI allocated |
| -------------- | <------- EfiFreeMemoryTop
| * PEI FREE * |
@@ -70,6 +76,9 @@ typedef struct {
| Mem Alloc Hob |
+------------------+
+ | |
+ | Mem Resource |
+ +------------------+ <=============== PLMR.Base (0)
**/
@@ -457,20 +466,21 @@ DumpPhitHob (
/**
Get the highest memory.
- @param HobList the HOB list.
-
@return the highest memory.
**/
UINT64
GetTopMemory (
- IN VOID *HobList
+ VOID
)
{
+ VOID *HobList;
EFI_PEI_HOB_POINTERS Hob;
EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
UINT64 TopMemory;
UINT64 ResourceTop;
+ HobList = GetHobList ();
+
TopMemory = 0;
for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
@@ -525,8 +535,8 @@ InitDmaProtection (
ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);
- LowMemoryAlignment = GetLowMemoryAlignment ();
- HighMemoryAlignment = GetHighMemoryAlignment ();
+ LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask);
+ HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask);
if (LowMemoryAlignment < HighMemoryAlignment) {
MemoryAlignment = (UINTN)HighMemoryAlignment;
} else {
@@ -542,9 +552,10 @@ InitDmaProtection (
LowBottom = 0;
LowTop = *DmaBufferBase;
HighBottom = *DmaBufferBase + DmaBufferSize;
- HighTop = GetTopMemory (HobList);
+ HighTop = GetTopMemory ();
Status = SetDmaProtectedRange (
+ mEngineMask,
(UINT32)LowBottom,
(UINT32)(LowTop - LowBottom),
HighBottom,
@@ -559,6 +570,541 @@ InitDmaProtection (
}
/**
+ Dump DMAR DeviceScopeEntry.
+
+ @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry
+**/
+VOID
+DumpDmarDeviceScopeEntry (
+ IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry
+ )
+{
+ UINTN PciPathNumber;
+ UINTN PciPathIndex;
+ EFI_ACPI_DMAR_PCI_PATH *PciPath;
+
+ if (DmarDeviceScopeEntry == NULL) {
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO,
+ " *************************************************************************\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ " * DMA-Remapping Device Scope Entry Structure *\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ " *************************************************************************\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ (sizeof(UINTN) == sizeof(UINT64)) ?
+ " DMAR Device Scope Entry address ...................... 0x%016lx\n" :
+ " DMAR Device Scope Entry address ...................... 0x%08x\n",
+ DmarDeviceScopeEntry
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Device Scope Entry Type ............................ 0x%02x\n",
+ DmarDeviceScopeEntry->Type
+ ));
+ switch (DmarDeviceScopeEntry->Type) {
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
+ DEBUG ((DEBUG_INFO,
+ " PCI Endpoint Device\n"
+ ));
+ break;
+ case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
+ DEBUG ((DEBUG_INFO,
+ " PCI Sub-hierachy\n"
+ ));
+ break;
+ default:
+ break;
+ }
+ DEBUG ((DEBUG_INFO,
+ " Length ............................................. 0x%02x\n",
+ DmarDeviceScopeEntry->Length
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Enumeration ID ..................................... 0x%02x\n",
+ DmarDeviceScopeEntry->EnumerationId
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Starting Bus Number ................................ 0x%02x\n",
+ DmarDeviceScopeEntry->StartBusNumber
+ ));
+
+ PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);
+ PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);
+ for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {
+ DEBUG ((DEBUG_INFO,
+ " Device ............................................. 0x%02x\n",
+ PciPath[PciPathIndex].Device
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Function ........................................... 0x%02x\n",
+ PciPath[PciPathIndex].Function
+ ));
+ }
+
+ DEBUG ((DEBUG_INFO,
+ " *************************************************************************\n\n"
+ ));
+
+ return;
+}
+
+/**
+ Dump DMAR RMRR table.
+
+ @param[in] Rmrr DMAR RMRR table
+**/
+VOID
+DumpDmarRmrr (
+ IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
+ )
+{
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;
+ INTN RmrrLen;
+
+ if (Rmrr == NULL) {
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO,
+ " ***************************************************************************\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ " * Reserved Memory Region Reporting Structure *\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ " ***************************************************************************\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ (sizeof(UINTN) == sizeof(UINT64)) ?
+ " RMRR address ........................................... 0x%016lx\n" :
+ " RMRR address ........................................... 0x%08x\n",
+ Rmrr
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Type ................................................. 0x%04x\n",
+ Rmrr->Header.Type
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Length ............................................... 0x%04x\n",
+ Rmrr->Header.Length
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Segment Number ....................................... 0x%04x\n",
+ Rmrr->SegmentNumber
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Reserved Memory Region Base Address .................. 0x%016lx\n",
+ Rmrr->ReservedMemoryRegionBaseAddress
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Reserved Memory Region Limit Address ................. 0x%016lx\n",
+ Rmrr->ReservedMemoryRegionLimitAddress
+ ));
+
+ RmrrLen = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);
+ while (RmrrLen > 0) {
+ DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+ RmrrLen -= DmarDeviceScopeEntry->Length;
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+ }
+
+ DEBUG ((DEBUG_INFO,
+ " ***************************************************************************\n\n"
+ ));
+
+ return;
+}
+
+/**
+ Dump DMAR DRHD table.
+
+ @param[in] Drhd DMAR DRHD table
+**/
+VOID
+DumpDmarDrhd (
+ IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
+ )
+{
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;
+ INTN DrhdLen;
+
+ if (Drhd == NULL) {
+ return;
+ }
+
+ DEBUG ((DEBUG_INFO,
+ " ***************************************************************************\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ " * DMA-Remapping Hardware Definition Structure *\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ " ***************************************************************************\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ (sizeof(UINTN) == sizeof(UINT64)) ?
+ " DRHD address ........................................... 0x%016lx\n" :
+ " DRHD address ........................................... 0x%08x\n",
+ Drhd
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Type ................................................. 0x%04x\n",
+ Drhd->Header.Type
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Length ............................................... 0x%04x\n",
+ Drhd->Header.Length
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Flags ................................................ 0x%02x\n",
+ Drhd->Flags
+ ));
+ DEBUG ((DEBUG_INFO,
+ " INCLUDE_PCI_ALL .................................... 0x%02x\n",
+ Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Segment Number ....................................... 0x%04x\n",
+ Drhd->SegmentNumber
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Register Base Address ................................ 0x%016lx\n",
+ Drhd->RegisterBaseAddress
+ ));
+
+ DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);
+ while (DrhdLen > 0) {
+ DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);
+ DrhdLen -= DmarDeviceScopeEntry->Length;
+ DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);
+ }
+
+ DEBUG ((DEBUG_INFO,
+ " ***************************************************************************\n\n"
+ ));
+
+ return;
+}
+
+/**
+ Dump DMAR ACPI table.
+
+ @param[in] Dmar DMAR ACPI table
+**/
+VOID
+DumpAcpiDMAR (
+ IN EFI_ACPI_DMAR_HEADER *Dmar
+ )
+{
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+ INTN DmarLen;
+
+ if (Dmar == NULL) {
+ return;
+ }
+
+ //
+ // Dump Dmar table
+ //
+ DEBUG ((DEBUG_INFO,
+ "*****************************************************************************\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ "* DMAR Table *\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ "*****************************************************************************\n"
+ ));
+
+ DEBUG ((DEBUG_INFO,
+ (sizeof(UINTN) == sizeof(UINT64)) ?
+ "DMAR address ............................................. 0x%016lx\n" :
+ "DMAR address ............................................. 0x%08x\n",
+ Dmar
+ ));
+
+ DEBUG ((DEBUG_INFO,
+ " Table Contents:\n"
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Host Address Width ................................... 0x%02x\n",
+ Dmar->HostAddressWidth
+ ));
+ DEBUG ((DEBUG_INFO,
+ " Flags ................................................ 0x%02x\n",
+ Dmar->Flags
+ ));
+ DEBUG ((DEBUG_INFO,
+ " INTR_REMAP ......................................... 0x%02x\n",
+ Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
+ ));
+ DEBUG ((DEBUG_INFO,
+ " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
+ Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
+ ));
+
+ DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);
+ while (DmarLen > 0) {
+ switch (DmarHeader->Type) {
+ case EFI_ACPI_DMAR_TYPE_DRHD:
+ DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+ break;
+ case EFI_ACPI_DMAR_TYPE_RMRR:
+ DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+ break;
+ default:
+ break;
+ }
+ DmarLen -= DmarHeader->Length;
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+ }
+
+ DEBUG ((DEBUG_INFO,
+ "*****************************************************************************\n\n"
+ ));
+
+ return;
+}
+
+/**
+ Get VTd engine number.
+
+ @return the VTd engine number.
+**/
+UINTN
+GetVtdEngineNumber (
+ VOID
+ )
+{
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+ UINTN VtdIndex;
+
+ VtdIndex = 0;
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
+ while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
+ switch (DmarHeader->Type) {
+ case EFI_ACPI_DMAR_TYPE_DRHD:
+ VtdIndex++;
+ break;
+ default:
+ break;
+ }
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+ }
+ return VtdIndex ;
+}
+
+/**
+ Process DMAR DHRD table.
+
+ @param[in] VtdIndex The index of VTd engine.
+ @param[in] DmarDrhd The DRHD table.
+**/
+VOID
+ProcessDhrd (
+ IN UINTN VtdIndex,
+ IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd
+ )
+{
+ DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
+ mVTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
+}
+
+/**
+ Parse DMAR DRHD table.
+
+ @return EFI_SUCCESS The DMAR DRHD table is parsed.
+**/
+EFI_STATUS
+ParseDmarAcpiTableDrhd (
+ VOID
+ )
+{
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+ UINTN VtdUnitNumber;
+ UINTN VtdIndex;
+
+ VtdUnitNumber = GetVtdEngineNumber ();
+ if (VtdUnitNumber == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));
+ if (mVTdInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth;
+ mVTdInfo->VTdEngineCount = VtdUnitNumber;
+
+ VtdIndex = 0;
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
+ while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
+ switch (DmarHeader->Type) {
+ case EFI_ACPI_DMAR_TYPE_DRHD:
+ ASSERT (VtdIndex < VtdUnitNumber);
+ ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);
+ VtdIndex++;
+
+ break;
+
+ default:
+ break;
+ }
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+ }
+ ASSERT (VtdIndex == VtdUnitNumber);
+
+ //
+ // Initialize the engine mask to all.
+ //
+ mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the VTd engine index according to the Segment and DevScopeEntry.
+
+ @param Segment The segment of the VTd engine
+ @param DevScopeEntry The DevScopeEntry of the VTd engine
+
+ @return The VTd engine index according to the Segment and DevScopeEntry.
+ @retval -1 The VTd engine is not found.
+**/
+UINTN
+GetVTdEngineFromDevScopeEntry (
+ IN UINT16 Segment,
+ IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
+ )
+{
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+ UINTN VtdIndex;
+ EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd;
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *ThisDevScopeEntry;
+
+ VtdIndex = 0;
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
+ while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
+ switch (DmarHeader->Type) {
+ case EFI_ACPI_DMAR_TYPE_DRHD:
+ DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;
+ if (DmarDrhd->SegmentNumber != Segment) {
+ // Mismatch
+ break;
+ }
+ if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
+ ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
+ // No DevScopeEntry
+ // Do not handle PCI_ALL
+ break;
+ }
+ ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));
+ while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {
+ if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&
+ (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {
+ return VtdIndex;
+ }
+ ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
+ }
+ break;
+ default:
+ break;
+ }
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+ }
+ return (UINTN)-1;
+}
+
+/**
+ Process DMAR RMRR table.
+
+ @param[in] DmarRmrr The RMRR table.
+**/
+VOID
+ProcessRmrr (
+ IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr
+ )
+{
+ EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;
+ UINTN VTdIndex;
+ UINT64 RmrrMask;
+ UINTN LowBottom;
+ UINTN LowTop;
+ UINTN HighBottom;
+ UINT64 HighTop;
+
+ DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
+
+ if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
+ (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
+ return ;
+ }
+
+ DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));
+ while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {
+ ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);
+
+ VTdIndex = GetVTdEngineFromDevScopeEntry (DmarRmrr->SegmentNumber, DmarDevScopeEntry);
+ if (VTdIndex != (UINTN)-1) {
+ RmrrMask = LShiftU64 (1, VTdIndex);
+
+ LowBottom = 0;
+ LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
+ HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
+ HighTop = GetTopMemory ();
+
+ SetDmaProtectedRange (
+ RmrrMask,
+ 0,
+ (UINT32)(LowTop - LowBottom),
+ HighBottom,
+ HighTop - HighBottom
+ );
+
+ //
+ // Remove the engine from the engine mask.
+ // The assumption is that any other PEI driver does not access
+ // the device covered by this engine.
+ //
+ mEngineMask = mEngineMask & (~RmrrMask);
+ }
+
+ DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
+ }
+}
+
+/**
+ Parse DMAR DRHD table.
+**/
+VOID
+ParseDmarAcpiTableRmrr (
+ VOID
+ )
+{
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
+
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));
+ while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {
+ switch (DmarHeader->Type) {
+ case EFI_ACPI_DMAR_TYPE_RMRR:
+ ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
+ break;
+ default:
+ break;
+ }
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
+ }
+}
+
+/**
Initializes the Intel VTd PMR PEIM.
@param FileHandle Handle of the file being invoked.
@@ -585,10 +1131,25 @@ IntelVTdPmrInitialize (
&gEdkiiVTdInfoPpiGuid,
0,
NULL,
- (VOID **)&mVTdInfoPpi
+ (VOID **)&mAcpiDmarTable
);
ASSERT_EFI_ERROR(Status);
+ DumpAcpiDMAR (mAcpiDmarTable);
+
+ //
+ // Get DMAR information to local VTdInfo
+ //
+ Status = ParseDmarAcpiTableDrhd ();
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // If there is RMRR memory, parse it here.
+ //
+ ParseDmarAcpiTableRmrr ();
+
//
// Find a pre-memory in resource hob as DMA buffer
// Mark PEI memory to be DMA protected.
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
index aa5926a7..720f5d4 100644
--- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
+++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h
@@ -15,9 +15,16 @@
#ifndef __DMA_ACCESS_LIB_H__
#define __DMA_ACCESS_LIB_H__
+typedef struct {
+ UINT8 HostAddressWidth;
+ UINTN VTdEngineCount;
+ UINT64 VTdEngineAddress[1];
+} VTD_INFO;
+
/**
Set DMA protected region.
+ @param EngineMask The mask of the VTd engine to be accessed.
@param LowMemoryBase The protected low memory region base.
@param LowMemoryLength The protected low memory region length.
@param HighMemoryBase The protected high memory region base.
@@ -28,6 +35,7 @@
**/
EFI_STATUS
SetDmaProtectedRange (
+ IN UINT64 EngineMask,
IN UINT32 LowMemoryBase,
IN UINT32 LowMemoryLength,
IN UINT64 HighMemoryBase,
@@ -37,31 +45,37 @@ SetDmaProtectedRange (
/**
Diable DMA protection.
+ @param EngineMask The mask of the VTd engine to be accessed.
+
@retval DMA protection is disabled.
**/
EFI_STATUS
DisableDmaProtection (
- VOID
+ IN UINT64 EngineMask
);
/**
Get protected low memory alignment.
+ @param EngineMask The mask of the VTd engine to be accessed.
+
@return protected low memory alignment.
**/
UINT32
GetLowMemoryAlignment (
- VOID
+ IN UINT64 EngineMask
);
/**
Get protected high memory alignment.
+ @param EngineMask The mask of the VTd engine to be accessed.
+
@return protected high memory alignment.
**/
UINT64
GetHighMemoryAlignment (
- VOID
+ IN UINT64 EngineMask
);
#endif
--
2.7.4.windows.1
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
The typo "reset" in commit log? Should it be "reset"? Thanks, Star -----Original Message----- From: Yao, Jiewen Sent: Sunday, September 17, 2017 2:07 PM To: edk2-devel@lists.01.org Cc: Zeng, Star <star.zeng@intel.com> Subject: [PATCH 2/3] IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table. In order to support PEI graphic, we let VTdPmrPei driver parse DMAR table RMRR entry and allow the UMA access. If a system has no PEI IGD, no RMRR is needed. The behavior is unchanged. If a system has PEI IGD, it must report RMRR in PEI phase. The PeiVTdPrm will program the IGD VTd engine to skip the RMRR region, and program the reset PCI VTd engine to skip the another DMA buffer allocated in PEI phase for other device driver. Cc: Star Zeng <star.zeng@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> --- IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c | 52 +- IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c | 581 +++++++++++++++++++- IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h | 20 +- 3 files changed, 624 insertions(+), 29 deletions(-) diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c index ef08e29..be841aa 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c @@ -22,7 +22,7 @@ #include "IntelVTdPmrPei.h" -extern EDKII_VTD_INFO_PPI *mVTdInfoPpi; +extern VTD_INFO *mVTdInfo; /** Get protected low memory alignment. @@ -60,7 +60,7 @@ GetPhmrAlignment ( UINT64 Data64; UINT8 HostAddressWidth; - HostAddressWidth = mVTdInfoPpi->HostAddressWidth; + HostAddressWidth = mVTdInfo->HostAddressWidth; MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF); Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG); @@ -73,11 +73,13 @@ GetPhmrAlignment ( /** Get protected low memory alignment. + @param EngineMask The mask of the VTd engine to be accessed. + @return protected low memory alignment. **/ UINT32 GetLowMemoryAlignment ( - VOID + IN UINT64 EngineMask ) { UINTN Index; @@ -85,8 +87,11 @@ GetLowMemoryAlignment ( UINT32 FinalAlignment; FinalAlignment = 0; - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { - Alignment = GetPlmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { + if ((EngineMask & LShiftU64(1, Index)) == 0) { + continue; + } + Alignment = GetPlmrAlignment + ((UINTN)mVTdInfo->VTdEngineAddress[Index]); if (FinalAlignment < Alignment) { FinalAlignment = Alignment; } @@ -97,11 +102,13 @@ GetLowMemoryAlignment ( /** Get protected high memory alignment. + @param EngineMask The mask of the VTd engine to be accessed. + @return protected high memory alignment. **/ UINT64 GetHighMemoryAlignment ( - VOID + IN UINT64 EngineMask ) { UINTN Index; @@ -109,8 +116,11 @@ GetHighMemoryAlignment ( UINT64 FinalAlignment; FinalAlignment = 0; - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { - Alignment = GetPhmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { + if ((EngineMask & LShiftU64(1, Index)) == 0) { + continue; + } + Alignment = GetPhmrAlignment + ((UINTN)mVTdInfo->VTdEngineAddress[Index]); if (FinalAlignment < Alignment) { FinalAlignment = Alignment; } @@ -246,6 +256,7 @@ SetPmrRegion ( /** Set DMA protected region. + @param EngineMask The mask of the VTd engine to be accessed. @param LowMemoryBase The protected low memory region base. @param LowMemoryLength The protected low memory region length. @param HighMemoryBase The protected high memory region base. @@ -256,6 +267,7 @@ SetPmrRegion ( **/ EFI_STATUS SetDmaProtectedRange ( + IN UINT64 EngineMask, IN UINT32 LowMemoryBase, IN UINT32 LowMemoryLength, IN UINT64 HighMemoryBase, @@ -265,12 +277,15 @@ SetDmaProtectedRange ( UINTN Index; EFI_STATUS Status; - DEBUG ((DEBUG_INFO, "SetDmaProtectedRange - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength)); + DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] + [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, + HighMemoryBase, HighMemoryLength)); - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { - DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { + if ((EngineMask & LShiftU64(1, Index)) == 0) { + continue; + } + DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); Status = SetPmrRegion ( - (UINTN)mVTdInfoPpi->VTdEngineAddress[Index], + (UINTN)mVTdInfo->VTdEngineAddress[Index], LowMemoryBase, LowMemoryLength, HighMemoryBase, @@ -279,7 +294,7 @@ SetDmaProtectedRange ( if (EFI_ERROR(Status)) { return Status; } - Status = EnablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); if (EFI_ERROR(Status)) { return Status; } @@ -291,11 +306,13 @@ SetDmaProtectedRange ( /** Diable DMA protection. + @param EngineMask The mask of the VTd engine to be accessed. + @retval DMA protection is disabled. **/ EFI_STATUS DisableDmaProtection ( - VOID + IN UINT64 EngineMask ) { UINTN Index; @@ -303,8 +320,11 @@ DisableDmaProtection ( DEBUG ((DEBUG_INFO, "DisableDmaProtection\n")); - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { - Status = DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { + if ((EngineMask & LShiftU64(1, Index)) == 0) { + continue; + } + Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); if (EFI_ERROR(Status)) { return Status; } diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c index d118b7e..063e8cd 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c @@ -29,7 +29,9 @@ #define TOTAL_DMA_BUFFER_SIZE SIZE_4MB -EDKII_VTD_INFO_PPI *mVTdInfoPpi; +EFI_ACPI_DMAR_HEADER *mAcpiDmarTable; +VTD_INFO *mVTdInfo; +UINT64 mEngineMask; UINTN mDmaBufferBase; UINTN mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE; UINTN mDmaBufferCurrentTop; @@ -48,15 +50,19 @@ typedef struct { PEI Memory Layout: + +------------------+ <=============== PHMR.Limit (Top of memory) + | Mem Resource | + | | + +------------------+ <------- EfiMemoryTop | PEI allocated | - =========== +==================+ + =========== +==================+ <=============== PHMR.Base ^ | Commom Buf | | | -------------- | DMA Buffer | * DMA FREE * | | | -------------- | V | Read/Write Buf | - =========== +==================+ + =========== +==================+ <=============== PLMR.Limit | PEI allocated | | -------------- | <------- EfiFreeMemoryTop | * PEI FREE * | @@ -70,6 +76,9 @@ typedef struct { | Mem Alloc Hob | +------------------+ + | | + | Mem Resource | + +------------------+ <=============== PLMR.Base (0) **/ @@ -457,20 +466,21 @@ DumpPhitHob ( /** Get the highest memory. - @param HobList the HOB list. - @return the highest memory. **/ UINT64 GetTopMemory ( - IN VOID *HobList + VOID ) { + VOID *HobList; EFI_PEI_HOB_POINTERS Hob; EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; UINT64 TopMemory; UINT64 ResourceTop; + HobList = GetHobList (); + TopMemory = 0; for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { @@ -525,8 +535,8 @@ InitDmaProtection ( ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop); - LowMemoryAlignment = GetLowMemoryAlignment (); - HighMemoryAlignment = GetHighMemoryAlignment (); + LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask); + HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask); if (LowMemoryAlignment < HighMemoryAlignment) { MemoryAlignment = (UINTN)HighMemoryAlignment; } else { @@ -542,9 +552,10 @@ InitDmaProtection ( LowBottom = 0; LowTop = *DmaBufferBase; HighBottom = *DmaBufferBase + DmaBufferSize; - HighTop = GetTopMemory (HobList); + HighTop = GetTopMemory (); Status = SetDmaProtectedRange ( + mEngineMask, (UINT32)LowBottom, (UINT32)(LowTop - LowBottom), HighBottom, @@ -559,6 +570,541 @@ InitDmaProtection ( } /** + Dump DMAR DeviceScopeEntry. + + @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry **/ VOID +DumpDmarDeviceScopeEntry ( + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry + ) +{ + UINTN PciPathNumber; + UINTN PciPathIndex; + EFI_ACPI_DMAR_PCI_PATH *PciPath; + + if (DmarDeviceScopeEntry == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, + " *************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + " * DMA-Remapping Device Scope Entry Structure *\n" + )); + DEBUG ((DEBUG_INFO, + " *************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + (sizeof(UINTN) == sizeof(UINT64)) ? + " DMAR Device Scope Entry address ...................... 0x%016lx\n" : + " DMAR Device Scope Entry address ...................... 0x%08x\n", + DmarDeviceScopeEntry + )); + DEBUG ((DEBUG_INFO, + " Device Scope Entry Type ............................ 0x%02x\n", + DmarDeviceScopeEntry->Type + )); + switch (DmarDeviceScopeEntry->Type) { case + EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT: + DEBUG ((DEBUG_INFO, + " PCI Endpoint Device\n" + )); + break; + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: + DEBUG ((DEBUG_INFO, + " PCI Sub-hierachy\n" + )); + break; + default: + break; + } + DEBUG ((DEBUG_INFO, + " Length ............................................. 0x%02x\n", + DmarDeviceScopeEntry->Length + )); + DEBUG ((DEBUG_INFO, + " Enumeration ID ..................................... 0x%02x\n", + DmarDeviceScopeEntry->EnumerationId + )); + DEBUG ((DEBUG_INFO, + " Starting Bus Number ................................ 0x%02x\n", + DmarDeviceScopeEntry->StartBusNumber + )); + + PciPathNumber = (DmarDeviceScopeEntry->Length - + sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / + sizeof(EFI_ACPI_DMAR_PCI_PATH); PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1); for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) { + DEBUG ((DEBUG_INFO, + " Device ............................................. 0x%02x\n", + PciPath[PciPathIndex].Device + )); + DEBUG ((DEBUG_INFO, + " Function ........................................... 0x%02x\n", + PciPath[PciPathIndex].Function + )); + } + + DEBUG ((DEBUG_INFO, + " *************************************************************************\n\n" + )); + + return; +} + +/** + Dump DMAR RMRR table. + + @param[in] Rmrr DMAR RMRR table +**/ +VOID +DumpDmarRmrr ( + IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr + ) +{ + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; + INTN RmrrLen; + + if (Rmrr == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + " * Reserved Memory Region Reporting Structure *\n" + )); + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + (sizeof(UINTN) == sizeof(UINT64)) ? + " RMRR address ........................................... 0x%016lx\n" : + " RMRR address ........................................... 0x%08x\n", + Rmrr + )); + DEBUG ((DEBUG_INFO, + " Type ................................................. 0x%04x\n", + Rmrr->Header.Type + )); + DEBUG ((DEBUG_INFO, + " Length ............................................... 0x%04x\n", + Rmrr->Header.Length + )); + DEBUG ((DEBUG_INFO, + " Segment Number ....................................... 0x%04x\n", + Rmrr->SegmentNumber + )); + DEBUG ((DEBUG_INFO, + " Reserved Memory Region Base Address .................. 0x%016lx\n", + Rmrr->ReservedMemoryRegionBaseAddress + )); + DEBUG ((DEBUG_INFO, + " Reserved Memory Region Limit Address ................. 0x%016lx\n", + Rmrr->ReservedMemoryRegionLimitAddress + )); + + RmrrLen = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER); + DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)(Rmrr + 1); while (RmrrLen > 0) { + DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); + RmrrLen -= DmarDeviceScopeEntry->Length; + DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } + + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n\n" + )); + + return; +} + +/** + Dump DMAR DRHD table. + + @param[in] Drhd DMAR DRHD table +**/ +VOID +DumpDmarDrhd ( + IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd + ) +{ + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; + INTN DrhdLen; + + if (Drhd == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + " * DMA-Remapping Hardware Definition Structure *\n" + )); + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + (sizeof(UINTN) == sizeof(UINT64)) ? + " DRHD address ........................................... 0x%016lx\n" : + " DRHD address ........................................... 0x%08x\n", + Drhd + )); + DEBUG ((DEBUG_INFO, + " Type ................................................. 0x%04x\n", + Drhd->Header.Type + )); + DEBUG ((DEBUG_INFO, + " Length ............................................... 0x%04x\n", + Drhd->Header.Length + )); + DEBUG ((DEBUG_INFO, + " Flags ................................................ 0x%02x\n", + Drhd->Flags + )); + DEBUG ((DEBUG_INFO, + " INCLUDE_PCI_ALL .................................... 0x%02x\n", + Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL + )); + DEBUG ((DEBUG_INFO, + " Segment Number ....................................... 0x%04x\n", + Drhd->SegmentNumber + )); + DEBUG ((DEBUG_INFO, + " Register Base Address ................................ 0x%016lx\n", + Drhd->RegisterBaseAddress + )); + + DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER); + DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)(Drhd + 1); while (DrhdLen > 0) { + DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); + DrhdLen -= DmarDeviceScopeEntry->Length; + DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } + + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n\n" + )); + + return; +} + +/** + Dump DMAR ACPI table. + + @param[in] Dmar DMAR ACPI table +**/ +VOID +DumpAcpiDMAR ( + IN EFI_ACPI_DMAR_HEADER *Dmar + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + INTN DmarLen; + + if (Dmar == NULL) { + return; + } + + // + // Dump Dmar table + // + DEBUG ((DEBUG_INFO, + "*****************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + "* DMAR Table *\n" + )); + DEBUG ((DEBUG_INFO, + "*****************************************************************************\n" + )); + + DEBUG ((DEBUG_INFO, + (sizeof(UINTN) == sizeof(UINT64)) ? + "DMAR address ............................................. 0x%016lx\n" : + "DMAR address ............................................. 0x%08x\n", + Dmar + )); + + DEBUG ((DEBUG_INFO, + " Table Contents:\n" + )); + DEBUG ((DEBUG_INFO, + " Host Address Width ................................... 0x%02x\n", + Dmar->HostAddressWidth + )); + DEBUG ((DEBUG_INFO, + " Flags ................................................ 0x%02x\n", + Dmar->Flags + )); + DEBUG ((DEBUG_INFO, + " INTR_REMAP ......................................... 0x%02x\n", + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP + )); + DEBUG ((DEBUG_INFO, + " X2APIC_OPT_OUT_SET ................................. 0x%02x\n", + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT + )); + + DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER); + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1); while + (DmarLen > 0) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_DRHD: + DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); + break; + case EFI_ACPI_DMAR_TYPE_RMRR: + DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); + break; + default: + break; + } + DmarLen -= DmarHeader->Length; + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + + DmarHeader->Length); } + + DEBUG ((DEBUG_INFO, + "*****************************************************************************\n\n" + )); + + return; +} + +/** + Get VTd engine number. + + @return the VTd engine number. +**/ +UINTN +GetVtdEngineNumber ( + VOID + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + UINTN VtdIndex; + + VtdIndex = 0; + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER +*)((UINTN)(mAcpiDmarTable + 1)); + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_DRHD: + VtdIndex++; + break; + default: + break; + } + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + +DmarHeader->Length); + } + return VtdIndex ; +} + +/** + Process DMAR DHRD table. + + @param[in] VtdIndex The index of VTd engine. + @param[in] DmarDrhd The DRHD table. +**/ +VOID +ProcessDhrd ( + IN UINTN VtdIndex, + IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd + ) +{ + DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, +DmarDrhd->RegisterBaseAddress)); + mVTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress; +} + +/** + Parse DMAR DRHD table. + + @return EFI_SUCCESS The DMAR DRHD table is parsed. +**/ +EFI_STATUS +ParseDmarAcpiTableDrhd ( + VOID + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + UINTN VtdUnitNumber; + UINTN VtdIndex; + + VtdUnitNumber = GetVtdEngineNumber (); if (VtdUnitNumber == 0) { + return EFI_UNSUPPORTED; + } + + mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * + sizeof(UINT64)); if (mVTdInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth; + mVTdInfo->VTdEngineCount = VtdUnitNumber; + + VtdIndex = 0; + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER + *)((UINTN)(mAcpiDmarTable + 1)); while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_DRHD: + ASSERT (VtdIndex < VtdUnitNumber); + ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); + VtdIndex++; + + break; + + default: + break; + } + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + + DmarHeader->Length); } ASSERT (VtdIndex == VtdUnitNumber); + + // + // Initialize the engine mask to all. + // + mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1; + + return EFI_SUCCESS; +} + +/** + Return the VTd engine index according to the Segment and DevScopeEntry. + + @param Segment The segment of the VTd engine + @param DevScopeEntry The DevScopeEntry of the VTd engine + + @return The VTd engine index according to the Segment and DevScopeEntry. + @retval -1 The VTd engine is not found. +**/ +UINTN +GetVTdEngineFromDevScopeEntry ( + IN UINT16 Segment, + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + UINTN VtdIndex; + EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd; + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *ThisDevScopeEntry; + + VtdIndex = 0; + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER +*)((UINTN)(mAcpiDmarTable + 1)); + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_DRHD: + DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader; + if (DmarDrhd->SegmentNumber != Segment) { + // Mismatch + break; + } + if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) || + ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) { + // No DevScopeEntry + // Do not handle PCI_ALL + break; + } + ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1)); + while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) { + if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) && + (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) { + return VtdIndex; + } + ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length); + } + break; + default: + break; + } + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + +DmarHeader->Length); + } + return (UINTN)-1; +} + +/** + Process DMAR RMRR table. + + @param[in] DmarRmrr The RMRR table. +**/ +VOID +ProcessRmrr ( + IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr + ) +{ + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry; + UINTN VTdIndex; + UINT64 RmrrMask; + UINTN LowBottom; + UINTN LowTop; + UINTN HighBottom; + UINT64 HighTop; + + DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", + DmarRmrr->ReservedMemoryRegionBaseAddress, + DmarRmrr->ReservedMemoryRegionLimitAddress)); + + if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) || + (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) { + return ; + } + + DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)((UINTN)(DmarRmrr + 1)); while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) { + ASSERT (DmarDevScopeEntry->Type == + EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT); + + VTdIndex = GetVTdEngineFromDevScopeEntry (DmarRmrr->SegmentNumber, DmarDevScopeEntry); + if (VTdIndex != (UINTN)-1) { + RmrrMask = LShiftU64 (1, VTdIndex); + + LowBottom = 0; + LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress; + HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1; + HighTop = GetTopMemory (); + + SetDmaProtectedRange ( + RmrrMask, + 0, + (UINT32)(LowTop - LowBottom), + HighBottom, + HighTop - HighBottom + ); + + // + // Remove the engine from the engine mask. + // The assumption is that any other PEI driver does not access + // the device covered by this engine. + // + mEngineMask = mEngineMask & (~RmrrMask); + } + + DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER +*)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length); + } +} + +/** + Parse DMAR DRHD table. +**/ +VOID +ParseDmarAcpiTableRmrr ( + VOID + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER +*)((UINTN)(mAcpiDmarTable + 1)); + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_RMRR: + ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); + break; + default: + break; + } + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + +DmarHeader->Length); + } +} + +/** Initializes the Intel VTd PMR PEIM. @param FileHandle Handle of the file being invoked. @@ -585,10 +1131,25 @@ IntelVTdPmrInitialize ( &gEdkiiVTdInfoPpiGuid, 0, NULL, - (VOID **)&mVTdInfoPpi + (VOID **)&mAcpiDmarTable ); ASSERT_EFI_ERROR(Status); + DumpAcpiDMAR (mAcpiDmarTable); + + // + // Get DMAR information to local VTdInfo // Status = + ParseDmarAcpiTableDrhd (); if (EFI_ERROR(Status)) { + return Status; + } + + // + // If there is RMRR memory, parse it here. + // + ParseDmarAcpiTableRmrr (); + // // Find a pre-memory in resource hob as DMA buffer // Mark PEI memory to be DMA protected. diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h index aa5926a7..720f5d4 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h @@ -15,9 +15,16 @@ #ifndef __DMA_ACCESS_LIB_H__ #define __DMA_ACCESS_LIB_H__ +typedef struct { + UINT8 HostAddressWidth; + UINTN VTdEngineCount; + UINT64 VTdEngineAddress[1]; +} VTD_INFO; + /** Set DMA protected region. + @param EngineMask The mask of the VTd engine to be accessed. @param LowMemoryBase The protected low memory region base. @param LowMemoryLength The protected low memory region length. @param HighMemoryBase The protected high memory region base. @@ -28,6 +35,7 @@ **/ EFI_STATUS SetDmaProtectedRange ( + IN UINT64 EngineMask, IN UINT32 LowMemoryBase, IN UINT32 LowMemoryLength, IN UINT64 HighMemoryBase, @@ -37,31 +45,37 @@ SetDmaProtectedRange ( /** Diable DMA protection. + @param EngineMask The mask of the VTd engine to be accessed. + @retval DMA protection is disabled. **/ EFI_STATUS DisableDmaProtection ( - VOID + IN UINT64 EngineMask ); /** Get protected low memory alignment. + @param EngineMask The mask of the VTd engine to be accessed. + @return protected low memory alignment. **/ UINT32 GetLowMemoryAlignment ( - VOID + IN UINT64 EngineMask ); /** Get protected high memory alignment. + @param EngineMask The mask of the VTd engine to be accessed. + @return protected high memory alignment. **/ UINT64 GetHighMemoryAlignment ( - VOID + IN UINT64 EngineMask ); #endif -- 2.7.4.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Sorry, should it be "rest"? -----Original Message----- From: Zeng, Star Sent: Wednesday, September 20, 2017 2:29 PM To: Yao, Jiewen <jiewen.yao@intel.com>; edk2-devel@lists.01.org Cc: Zeng, Star <star.zeng@intel.com> Subject: RE: [PATCH 2/3] IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table. The typo "reset" in commit log? Should it be "reset"? Thanks, Star -----Original Message----- From: Yao, Jiewen Sent: Sunday, September 17, 2017 2:07 PM To: edk2-devel@lists.01.org Cc: Zeng, Star <star.zeng@intel.com> Subject: [PATCH 2/3] IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table. In order to support PEI graphic, we let VTdPmrPei driver parse DMAR table RMRR entry and allow the UMA access. If a system has no PEI IGD, no RMRR is needed. The behavior is unchanged. If a system has PEI IGD, it must report RMRR in PEI phase. The PeiVTdPrm will program the IGD VTd engine to skip the RMRR region, and program the reset PCI VTd engine to skip the another DMA buffer allocated in PEI phase for other device driver. Cc: Star Zeng <star.zeng@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> --- IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c | 52 +- IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c | 581 +++++++++++++++++++- IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h | 20 +- 3 files changed, 624 insertions(+), 29 deletions(-) diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c index ef08e29..be841aa 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c @@ -22,7 +22,7 @@ #include "IntelVTdPmrPei.h" -extern EDKII_VTD_INFO_PPI *mVTdInfoPpi; +extern VTD_INFO *mVTdInfo; /** Get protected low memory alignment. @@ -60,7 +60,7 @@ GetPhmrAlignment ( UINT64 Data64; UINT8 HostAddressWidth; - HostAddressWidth = mVTdInfoPpi->HostAddressWidth; + HostAddressWidth = mVTdInfo->HostAddressWidth; MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF); Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG); @@ -73,11 +73,13 @@ GetPhmrAlignment ( /** Get protected low memory alignment. + @param EngineMask The mask of the VTd engine to be accessed. + @return protected low memory alignment. **/ UINT32 GetLowMemoryAlignment ( - VOID + IN UINT64 EngineMask ) { UINTN Index; @@ -85,8 +87,11 @@ GetLowMemoryAlignment ( UINT32 FinalAlignment; FinalAlignment = 0; - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { - Alignment = GetPlmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { + if ((EngineMask & LShiftU64(1, Index)) == 0) { + continue; + } + Alignment = GetPlmrAlignment + ((UINTN)mVTdInfo->VTdEngineAddress[Index]); if (FinalAlignment < Alignment) { FinalAlignment = Alignment; } @@ -97,11 +102,13 @@ GetLowMemoryAlignment ( /** Get protected high memory alignment. + @param EngineMask The mask of the VTd engine to be accessed. + @return protected high memory alignment. **/ UINT64 GetHighMemoryAlignment ( - VOID + IN UINT64 EngineMask ) { UINTN Index; @@ -109,8 +116,11 @@ GetHighMemoryAlignment ( UINT64 FinalAlignment; FinalAlignment = 0; - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { - Alignment = GetPhmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { + if ((EngineMask & LShiftU64(1, Index)) == 0) { + continue; + } + Alignment = GetPhmrAlignment + ((UINTN)mVTdInfo->VTdEngineAddress[Index]); if (FinalAlignment < Alignment) { FinalAlignment = Alignment; } @@ -246,6 +256,7 @@ SetPmrRegion ( /** Set DMA protected region. + @param EngineMask The mask of the VTd engine to be accessed. @param LowMemoryBase The protected low memory region base. @param LowMemoryLength The protected low memory region length. @param HighMemoryBase The protected high memory region base. @@ -256,6 +267,7 @@ SetPmrRegion ( **/ EFI_STATUS SetDmaProtectedRange ( + IN UINT64 EngineMask, IN UINT32 LowMemoryBase, IN UINT32 LowMemoryLength, IN UINT64 HighMemoryBase, @@ -265,12 +277,15 @@ SetDmaProtectedRange ( UINTN Index; EFI_STATUS Status; - DEBUG ((DEBUG_INFO, "SetDmaProtectedRange - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength)); + DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] + [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, + HighMemoryBase, HighMemoryLength)); - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { - DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { + if ((EngineMask & LShiftU64(1, Index)) == 0) { + continue; + } + DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); Status = SetPmrRegion ( - (UINTN)mVTdInfoPpi->VTdEngineAddress[Index], + (UINTN)mVTdInfo->VTdEngineAddress[Index], LowMemoryBase, LowMemoryLength, HighMemoryBase, @@ -279,7 +294,7 @@ SetDmaProtectedRange ( if (EFI_ERROR(Status)) { return Status; } - Status = EnablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); if (EFI_ERROR(Status)) { return Status; } @@ -291,11 +306,13 @@ SetDmaProtectedRange ( /** Diable DMA protection. + @param EngineMask The mask of the VTd engine to be accessed. + @retval DMA protection is disabled. **/ EFI_STATUS DisableDmaProtection ( - VOID + IN UINT64 EngineMask ) { UINTN Index; @@ -303,8 +320,11 @@ DisableDmaProtection ( DEBUG ((DEBUG_INFO, "DisableDmaProtection\n")); - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { - Status = DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { + if ((EngineMask & LShiftU64(1, Index)) == 0) { + continue; + } + Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); if (EFI_ERROR(Status)) { return Status; } diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c index d118b7e..063e8cd 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c @@ -29,7 +29,9 @@ #define TOTAL_DMA_BUFFER_SIZE SIZE_4MB -EDKII_VTD_INFO_PPI *mVTdInfoPpi; +EFI_ACPI_DMAR_HEADER *mAcpiDmarTable; +VTD_INFO *mVTdInfo; +UINT64 mEngineMask; UINTN mDmaBufferBase; UINTN mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE; UINTN mDmaBufferCurrentTop; @@ -48,15 +50,19 @@ typedef struct { PEI Memory Layout: + +------------------+ <=============== PHMR.Limit (Top of memory) + | Mem Resource | + | | + +------------------+ <------- EfiMemoryTop | PEI allocated | - =========== +==================+ + =========== +==================+ <=============== PHMR.Base ^ | Commom Buf | | | -------------- | DMA Buffer | * DMA FREE * | | | -------------- | V | Read/Write Buf | - =========== +==================+ + =========== +==================+ <=============== PLMR.Limit | PEI allocated | | -------------- | <------- EfiFreeMemoryTop | * PEI FREE * | @@ -70,6 +76,9 @@ typedef struct { | Mem Alloc Hob | +------------------+ + | | + | Mem Resource | + +------------------+ <=============== PLMR.Base (0) **/ @@ -457,20 +466,21 @@ DumpPhitHob ( /** Get the highest memory. - @param HobList the HOB list. - @return the highest memory. **/ UINT64 GetTopMemory ( - IN VOID *HobList + VOID ) { + VOID *HobList; EFI_PEI_HOB_POINTERS Hob; EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; UINT64 TopMemory; UINT64 ResourceTop; + HobList = GetHobList (); + TopMemory = 0; for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) { if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { @@ -525,8 +535,8 @@ InitDmaProtection ( ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop); - LowMemoryAlignment = GetLowMemoryAlignment (); - HighMemoryAlignment = GetHighMemoryAlignment (); + LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask); + HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask); if (LowMemoryAlignment < HighMemoryAlignment) { MemoryAlignment = (UINTN)HighMemoryAlignment; } else { @@ -542,9 +552,10 @@ InitDmaProtection ( LowBottom = 0; LowTop = *DmaBufferBase; HighBottom = *DmaBufferBase + DmaBufferSize; - HighTop = GetTopMemory (HobList); + HighTop = GetTopMemory (); Status = SetDmaProtectedRange ( + mEngineMask, (UINT32)LowBottom, (UINT32)(LowTop - LowBottom), HighBottom, @@ -559,6 +570,541 @@ InitDmaProtection ( } /** + Dump DMAR DeviceScopeEntry. + + @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry **/ VOID +DumpDmarDeviceScopeEntry ( + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry + ) +{ + UINTN PciPathNumber; + UINTN PciPathIndex; + EFI_ACPI_DMAR_PCI_PATH *PciPath; + + if (DmarDeviceScopeEntry == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, + " *************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + " * DMA-Remapping Device Scope Entry Structure *\n" + )); + DEBUG ((DEBUG_INFO, + " *************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + (sizeof(UINTN) == sizeof(UINT64)) ? + " DMAR Device Scope Entry address ...................... 0x%016lx\n" : + " DMAR Device Scope Entry address ...................... 0x%08x\n", + DmarDeviceScopeEntry + )); + DEBUG ((DEBUG_INFO, + " Device Scope Entry Type ............................ 0x%02x\n", + DmarDeviceScopeEntry->Type + )); + switch (DmarDeviceScopeEntry->Type) { case + EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT: + DEBUG ((DEBUG_INFO, + " PCI Endpoint Device\n" + )); + break; + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: + DEBUG ((DEBUG_INFO, + " PCI Sub-hierachy\n" + )); + break; + default: + break; + } + DEBUG ((DEBUG_INFO, + " Length ............................................. 0x%02x\n", + DmarDeviceScopeEntry->Length + )); + DEBUG ((DEBUG_INFO, + " Enumeration ID ..................................... 0x%02x\n", + DmarDeviceScopeEntry->EnumerationId + )); + DEBUG ((DEBUG_INFO, + " Starting Bus Number ................................ 0x%02x\n", + DmarDeviceScopeEntry->StartBusNumber + )); + + PciPathNumber = (DmarDeviceScopeEntry->Length - + sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / + sizeof(EFI_ACPI_DMAR_PCI_PATH); PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1); for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) { + DEBUG ((DEBUG_INFO, + " Device ............................................. 0x%02x\n", + PciPath[PciPathIndex].Device + )); + DEBUG ((DEBUG_INFO, + " Function ........................................... 0x%02x\n", + PciPath[PciPathIndex].Function + )); + } + + DEBUG ((DEBUG_INFO, + " *************************************************************************\n\n" + )); + + return; +} + +/** + Dump DMAR RMRR table. + + @param[in] Rmrr DMAR RMRR table +**/ +VOID +DumpDmarRmrr ( + IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr + ) +{ + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; + INTN RmrrLen; + + if (Rmrr == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + " * Reserved Memory Region Reporting Structure *\n" + )); + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + (sizeof(UINTN) == sizeof(UINT64)) ? + " RMRR address ........................................... 0x%016lx\n" : + " RMRR address ........................................... 0x%08x\n", + Rmrr + )); + DEBUG ((DEBUG_INFO, + " Type ................................................. 0x%04x\n", + Rmrr->Header.Type + )); + DEBUG ((DEBUG_INFO, + " Length ............................................... 0x%04x\n", + Rmrr->Header.Length + )); + DEBUG ((DEBUG_INFO, + " Segment Number ....................................... 0x%04x\n", + Rmrr->SegmentNumber + )); + DEBUG ((DEBUG_INFO, + " Reserved Memory Region Base Address .................. 0x%016lx\n", + Rmrr->ReservedMemoryRegionBaseAddress + )); + DEBUG ((DEBUG_INFO, + " Reserved Memory Region Limit Address ................. 0x%016lx\n", + Rmrr->ReservedMemoryRegionLimitAddress + )); + + RmrrLen = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER); + DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)(Rmrr + 1); while (RmrrLen > 0) { + DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); + RmrrLen -= DmarDeviceScopeEntry->Length; + DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } + + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n\n" + )); + + return; +} + +/** + Dump DMAR DRHD table. + + @param[in] Drhd DMAR DRHD table +**/ +VOID +DumpDmarDrhd ( + IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd + ) +{ + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; + INTN DrhdLen; + + if (Drhd == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + " * DMA-Remapping Hardware Definition Structure *\n" + )); + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + (sizeof(UINTN) == sizeof(UINT64)) ? + " DRHD address ........................................... 0x%016lx\n" : + " DRHD address ........................................... 0x%08x\n", + Drhd + )); + DEBUG ((DEBUG_INFO, + " Type ................................................. 0x%04x\n", + Drhd->Header.Type + )); + DEBUG ((DEBUG_INFO, + " Length ............................................... 0x%04x\n", + Drhd->Header.Length + )); + DEBUG ((DEBUG_INFO, + " Flags ................................................ 0x%02x\n", + Drhd->Flags + )); + DEBUG ((DEBUG_INFO, + " INCLUDE_PCI_ALL .................................... 0x%02x\n", + Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL + )); + DEBUG ((DEBUG_INFO, + " Segment Number ....................................... 0x%04x\n", + Drhd->SegmentNumber + )); + DEBUG ((DEBUG_INFO, + " Register Base Address ................................ 0x%016lx\n", + Drhd->RegisterBaseAddress + )); + + DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER); + DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)(Drhd + 1); while (DrhdLen > 0) { + DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); + DrhdLen -= DmarDeviceScopeEntry->Length; + DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } + + DEBUG ((DEBUG_INFO, + " ***************************************************************************\n\n" + )); + + return; +} + +/** + Dump DMAR ACPI table. + + @param[in] Dmar DMAR ACPI table +**/ +VOID +DumpAcpiDMAR ( + IN EFI_ACPI_DMAR_HEADER *Dmar + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + INTN DmarLen; + + if (Dmar == NULL) { + return; + } + + // + // Dump Dmar table + // + DEBUG ((DEBUG_INFO, + "*****************************************************************************\n" + )); + DEBUG ((DEBUG_INFO, + "* DMAR Table *\n" + )); + DEBUG ((DEBUG_INFO, + "*****************************************************************************\n" + )); + + DEBUG ((DEBUG_INFO, + (sizeof(UINTN) == sizeof(UINT64)) ? + "DMAR address ............................................. 0x%016lx\n" : + "DMAR address ............................................. 0x%08x\n", + Dmar + )); + + DEBUG ((DEBUG_INFO, + " Table Contents:\n" + )); + DEBUG ((DEBUG_INFO, + " Host Address Width ................................... 0x%02x\n", + Dmar->HostAddressWidth + )); + DEBUG ((DEBUG_INFO, + " Flags ................................................ 0x%02x\n", + Dmar->Flags + )); + DEBUG ((DEBUG_INFO, + " INTR_REMAP ......................................... 0x%02x\n", + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP + )); + DEBUG ((DEBUG_INFO, + " X2APIC_OPT_OUT_SET ................................. 0x%02x\n", + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT + )); + + DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER); + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1); while + (DmarLen > 0) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_DRHD: + DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); + break; + case EFI_ACPI_DMAR_TYPE_RMRR: + DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); + break; + default: + break; + } + DmarLen -= DmarHeader->Length; + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + + DmarHeader->Length); } + + DEBUG ((DEBUG_INFO, + "*****************************************************************************\n\n" + )); + + return; +} + +/** + Get VTd engine number. + + @return the VTd engine number. +**/ +UINTN +GetVtdEngineNumber ( + VOID + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + UINTN VtdIndex; + + VtdIndex = 0; + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER +*)((UINTN)(mAcpiDmarTable + 1)); + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_DRHD: + VtdIndex++; + break; + default: + break; + } + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + +DmarHeader->Length); + } + return VtdIndex ; +} + +/** + Process DMAR DHRD table. + + @param[in] VtdIndex The index of VTd engine. + @param[in] DmarDrhd The DRHD table. +**/ +VOID +ProcessDhrd ( + IN UINTN VtdIndex, + IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd + ) +{ + DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, +DmarDrhd->RegisterBaseAddress)); + mVTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress; +} + +/** + Parse DMAR DRHD table. + + @return EFI_SUCCESS The DMAR DRHD table is parsed. +**/ +EFI_STATUS +ParseDmarAcpiTableDrhd ( + VOID + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + UINTN VtdUnitNumber; + UINTN VtdIndex; + + VtdUnitNumber = GetVtdEngineNumber (); if (VtdUnitNumber == 0) { + return EFI_UNSUPPORTED; + } + + mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * + sizeof(UINT64)); if (mVTdInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth; + mVTdInfo->VTdEngineCount = VtdUnitNumber; + + VtdIndex = 0; + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER + *)((UINTN)(mAcpiDmarTable + 1)); while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_DRHD: + ASSERT (VtdIndex < VtdUnitNumber); + ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); + VtdIndex++; + + break; + + default: + break; + } + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + + DmarHeader->Length); } ASSERT (VtdIndex == VtdUnitNumber); + + // + // Initialize the engine mask to all. + // + mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1; + + return EFI_SUCCESS; +} + +/** + Return the VTd engine index according to the Segment and DevScopeEntry. + + @param Segment The segment of the VTd engine + @param DevScopeEntry The DevScopeEntry of the VTd engine + + @return The VTd engine index according to the Segment and DevScopeEntry. + @retval -1 The VTd engine is not found. +**/ +UINTN +GetVTdEngineFromDevScopeEntry ( + IN UINT16 Segment, + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + UINTN VtdIndex; + EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd; + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *ThisDevScopeEntry; + + VtdIndex = 0; + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER +*)((UINTN)(mAcpiDmarTable + 1)); + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_DRHD: + DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader; + if (DmarDrhd->SegmentNumber != Segment) { + // Mismatch + break; + } + if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) || + ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) { + // No DevScopeEntry + // Do not handle PCI_ALL + break; + } + ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1)); + while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) { + if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) && + (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) { + return VtdIndex; + } + ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length); + } + break; + default: + break; + } + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + +DmarHeader->Length); + } + return (UINTN)-1; +} + +/** + Process DMAR RMRR table. + + @param[in] DmarRmrr The RMRR table. +**/ +VOID +ProcessRmrr ( + IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr + ) +{ + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry; + UINTN VTdIndex; + UINT64 RmrrMask; + UINTN LowBottom; + UINTN LowTop; + UINTN HighBottom; + UINT64 HighTop; + + DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", + DmarRmrr->ReservedMemoryRegionBaseAddress, + DmarRmrr->ReservedMemoryRegionLimitAddress)); + + if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) || + (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) { + return ; + } + + DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER + *)((UINTN)(DmarRmrr + 1)); while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) { + ASSERT (DmarDevScopeEntry->Type == + EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT); + + VTdIndex = GetVTdEngineFromDevScopeEntry (DmarRmrr->SegmentNumber, DmarDevScopeEntry); + if (VTdIndex != (UINTN)-1) { + RmrrMask = LShiftU64 (1, VTdIndex); + + LowBottom = 0; + LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress; + HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1; + HighTop = GetTopMemory (); + + SetDmaProtectedRange ( + RmrrMask, + 0, + (UINT32)(LowTop - LowBottom), + HighBottom, + HighTop - HighBottom + ); + + // + // Remove the engine from the engine mask. + // The assumption is that any other PEI driver does not access + // the device covered by this engine. + // + mEngineMask = mEngineMask & (~RmrrMask); + } + + DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER +*)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length); + } +} + +/** + Parse DMAR DRHD table. +**/ +VOID +ParseDmarAcpiTableRmrr ( + VOID + ) +{ + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; + + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER +*)((UINTN)(mAcpiDmarTable + 1)); + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { + switch (DmarHeader->Type) { + case EFI_ACPI_DMAR_TYPE_RMRR: + ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); + break; + default: + break; + } + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + +DmarHeader->Length); + } +} + +/** Initializes the Intel VTd PMR PEIM. @param FileHandle Handle of the file being invoked. @@ -585,10 +1131,25 @@ IntelVTdPmrInitialize ( &gEdkiiVTdInfoPpiGuid, 0, NULL, - (VOID **)&mVTdInfoPpi + (VOID **)&mAcpiDmarTable ); ASSERT_EFI_ERROR(Status); + DumpAcpiDMAR (mAcpiDmarTable); + + // + // Get DMAR information to local VTdInfo // Status = + ParseDmarAcpiTableDrhd (); if (EFI_ERROR(Status)) { + return Status; + } + + // + // If there is RMRR memory, parse it here. + // + ParseDmarAcpiTableRmrr (); + // // Find a pre-memory in resource hob as DMA buffer // Mark PEI memory to be DMA protected. diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h index aa5926a7..720f5d4 100644 --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h @@ -15,9 +15,16 @@ #ifndef __DMA_ACCESS_LIB_H__ #define __DMA_ACCESS_LIB_H__ +typedef struct { + UINT8 HostAddressWidth; + UINTN VTdEngineCount; + UINT64 VTdEngineAddress[1]; +} VTD_INFO; + /** Set DMA protected region. + @param EngineMask The mask of the VTd engine to be accessed. @param LowMemoryBase The protected low memory region base. @param LowMemoryLength The protected low memory region length. @param HighMemoryBase The protected high memory region base. @@ -28,6 +35,7 @@ **/ EFI_STATUS SetDmaProtectedRange ( + IN UINT64 EngineMask, IN UINT32 LowMemoryBase, IN UINT32 LowMemoryLength, IN UINT64 HighMemoryBase, @@ -37,31 +45,37 @@ SetDmaProtectedRange ( /** Diable DMA protection. + @param EngineMask The mask of the VTd engine to be accessed. + @retval DMA protection is disabled. **/ EFI_STATUS DisableDmaProtection ( - VOID + IN UINT64 EngineMask ); /** Get protected low memory alignment. + @param EngineMask The mask of the VTd engine to be accessed. + @return protected low memory alignment. **/ UINT32 GetLowMemoryAlignment ( - VOID + IN UINT64 EngineMask ); /** Get protected high memory alignment. + @param EngineMask The mask of the VTd engine to be accessed. + @return protected high memory alignment. **/ UINT64 GetHighMemoryAlignment ( - VOID + IN UINT64 EngineMask ); #endif -- 2.7.4.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
Yes, Typo. will be fixed. > -----Original Message----- > From: Zeng, Star > Sent: Wednesday, September 20, 2017 2:30 PM > To: Yao, Jiewen <jiewen.yao@intel.com>; edk2-devel@lists.01.org > Cc: Zeng, Star <star.zeng@intel.com> > Subject: RE: [PATCH 2/3] IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table. > > Sorry, should it be "rest"? > > -----Original Message----- > From: Zeng, Star > Sent: Wednesday, September 20, 2017 2:29 PM > To: Yao, Jiewen <jiewen.yao@intel.com>; edk2-devel@lists.01.org > Cc: Zeng, Star <star.zeng@intel.com> > Subject: RE: [PATCH 2/3] IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table. > > The typo "reset" in commit log? Should it be "reset"? > > Thanks, > Star > -----Original Message----- > From: Yao, Jiewen > Sent: Sunday, September 17, 2017 2:07 PM > To: edk2-devel@lists.01.org > Cc: Zeng, Star <star.zeng@intel.com> > Subject: [PATCH 2/3] IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table. > > In order to support PEI graphic, we let VTdPmrPei driver parse DMAR table RMRR > entry and allow the UMA access. > > If a system has no PEI IGD, no RMRR is needed. The behavior is unchanged. > > If a system has PEI IGD, it must report RMRR in PEI phase. > The PeiVTdPrm will program the IGD VTd engine to skip the RMRR region, and > program the reset PCI VTd engine to skip the another DMA buffer allocated in PEI > phase for other device driver. > > Cc: Star Zeng <star.zeng@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> > --- > IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c | 52 +- > IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c | 581 > +++++++++++++++++++- > IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h | 20 +- > 3 files changed, 624 insertions(+), 29 deletions(-) > > diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c > b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c > index ef08e29..be841aa 100644 > --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c > +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c > @@ -22,7 +22,7 @@ > > #include "IntelVTdPmrPei.h" > > -extern EDKII_VTD_INFO_PPI *mVTdInfoPpi; > +extern VTD_INFO *mVTdInfo; > > /** > Get protected low memory alignment. > @@ -60,7 +60,7 @@ GetPhmrAlignment ( > UINT64 Data64; > UINT8 HostAddressWidth; > > - HostAddressWidth = mVTdInfoPpi->HostAddressWidth; > + HostAddressWidth = mVTdInfo->HostAddressWidth; > > MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, > 0xFFFFFFFFFFFFFFFF); > Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG); > @@ -73,11 +73,13 @@ GetPhmrAlignment ( > /** > Get protected low memory alignment. > > + @param EngineMask The mask of the VTd engine to be accessed. > + > @return protected low memory alignment. > **/ > UINT32 > GetLowMemoryAlignment ( > - VOID > + IN UINT64 EngineMask > ) > { > UINTN Index; > @@ -85,8 +87,11 @@ GetLowMemoryAlignment ( > UINT32 FinalAlignment; > > FinalAlignment = 0; > - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { > - Alignment = GetPlmrAlignment > ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); > + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { > + if ((EngineMask & LShiftU64(1, Index)) == 0) { > + continue; > + } > + Alignment = GetPlmrAlignment > + ((UINTN)mVTdInfo->VTdEngineAddress[Index]); > if (FinalAlignment < Alignment) { > FinalAlignment = Alignment; > } > @@ -97,11 +102,13 @@ GetLowMemoryAlignment ( > /** > Get protected high memory alignment. > > + @param EngineMask The mask of the VTd engine to be accessed. > + > @return protected high memory alignment. > **/ > UINT64 > GetHighMemoryAlignment ( > - VOID > + IN UINT64 EngineMask > ) > { > UINTN Index; > @@ -109,8 +116,11 @@ GetHighMemoryAlignment ( > UINT64 FinalAlignment; > > FinalAlignment = 0; > - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { > - Alignment = GetPhmrAlignment > ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); > + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { > + if ((EngineMask & LShiftU64(1, Index)) == 0) { > + continue; > + } > + Alignment = GetPhmrAlignment > + ((UINTN)mVTdInfo->VTdEngineAddress[Index]); > if (FinalAlignment < Alignment) { > FinalAlignment = Alignment; > } > @@ -246,6 +256,7 @@ SetPmrRegion ( > /** > Set DMA protected region. > > + @param EngineMask The mask of the VTd engine to be accessed. > @param LowMemoryBase The protected low memory region base. > @param LowMemoryLength The protected low memory region length. > @param HighMemoryBase The protected high memory region base. > @@ -256,6 +267,7 @@ SetPmrRegion ( > **/ > EFI_STATUS > SetDmaProtectedRange ( > + IN UINT64 EngineMask, > IN UINT32 LowMemoryBase, > IN UINT32 LowMemoryLength, > IN UINT64 HighMemoryBase, > @@ -265,12 +277,15 @@ SetDmaProtectedRange ( > UINTN Index; > EFI_STATUS Status; > > - DEBUG ((DEBUG_INFO, "SetDmaProtectedRange - [0x%x, 0x%x] [0x%lx, > 0x%lx]\n", LowMemoryBase, LowMemoryLength, HighMemoryBase, > HighMemoryLength)); > + DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] > + [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, > + HighMemoryBase, HighMemoryLength)); > > - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { > - DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); > + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { > + if ((EngineMask & LShiftU64(1, Index)) == 0) { > + continue; > + } > + DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); > Status = SetPmrRegion ( > - (UINTN)mVTdInfoPpi->VTdEngineAddress[Index], > + (UINTN)mVTdInfo->VTdEngineAddress[Index], > LowMemoryBase, > LowMemoryLength, > HighMemoryBase, > @@ -279,7 +294,7 @@ SetDmaProtectedRange ( > if (EFI_ERROR(Status)) { > return Status; > } > - Status = EnablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); > + Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); > if (EFI_ERROR(Status)) { > return Status; > } > @@ -291,11 +306,13 @@ SetDmaProtectedRange ( > /** > Diable DMA protection. > > + @param EngineMask The mask of the VTd engine to be accessed. > + > @retval DMA protection is disabled. > **/ > EFI_STATUS > DisableDmaProtection ( > - VOID > + IN UINT64 EngineMask > ) > { > UINTN Index; > @@ -303,8 +320,11 @@ DisableDmaProtection ( > > DEBUG ((DEBUG_INFO, "DisableDmaProtection\n")); > > - for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) { > - Status = DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]); > + for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) { > + if ((EngineMask & LShiftU64(1, Index)) == 0) { > + continue; > + } > + Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]); > if (EFI_ERROR(Status)) { > return Status; > } > diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c > b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c > index d118b7e..063e8cd 100644 > --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c > +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c > @@ -29,7 +29,9 @@ > > #define TOTAL_DMA_BUFFER_SIZE SIZE_4MB > > -EDKII_VTD_INFO_PPI *mVTdInfoPpi; > +EFI_ACPI_DMAR_HEADER *mAcpiDmarTable; > +VTD_INFO *mVTdInfo; > +UINT64 mEngineMask; > UINTN mDmaBufferBase; > UINTN mDmaBufferSize = > TOTAL_DMA_BUFFER_SIZE; > UINTN mDmaBufferCurrentTop; > @@ -48,15 +50,19 @@ typedef struct { > > PEI Memory Layout: > > + +------------------+ <=============== PHMR.Limit (Top of > memory) > + | Mem Resource | > + | | > + > +------------------+ <------- EfiMemoryTop > | PEI allocated | > - =========== +==================+ > + =========== +==================+ <=============== PHMR.Base > ^ | Commom Buf | > | | -------------- | > DMA Buffer | * DMA FREE * | > | | -------------- | > V | Read/Write Buf | > - =========== +==================+ > + =========== +==================+ <=============== PLMR.Limit > | PEI allocated | > | -------------- | <------- EfiFreeMemoryTop > | * PEI FREE * | > @@ -70,6 +76,9 @@ typedef struct { > | Mem Alloc Hob | > +------------------+ > > + | | > + | Mem Resource | > + +------------------+ <=============== PLMR.Base (0) > **/ > > > @@ -457,20 +466,21 @@ DumpPhitHob ( > /** > Get the highest memory. > > - @param HobList the HOB list. > - > @return the highest memory. > **/ > UINT64 > GetTopMemory ( > - IN VOID *HobList > + VOID > ) > { > + VOID *HobList; > EFI_PEI_HOB_POINTERS Hob; > EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; > UINT64 TopMemory; > UINT64 ResourceTop; > > + HobList = GetHobList (); > + > TopMemory = 0; > for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = > GET_NEXT_HOB (Hob)) { > if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) > { @@ -525,8 +535,8 @@ InitDmaProtection ( > > ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop); > > - LowMemoryAlignment = GetLowMemoryAlignment (); > - HighMemoryAlignment = GetHighMemoryAlignment (); > + LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask); > + HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask); > if (LowMemoryAlignment < HighMemoryAlignment) { > MemoryAlignment = (UINTN)HighMemoryAlignment; > } else { > @@ -542,9 +552,10 @@ InitDmaProtection ( > LowBottom = 0; > LowTop = *DmaBufferBase; > HighBottom = *DmaBufferBase + DmaBufferSize; > - HighTop = GetTopMemory (HobList); > + HighTop = GetTopMemory (); > > Status = SetDmaProtectedRange ( > + mEngineMask, > (UINT32)LowBottom, > (UINT32)(LowTop - LowBottom), > HighBottom, > @@ -559,6 +570,541 @@ InitDmaProtection ( } > > /** > + Dump DMAR DeviceScopeEntry. > + > + @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry **/ VOID > +DumpDmarDeviceScopeEntry ( > + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > *DmarDeviceScopeEntry > + ) > +{ > + UINTN PciPathNumber; > + UINTN PciPathIndex; > + EFI_ACPI_DMAR_PCI_PATH *PciPath; > + > + if (DmarDeviceScopeEntry == NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > ************\n" > + )); > + DEBUG ((DEBUG_INFO, > + " * DMA-Remapping Device Scope Entry Structure > *\n" > + )); > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > ************\n" > + )); > + DEBUG ((DEBUG_INFO, > + (sizeof(UINTN) == sizeof(UINT64)) ? > + " DMAR Device Scope Entry address ...................... 0x%016lx\n" : > + " DMAR Device Scope Entry address ...................... 0x%08x\n", > + DmarDeviceScopeEntry > + )); > + DEBUG ((DEBUG_INFO, > + " Device Scope Entry Type ............................ 0x%02x\n", > + DmarDeviceScopeEntry->Type > + )); > + switch (DmarDeviceScopeEntry->Type) { case > + EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT: > + DEBUG ((DEBUG_INFO, > + " PCI Endpoint Device\n" > + )); > + break; > + case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: > + DEBUG ((DEBUG_INFO, > + " PCI Sub-hierachy\n" > + )); > + break; > + default: > + break; > + } > + DEBUG ((DEBUG_INFO, > + " Length ............................................. 0x%02x\n", > + DmarDeviceScopeEntry->Length > + )); > + DEBUG ((DEBUG_INFO, > + " Enumeration ID ..................................... 0x%02x\n", > + DmarDeviceScopeEntry->EnumerationId > + )); > + DEBUG ((DEBUG_INFO, > + " Starting Bus Number ................................ 0x%02x\n", > + DmarDeviceScopeEntry->StartBusNumber > + )); > + > + PciPathNumber = (DmarDeviceScopeEntry->Length - > + sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / > + sizeof(EFI_ACPI_DMAR_PCI_PATH); PciPath = (EFI_ACPI_DMAR_PCI_PATH > *)(DmarDeviceScopeEntry + 1); for (PciPathIndex = 0; PciPathIndex < > PciPathNumber; PciPathIndex++) { > + DEBUG ((DEBUG_INFO, > + " Device ............................................. 0x%02x\n", > + PciPath[PciPathIndex].Device > + )); > + DEBUG ((DEBUG_INFO, > + " Function ........................................... 0x%02x\n", > + PciPath[PciPathIndex].Function > + )); > + } > + > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > ************\n\n" > + )); > + > + return; > +} > + > +/** > + Dump DMAR RMRR table. > + > + @param[in] Rmrr DMAR RMRR table > +**/ > +VOID > +DumpDmarRmrr ( > + IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr > + ) > +{ > + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > *DmarDeviceScopeEntry; > + INTN RmrrLen; > + > + if (Rmrr == NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > **************\n" > + )); > + DEBUG ((DEBUG_INFO, > + " * Reserved Memory Region Reporting Structure > *\n" > + )); > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > **************\n" > + )); > + DEBUG ((DEBUG_INFO, > + (sizeof(UINTN) == sizeof(UINT64)) ? > + " RMRR address ........................................... 0x%016lx\n" : > + " RMRR address ........................................... 0x%08x\n", > + Rmrr > + )); > + DEBUG ((DEBUG_INFO, > + " Type ................................................. 0x%04x\n", > + Rmrr->Header.Type > + )); > + DEBUG ((DEBUG_INFO, > + " Length ............................................... 0x%04x\n", > + Rmrr->Header.Length > + )); > + DEBUG ((DEBUG_INFO, > + " Segment Number ....................................... 0x%04x\n", > + Rmrr->SegmentNumber > + )); > + DEBUG ((DEBUG_INFO, > + " Reserved Memory Region Base Address .................. 0x%016lx\n", > + Rmrr->ReservedMemoryRegionBaseAddress > + )); > + DEBUG ((DEBUG_INFO, > + " Reserved Memory Region Limit Address ................. 0x%016lx\n", > + Rmrr->ReservedMemoryRegionLimitAddress > + )); > + > + RmrrLen = Rmrr->Header.Length - > sizeof(EFI_ACPI_DMAR_RMRR_HEADER); > + DmarDeviceScopeEntry = > (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > + *)(Rmrr + 1); while (RmrrLen > 0) { > + DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); > + RmrrLen -= DmarDeviceScopeEntry->Length; > + DmarDeviceScopeEntry = > (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > + *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } > + > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > **************\n\n" > + )); > + > + return; > +} > + > +/** > + Dump DMAR DRHD table. > + > + @param[in] Drhd DMAR DRHD table > +**/ > +VOID > +DumpDmarDrhd ( > + IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd > + ) > +{ > + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > *DmarDeviceScopeEntry; > + INTN DrhdLen; > + > + if (Drhd == NULL) { > + return; > + } > + > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > **************\n" > + )); > + DEBUG ((DEBUG_INFO, > + " * DMA-Remapping Hardware Definition Structure > *\n" > + )); > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > **************\n" > + )); > + DEBUG ((DEBUG_INFO, > + (sizeof(UINTN) == sizeof(UINT64)) ? > + " DRHD address ........................................... 0x%016lx\n" : > + " DRHD address ........................................... 0x%08x\n", > + Drhd > + )); > + DEBUG ((DEBUG_INFO, > + " Type ................................................. 0x%04x\n", > + Drhd->Header.Type > + )); > + DEBUG ((DEBUG_INFO, > + " Length ............................................... 0x%04x\n", > + Drhd->Header.Length > + )); > + DEBUG ((DEBUG_INFO, > + " Flags ................................................ 0x%02x\n", > + Drhd->Flags > + )); > + DEBUG ((DEBUG_INFO, > + " INCLUDE_PCI_ALL .................................... 0x%02x\n", > + Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL > + )); > + DEBUG ((DEBUG_INFO, > + " Segment Number ....................................... 0x%04x\n", > + Drhd->SegmentNumber > + )); > + DEBUG ((DEBUG_INFO, > + " Register Base Address ................................ 0x%016lx\n", > + Drhd->RegisterBaseAddress > + )); > + > + DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER); > + DmarDeviceScopeEntry = > (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > + *)(Drhd + 1); while (DrhdLen > 0) { > + DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); > + DrhdLen -= DmarDeviceScopeEntry->Length; > + DmarDeviceScopeEntry = > (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > + *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } > + > + DEBUG ((DEBUG_INFO, > + " > ************************************************************* > **************\n\n" > + )); > + > + return; > +} > + > +/** > + Dump DMAR ACPI table. > + > + @param[in] Dmar DMAR ACPI table > +**/ > +VOID > +DumpAcpiDMAR ( > + IN EFI_ACPI_DMAR_HEADER *Dmar > + ) > +{ > + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; > + INTN DmarLen; > + > + if (Dmar == NULL) { > + return; > + } > + > + // > + // Dump Dmar table > + // > + DEBUG ((DEBUG_INFO, > + > "************************************************************* > ****************\n" > + )); > + DEBUG ((DEBUG_INFO, > + "* DMAR Table > *\n" > + )); > + DEBUG ((DEBUG_INFO, > + > "************************************************************* > ****************\n" > + )); > + > + DEBUG ((DEBUG_INFO, > + (sizeof(UINTN) == sizeof(UINT64)) ? > + "DMAR address ............................................. 0x%016lx\n" : > + "DMAR address ............................................. 0x%08x\n", > + Dmar > + )); > + > + DEBUG ((DEBUG_INFO, > + " Table Contents:\n" > + )); > + DEBUG ((DEBUG_INFO, > + " Host Address Width ................................... 0x%02x\n", > + Dmar->HostAddressWidth > + )); > + DEBUG ((DEBUG_INFO, > + " Flags ................................................ 0x%02x\n", > + Dmar->Flags > + )); > + DEBUG ((DEBUG_INFO, > + " INTR_REMAP ......................................... 0x%02x\n", > + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP > + )); > + DEBUG ((DEBUG_INFO, > + " X2APIC_OPT_OUT_SET ................................. 0x%02x\n", > + Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT > + )); > + > + DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER); > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1); while > + (DmarLen > 0) { > + switch (DmarHeader->Type) { > + case EFI_ACPI_DMAR_TYPE_DRHD: > + DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); > + break; > + case EFI_ACPI_DMAR_TYPE_RMRR: > + DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); > + break; > + default: > + break; > + } > + DmarLen -= DmarHeader->Length; > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > *)((UINTN)DmarHeader + > + DmarHeader->Length); } > + > + DEBUG ((DEBUG_INFO, > + > "************************************************************* > ****************\n\n" > + )); > + > + return; > +} > + > +/** > + Get VTd engine number. > + > + @return the VTd engine number. > +**/ > +UINTN > +GetVtdEngineNumber ( > + VOID > + ) > +{ > + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; > + UINTN VtdIndex; > + > + VtdIndex = 0; > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > +*)((UINTN)(mAcpiDmarTable + 1)); > + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + > mAcpiDmarTable->Header.Length) { > + switch (DmarHeader->Type) { > + case EFI_ACPI_DMAR_TYPE_DRHD: > + VtdIndex++; > + break; > + default: > + break; > + } > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > *)((UINTN)DmarHeader + > +DmarHeader->Length); > + } > + return VtdIndex ; > +} > + > +/** > + Process DMAR DHRD table. > + > + @param[in] VtdIndex The index of VTd engine. > + @param[in] DmarDrhd The DRHD table. > +**/ > +VOID > +ProcessDhrd ( > + IN UINTN VtdIndex, > + IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd > + ) > +{ > + DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, > +DmarDrhd->RegisterBaseAddress)); > + mVTdInfo->VTdEngineAddress[VtdIndex] = > DmarDrhd->RegisterBaseAddress; > +} > + > +/** > + Parse DMAR DRHD table. > + > + @return EFI_SUCCESS The DMAR DRHD table is parsed. > +**/ > +EFI_STATUS > +ParseDmarAcpiTableDrhd ( > + VOID > + ) > +{ > + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; > + UINTN VtdUnitNumber; > + UINTN VtdIndex; > + > + VtdUnitNumber = GetVtdEngineNumber (); if (VtdUnitNumber == 0) { > + return EFI_UNSUPPORTED; > + } > + > + mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * > + sizeof(UINT64)); if (mVTdInfo == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth; > + mVTdInfo->VTdEngineCount = VtdUnitNumber; > + > + VtdIndex = 0; > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > + *)((UINTN)(mAcpiDmarTable + 1)); while ((UINTN)DmarHeader < > (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { > + switch (DmarHeader->Type) { > + case EFI_ACPI_DMAR_TYPE_DRHD: > + ASSERT (VtdIndex < VtdUnitNumber); > + ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER > *)DmarHeader); > + VtdIndex++; > + > + break; > + > + default: > + break; > + } > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > *)((UINTN)DmarHeader + > + DmarHeader->Length); } ASSERT (VtdIndex == VtdUnitNumber); > + > + // > + // Initialize the engine mask to all. > + // > + mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1; > + > + return EFI_SUCCESS; > +} > + > +/** > + Return the VTd engine index according to the Segment and DevScopeEntry. > + > + @param Segment The segment of the VTd engine > + @param DevScopeEntry The DevScopeEntry of the VTd engine > + > + @return The VTd engine index according to the Segment and DevScopeEntry. > + @retval -1 The VTd engine is not found. > +**/ > +UINTN > +GetVTdEngineFromDevScopeEntry ( > + IN UINT16 Segment, > + IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry > + ) > +{ > + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; > + UINTN VtdIndex; > + EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd; > + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > *ThisDevScopeEntry; > + > + VtdIndex = 0; > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > +*)((UINTN)(mAcpiDmarTable + 1)); > + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + > mAcpiDmarTable->Header.Length) { > + switch (DmarHeader->Type) { > + case EFI_ACPI_DMAR_TYPE_DRHD: > + DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader; > + if (DmarDrhd->SegmentNumber != Segment) { > + // Mismatch > + break; > + } > + if ((DmarDrhd->Header.Length == > sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) || > + ((DmarDrhd->Flags & > EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) { > + // No DevScopeEntry > + // Do not handle PCI_ALL > + break; > + } > + ThisDevScopeEntry = > (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + > 1)); > + while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + > DmarDrhd->Header.Length) { > + if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) && > + (CompareMem (ThisDevScopeEntry, DevScopeEntry, > DevScopeEntry->Length) == 0)) { > + return VtdIndex; > + } > + ThisDevScopeEntry = > (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length); > + } > + break; > + default: > + break; > + } > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > *)((UINTN)DmarHeader + > +DmarHeader->Length); > + } > + return (UINTN)-1; > +} > + > +/** > + Process DMAR RMRR table. > + > + @param[in] DmarRmrr The RMRR table. > +**/ > +VOID > +ProcessRmrr ( > + IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr > + ) > +{ > + EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > *DmarDevScopeEntry; > + UINTN VTdIndex; > + UINT64 RmrrMask; > + UINTN LowBottom; > + UINTN LowTop; > + UINTN HighBottom; > + UINT64 HighTop; > + > + DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", > + DmarRmrr->ReservedMemoryRegionBaseAddress, > + DmarRmrr->ReservedMemoryRegionLimitAddress)); > + > + if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) || > + (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) { > + return ; > + } > + > + DmarDevScopeEntry = > (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > + *)((UINTN)(DmarRmrr + 1)); while ((UINTN)DmarDevScopeEntry < > (UINTN)DmarRmrr + DmarRmrr->Header.Length) { > + ASSERT (DmarDevScopeEntry->Type == > + EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT); > + > + VTdIndex = GetVTdEngineFromDevScopeEntry > (DmarRmrr->SegmentNumber, DmarDevScopeEntry); > + if (VTdIndex != (UINTN)-1) { > + RmrrMask = LShiftU64 (1, VTdIndex); > + > + LowBottom = 0; > + LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress; > + HighBottom = > (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1; > + HighTop = GetTopMemory (); > + > + SetDmaProtectedRange ( > + RmrrMask, > + 0, > + (UINT32)(LowTop - LowBottom), > + HighBottom, > + HighTop - HighBottom > + ); > + > + // > + // Remove the engine from the engine mask. > + // The assumption is that any other PEI driver does not access > + // the device covered by this engine. > + // > + mEngineMask = mEngineMask & (~RmrrMask); > + } > + > + DmarDevScopeEntry = > (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER > +*)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length); > + } > +} > + > +/** > + Parse DMAR DRHD table. > +**/ > +VOID > +ParseDmarAcpiTableRmrr ( > + VOID > + ) > +{ > + EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; > + > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > +*)((UINTN)(mAcpiDmarTable + 1)); > + while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + > mAcpiDmarTable->Header.Length) { > + switch (DmarHeader->Type) { > + case EFI_ACPI_DMAR_TYPE_RMRR: > + ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); > + break; > + default: > + break; > + } > + DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER > *)((UINTN)DmarHeader + > +DmarHeader->Length); > + } > +} > + > +/** > Initializes the Intel VTd PMR PEIM. > > @param FileHandle Handle of the file being invoked. > @@ -585,10 +1131,25 @@ IntelVTdPmrInitialize ( > &gEdkiiVTdInfoPpiGuid, > 0, > NULL, > - (VOID **)&mVTdInfoPpi > + (VOID **)&mAcpiDmarTable > ); > ASSERT_EFI_ERROR(Status); > > + DumpAcpiDMAR (mAcpiDmarTable); > + > + // > + // Get DMAR information to local VTdInfo // Status = > + ParseDmarAcpiTableDrhd (); if (EFI_ERROR(Status)) { > + return Status; > + } > + > + // > + // If there is RMRR memory, parse it here. > + // > + ParseDmarAcpiTableRmrr (); > + > // > // Find a pre-memory in resource hob as DMA buffer > // Mark PEI memory to be DMA protected. > diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h > b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h > index aa5926a7..720f5d4 100644 > --- a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h > +++ b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h > @@ -15,9 +15,16 @@ > #ifndef __DMA_ACCESS_LIB_H__ > #define __DMA_ACCESS_LIB_H__ > > +typedef struct { > + UINT8 HostAddressWidth; > + UINTN VTdEngineCount; > + UINT64 VTdEngineAddress[1]; > +} VTD_INFO; > + > /** > Set DMA protected region. > > + @param EngineMask The mask of the VTd engine to be accessed. > @param LowMemoryBase The protected low memory region base. > @param LowMemoryLength The protected low memory region length. > @param HighMemoryBase The protected high memory region base. > @@ -28,6 +35,7 @@ > **/ > EFI_STATUS > SetDmaProtectedRange ( > + IN UINT64 EngineMask, > IN UINT32 LowMemoryBase, > IN UINT32 LowMemoryLength, > IN UINT64 HighMemoryBase, > @@ -37,31 +45,37 @@ SetDmaProtectedRange ( > /** > Diable DMA protection. > > + @param EngineMask The mask of the VTd engine to be accessed. > + > @retval DMA protection is disabled. > **/ > EFI_STATUS > DisableDmaProtection ( > - VOID > + IN UINT64 EngineMask > ); > > /** > Get protected low memory alignment. > > + @param EngineMask The mask of the VTd engine to be accessed. > + > @return protected low memory alignment. > **/ > UINT32 > GetLowMemoryAlignment ( > - VOID > + IN UINT64 EngineMask > ); > > /** > Get protected high memory alignment. > > + @param EngineMask The mask of the VTd engine to be accessed. > + > @return protected high memory alignment. > **/ > UINT64 > GetHighMemoryAlignment ( > - VOID > + IN UINT64 EngineMask > ); > > #endif > -- > 2.7.4.windows.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.