--- /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