-/** @file\r
-\r
- Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\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