]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
IntelSiliconPkg/IntelVTdPmrPei: Move to feature dir.
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmr.c
diff --git a/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c b/IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmr.c
new file mode 100644 (file)
index 0000000..ef08e29
--- /dev/null
@@ -0,0 +1,314 @@
+/** @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 <IndustryStandard/Vtd.h>\r
+#include <Ppi/VTdInfo.h>\r
+\r
+#include "IntelVTdPmrPei.h"\r
+\r
+extern EDKII_VTD_INFO_PPI                *mVTdInfoPpi;\r
+\r
+/**\r
+  Get protected low memory alignment.\r
+\r
+  @param VtdUnitBaseAddress The base address of the VTd engine.\r
+\r
+  @return protected low memory alignment.\r
+**/\r
+UINT32\r
+GetPlmrAlignment (\r
+  IN UINTN         VtdUnitBaseAddress\r
+  )\r
+{\r
+  UINT32        Data32;\r
+\r
+  MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG, 0xFFFFFFFF);\r
+  Data32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG);\r
+  Data32 = ~Data32 + 1;\r
+\r
+  return Data32;\r
+}\r
+\r
+/**\r
+  Get protected high memory alignment.\r
+\r
+  @param VtdUnitBaseAddress The base address of the VTd engine.\r
+\r
+  @return protected high memory alignment.\r
+**/\r
+UINT64\r
+GetPhmrAlignment (\r
+  IN UINTN         VtdUnitBaseAddress\r
+  )\r
+{\r
+  UINT64        Data64;\r
+  UINT8         HostAddressWidth;\r
+\r
+  HostAddressWidth = mVTdInfoPpi->HostAddressWidth;\r
+\r
+  MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG, 0xFFFFFFFFFFFFFFFF);\r
+  Data64 = MmioRead64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG);\r
+  Data64 = ~Data64 + 1;\r
+  Data64 = Data64 & (LShiftU64 (1, HostAddressWidth) - 1);\r
+\r
+  return Data64;\r
+}\r
+\r
+/**\r
+  Get protected low memory alignment.\r
+\r
+  @return protected low memory alignment.\r
+**/\r
+UINT32\r
+GetLowMemoryAlignment (\r
+  VOID\r
+  )\r
+{\r
+  UINTN         Index;\r
+  UINT32        Alignment;\r
+  UINT32        FinalAlignment;\r
+\r
+  FinalAlignment = 0;\r
+  for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {\r
+    Alignment = GetPlmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+    if (FinalAlignment < Alignment) {\r
+      FinalAlignment = Alignment;\r
+    }\r
+  }\r
+  return FinalAlignment;\r
+}\r
+\r
+/**\r
+  Get protected high memory alignment.\r
+\r
+  @return protected high memory alignment.\r
+**/\r
+UINT64\r
+GetHighMemoryAlignment (\r
+  VOID\r
+  )\r
+{\r
+  UINTN         Index;\r
+  UINT64        Alignment;\r
+  UINT64        FinalAlignment;\r
+\r
+  FinalAlignment = 0;\r
+  for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {\r
+    Alignment = GetPhmrAlignment ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+    if (FinalAlignment < Alignment) {\r
+      FinalAlignment = Alignment;\r
+    }\r
+  }\r
+  return FinalAlignment;\r
+}\r
+\r
+/**\r
+  Enable PMR in the VTd engine.\r
+\r
+  @param VtdUnitBaseAddress The base address of the VTd engine.\r
+\r
+  @retval EFI_SUCCESS      The PMR is enabled.\r
+  @retval EFI_UNSUPPORTED  The PMR is not supported.\r
+**/\r
+EFI_STATUS\r
+EnablePmr (\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 EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+  if ((Reg32 & BIT0) == 0) {\r
+    MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, BIT31);\r
+    do {\r
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+    } while((Reg32 & BIT0) == 0);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Disable PMR in the VTd engine.\r
+\r
+  @param VtdUnitBaseAddress The base address of the VTd engine.\r
+\r
+  @retval EFI_SUCCESS      The PMR is disabled.\r
+  @retval EFI_UNSUPPORTED  The PMR is not supported.\r
+**/\r
+EFI_STATUS\r
+DisablePmr (\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 EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+  if ((Reg32 & BIT0) != 0) {\r
+    MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0);\r
+    do {\r
+      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG);\r
+    } while((Reg32 & BIT0) != 0);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set PMR region in the VTd engine.\r
+\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
+  @param HighMemoryBase     The protected high memory region base.\r
+  @param HighMemoryLength   The protected high memory region length.\r
+\r
+  @retval EFI_SUCCESS      The PMR is set to protected region.\r
+  @retval EFI_UNSUPPORTED  The PMR is not supported.\r
+**/\r
+EFI_STATUS\r
+SetPmrRegion (\r
+  IN UINTN         VtdUnitBaseAddress,\r
+  IN UINT32        LowMemoryBase,\r
+  IN UINT32        LowMemoryLength,\r
+  IN UINT64        HighMemoryBase,\r
+  IN UINT64        HighMemoryLength\r
+  )\r
+{\r
+  VTD_CAP_REG   CapReg;\r
+  UINT32        PlmrAlignment;\r
+  UINT64        PhmrAlignment;\r
+\r
+  DEBUG ((DEBUG_INFO, "VtdUnitBaseAddress - 0x%x\n", VtdUnitBaseAddress));\r
+\r
+  CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);\r
+  if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) {\r
+    DEBUG ((DEBUG_ERROR, "PLMR/PHMR unsupported\n"));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  PlmrAlignment = GetPlmrAlignment (VtdUnitBaseAddress);\r
+  DEBUG ((DEBUG_INFO, "PlmrAlignment - 0x%x\n", PlmrAlignment));\r
+  PhmrAlignment = GetPhmrAlignment (VtdUnitBaseAddress);\r
+  DEBUG ((DEBUG_INFO, "PhmrAlignment - 0x%lx\n", PhmrAlignment));\r
+\r
+  if ((LowMemoryBase    != ALIGN_VALUE(LowMemoryBase, PlmrAlignment)) ||\r
+      (LowMemoryLength  != ALIGN_VALUE(LowMemoryLength, PlmrAlignment)) ||\r
+      (HighMemoryBase   != ALIGN_VALUE(HighMemoryBase, PhmrAlignment)) ||\r
+      (HighMemoryLength != ALIGN_VALUE(HighMemoryLength, PhmrAlignment))) {\r
+    DEBUG ((DEBUG_ERROR, "PLMR/PHMR alignment issue\n"));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (LowMemoryBase == 0 && LowMemoryLength == 0) {\r
+    LowMemoryBase = 0xFFFFFFFF;\r
+  }\r
+  if (HighMemoryBase == 0 && HighMemoryLength == 0) {\r
+    HighMemoryBase = 0xFFFFFFFFFFFFFFFF;\r
+  }\r
+\r
+  MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_BASE_REG,    LowMemoryBase);\r
+  MmioWrite32 (VtdUnitBaseAddress + R_PMEN_LOW_LIMITE_REG,  LowMemoryBase + LowMemoryLength - 1);\r
+  MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_BASE_REG,   HighMemoryBase);\r
+  MmioWrite64 (VtdUnitBaseAddress + R_PMEN_HIGH_LIMITE_REG, HighMemoryBase + HighMemoryLength - 1);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set DMA protected region.\r
+\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
+  @param HighMemoryLength   The protected high memory region length.\r
+\r
+  @retval EFI_SUCCESS      The DMA protection is set.\r
+  @retval EFI_UNSUPPORTED  The DMA protection is not set.\r
+**/\r
+EFI_STATUS\r
+SetDmaProtectedRange (\r
+  IN UINT32        LowMemoryBase,\r
+  IN UINT32        LowMemoryLength,\r
+  IN UINT64        HighMemoryBase,\r
+  IN UINT64        HighMemoryLength\r
+  )\r
+{\r
+  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
+\r
+  for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {\r
+    DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+    Status = SetPmrRegion (\r
+               (UINTN)mVTdInfoPpi->VTdEngineAddress[Index],\r
+               LowMemoryBase,\r
+               LowMemoryLength,\r
+               HighMemoryBase,\r
+               HighMemoryLength\r
+               );\r
+    if (EFI_ERROR(Status)) {\r
+      return Status;\r
+    }\r
+    Status = EnablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+    if (EFI_ERROR(Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Diable DMA protection.\r
+\r
+  @retval DMA protection is disabled.\r
+**/\r
+EFI_STATUS\r
+DisableDmaProtection (\r
+  VOID\r
+  )\r
+{\r
+  UINTN       Index;\r
+  EFI_STATUS  Status;\r
+\r
+  DEBUG ((DEBUG_INFO, "DisableDmaProtection\n"));\r
+\r
+  for (Index = 0; Index < mVTdInfoPpi->VTdEngineCount; Index++) {\r
+    Status = DisablePmr ((UINTN)mVTdInfoPpi->VTdEngineAddress[Index]);\r
+    if (EFI_ERROR(Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r