--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <PiPei.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/HobLib.h>\r
+#include <IndustryStandard/Vtd.h>\r
+#include <Ppi/VtdInfo.h>\r
+\r
+#include "IntelVTdPmrPei.h"\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
+ @param[in] AcpiDmarTable DMAR ACPI table\r
+\r
+ @return the VTd engine number.\r
+**/\r
+UINTN\r
+GetVtdEngineNumber (\r
+ IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
+ UINTN VtdIndex;\r
+\r
+ VtdIndex = 0;\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));\r
+ while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->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] VTdInfo The VTd engine context information.\r
+ @param[in] VtdIndex The index of VTd engine.\r
+ @param[in] DmarDrhd The DRHD table.\r
+**/\r
+VOID\r
+ProcessDhrd (\r
+ IN VTD_INFO *VTdInfo,\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
+ VTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;\r
+}\r
+\r
+/**\r
+ Parse DMAR DRHD table.\r
+\r
+ @param[in] AcpiDmarTable DMAR ACPI table\r
+\r
+ @return EFI_SUCCESS The DMAR DRHD table is parsed.\r
+**/\r
+EFI_STATUS\r
+ParseDmarAcpiTableDrhd (\r
+ IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
+ UINTN VtdUnitNumber;\r
+ UINTN VtdIndex;\r
+ VTD_INFO *VTdInfo;\r
+\r
+ VtdUnitNumber = GetVtdEngineNumber (AcpiDmarTable);\r
+ if (VtdUnitNumber == 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ VTdInfo = BuildGuidHob (&mVTdInfoGuid, sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));\r
+ ASSERT(VTdInfo != NULL);\r
+ if (VTdInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Initialize the engine mask to all.\r
+ //\r
+ VTdInfo->AcpiDmarTable = AcpiDmarTable;\r
+ VTdInfo->EngineMask = LShiftU64 (1, VtdUnitNumber) - 1;\r
+ VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth;\r
+ VTdInfo->VTdEngineCount = VtdUnitNumber;\r
+\r
+ VtdIndex = 0;\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));\r
+ while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {\r
+ switch (DmarHeader->Type) {\r
+ case EFI_ACPI_DMAR_TYPE_DRHD:\r
+ ASSERT (VtdIndex < VtdUnitNumber);\r
+ ProcessDhrd (VTdInfo, 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
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Return the VTd engine index according to the Segment and DevScopeEntry.\r
+\r
+ @param AcpiDmarTable DMAR ACPI table\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 EFI_ACPI_DMAR_HEADER *AcpiDmarTable,\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)(AcpiDmarTable + 1));\r
+ while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->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] VTdInfo The VTd engine context information.\r
+ @param[in] DmarRmrr The RMRR table.\r
+**/\r
+VOID\r
+ProcessRmrr (\r
+ IN VTD_INFO *VTdInfo,\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
+ EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
+\r
+ AcpiDmarTable = VTdInfo->AcpiDmarTable;\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 (AcpiDmarTable, 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
+ VTdInfo,\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
+ VTdInfo->EngineMask = VTdInfo->EngineMask & (~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
+ @param[in] VTdInfo The VTd engine context information.\r
+**/\r
+VOID\r
+ParseDmarAcpiTableRmrr (\r
+ IN VTD_INFO *VTdInfo\r
+ )\r
+{\r
+ EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
+ EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
+\r
+ AcpiDmarTable = VTdInfo->AcpiDmarTable;\r
+\r
+ DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(AcpiDmarTable + 1));\r
+ while ((UINTN)DmarHeader < (UINTN)AcpiDmarTable + AcpiDmarTable->Header.Length) {\r
+ switch (DmarHeader->Type) {\r
+ case EFI_ACPI_DMAR_TYPE_RMRR:\r
+ ProcessRmrr (VTdInfo, (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
#include "IntelVTdPmrPei.h"\r
\r
-extern VTD_INFO *mVTdInfo;\r
-\r
/**\r
Get protected low memory alignment.\r
\r
+ @param HostAddressWidth The host address width.\r
@param VtdUnitBaseAddress The base address of the VTd engine.\r
\r
@return protected low memory alignment.\r
**/\r
UINT32\r
GetPlmrAlignment (\r
+ IN UINT8 HostAddressWidth,\r
IN UINTN VtdUnitBaseAddress\r
)\r
{\r
/**\r
Get protected high memory alignment.\r
\r
+ @param HostAddressWidth The host address width.\r
@param VtdUnitBaseAddress The base address of the VTd engine.\r
\r
@return protected high memory alignment.\r
**/\r
UINT64\r
GetPhmrAlignment (\r
+ IN UINT8 HostAddressWidth,\r
IN UINTN VtdUnitBaseAddress\r
)\r
{\r
UINT64 Data64;\r
- UINT8 HostAddressWidth;\r
-\r
- HostAddressWidth = mVTdInfo->HostAddressWidth;\r
\r
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);\r
Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);\r
/**\r
Get protected low memory alignment.\r
\r
+ @param VTdInfo The VTd engine context information.\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
+ IN VTD_INFO *VTdInfo,\r
IN UINT64 EngineMask\r
)\r
{\r
UINT32 FinalAlignment;\r
\r
FinalAlignment = 0;\r
- for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {\r
+ for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
continue;\r
}\r
- Alignment = GetPlmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
+ Alignment = GetPlmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);\r
if (FinalAlignment < Alignment) {\r
FinalAlignment = Alignment;\r
}\r
/**\r
Get protected high memory alignment.\r
\r
+ @param VTdInfo The VTd engine context information.\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
+ IN VTD_INFO *VTdInfo,\r
IN UINT64 EngineMask\r
)\r
{\r
UINT64 FinalAlignment;\r
\r
FinalAlignment = 0;\r
- for (Index = 0; Index < mVTdInfo->VTdEngineCount; Index++) {\r
+ for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
continue;\r
}\r
- Alignment = GetPhmrAlignment ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
+ Alignment = GetPhmrAlignment (VTdInfo->HostAddressWidth, (UINTN)VTdInfo->VTdEngineAddress[Index]);\r
if (FinalAlignment < Alignment) {\r
FinalAlignment = Alignment;\r
}\r
UINT32 Reg32;\r
VTD_CAP_REG CapReg;\r
\r
+ DEBUG ((DEBUG_INFO, "EnablePmr - %x\n", VtdUnitBaseAddress));\r
+\r
CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);\r
if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {\r
return EFI_UNSUPPORTED;\r
}\r
\r
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+ if (Reg32 == 0xFFFFFFFF) {\r
+ DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
if ((Reg32 & BIT0) == 0) {\r
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);\r
do {\r
} while((Reg32 & BIT0) == 0);\r
}\r
\r
+ DEBUG ((DEBUG_INFO, "EnablePmr - Done\n"));\r
+\r
return EFI_SUCCESS;\r
}\r
\r
}\r
\r
Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+ if (Reg32 == 0xFFFFFFFF) {\r
+ DEBUG ((DEBUG_ERROR, "R_PMEN_ENABLE_REG - 0x%x\n", Reg32));\r
+ ASSERT(FALSE);\r
+ }\r
+\r
if ((Reg32 & BIT0) != 0) {\r
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);\r
do {\r
/**\r
Set PMR region in the VTd engine.\r
\r
+ @param HostAddressWidth The host address width.\r
@param VtdUnitBaseAddress The base address of the VTd engine.\r
@param LowMemoryBase The protected low memory region base.\r
@param LowMemoryLength The protected low memory region length.\r
**/\r
EFI_STATUS\r
SetPmrRegion (\r
+ IN UINT8 HostAddressWidth,\r
IN UINTN VtdUnitBaseAddress,\r
IN UINT32 LowMemoryBase,\r
IN UINT32 LowMemoryLength,\r
return EFI_UNSUPPORTED;\r
}\r
\r
- PlmrAlignment = GetPlmrAlignment (VtdUnitBaseAddress);\r
+ PlmrAlignment = GetPlmrAlignment (HostAddressWidth, VtdUnitBaseAddress);\r
DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));\r
- PhmrAlignment = GetPhmrAlignment (VtdUnitBaseAddress);\r
+ PhmrAlignment = GetPhmrAlignment (HostAddressWidth, VtdUnitBaseAddress);\r
DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));\r
\r
if ((LowMemoryBase != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||\r
\r
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, LowMemoryBase);\r
MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG, LowMemoryBase + LowMemoryLength - 1);\r
+ DEBUG ((DEBUG_INFO, "PLMR set done\n"));\r
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, HighMemoryBase);\r
MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);\r
+ DEBUG ((DEBUG_INFO, "PHMR set done\n"));\r
\r
return EFI_SUCCESS;\r
}\r
/**\r
Set DMA protected region.\r
\r
+ @param VTdInfo The VTd engine context information.\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
**/\r
EFI_STATUS\r
SetDmaProtectedRange (\r
+ IN VTD_INFO *VTdInfo,\r
IN UINT64 EngineMask,\r
IN UINT32 LowMemoryBase,\r
IN UINT32 LowMemoryLength,\r
\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 < mVTdInfo->VTdEngineCount; Index++) {\r
+ for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
continue;\r
}\r
- DisablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
+ DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
Status = SetPmrRegion (\r
- (UINTN)mVTdInfo->VTdEngineAddress[Index],\r
+ VTdInfo->HostAddressWidth,\r
+ (UINTN)VTdInfo->VTdEngineAddress[Index],\r
LowMemoryBase,\r
LowMemoryLength,\r
HighMemoryBase,\r
if (EFI_ERROR(Status)) {\r
return Status;\r
}\r
- Status = EnablePmr ((UINTN)mVTdInfo->VTdEngineAddress[Index]);\r
+ Status = EnablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
if (EFI_ERROR(Status)) {\r
return Status;\r
}\r
/**\r
Diable DMA protection.\r
\r
+ @param VTdInfo The VTd engine context information.\r
@param EngineMask The mask of the VTd engine to be accessed.\r
\r
- @retval DMA protection is disabled.\r
+ @retval EFI_SUCCESS DMA protection is disabled.\r
**/\r
EFI_STATUS\r
DisableDmaProtection (\r
+ IN VTD_INFO *VTdInfo,\r
IN UINT64 EngineMask\r
)\r
{\r
UINTN Index;\r
EFI_STATUS Status;\r
\r
- DEBUG ((DEBUG_INFO, "DisableDmaProtection\n"));\r
+ DEBUG ((DEBUG_INFO, "DisableDmaProtection - 0x%lx\n", EngineMask));\r
+\r
+ for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
+ DEBUG ((DEBUG_INFO, "Disabling...%d\n", Index));\r
\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
+ Status = DisablePmr ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
if (EFI_ERROR(Status)) {\r
return Status;\r
}\r
\r
return EFI_SUCCESS;\r
}\r
+\r
+/**\r
+ Return if the PMR is enabled.\r
+\r
+ @param VtdUnitBaseAddress The base address of the VTd engine.\r
+\r
+ @retval TRUE PMR is enabled.\r
+ @retval FALSE PMR is disabled or unsupported.\r
+**/\r
+BOOLEAN\r
+IsPmrEnabled (\r
+ IN UINTN VtdUnitBaseAddress\r
+ )\r
+{\r
+ UINT32 Reg32;\r
+ VTD_CAP_REG CapReg;\r
+\r
+ CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);\r
+ if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+ if ((Reg32 & BIT0) == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Return the mask of the VTd engine which is enabled.\r
+\r
+ @param VTdInfo The VTd engine context information.\r
+ @param EngineMask The mask of the VTd engine to be accessed.\r
+\r
+ @return the mask of the VTd engine which is enabled.\r
+**/\r
+UINT64\r
+GetDmaProtectionEnabledEngineMask (\r
+ IN VTD_INFO *VTdInfo,\r
+ IN UINT64 EngineMask\r
+ )\r
+{\r
+ UINTN Index;\r
+ BOOLEAN Result;\r
+ UINT64 EnabledEngineMask;\r
+\r
+ DEBUG ((DEBUG_INFO, "GetDmaProtectionEnabledEngineMask - 0x%lx\n", EngineMask));\r
+\r
+ EnabledEngineMask = 0;\r
+ for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
+ if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
+ continue;\r
+ }\r
+ Result = IsPmrEnabled ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
+ if (Result) {\r
+ EnabledEngineMask |= LShiftU64(1, Index);\r
+ }\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "EnabledEngineMask - 0x%lx\n", EnabledEngineMask));\r
+ return EnabledEngineMask;\r
+}\r
#include <IndustryStandard/Vtd.h>\r
#include <Ppi/IoMmu.h>\r
#include <Ppi/VtdInfo.h>\r
+#include <Ppi/MemoryDiscovered.h>\r
#include <Ppi/EndOfPeiPhase.h>\r
\r
#include "IntelVTdPmrPei.h"\r
#define TOTAL_DMA_BUFFER_SIZE SIZE_4MB\r
#define TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB\r
\r
-EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;\r
-VTD_INFO *mVTdInfo;\r
-UINT64 mEngineMask;\r
-UINTN mDmaBufferBase;\r
-UINTN mDmaBufferSize;\r
-UINTN mDmaBufferCurrentTop;\r
-UINTN mDmaBufferCurrentBottom;\r
+EFI_GUID mVTdInfoGuid = {\r
+ 0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }\r
+};\r
+\r
+EFI_GUID mDmaBufferInfoGuid = {\r
+ 0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }\r
+};\r
+\r
+typedef struct {\r
+ UINTN DmaBufferBase;\r
+ UINTN DmaBufferSize;\r
+ UINTN DmaBufferCurrentTop;\r
+ UINTN DmaBufferCurrentBottom;\r
+} DMA_BUFFER_INFO;\r
\r
#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')\r
typedef struct {\r
+------------------+ <=============== PLMR.Base (0)\r
**/\r
\r
-\r
/**\r
Set IOMMU attribute for a system memory.\r
\r
OUT VOID **Mapping\r
)\r
{\r
- MAP_INFO *MapInfo;\r
- UINTN Length;\r
+ MAP_INFO *MapInfo;\r
+ UINTN Length;\r
+ VOID *Hob;\r
+ DMA_BUFFER_INFO *DmaBufferInfo;\r
+\r
+ Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
+ DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
\r
if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
}\r
\r
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));\r
- DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));\r
- DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));\r
+ DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
+ DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
\r
Length = *NumberOfBytes + sizeof(MAP_INFO);\r
- if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {\r
+ if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));\r
ASSERT (FALSE);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- *DeviceAddress = mDmaBufferCurrentBottom;\r
- mDmaBufferCurrentBottom += Length;\r
+ *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;\r
+ DmaBufferInfo->DmaBufferCurrentBottom += Length;\r
\r
MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);\r
MapInfo->Signature = MAP_INFO_SIGNATURE;\r
IN VOID *Mapping\r
)\r
{\r
- MAP_INFO *MapInfo;\r
- UINTN Length;\r
+ MAP_INFO *MapInfo;\r
+ UINTN Length;\r
+ VOID *Hob;\r
+ DMA_BUFFER_INFO *DmaBufferInfo;\r
+\r
+ Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
+ DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
\r
if (Mapping == NULL) {\r
return EFI_SUCCESS;\r
}\r
\r
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));\r
- DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));\r
- DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));\r
+ DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
+ DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
\r
MapInfo = Mapping;\r
ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);\r
}\r
\r
Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);\r
- if (mDmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {\r
- mDmaBufferCurrentBottom -= Length;\r
+ if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {\r
+ DmaBufferInfo->DmaBufferCurrentBottom -= Length;\r
}\r
\r
return EFI_SUCCESS;\r
IN UINT64 Attributes\r
)\r
{\r
- UINTN Length;\r
+ UINTN Length;\r
+ VOID *Hob;\r
+ DMA_BUFFER_INFO *DmaBufferInfo;\r
+\r
+ Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
+ DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
\r
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));\r
- DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));\r
- DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));\r
+ DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
+ DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
\r
Length = EFI_PAGES_TO_SIZE(Pages);\r
- if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {\r
+ if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));\r
ASSERT (FALSE);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- *HostAddress = (VOID *)(UINTN)(mDmaBufferCurrentTop - Length);\r
- mDmaBufferCurrentTop -= Length;\r
+ *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);\r
+ DmaBufferInfo->DmaBufferCurrentTop -= Length;\r
\r
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));\r
return EFI_SUCCESS;\r
IN VOID *HostAddress\r
)\r
{\r
- UINTN Length;\r
+ UINTN Length;\r
+ VOID *Hob;\r
+ DMA_BUFFER_INFO *DmaBufferInfo;\r
+\r
+ Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
+ DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
\r
DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));\r
- DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));\r
- DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));\r
+ DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
+ DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
\r
Length = EFI_PAGES_TO_SIZE(Pages);\r
- if ((UINTN)HostAddress == mDmaBufferCurrentTop) {\r
- mDmaBufferCurrentTop += Length;\r
+ if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {\r
+ DmaBufferInfo->DmaBufferCurrentTop += Length;\r
}\r
\r
return EFI_SUCCESS;\r
/**\r
Initialize DMA protection.\r
\r
+ @param VTdInfo The VTd engine context information.\r
@param DmaBufferSize the DMA buffer size\r
@param DmaBufferBase the DMA buffer base\r
\r
**/\r
EFI_STATUS\r
InitDmaProtection (\r
- IN UINTN DmaBufferSize,\r
- OUT UINTN *DmaBufferBase\r
+ IN VTD_INFO *VTdInfo,\r
+ IN UINTN DmaBufferSize,\r
+ OUT UINTN *DmaBufferBase\r
)\r
{\r
EFI_STATUS Status;\r
\r
ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);\r
\r
- LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask);\r
- HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask);\r
+ LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
+ HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
if (LowMemoryAlignment < HighMemoryAlignment) {\r
MemoryAlignment = (UINTN)HighMemoryAlignment;\r
} else {\r
HighTop = GetTopMemory ();\r
\r
Status = SetDmaProtectedRange (\r
- mEngineMask,\r
- (UINT32)LowBottom,\r
- (UINT32)(LowTop - LowBottom),\r
- HighBottom,\r
- HighTop - HighBottom\r
- );\r
+ VTdInfo,\r
+ VTdInfo->EngineMask,\r
+ (UINT32)LowBottom,\r
+ (UINT32)(LowTop - LowBottom),\r
+ HighBottom,\r
+ HighTop - HighBottom\r
+ );\r
\r
if (EFI_ERROR(Status)) {\r
FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize));\r
}\r
\r
/**\r
- Dump DMAR DeviceScopeEntry.\r
+ Initializes the Intel VTd Info.\r
+\r
+ @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
\r
- @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry\r
**/\r
-VOID\r
-DumpDmarDeviceScopeEntry (\r
- IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry\r
+EFI_STATUS\r
+InitVTdInfo (\r
+ VOID\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
+ EFI_STATUS Status;\r
+ EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
+ VOID *Hob;\r
\r
-/**\r
- Dump DMAR RMRR table.\r
+ Status = PeiServicesLocatePpi (\r
+ &gEdkiiVTdInfoPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **)&AcpiDmarTable\r
+ );\r
+ ASSERT_EFI_ERROR(Status);\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
+ DumpAcpiDMAR (AcpiDmarTable);\r
\r
- if (Rmrr == NULL) {\r
- return;\r
+ //\r
+ // Clear old VTdInfo Hob.\r
+ //\r
+ Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
+ if (Hob != NULL) {\r
+ ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));\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
+ // Get DMAR information to local VTdInfo\r
+ //\r
+ Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
}\r
\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n\n"\r
- ));\r
+ //\r
+ // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.\r
+ //\r
\r
- return;\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
- Dump DMAR DRHD table.\r
+ Initializes the Intel VTd PMR for all memory.\r
+\r
+ @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
\r
- @param[in] Drhd DMAR DRHD table\r
**/\r
-VOID\r
-DumpDmarDrhd (\r
- IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd\r
+EFI_STATUS\r
+InitVTdPmrForAll (\r
+ VOID\r
)\r
{\r
- EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
- INTN DrhdLen;\r
+ EFI_STATUS Status;\r
+ VOID *Hob;\r
+ VTD_INFO *VTdInfo;\r
+ UINTN LowBottom;\r
+ UINTN LowTop;\r
+ UINTN HighBottom;\r
+ UINT64 HighTop;\r
\r
- if (Drhd == NULL) {\r
- return;\r
- }\r
+ Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
+ VTdInfo = GET_GUID_HOB_DATA(Hob);\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
+ LowBottom = 0;\r
+ LowTop = 0;\r
+ HighBottom = 0;\r
+ HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth);\r
\r
- DEBUG ((DEBUG_INFO,\r
- " ***************************************************************************\n\n"\r
- ));\r
+ Status = SetDmaProtectedRange (\r
+ VTdInfo,\r
+ VTdInfo->EngineMask,\r
+ (UINT32)LowBottom,\r
+ (UINT32)(LowTop - LowBottom),\r
+ HighBottom,\r
+ HighTop - HighBottom\r
+ );\r
\r
- return;\r
+ return Status;\r
}\r
\r
/**\r
- Dump DMAR ACPI table.\r
+ Initializes the Intel VTd PMR for DMA buffer.\r
+\r
+ @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
+ @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
\r
- @param[in] Dmar DMAR ACPI table\r
**/\r
-VOID\r
-DumpAcpiDMAR (\r
- IN EFI_ACPI_DMAR_HEADER *Dmar\r
+EFI_STATUS\r
+InitVTdPmrForDma (\r
+ VOID\r
)\r
{\r
- EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
- INTN DmarLen;\r
+ EFI_STATUS Status;\r
+ VOID *Hob;\r
+ VTD_INFO *VTdInfo;\r
+ DMA_BUFFER_INFO *DmaBufferInfo;\r
\r
- if (Dmar == NULL) {\r
- return;\r
- }\r
+ Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
+ VTdInfo = GET_GUID_HOB_DATA(Hob);\r
\r
//\r
- // Dump Dmar table\r
+ // If there is RMRR memory, parse it here.\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
+ ParseDmarAcpiTableRmrr (VTdInfo);\r
\r
-/**\r
- Get VTd engine number.\r
+ Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
+ DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\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
+ DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));\r
+ //\r
+ // Find a pre-memory in resource hob as DMA buffer\r
+ // Mark PEI memory to be DMA protected.\r
+ //\r
+ Status = InitDmaProtection (VTdInfo, DmaBufferInfo->DmaBufferSize, &DmaBufferInfo->DmaBufferBase);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\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
+ DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));\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
+ DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
+ DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;\r
\r
//\r
- // Initialize the engine mask to all.\r
+ // Install PPI.\r
//\r
- mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1;\r
+ Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
+ ASSERT_EFI_ERROR(Status);\r
\r
- return EFI_SUCCESS;\r
+ return Status;\r
}\r
\r
/**\r
- Return the VTd engine index according to the Segment and DevScopeEntry.\r
+ This function handles S3 resume task at the end of PEI\r
\r
- @param Segment The segment of the VTd engine\r
- @param DevScopeEntry The DevScopeEntry of the VTd engine\r
+ @param[in] PeiServices Pointer to PEI Services Table.\r
+ @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
+ caused this function to execute.\r
+ @param[in] Ppi Pointer to the PPI data associated with this function.\r
\r
- @return The VTd engine index according to the Segment and DevScopeEntry.\r
- @retval -1 The VTd engine is not found.\r
+ @retval EFI_STATUS Always return EFI_SUCCESS\r
**/\r
-UINTN\r
-GetVTdEngineFromDevScopeEntry (\r
- IN UINT16 Segment,\r
- IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry\r
+EFI_STATUS\r
+EFIAPI\r
+S3EndOfPeiNotify(\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
+ IN VOID *Ppi\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
+ VOID *Hob;\r
+ VTD_INFO *VTdInfo;\r
+ UINT64 EngineMask;\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
+ DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));\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
+ if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
+ Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
+ if (Hob == NULL) {\r
+ return EFI_SUCCESS;\r
}\r
+ VTdInfo = GET_GUID_HOB_DATA(Hob);\r
\r
- DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);\r
+ EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;\r
+ DisableDmaProtection (VTdInfo, EngineMask);\r
}\r
+ return EFI_SUCCESS;\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
+EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiEndOfPeiSignalPpiGuid,\r
+ S3EndOfPeiNotify\r
+};\r
\r
/**\r
- This function handles S3 resume task at the end of PEI\r
+ This function handles VTd engine setup\r
\r
@param[in] PeiServices Pointer to PEI Services Table.\r
@param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
**/\r
EFI_STATUS\r
EFIAPI\r
-S3EndOfPeiNotify(\r
+VTdInfoNotify (\r
IN EFI_PEI_SERVICES **PeiServices,\r
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
IN VOID *Ppi\r
)\r
{\r
- UINT64 EngineMask;\r
+ EFI_STATUS Status;\r
+ VOID *MemoryDiscovered;\r
+ UINT64 EnabledEngineMask;\r
+ VOID *Hob;\r
+ VTD_INFO *VTdInfo;\r
+ BOOLEAN MemoryInitialized;\r
\r
- DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));\r
+ DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));\r
+\r
+ //\r
+ // Check if memory is initialized.\r
+ //\r
+ MemoryInitialized = FALSE;\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiMemoryDiscoveredPpiGuid,\r
+ 0,\r
+ NULL,\r
+ &MemoryDiscovered\r
+ );\r
+ if (!EFI_ERROR(Status)) {\r
+ MemoryInitialized = TRUE;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));\r
+\r
+ if (!MemoryInitialized) {\r
+ //\r
+ // If the memory is not initialized,\r
+ // Protect all system memory\r
+ //\r
+ InitVTdInfo ();\r
+ InitVTdPmrForAll ();\r
+ } else {\r
+ //\r
+ // If the memory is initialized,\r
+ // Allocate DMA buffer and protect rest system memory\r
+ //\r
+\r
+ //\r
+ // NOTE: We need reinit VTdInfo because previous information might be overriden.\r
+ //\r
+ InitVTdInfo ();\r
+\r
+ Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
+ VTdInfo = GET_GUID_HOB_DATA(Hob);\r
+\r
+ //\r
+ // NOTE: We need check if PMR is enabled or not.\r
+ //\r
+ EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);\r
+ if (EnabledEngineMask != 0) {\r
+ EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
+ DisableDmaProtection (VTdInfo, EnabledEngineMask);\r
+ }\r
+ InitVTdPmrForDma ();\r
+ if (EnabledEngineMask != 0) {\r
+ DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
+ }\r
\r
- if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
- EngineMask = LShiftU64 (1, mVTdInfo->VTdEngineCount) - 1;\r
- DisableDmaProtection (EngineMask);\r
}\r
+\r
return EFI_SUCCESS;\r
}\r
\r
-EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {\r
+EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {\r
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
- &gEfiEndOfPeiSignalPpiGuid,\r
- S3EndOfPeiNotify\r
+ &gEdkiiVTdInfoPpiGuid,\r
+ VTdInfoNotify\r
};\r
\r
/**\r
{\r
EFI_STATUS Status;\r
EFI_BOOT_MODE BootMode;\r
+ DMA_BUFFER_INFO *DmaBufferInfo;\r
+\r
+ DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));\r
\r
if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {\r
return EFI_UNSUPPORTED;\r
}\r
\r
- PeiServicesGetBootMode (&BootMode);\r
-\r
- Status = PeiServicesLocatePpi (\r
- &gEdkiiVTdInfoPpiGuid,\r
- 0,\r
- NULL,\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
+ DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));\r
+ ASSERT(DmaBufferInfo != NULL);\r
+ if (DmaBufferInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
}\r
+ ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));\r
\r
- //\r
- // If there is RMRR memory, parse it here.\r
- //\r
- ParseDmarAcpiTableRmrr ();\r
+ PeiServicesGetBootMode (&BootMode);\r
\r
if (BootMode == BOOT_ON_S3_RESUME) {\r
- mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;\r
+ DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;\r
} else {\r
- mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE;\r
- }\r
- DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", mDmaBufferSize));\r
-\r
- //\r
- // Find a pre-memory in resource hob as DMA buffer\r
- // Mark PEI memory to be DMA protected.\r
- //\r
- Status = InitDmaProtection (mDmaBufferSize, &mDmaBufferBase);\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
+ DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;\r
}\r
\r
- DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", mDmaBufferBase));\r
-\r
- mDmaBufferCurrentTop = mDmaBufferBase + mDmaBufferSize;\r
- mDmaBufferCurrentBottom = mDmaBufferBase;\r
-\r
- //\r
- // Install PPI.\r
- //\r
- Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
- ASSERT_EFI_ERROR(Status);\r
+ Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);\r
+ ASSERT_EFI_ERROR (Status);\r
\r
//\r
- // Register EndOfPei Notify for S3 to run FSP NotifyPhase\r
+ // Register EndOfPei Notify for S3\r
//\r
if (BootMode == BOOT_ON_S3_RESUME) {\r
Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);\r
ASSERT_EFI_ERROR (Status);\r
}\r
\r
- return Status;\r
+ return EFI_SUCCESS;\r
}\r
\r
#define __DMA_ACCESS_LIB_H__\r
\r
typedef struct {\r
+ EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
+ UINT64 EngineMask;\r
UINT8 HostAddressWidth;\r
UINTN VTdEngineCount;\r
UINT64 VTdEngineAddress[1];\r
/**\r
Set DMA protected region.\r
\r
+ @param VTdInfo The VTd engine context information.\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
**/\r
EFI_STATUS\r
SetDmaProtectedRange (\r
+ IN VTD_INFO *VTdInfo,\r
IN UINT64 EngineMask,\r
IN UINT32 LowMemoryBase,\r
IN UINT32 LowMemoryLength,\r
/**\r
Diable DMA protection.\r
\r
+ @param VTdInfo The VTd engine context information.\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
+ IN VTD_INFO *VTdInfo,\r
+ IN UINT64 EngineMask\r
+ );\r
+\r
+/**\r
+ Return if the DMA protection is enabled.\r
+\r
+ @param VTdInfo The VTd engine context information.\r
+ @param EngineMask The mask of the VTd engine to be accessed.\r
+\r
+ @retval TRUE DMA protection is enabled in at least one VTd engine.\r
+ @retval FALSE DMA protection is disabled in all VTd engines.\r
+**/\r
+UINT64\r
+GetDmaProtectionEnabledEngineMask (\r
+ IN VTD_INFO *VTdInfo,\r
IN UINT64 EngineMask\r
);\r
\r
/**\r
Get protected low memory alignment.\r
\r
+ @param VTdInfo The VTd engine context information.\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
+ IN VTD_INFO *VTdInfo,\r
IN UINT64 EngineMask\r
);\r
\r
/**\r
Get protected high memory alignment.\r
\r
+ @param VTdInfo The VTd engine context information.\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
+ IN VTD_INFO *VTdInfo,\r
+ IN UINT64 EngineMask\r
+ );\r
+\r
+/**\r
+ Enable VTd translation table protection.\r
+\r
+ @param VTdInfo The VTd engine context information.\r
+ @param EngineMask The mask of the VTd engine to be accessed.\r
+**/\r
+VOID\r
+EnableVTdTranslationProtection (\r
+ IN VTD_INFO *VTdInfo,\r
+ IN UINT64 EngineMask\r
+ );\r
+\r
+/**\r
+ Disable VTd translation table protection.\r
+\r
+ @param VTdInfo The VTd engine context information.\r
+ @param EngineMask The mask of the VTd engine to be accessed.\r
+**/\r
+VOID\r
+DisableVTdTranslationProtection (\r
+ IN VTD_INFO *VTdInfo,\r
IN UINT64 EngineMask\r
);\r
\r
+/**\r
+ Parse DMAR DRHD table.\r
+\r
+ @param[in] AcpiDmarTable DMAR ACPI table\r
+\r
+ @return EFI_SUCCESS The DMAR DRHD table is parsed.\r
+**/\r
+EFI_STATUS\r
+ParseDmarAcpiTableDrhd (\r
+ IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable\r
+ );\r
+\r
+/**\r
+ Parse DMAR DRHD table.\r
+\r
+ @param VTdInfo The VTd engine context information.\r
+**/\r
+VOID\r
+ParseDmarAcpiTableRmrr (\r
+ IN VTD_INFO *VTdInfo\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
+/**\r
+ Get the highest memory.\r
+\r
+ @return the highest memory.\r
+**/\r
+UINT64\r
+GetTopMemory (\r
+ VOID\r
+ );\r
+\r
+extern EFI_GUID mVTdInfoGuid;\r
+\r
#endif\r
\r
IntelVTdPmrPei.c\r
IntelVTdPmrPei.h\r
IntelVTdPmr.c\r
+ DmarTable.c\r
+ VtdReg.c\r
\r
[LibraryClasses]\r
DebugLib\r
PeiServicesLib\r
HobLib\r
IoLib\r
+ CacheMaintenanceLib\r
\r
[Ppis]\r
- gEdkiiIoMmuPpiGuid ## PRODUCES\r
- gEdkiiVTdInfoPpiGuid ## CONSUMES\r
- gEfiEndOfPeiSignalPpiGuid ## CONSUMES\r
+ gEdkiiIoMmuPpiGuid ## PRODUCES\r
+ gEdkiiVTdInfoPpiGuid ## CONSUMES\r
+ gEfiPeiMemoryDiscoveredPpiGuid ## CONSUMES\r
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES\r
\r
[Pcd]\r
gIntelSiliconPkgTokenSpaceGuid.PcdVTdPolicyPropertyMask ## CONSUMES\r
\r
[Depex]\r
- gEfiPeiMemoryDiscoveredPpiGuid AND\r
gEfiPeiMasterBootModePpiGuid AND\r
gEdkiiVTdInfoPpiGuid\r
\r
--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials are licensed and made available under\r
+ the terms and conditions of the BSD License which accompanies this distribution.\r
+ The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <IndustryStandard/Vtd.h>\r
+#include <Ppi/VtdInfo.h>\r
+\r
+#include "IntelVTdPmrPei.h"\r
+\r
+/**\r
+ Flush VTD page table and context table memory.\r
+\r
+ This action is to make sure the IOMMU engine can get final data in memory.\r
+\r
+ @param[in] Base The base address of memory to be flushed.\r
+ @param[in] Size The size of memory in bytes to be flushed.\r
+**/\r
+VOID\r
+FlushPageTableMemory (\r
+ IN UINTN Base,\r
+ IN UINTN Size\r
+ )\r
+{\r
+ WriteBackDataCacheRange ((VOID *)Base, Size);\r
+}\r
+\r
+/**\r
+ Flush VTd engine write buffer.\r
+\r
+ @param VtdUnitBaseAddress The base address of the VTd engine.\r
+**/\r
+VOID\r
+FlushWriteBuffer (\r
+ IN UINTN VtdUnitBaseAddress\r
+ )\r
+{\r
+ UINT32 Reg32;\r
+ VTD_CAP_REG CapReg;\r
+\r
+ CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);\r
+\r
+ if (CapReg.Bits.RWBF != 0) {\r
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);\r
+ MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);\r
+ do {\r
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);\r
+ } while ((Reg32 & B_GSTS_REG_WBF) != 0);\r
+ }\r
+}\r
+\r
+/**\r
+ Invalidate VTd context cache.\r
+\r
+ @param VtdUnitBaseAddress The base address of the VTd engine.\r
+**/\r
+EFI_STATUS\r
+InvalidateContextCache (\r
+ IN UINTN VtdUnitBaseAddress\r
+ )\r
+{\r
+ UINT64 Reg64;\r
+\r
+ Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);\r
+ if ((Reg64 & B_CCMD_REG_ICC) != 0) {\r
+ DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n",VtdUnitBaseAddress));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));\r
+ Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);\r
+ MmioWrite64 (VtdUnitBaseAddress + R_CCMD_REG, Reg64);\r
+\r
+ do {\r
+ Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);\r
+ } while ((Reg64 & B_CCMD_REG_ICC) != 0);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Invalidate VTd IOTLB.\r
+\r
+ @param VtdUnitBaseAddress The base address of the VTd engine.\r
+**/\r
+EFI_STATUS\r
+InvalidateIOTLB (\r
+ IN UINTN VtdUnitBaseAddress\r
+ )\r
+{\r
+ UINT64 Reg64;\r
+ VTD_ECAP_REG ECapReg;\r
+\r
+ ECapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);\r
+\r
+ Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);\r
+ if ((Reg64 & B_IOTLB_REG_IVT) != 0) {\r
+ DEBUG ((DEBUG_ERROR,"ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", VtdUnitBaseAddress));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));\r
+ Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);\r
+ MmioWrite64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);\r
+\r
+ do {\r
+ Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);\r
+ } while ((Reg64 & B_IOTLB_REG_IVT) != 0);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Enable DMAR translation.\r
+\r
+ @param VtdUnitBaseAddress The base address of the VTd engine.\r
+ @param RootEntryTable The address of the VTd RootEntryTable.\r
+\r
+ @retval EFI_SUCCESS DMAR translation is enabled.\r
+ @retval EFI_DEVICE_ERROR DMAR translation is not enabled.\r
+**/\r
+EFI_STATUS\r
+EnableDmar (\r
+ IN UINTN VtdUnitBaseAddress,\r
+ IN UINTN RootEntryTable\r
+ )\r
+{\r
+ UINT32 Reg32;\r
+\r
+ DEBUG((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress));\r
+\r
+ DEBUG((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));\r
+ MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64)(UINTN)RootEntryTable);\r
+\r
+ MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);\r
+\r
+ DEBUG((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));\r
+ do {\r
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);\r
+ } while((Reg32 & B_GSTS_REG_RTPS) == 0);\r
+\r
+ //\r
+ // Init DMAr Fault Event and Data registers\r
+ //\r
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);\r
+\r
+ //\r
+ // Write Buffer Flush before invalidation\r
+ //\r
+ FlushWriteBuffer (VtdUnitBaseAddress);\r
+\r
+ //\r
+ // Invalidate the context cache\r
+ //\r
+ InvalidateContextCache (VtdUnitBaseAddress);\r
+\r
+ //\r
+ // Invalidate the IOTLB cache\r
+ //\r
+ InvalidateIOTLB (VtdUnitBaseAddress);\r
+\r
+ //\r
+ // Enable VTd\r
+ //\r
+ MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);\r
+ DEBUG((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));\r
+ do {\r
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);\r
+ } while ((Reg32 & B_GSTS_REG_TE) == 0);\r
+\r
+ DEBUG ((DEBUG_INFO,"VTD () enabled!<<<<<<\n"));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Disable DMAR translation.\r
+\r
+ @param VtdUnitBaseAddress The base address of the VTd engine.\r
+\r
+ @retval EFI_SUCCESS DMAR translation is disabled.\r
+ @retval EFI_DEVICE_ERROR DMAR translation is not disabled.\r
+**/\r
+EFI_STATUS\r
+DisableDmar (\r
+ IN UINTN VtdUnitBaseAddress\r
+ )\r
+{\r
+ UINT32 Reg32;\r
+\r
+ DEBUG((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x] \n", VtdUnitBaseAddress));\r
+\r
+ //\r
+ // Write Buffer Flush before invalidation\r
+ //\r
+ FlushWriteBuffer (VtdUnitBaseAddress);\r
+\r
+ //\r
+ // Disable VTd\r
+ //\r
+ MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);\r
+ do {\r
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);\r
+ } while((Reg32 & B_GSTS_REG_RTPS) == 0);\r
+\r
+ Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);\r
+ DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));\r
+\r
+ MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0);\r
+\r
+ DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n"));\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Enable VTd translation table protection.\r
+\r
+ @param VTdInfo The VTd engine context information.\r
+ @param EngineMask The mask of the VTd engine to be accessed.\r
+**/\r
+VOID\r
+EnableVTdTranslationProtection (\r
+ IN VTD_INFO *VTdInfo,\r
+ IN UINT64 EngineMask\r
+ )\r
+{\r
+ UINTN Index;\r
+ VOID *RootEntryTable;\r
+\r
+ DEBUG ((DEBUG_INFO, "EnableVTdTranslationProtection - 0x%lx\n", EngineMask));\r
+\r
+ RootEntryTable = AllocatePages (1);\r
+ ASSERT (RootEntryTable != NULL);\r
+ if (RootEntryTable == NULL) {\r
+ DEBUG ((DEBUG_INFO, " EnableVTdTranslationProtection : OutOfResource\n"));\r
+ return ;\r
+ }\r
+\r
+ ZeroMem (RootEntryTable, EFI_PAGES_TO_SIZE(1));\r
+ FlushPageTableMemory ((UINTN)RootEntryTable, EFI_PAGES_TO_SIZE(1));\r
+\r
+ for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
+ if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
+ continue;\r
+ }\r
+ EnableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index], (UINTN)RootEntryTable);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Disable VTd translation table protection.\r
+\r
+ @param VTdInfo The VTd engine context information.\r
+ @param EngineMask The mask of the VTd engine to be accessed.\r
+**/\r
+VOID\r
+DisableVTdTranslationProtection (\r
+ IN VTD_INFO *VTdInfo,\r
+ IN UINT64 EngineMask\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ DEBUG ((DEBUG_INFO, "DisableVTdTranslationProtection - 0x%lx\n", EngineMask));\r
+\r
+ for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {\r
+ if ((EngineMask & LShiftU64(1, Index)) == 0) {\r
+ continue;\r
+ }\r
+ DisableDmar ((UINTN)VTdInfo->VTdEngineAddress[Index]);\r
+ }\r
+\r
+ return ;\r
+}\r