IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table.
authorJiewen Yao <jiewen.yao@intel.com>
Fri, 15 Sep 2017 04:29:10 +0000 (12:29 +0800)
committerJiewen Yao <jiewen.yao@intel.com>
Wed, 20 Sep 2017 06:45:43 +0000 (14:45 +0800)
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 rest 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>
Reviewed-by: Star Zeng <star.zeng@intel.com>
IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.h

index 0fe9645..6179dfe 100644 (file)
@@ -22,7 +22,7 @@
 \r
 #include "IntelVTdPmrPei.h"\r
 \r
-extern EDKII_VTD_INFO_PPI                *mVTdInfoPpi;\r
+extern VTD_INFO                *mVTdInfo;\r
 \r
 /**\r
   Get protected low memory alignment.\r
@@ -60,7 +60,7 @@ GetPhmrAlignment (
   UINT64        Data64;\r
   UINT8         HostAddressWidth;\r
 \r
-  HostAddressWidth = mVTdInfoPpi->HostAddressWidth;\r
+  HostAddressWidth = mVTdInfo->HostAddressWidth;\r
 \r
   MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);\r
   Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);\r
@@ -73,11 +73,13 @@ GetPhmrAlignment (
 /**\r
   Get protected low memory alignment.\r
 \r
+  @param EngineMask         The mask of the VTd engine to be accessed.\r
+\r
   @return protected low memory alignment.\r
 **/\r
 UINT32\r
 GetLowMemoryAlignment (\r
-  VOID\r
+  IN UINT64        EngineMask\r
   )\r
 {\r
   UINTN         Index;\r
@@ -85,8 +87,11 @@ GetLowMemoryAlignment (
   UINT32        FinalAlignment;\r
 \r
   FinalAlignment = 0;\r
-  for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {\r
-    Alignment = GetPlmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {\r
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
+      continue;\r
+    }\r
+    Alignment = GetPlmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
     if (FinalAlignment < Alignment) {\r
       FinalAlignment = Alignment;\r
     }\r
@@ -97,11 +102,13 @@ GetLowMemoryAlignment (
 /**\r
   Get protected high memory alignment.\r
 \r
+  @param EngineMask         The mask of the VTd engine to be accessed.\r
+\r
   @return protected high memory alignment.\r
 **/\r
 UINT64\r
 GetHighMemoryAlignment (\r
-  VOID\r
+  IN UINT64        EngineMask\r
   )\r
 {\r
   UINTN         Index;\r
@@ -109,8 +116,11 @@ GetHighMemoryAlignment (
   UINT64        FinalAlignment;\r
 \r
   FinalAlignment = 0;\r
-  for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {\r
-    Alignment = GetPhmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {\r
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
+      continue;\r
+    }\r
+    Alignment = GetPhmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
     if (FinalAlignment < Alignment) {\r
       FinalAlignment = Alignment;\r
     }\r
@@ -246,6 +256,7 @@ SetPmrRegion (
 /**\r
   Set DMA protected region.\r
 \r
+  @param EngineMask         The mask of the VTd engine to be accessed.\r
   @param LowMemoryBase      The protected low memory region base.\r
   @param LowMemoryLength    The protected low memory region length.\r
   @param HighMemoryBase     The protected high memory region base.\r
@@ -256,6 +267,7 @@ SetPmrRegion (
 **/\r
 EFI_STATUS\r
 SetDmaProtectedRange (\r
+  IN UINT64        EngineMask,\r
   IN UINT32        LowMemoryBase,\r
   IN UINT32        LowMemoryLength,\r
   IN UINT64        HighMemoryBase,\r
@@ -265,12 +277,15 @@ SetDmaProtectedRange (
   UINTN       Index;\r
   EFI_STATUS  Status;\r
 \r
-  DEBUG ((DEBUG_INFO, "SetDmaProtectedRange - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));\r
+  DEBUG ((DEBUG_INFO, "SetDmaProtectedRange(0x%lx) - [0x%x, 0x%x] [0x%lx, 0x%lx]\n", EngineMask, LowMemoryBase, LowMemoryLength, HighMemoryBase, HighMemoryLength));\r
 \r
-  for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {\r
-    DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {\r
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
+      continue;\r
+    }\r
+    DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
     Status = SetPmrRegion (\r
-               (UINTN)mVTdInfoPpi->VTdEngineAddress[Index],\r
+               (UINTN)mVTdInfo->VTdEngineAddress[Index],\r
                LowMemoryBase,\r
                LowMemoryLength,\r
                HighMemoryBase,\r
@@ -279,7 +294,7 @@ SetDmaProtectedRange (
     if (EFI_ERROR(Status)) {\r
       return Status;\r
     }\r
-    Status = EnablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+    Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
     if (EFI_ERROR(Status)) {\r
       return Status;\r
     }\r
@@ -291,11 +306,13 @@ SetDmaProtectedRange (
 /**\r
   Diable DMA protection.\r
 \r
+  @param EngineMask         The mask of the VTd engine to be accessed.\r
+\r
   @retval DMA protection is disabled.\r
 **/\r
 EFI_STATUS\r
 DisableDmaProtection (\r
-  VOID\r
+  IN UINT64        EngineMask\r
   )\r
 {\r
   UINTN       Index;\r
@@ -303,8 +320,11 @@ DisableDmaProtection (
 \r
   DEBUG ((DEBUG_INFO, "DisableDmaProtection\n"));\r
 \r
-  for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {\r
-    Status = DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+  for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {\r
+    if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
+      continue;\r
+    }\r
+    Status = DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
     if (EFI_ERROR(Status)) {\r
       return Status;\r
     }\r
index 6a19c88..e768274 100644 (file)
@@ -29,7 +29,9 @@
 \r
 #define  TOTAL_DMA_BUFFER_SIZE    SIZE_4MB\r
 \r
-EDKII_VTD_INFO_PPI                *mVTdInfoPpi;\r
+EFI_ACPI_DMAR_HEADER              *mAcpiDmarTable;\r
+VTD_INFO                          *mVTdInfo;\r
+UINT64                            mEngineMask;\r
 UINTN                             mDmaBufferBase;\r
 UINTN                             mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE;\r
 UINTN                             mDmaBufferCurrentTop;\r
@@ -48,15 +50,19 @@ typedef struct {
 \r
   PEI Memory Layout:\r
 \r
+              +------------------+ <=============== PHMR.Limit (Top of memory)\r
+              |   Mem Resource   |\r
+              |                  |\r
+\r
               +------------------+ <------- EfiMemoryTop\r
               |   PEI allocated  |\r
-  =========== +==================+\r
+  =========== +==================+ <=============== PHMR.Base\r
        ^      |    Commom Buf    |\r
        |      |  --------------  |\r
   DMA Buffer  |   * DMA FREE *   |\r
        |      |  --------------  |\r
        V      |  Read/Write Buf  |\r
-  =========== +==================+\r
+  =========== +==================+ <=============== PLMR.Limit\r
               |   PEI allocated  |\r
               |  --------------  | <------- EfiFreeMemoryTop\r
               |   * PEI FREE *   |\r
@@ -70,6 +76,9 @@ typedef struct {
               |   Mem Alloc Hob  |\r
               +------------------+\r
 \r
+              |                  |\r
+              |   Mem Resource   |\r
+              +------------------+ <=============== PLMR.Base (0)\r
 **/\r
 \r
 \r
@@ -457,20 +466,21 @@ DumpPhitHob (
 /**\r
   Get the highest memory.\r
 \r
-  @param HobList  the HOB list.\r
-\r
   @return the highest memory.\r
 **/\r
 UINT64\r
 GetTopMemory (\r
-  IN VOID                        *HobList\r
+  VOID\r
   )\r
 {\r
+  VOID                        *HobList;\r
   EFI_PEI_HOB_POINTERS        Hob;\r
   EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
   UINT64                      TopMemory;\r
   UINT64                      ResourceTop;\r
 \r
+  HobList = GetHobList ();\r
+\r
   TopMemory = 0;\r
   for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
     if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
@@ -525,8 +535,8 @@ InitDmaProtection (
 \r
   ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);\r
 \r
-  LowMemoryAlignment = GetLowMemoryAlignment ();\r
-  HighMemoryAlignment = GetHighMemoryAlignment ();\r
+  LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask);\r
+  HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask);\r
   if (LowMemoryAlignment < HighMemoryAlignment) {\r
     MemoryAlignment = (UINTN)HighMemoryAlignment;\r
   } else {\r
@@ -542,9 +552,10 @@ InitDmaProtection (
   LowBottom = 0;\r
   LowTop = *DmaBufferBase;\r
   HighBottom = *DmaBufferBase + DmaBufferSize;\r
-  HighTop = GetTopMemory (HobList);\r
+  HighTop = GetTopMemory ();\r
 \r
   Status = SetDmaProtectedRange (\r
+               mEngineMask,\r
                (UINT32)LowBottom,\r
                (UINT32)(LowTop - LowBottom),\r
                HighBottom,\r
@@ -558,6 +569,541 @@ InitDmaProtection (
   return Status;\r
 }\r
 \r
+/**\r
+  Dump DMAR DeviceScopeEntry.\r
+\r
+  @param[in]  DmarDeviceScopeEntry  DMAR DeviceScopeEntry\r
+**/\r
+VOID\r
+DumpDmarDeviceScopeEntry (\r
+  IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER     *DmarDeviceScopeEntry\r
+  )\r
+{\r
+  UINTN   PciPathNumber;\r
+  UINTN   PciPathIndex;\r
+  EFI_ACPI_DMAR_PCI_PATH  *PciPath;\r
+\r
+  if (DmarDeviceScopeEntry == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    "    *************************************************************************\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    *       DMA-Remapping Device Scope Entry Structure                      *\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    *************************************************************************\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    (sizeof(UINTN) == sizeof(UINT64)) ?\r
+    "    DMAR Device Scope Entry address ...................... 0x%016lx\n" :\r
+    "    DMAR Device Scope Entry address ...................... 0x%08x\n",\r
+    DmarDeviceScopeEntry\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "      Device Scope Entry Type ............................ 0x%02x\n",\r
+    DmarDeviceScopeEntry->Type\r
+    ));\r
+  switch (DmarDeviceScopeEntry->Type) {\r
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
+    DEBUG ((DEBUG_INFO,\r
+      "        PCI Endpoint Device\n"\r
+      ));\r
+    break;\r
+  case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
+    DEBUG ((DEBUG_INFO,\r
+      "        PCI Sub-hierachy\n"\r
+      ));\r
+    break;\r
+  default:\r
+    break;\r
+  }\r
+  DEBUG ((DEBUG_INFO,\r
+    "      Length ............................................. 0x%02x\n",\r
+    DmarDeviceScopeEntry->Length\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "      Enumeration ID ..................................... 0x%02x\n",\r
+    DmarDeviceScopeEntry->EnumerationId\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "      Starting Bus Number ................................ 0x%02x\n",\r
+    DmarDeviceScopeEntry->StartBusNumber\r
+    ));\r
+\r
+  PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);\r
+  PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);\r
+  for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {\r
+    DEBUG ((DEBUG_INFO,\r
+      "      Device ............................................. 0x%02x\n",\r
+      PciPath[PciPathIndex].Device\r
+      ));\r
+    DEBUG ((DEBUG_INFO,\r
+      "      Function ........................................... 0x%02x\n",\r
+      PciPath[PciPathIndex].Function\r
+      ));\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    "    *************************************************************************\n\n"\r
+    ));\r
+\r
+  return;\r
+}\r
+\r
+/**\r
+  Dump DMAR RMRR table.\r
+\r
+  @param[in]  Rmrr  DMAR RMRR table\r
+**/\r
+VOID\r
+DumpDmarRmrr (\r
+  IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr\r
+  )\r
+{\r
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;\r
+  INTN                                    RmrrLen;\r
+\r
+  if (Rmrr == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    "  ***************************************************************************\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "  *       Reserved Memory Region Reporting Structure                        *\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "  ***************************************************************************\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    (sizeof(UINTN) == sizeof(UINT64)) ?\r
+    "  RMRR address ........................................... 0x%016lx\n" :\r
+    "  RMRR address ........................................... 0x%08x\n",\r
+    Rmrr\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Type ................................................. 0x%04x\n",\r
+    Rmrr->Header.Type\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Length ............................................... 0x%04x\n",\r
+    Rmrr->Header.Length\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Segment Number ....................................... 0x%04x\n",\r
+    Rmrr->SegmentNumber\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Reserved Memory Region Base Address .................. 0x%016lx\n",\r
+    Rmrr->ReservedMemoryRegionBaseAddress\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Reserved Memory Region Limit Address ................. 0x%016lx\n",\r
+    Rmrr->ReservedMemoryRegionLimitAddress\r
+    ));\r
+\r
+  RmrrLen  = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);\r
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);\r
+  while (RmrrLen > 0) {\r
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
+    RmrrLen -= DmarDeviceScopeEntry->Length;\r
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    "  ***************************************************************************\n\n"\r
+    ));\r
+\r
+  return;\r
+}\r
+\r
+/**\r
+  Dump DMAR DRHD table.\r
+\r
+  @param[in]  Drhd  DMAR DRHD table\r
+**/\r
+VOID\r
+DumpDmarDrhd (\r
+  IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd\r
+  )\r
+{\r
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDeviceScopeEntry;\r
+  INTN                                    DrhdLen;\r
+\r
+  if (Drhd == NULL) {\r
+    return;\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    "  ***************************************************************************\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "  *       DMA-Remapping Hardware Definition Structure                       *\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "  ***************************************************************************\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    (sizeof(UINTN) == sizeof(UINT64)) ?\r
+    "  DRHD address ........................................... 0x%016lx\n" :\r
+    "  DRHD address ........................................... 0x%08x\n",\r
+    Drhd\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Type ................................................. 0x%04x\n",\r
+    Drhd->Header.Type\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Length ............................................... 0x%04x\n",\r
+    Drhd->Header.Length\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Flags ................................................ 0x%02x\n",\r
+    Drhd->Flags\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "      INCLUDE_PCI_ALL .................................... 0x%02x\n",\r
+    Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Segment Number ....................................... 0x%04x\n",\r
+    Drhd->SegmentNumber\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Register Base Address ................................ 0x%016lx\n",\r
+    Drhd->RegisterBaseAddress\r
+    ));\r
+\r
+  DrhdLen  = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);\r
+  DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);\r
+  while (DrhdLen > 0) {\r
+    DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
+    DrhdLen -= DmarDeviceScopeEntry->Length;\r
+    DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    "  ***************************************************************************\n\n"\r
+    ));\r
+\r
+  return;\r
+}\r
+\r
+/**\r
+  Dump DMAR ACPI table.\r
+\r
+  @param[in]  Dmar  DMAR ACPI table\r
+**/\r
+VOID\r
+DumpAcpiDMAR (\r
+  IN EFI_ACPI_DMAR_HEADER  *Dmar\r
+  )\r
+{\r
+  EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
+  INTN                  DmarLen;\r
+\r
+  if (Dmar == NULL) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Dump Dmar table\r
+  //\r
+  DEBUG ((DEBUG_INFO,\r
+    "*****************************************************************************\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "*         DMAR Table                                                        *\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "*****************************************************************************\n"\r
+    ));\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    (sizeof(UINTN) == sizeof(UINT64)) ?\r
+    "DMAR address ............................................. 0x%016lx\n" :\r
+    "DMAR address ............................................. 0x%08x\n",\r
+    Dmar\r
+    ));\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    "  Table Contents:\n"\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Host Address Width ................................... 0x%02x\n",\r
+    Dmar->HostAddressWidth\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "    Flags ................................................ 0x%02x\n",\r
+    Dmar->Flags\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "      INTR_REMAP ......................................... 0x%02x\n",\r
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP\r
+    ));\r
+  DEBUG ((DEBUG_INFO,\r
+    "      X2APIC_OPT_OUT_SET ................................. 0x%02x\n",\r
+    Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT\r
+    ));\r
+\r
+  DmarLen  = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);\r
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);\r
+  while (DmarLen > 0) {\r
+    switch (DmarHeader->Type) {\r
+    case EFI_ACPI_DMAR_TYPE_DRHD:\r
+      DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);\r
+      break;\r
+    case EFI_ACPI_DMAR_TYPE_RMRR:\r
+      DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);\r
+      break;\r
+    default:\r
+      break;\r
+    }\r
+    DmarLen -= DmarHeader->Length;\r
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO,\r
+    "*****************************************************************************\n\n"\r
+    ));\r
+\r
+  return;\r
+}\r
+\r
+/**\r
+  Get VTd engine number.\r
+\r
+  @return the VTd engine number.\r
+**/\r
+UINTN\r
+GetVtdEngineNumber (\r
+  VOID\r
+  )\r
+{\r
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;\r
+  UINTN                                             VtdIndex;\r
+\r
+  VtdIndex = 0;\r
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
+  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
+    switch (DmarHeader->Type) {\r
+    case EFI_ACPI_DMAR_TYPE_DRHD:\r
+      VtdIndex++;\r
+      break;\r
+    default:\r
+      break;\r
+    }\r
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+  }\r
+  return VtdIndex ;\r
+}\r
+\r
+/**\r
+  Process DMAR DHRD table.\r
+\r
+  @param[in]  VtdIndex  The index of VTd engine.\r
+  @param[in]  DmarDrhd  The DRHD table.\r
+**/\r
+VOID\r
+ProcessDhrd (\r
+  IN UINTN                      VtdIndex,\r
+  IN EFI_ACPI_DMAR_DRHD_HEADER  *DmarDrhd\r
+  )\r
+{\r
+  DEBUG ((DEBUG_INFO,"  VTD (%d) BaseAddress -  0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));\r
+  mVTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;\r
+}\r
+\r
+/**\r
+  Parse DMAR DRHD table.\r
+\r
+  @return EFI_SUCCESS  The DMAR DRHD table is parsed.\r
+**/\r
+EFI_STATUS\r
+ParseDmarAcpiTableDrhd (\r
+  VOID\r
+  )\r
+{\r
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;\r
+  UINTN                                             VtdUnitNumber;\r
+  UINTN                                             VtdIndex;\r
+\r
+  VtdUnitNumber = GetVtdEngineNumber ();\r
+  if (VtdUnitNumber == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));\r
+  if (mVTdInfo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth;\r
+  mVTdInfo->VTdEngineCount   = VtdUnitNumber;\r
+\r
+  VtdIndex = 0;\r
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
+  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
+    switch (DmarHeader->Type) {\r
+    case EFI_ACPI_DMAR_TYPE_DRHD:\r
+      ASSERT (VtdIndex < VtdUnitNumber);\r
+      ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);\r
+      VtdIndex++;\r
+\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+  }\r
+  ASSERT (VtdIndex == VtdUnitNumber);\r
+\r
+  //\r
+  // Initialize the engine mask to all.\r
+  //\r
+  mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return the VTd engine index according to the Segment and DevScopeEntry.\r
+\r
+  @param Segment         The segment of the VTd engine\r
+  @param DevScopeEntry   The DevScopeEntry of the VTd engine\r
+\r
+  @return The VTd engine index according to the Segment and DevScopeEntry.\r
+  @retval -1  The VTd engine is not found.\r
+**/\r
+UINTN\r
+GetVTdEngineFromDevScopeEntry (\r
+  IN  UINT16                                      Segment,\r
+  IN  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry\r
+  )\r
+{\r
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;\r
+  UINTN                                             VtdIndex;\r
+  EFI_ACPI_DMAR_DRHD_HEADER                         *DmarDrhd;\r
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *ThisDevScopeEntry;\r
+\r
+  VtdIndex = 0;\r
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
+  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
+    switch (DmarHeader->Type) {\r
+    case EFI_ACPI_DMAR_TYPE_DRHD:\r
+      DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;\r
+      if (DmarDrhd->SegmentNumber != Segment) {\r
+        // Mismatch\r
+        break;\r
+      }\r
+      if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||\r
+          ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {\r
+        // No DevScopeEntry\r
+        // Do not handle PCI_ALL\r
+        break;\r
+      }\r
+      ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));\r
+      while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {\r
+        if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&\r
+            (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {\r
+          return VtdIndex;\r
+        }\r
+        ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);\r
+      }\r
+      break;\r
+    default:\r
+      break;\r
+    }\r
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+  }\r
+  return (UINTN)-1;\r
+}\r
+\r
+/**\r
+  Process DMAR RMRR table.\r
+\r
+  @param[in]  DmarRmrr  The RMRR table.\r
+**/\r
+VOID\r
+ProcessRmrr (\r
+  IN EFI_ACPI_DMAR_RMRR_HEADER  *DmarRmrr\r
+  )\r
+{\r
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER       *DmarDevScopeEntry;\r
+  UINTN                                             VTdIndex;\r
+  UINT64                                            RmrrMask;\r
+  UINTN                                             LowBottom;\r
+  UINTN                                             LowTop;\r
+  UINTN                                             HighBottom;\r
+  UINT64                                            HighTop;\r
+\r
+  DEBUG ((DEBUG_INFO,"  RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));\r
+\r
+  if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||\r
+      (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {\r
+    return ;\r
+  }\r
+\r
+  DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));\r
+  while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {\r
+    ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);\r
+\r
+    VTdIndex = GetVTdEngineFromDevScopeEntry (DmarRmrr->SegmentNumber, DmarDevScopeEntry);\r
+    if (VTdIndex != (UINTN)-1) {\r
+      RmrrMask = LShiftU64 (1, VTdIndex);\r
+\r
+      LowBottom = 0;\r
+      LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;\r
+      HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;\r
+      HighTop = GetTopMemory ();\r
+\r
+      SetDmaProtectedRange (\r
+        RmrrMask,\r
+        0,\r
+        (UINT32)(LowTop - LowBottom),\r
+        HighBottom,\r
+        HighTop - HighBottom\r
+        );\r
+\r
+      //\r
+      // Remove the engine from the engine mask.\r
+      // The assumption is that any other PEI driver does not access\r
+      // the device covered by this engine.\r
+      //\r
+      mEngineMask = mEngineMask & (~RmrrMask);\r
+    }\r
+\r
+    DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);\r
+  }\r
+}\r
+\r
+/**\r
+  Parse DMAR DRHD table.\r
+**/\r
+VOID\r
+ParseDmarAcpiTableRmrr (\r
+  VOID\r
+  )\r
+{\r
+  EFI_ACPI_DMAR_STRUCTURE_HEADER                    *DmarHeader;\r
+\r
+  DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
+  while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
+    switch (DmarHeader->Type) {\r
+    case EFI_ACPI_DMAR_TYPE_RMRR:\r
+      ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);\r
+      break;\r
+    default:\r
+      break;\r
+    }\r
+    DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
+  }\r
+}\r
+\r
 /**\r
   Initializes the Intel VTd PMR PEIM.\r
 \r
@@ -585,10 +1131,25 @@ IntelVTdPmrInitialize (
              &gEdkiiVTdInfoPpiGuid,\r
              0,\r
              NULL,\r
-             (VOID **)&mVTdInfoPpi\r
+             (VOID **)&mAcpiDmarTable\r
              );\r
   ASSERT_EFI_ERROR(Status);\r
 \r
+  DumpAcpiDMAR (mAcpiDmarTable);\r
+\r
+  //\r
+  // Get DMAR information to local VTdInfo\r
+  //\r
+  Status = ParseDmarAcpiTableDrhd ();\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // If there is RMRR memory, parse it here.\r
+  //\r
+  ParseDmarAcpiTableRmrr ();\r
+\r
   //\r
   // Find a pre-memory in resource hob as DMA buffer\r
   // Mark PEI memory to be DMA protected.\r
index aa5926a..720f5d4 100644 (file)
 #ifndef __DMA_ACCESS_LIB_H__\r
 #define __DMA_ACCESS_LIB_H__\r
 \r
+typedef struct {\r
+  UINT8                                   HostAddressWidth;\r
+  UINTN                                   VTdEngineCount;\r
+  UINT64                                  VTdEngineAddress[1];\r
+} VTD_INFO;\r
+\r
 /**\r
   Set DMA protected region.\r
 \r
+  @param EngineMask         The mask of the VTd engine to be accessed.\r
   @param LowMemoryBase      The protected low memory region base.\r
   @param LowMemoryLength    The protected low memory region length.\r
   @param HighMemoryBase     The protected high memory region base.\r
@@ -28,6 +35,7 @@
 **/\r
 EFI_STATUS\r
 SetDmaProtectedRange (\r
+  IN UINT64        EngineMask,\r
   IN UINT32        LowMemoryBase,\r
   IN UINT32        LowMemoryLength,\r
   IN UINT64        HighMemoryBase,\r
@@ -37,31 +45,37 @@ SetDmaProtectedRange (
 /**\r
   Diable DMA protection.\r
 \r
+  @param EngineMask         The mask of the VTd engine to be accessed.\r
+\r
   @retval DMA protection is disabled.\r
 **/\r
 EFI_STATUS\r
 DisableDmaProtection (\r
-  VOID\r
+  IN UINT64        EngineMask\r
   );\r
 \r
 /**\r
   Get protected low memory alignment.\r
 \r
+  @param EngineMask         The mask of the VTd engine to be accessed.\r
+\r
   @return protected low memory alignment.\r
 **/\r
 UINT32\r
 GetLowMemoryAlignment (\r
-  VOID\r
+  IN UINT64        EngineMask\r
   );\r
 \r
 /**\r
   Get protected high memory alignment.\r
 \r
+  @param EngineMask         The mask of the VTd engine to be accessed.\r
+\r
   @return protected high memory alignment.\r
 **/\r
 UINT64\r
 GetHighMemoryAlignment (\r
-  VOID\r
+  IN UINT64        EngineMask\r
   );\r
 \r
 #endif\r