Procházet zdrojové kódy

WhitleyOpenBoardPkg: Enable VT-D support

Implements VT-D DMAR table functionality.
VT-D is currently implemented as an OpenBoardPkg feature.
More work would be needed to promote to an Advanced Feature.
Specifically reducing dependencies and improving API and integration
with OpenBoardPkg ACPI implementation.
This fix depends on FvOpenBoardPkg providing extended ACPI tables and
AcpiPlatform binaries.

Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Isaac Oram <isaac.w.oram@intel.com>
Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
Oram, Isaac W před 2 roky
rodič
revize
df7fbfbaab

+ 604 - 0
Platform/Intel/WhitleyOpenBoardPkg/Features/AcpiVtd/AcpiVtd.c

@@ -0,0 +1,604 @@
+/** @file AcpiVtd.c
+
+  @copyright
+  Copyright 1996 - 2021 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+//
+// Statements that include other files
+//
+#include <AcpiVtd.h>
+#include <Library/SetupLib.h>
+#include <IioRegs.h>
+#include <IioSetupDefinitions.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Library/TpmMeasurementLib.h>
+
+VTD_SUPPORT_INSTANCE mPrivateData;
+
+#define MAX_BUS_ADDR_WIDTH 45
+
+/**
+
+  Add DMAR entry
+
+  @param This        - DMA Remap protocol pointer
+  @param RemapType   - Type of DMA remapping structure to add
+  @param RemapEntry  - Entry to add
+
+  @retval EFI_INVALID_PARAMETER - DMA remapping support not initialized or entry is malformed
+  @retval EFI_UNSUPPORTED       - Adding entries is not supported
+  @retval EFI_SUCCESS           - The entry was inserted successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InsertDmaRemap (
+  IN  DMA_REMAP_PROTOCOL                *This,
+  IN  REMAP_TYPE                        RemapType,
+  IN  VOID                              *RemapEntry
+  )
+{
+  UINTN                                                       DevIndex;
+  EFI_ACPI_DMAR_HEADER                                        *Dmar;
+  EFI_ACPI_DMAR_DRHD_HEADER                                   *Drhd;
+  EFI_ACPI_DMAR_RMRR_HEADER                                   *Rmrr;
+  EFI_ACPI_DMAR_SATC_HEADER                                   *Atsr;
+  EFI_ACPI_DMAR_RHSA_HEADER                                   *Rhsa;
+  EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER                 *DevScope;
+  DMAR_DRHD                                                   *DmaRemap;
+  DMAR_RMRR                                                   *RevMemRegion;
+  DMAR_ATSR                                                   *AtsrRegion;
+  DMAR_RHSA                                                   *RhsaRegion;
+  EFI_ACPI_DMAR_PCI_PATH                                      *PciPath;
+  EFI_ACPI_DMAR_PCI_PATH                                      *PciInputPath;
+
+  if (mPrivateData.Dmar == NULL) {
+      ASSERT (FALSE);
+      return EFI_INVALID_PARAMETER;
+  }
+
+  Dmar = mPrivateData.Dmar;
+  if (((UINT8 *) Dmar + Dmar->Header.Length) == NULL) {
+      ASSERT (FALSE);
+      return EFI_INVALID_PARAMETER;
+  }
+
+  if (RemapType == DrhdType) {
+    DmaRemap = (DMAR_DRHD *) RemapEntry;
+    ASSERT (DmaRemap->Signature == DRHD_SIGNATURE);
+    Drhd = (EFI_ACPI_DMAR_DRHD_HEADER *) ((UINT8 *) Dmar + Dmar->Header.Length);
+    if (Drhd == NULL) {
+      ASSERT (FALSE);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (DmaRemap->RegisterBase == 0) {
+      return EFI_UNSUPPORTED;
+    }
+
+    Drhd->Header.Type         = EFI_ACPI_DMAR_TYPE_DRHD;
+    Drhd->Header.Length       = sizeof (EFI_ACPI_DMAR_DRHD_HEADER);
+    Drhd->Flags               = DmaRemap->Flags;
+    Drhd->SegmentNumber       = DmaRemap->SegmentNumber;
+    Drhd->RegisterBaseAddress = DmaRemap->RegisterBase;
+    DevScope                  = NULL;
+
+    for (DevIndex = 0; DevIndex < DmaRemap->DeviceScopeNumber; DevIndex++) {
+      if (((UINT8 *) Drhd + Drhd->Header.Length) == NULL) {
+          ASSERT (FALSE);
+          return EFI_INVALID_PARAMETER;
+      }
+
+      DevScope = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *) ((UINT8 *) Drhd + Drhd->Header.Length);
+      if (DevScope != NULL) {
+        DevScope->Type              = DmaRemap->DeviceScope[DevIndex].DeviceType;
+        DevScope->Length            = sizeof (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER);
+        DevScope->EnumerationId     = DmaRemap->DeviceScope[DevIndex].EnumerationID;
+        DevScope->StartBusNumber    = DmaRemap->DeviceScope[DevIndex].StartBusNumber;
+        if (((UINT8 *) DevScope + DevScope->Length) == NULL) {
+          ASSERT (FALSE);
+          return EFI_INVALID_PARAMETER;
+        }
+
+        PciPath = (EFI_ACPI_DMAR_PCI_PATH *) ((UINT8 *) DevScope + DevScope->Length);
+        PciInputPath = (EFI_ACPI_DMAR_PCI_PATH *) DmaRemap->DeviceScope[DevIndex].PciNode;
+        while (*(UINT8 *) PciInputPath != (UINT8) -1) {
+          CopyMem(PciPath, PciInputPath, sizeof (EFI_ACPI_DMAR_PCI_PATH));
+          DevScope->Length += sizeof (EFI_ACPI_DMAR_PCI_PATH);
+          PciInputPath++;
+          PciPath++;
+        }
+        Drhd->Header.Length = Drhd->Header.Length + (UINT16) DevScope->Length;
+      } else {
+        DEBUG ((DEBUG_ERROR, "DevScope Error. Invalid pointer.\n"));
+      }
+    }
+
+    Dmar->Header.Length += Drhd->Header.Length;
+
+  } else if (RemapType == RmrrType) {
+    RevMemRegion = (DMAR_RMRR *) RemapEntry;
+    ASSERT (RevMemRegion->Signature == RMRR_SIGNATURE);
+    Rmrr = (EFI_ACPI_DMAR_RMRR_HEADER *) ((UINT8 *) Dmar + Dmar->Header.Length);
+    if (Rmrr == NULL) {
+      ASSERT (FALSE);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Rmrr->Header.Type                       = EFI_ACPI_DMAR_TYPE_RMRR;
+    Rmrr->Header.Length                     = sizeof (EFI_ACPI_DMAR_RMRR_HEADER);
+    Rmrr->SegmentNumber                     = RevMemRegion->SegmentNumber;
+    Rmrr->ReservedMemoryRegionBaseAddress   = RevMemRegion->RsvdMemBase;
+    Rmrr->ReservedMemoryRegionLimitAddress  = RevMemRegion->RsvdMemLimit;
+
+    DevScope = NULL;
+    for (DevIndex = 0; DevIndex < RevMemRegion->DeviceScopeNumber; DevIndex++) {
+      if (((UINT8 *) Rmrr + Rmrr->Header.Length) == NULL) {
+        ASSERT (FALSE);
+        return EFI_INVALID_PARAMETER;
+      }
+
+      DevScope                        = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *) ((UINT8 *) Rmrr + Rmrr->Header.Length);
+      if (DevScope != NULL) {
+        DevScope->Type                  = RevMemRegion->DeviceScope[DevIndex].DeviceType;
+        DevScope->StartBusNumber        = RevMemRegion->DeviceScope[DevIndex].StartBusNumber;
+        DevScope->Length                = sizeof (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER);
+        if (((UINT8 *) DevScope + DevScope->Length) == NULL) {
+          ASSERT (FALSE);
+          return EFI_INVALID_PARAMETER;
+        }
+
+        PciPath                         = (EFI_ACPI_DMAR_PCI_PATH *) ((UINT8 *) DevScope + DevScope->Length);
+        PciInputPath                    = (EFI_ACPI_DMAR_PCI_PATH *) RevMemRegion->DeviceScope[DevIndex].PciNode;
+        while (*(UINT8 *) PciInputPath != (UINT8) -1) {
+          CopyMem (PciPath, PciInputPath, sizeof (EFI_ACPI_DMAR_PCI_PATH));
+          DevScope->Length += sizeof (EFI_ACPI_DMAR_PCI_PATH);
+          PciInputPath++;
+          PciPath++;
+        }
+        Rmrr->Header.Length = Rmrr->Header.Length + (UINT16) DevScope->Length;
+      } else {
+        DEBUG ((DEBUG_ERROR, "DevScope Error. Invalid pointer.\n"));
+      }
+    }
+
+    Dmar->Header.Length += Rmrr->Header.Length;
+
+  } else if (RemapType == AtsrType) {
+    AtsrRegion = (DMAR_ATSR *) RemapEntry;
+    ASSERT (AtsrRegion->Signature == ATSR_SIGNATURE);
+    Atsr = (EFI_ACPI_DMAR_SATC_HEADER *) ((UINT8 *) Dmar + Dmar->Header.Length);
+    if (Atsr == NULL) {
+      ASSERT (FALSE);
+      return EFI_INVALID_PARAMETER;
+    }
+
+    Atsr->Header.Type   = EFI_ACPI_DMAR_TYPE_ATSR;
+    Atsr->Flags         = AtsrRegion->Flags;
+    Atsr->SegmentNumber = AtsrRegion->SegmentNumber;
+    Atsr->Header.Length = sizeof (EFI_ACPI_DMAR_SATC_HEADER);
+
+    DevScope = NULL;
+    for (DevIndex = 0; DevIndex < AtsrRegion->DeviceScopeNumber; DevIndex++) {
+      if ((AtsrRegion->ATSRPresentBit & (01 << DevIndex)) == 00) {
+        continue;
+      }
+      if (((UINT8 *) Atsr + Atsr->Header.Length) == NULL) {
+        ASSERT (FALSE);
+        return EFI_INVALID_PARAMETER;
+      }
+
+      DevScope = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *) ((UINT8 *) Atsr + Atsr->Header.Length);
+      if (DevScope != NULL) {
+        DevScope->Type              = AtsrRegion->DeviceScope[DevIndex].DeviceType;
+        DevScope->StartBusNumber    = AtsrRegion->DeviceScope[DevIndex].StartBusNumber;
+        DevScope->Length            = sizeof (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER);
+        if (((UINT8 *) DevScope + DevScope->Length) == NULL) {
+          ASSERT (FALSE);
+          return EFI_INVALID_PARAMETER;
+        }
+
+        PciPath = (EFI_ACPI_DMAR_PCI_PATH *) ((UINT8 *) DevScope + DevScope->Length);
+        PciInputPath = (EFI_ACPI_DMAR_PCI_PATH *) AtsrRegion->DeviceScope[DevIndex].PciNode;
+        while (*(UINT8 *) PciInputPath != (UINT8) -1) {
+          CopyMem(PciPath, PciInputPath, sizeof (EFI_ACPI_DMAR_PCI_PATH));
+          DevScope->Length += sizeof (EFI_ACPI_DMAR_PCI_PATH);
+          PciInputPath++;
+          PciPath++;
+        }
+
+        Atsr->Header.Length = Atsr->Header.Length + (UINT16) DevScope->Length;
+
+      } else {
+        DEBUG ((DEBUG_ERROR, "DevScope Error. Invalid pointer.\n"));
+      }
+    }
+
+    Dmar->Header.Length += Atsr->Header.Length;
+
+  } else if (RemapType == RhsaType) {
+    RhsaRegion = (DMAR_RHSA *) RemapEntry;
+    ASSERT (RhsaRegion->Signature == RHSA_SIGNATURE);
+
+    Rhsa                        = (EFI_ACPI_DMAR_RHSA_HEADER *) ((UINT8 *) Dmar + Dmar->Header.Length);
+    Rhsa->Header.Type           = EFI_ACPI_DMAR_TYPE_RHSA;
+    Rhsa->ProximityDomain       = RhsaRegion->Domian;
+    Rhsa->RegisterBaseAddress   = RhsaRegion->RegisterBase;
+    Rhsa->Header.Length         = sizeof (EFI_ACPI_DMAR_RHSA_HEADER);
+    Dmar->Header.Length         += Rhsa->Header.Length;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ASSERT (Dmar->Header.Length < TABLE_SIZE);
+  return EFI_SUCCESS;
+}
+
+/**
+
+    Returns info about the provided entry
+
+    @param Entry      - DMA remapping entry
+    @param Type       - DMA remapping type
+    @param IncludeAll - Include all or all root port ASTR
+    @param Length     - GC_TODO: add arg description
+
+    @retval EFI_INVALID_PARAMETER - Null input pointer
+    @retval EFI_SUCCESS           - Table info updated
+
+**/
+EFI_STATUS
+GetTablesInfo (
+  IN     UINT8       *Entry,
+  IN OUT REMAP_TYPE  *Type,
+  IN OUT BOOLEAN     *IncludeAll,
+  IN OUT UINTN       *Length
+  )
+{
+  EFI_ACPI_DMAR_DRHD_HEADER  *Comm;
+
+  if (!Entry || !Type || !IncludeAll || !Length) {
+    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Comm    = (EFI_ACPI_DMAR_DRHD_HEADER *) Entry;
+  *Length = Comm->Header.Length;
+
+  if (Comm->Header.Type == EFI_ACPI_DMAR_TYPE_RMRR) {
+    *Type = RmrrType;
+  } else if (Comm->Header.Type == EFI_ACPI_DMAR_TYPE_DRHD) {
+    *Type = DrhdType;
+  } else if (Comm->Header.Type == EFI_ACPI_DMAR_TYPE_ATSR) {
+    *Type = AtsrType;
+  } else if (Comm->Header.Type == EFI_ACPI_DMAR_TYPE_RHSA) {
+    *Type = RhsaType;
+  } else {
+    *Type = 0xFF;
+  }
+
+  if (Comm->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) {
+    *IncludeAll = TRUE;
+  } else {
+    *IncludeAll = FALSE;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+    Reorder the table entries
+
+    @param None
+
+    @retval EFI_SUCCESS - The table entries are ordered
+
+**/
+EFI_STATUS
+ReorderTables (
+  VOID
+  )
+{
+  REMAP_TYPE  Type;
+  BOOLEAN     IncludeAll;
+  UINTN       Length;
+  UINTN       CurrLength;
+  UINTN       TableLength;
+  UINT8       *Ptr;
+  UINT8       *PtrOrder;
+
+  Ptr       = (UINT8 *) mPrivateData.Dmar;
+  PtrOrder  = (UINT8 *) mPrivateData.DmarOrder;
+
+  CopyMem (PtrOrder, Ptr, sizeof (EFI_ACPI_DMAR_HEADER));
+  PtrOrder += sizeof (EFI_ACPI_DMAR_HEADER);
+
+  TableLength = mPrivateData.Dmar->Header.Length;
+
+  CurrLength  = sizeof (EFI_ACPI_DMAR_HEADER);
+  Ptr         = (UINT8 *) mPrivateData.Dmar + CurrLength;
+  while (CurrLength < TableLength) {
+    GetTablesInfo (Ptr, &Type, &IncludeAll, &Length);
+    if (Type == DrhdType && !IncludeAll) {
+      CopyMem (PtrOrder, Ptr, Length);
+      PtrOrder += Length;
+    }
+
+    Ptr += Length;
+    CurrLength += Length;
+  }
+
+  CurrLength  = sizeof (EFI_ACPI_DMAR_HEADER);
+  Ptr         = (UINT8 *) mPrivateData.Dmar + CurrLength;
+  while (CurrLength < TableLength) {
+    GetTablesInfo (Ptr, &Type, &IncludeAll, &Length);
+    if (Type == DrhdType && IncludeAll) {
+      CopyMem (PtrOrder, Ptr, Length);
+      PtrOrder += Length;
+    }
+
+    Ptr += Length;
+    CurrLength += Length;
+  }
+
+  CurrLength  = sizeof (EFI_ACPI_DMAR_HEADER);
+  Ptr         = (UINT8 *) mPrivateData.Dmar + CurrLength;
+  while (CurrLength < TableLength) {
+    GetTablesInfo (Ptr, &Type, &IncludeAll, &Length);
+    if (Type == RmrrType && !IncludeAll) {
+      CopyMem (PtrOrder, Ptr, Length);
+      PtrOrder += Length;
+    }
+
+    Ptr += Length;
+    CurrLength += Length;
+  }
+
+  CurrLength  = sizeof (EFI_ACPI_DMAR_HEADER);
+  Ptr         = (UINT8 *) mPrivateData.Dmar + CurrLength;
+  while (CurrLength < TableLength) {
+    GetTablesInfo (Ptr, &Type, &IncludeAll, &Length);
+    if (Type == AtsrType && !IncludeAll) {
+      CopyMem (PtrOrder, Ptr, Length);
+      PtrOrder += Length;
+    }
+
+    Ptr += Length;
+    CurrLength += Length;
+  }
+
+  CurrLength  = sizeof (EFI_ACPI_DMAR_HEADER);
+  Ptr         = (UINT8 *) mPrivateData.Dmar + CurrLength;
+  while (CurrLength < TableLength) {
+    GetTablesInfo (Ptr, &Type, &IncludeAll, &Length);
+    if (Type == RhsaType) {
+      CopyMem (PtrOrder, Ptr, Length);
+      PtrOrder += Length;
+    }
+
+    Ptr += Length;
+    CurrLength += Length;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Return a reordered version of the DMAR table provided on input
+
+  @param[in]      This      - DMA remap protocol
+  @param[in][out] DmarTable - DMAR table
+
+  @retval EFI_INVALID_PARAMETER - DmarTable NULL
+  @retval EFI_UNSUPPORTED       - DMAR table length doesn't meet expected value
+  @retval EFI_SUCCESS           - Updated DMAR table returned
+
+**/
+EFI_STATUS
+EFIAPI
+GetDmarTable (
+  IN     DMA_REMAP_PROTOCOL                *This,
+  IN OUT VOID                              **DmarTable
+  )
+{
+  if (DmarTable == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (mPrivateData.Dmar->Header.Length <= sizeof (EFI_ACPI_DMAR_HEADER)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  ReorderTables ();
+  *DmarTable = mPrivateData.DmarOrder;
+  return EFI_SUCCESS;
+}
+
+#define TBT_SECURITY_EVENT_STRING      "DMA Protection Disabled"
+#define TBT_SECURITY_EVENT_STRING_LEN  (sizeof (TBT_SECURITY_EVENT_STRING) - 1)
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_EVENT                         EndOfDxeEvent;
+
+/**
+  Security EndOfDxe CallBack Function
+  If the firmware/BIOS has an option to enable and disable DMA protections via a VT-d switch in BIOS options, then the shipping configuration must be with VT-d protection enabled.
+  On every boot where VT-d/DMA protection is disabled, or will be disabled, or configured to a lower security state, and a platform has a TPM enabled, then the platform SHALL
+  extend an EV_EFI_ACTION event into PCR[7] before enabling external DMA
+  The event string SHALL be "DMA Protection Disabled". The platform firmware MUST log this measurement in the event log using the string "DMA Protection Disabled" for the Event Data.
+  Measure and log launch of TBT Security, and extend the measurement result into a specific PCR.
+  Extend an EV_EFI_ACTION event into PCR[7] before enabling external DMA. The event string SHALL be "DMA Protection Disabled". The platform firmware MUST log this measurement
+  in the event log using the string "DMA Protection Disabled" for the Event Data.
+
+  @param[in] Event     - A pointer to the Event that triggered the callback.
+  @param[in] Context   - A pointer to private data registered with the callback function.
+**/
+VOID
+EFIAPI
+ExtendPCR7CallBack (
+  IN EFI_EVENT          Event,
+  IN VOID               *Context
+  )
+{
+  UINTN                 Status;
+  UINT64                HashDataLen;
+
+  DEBUG ((DEBUG_INFO, "ExtendPCR7CallBack START\n"));
+
+  //
+  // When VT-d/DMA protection is disabled and a platform has a TPM enabled,
+  // the platform SHALL extend an EV_EFI_ACTION event into PCR[7].
+  //
+  HashDataLen = TBT_SECURITY_EVENT_STRING_LEN;
+
+  Status = TpmMeasureAndLogData (
+             7,
+             EV_EFI_ACTION,
+             TBT_SECURITY_EVENT_STRING,
+             (UINT32) HashDataLen,
+             TBT_SECURITY_EVENT_STRING,
+             HashDataLen
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "TpmMeasureAndLogData Status: %r\n", Status));
+  } else {
+    DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData Successfully\n"));
+  }
+
+  DEBUG ((DEBUG_INFO, "ExtendPCR7CallBack END\n"));
+}
+
+/**
+  Register an End of DXE event for extended a TPM log to PCR[7] when vtd is diable
+  This feature is introduced by TBT Security requirment
+**/
+VOID
+RegisterExtendPCR7CallBack (
+  VOID
+  )
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+
+  //
+  // Register an End of DXE event for extended a TPM log to PCR[7].
+  //
+  DEBUG ((DEBUG_INFO, "Register an End of DXE event for extended a TPM log to PCR[7] when VTd/DMA protection is disabled.\n"));
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  ExtendPCR7CallBack,
+                  NULL,
+                  &gEfiEndOfDxeEventGroupGuid,
+                  &EndOfDxeEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to Register an End of DXE event for extended a TPM log to PCR[7], Status: %r\n", Status));
+  }
+}
+
+/**
+
+  VT-D Driver entry point
+
+  @param ImageHandle     The image handle.
+  @param SystemTable     The system table.
+
+  @retval Status - If not EFI_SUCCESS then an error occurred during initialization.
+
+**/
+EFI_STATUS
+EFIAPI
+VtdTableEntryPoint (
+  IN EFI_HANDLE                         ImageHandle,
+  IN EFI_SYSTEM_TABLE                   *SystemTable
+  )
+{
+  EFI_STATUS                            Status = EFI_SUCCESS;
+  EFI_ACPI_DMAR_HEADER                  *Dmar;
+  UINT64                                TempOemTableId;
+  UINT8                                 VTdSupport;
+  UINT8                                 DmaCtrlOptIn;
+  UINT8                                 InterruptRemap;
+  UINT8                                 X2ApicOptOut;
+  UINT8                                 ATS;
+  UINTN                                 Dmarlength;
+  UINT8                                 ControlIommu;
+
+  //
+  // Initialize our protocol
+  //
+  ZeroMem (&mPrivateData, sizeof (VTD_SUPPORT_INSTANCE));
+
+  Status = GetOptionData (&gEfiSocketIioVariableGuid, OFFSET_OF (SOCKET_IIO_CONFIGURATION, VTdSupport), &VTdSupport, sizeof (VTdSupport));
+  Status |= GetOptionData (&gEfiSocketIioVariableGuid, OFFSET_OF (SOCKET_IIO_CONFIGURATION, DmaCtrlOptIn), &DmaCtrlOptIn, sizeof (DmaCtrlOptIn));
+  Status |= GetOptionData (&gEfiSocketIioVariableGuid, OFFSET_OF (SOCKET_IIO_CONFIGURATION, InterruptRemap), &InterruptRemap, sizeof (InterruptRemap));
+  Status |= GetOptionData (&gEfiSocketIioVariableGuid, OFFSET_OF (SOCKET_IIO_CONFIGURATION, ATS), &ATS, sizeof (ATS));
+  Status |= GetOptionData (&gEfiSocketIioVariableGuid, OFFSET_OF (SOCKET_IIO_CONFIGURATION, X2ApicOptOut), &X2ApicOptOut, sizeof (X2ApicOptOut));
+
+  if (!EFI_ERROR (Status)) {
+    mPrivateData.DmaRemapProt.VTdSupport      = VTdSupport;
+    mPrivateData.DmaRemapProt.DmaCtrlOptIn    = DmaCtrlOptIn;
+    mPrivateData.DmaRemapProt.InterruptRemap  = VTdSupport && (InterruptRemap != IIO_OPTION_DISABLE);
+    mPrivateData.DmaRemapProt.ATS             = ATS;
+    mPrivateData.DmaRemapProt.X2ApicOptOut    = X2ApicOptOut;
+  }
+
+  Status = GetOptionData (&gEfiSocketIioVariableGuid, OFFSET_OF (SOCKET_IIO_CONFIGURATION, ControlIommu), &ControlIommu, sizeof (ControlIommu));
+  if (EFI_ERROR (Status)) {
+    ControlIommu = 0;
+  }
+
+  mPrivateData.Signature = EFI_ACPI_6_4_DMA_REMAPPING_TABLE_SIGNATURE;
+
+  Dmarlength = MAX_SOCKET * NUMBER_PORTS_PER_SOCKET * ( sizeof (EFI_ACPI_DMAR_HEADER) + sizeof (EFI_ACPI_DMAR_DRHD_HEADER) +
+                    sizeof (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) + sizeof (EFI_ACPI_DMAR_PCI_PATH));
+
+  mPrivateData.Dmar = (EFI_ACPI_DMAR_HEADER *) AllocateZeroPool (Dmarlength);
+
+  mPrivateData.DmarOrder = (EFI_ACPI_DMAR_HEADER *) AllocateZeroPool (Dmarlength);
+
+  mPrivateData.DmaRemapProt.InsertDmaRemap = InsertDmaRemap;
+  mPrivateData.DmaRemapProt.GetDmarTable = GetDmarTable;
+
+  if (mPrivateData.Dmar != NULL) {
+    Dmar                          = mPrivateData.Dmar;
+    Dmar->Header.Length           = sizeof (EFI_ACPI_DMAR_HEADER);
+    Dmar->Header.Signature        = EFI_ACPI_6_4_DMA_REMAPPING_TABLE_SIGNATURE;
+    Dmar->Header.Revision         = EFI_ACPI_DMAR_REVISION;
+    Dmar->Header.OemRevision      = ACPI_DMAR_OEM_REVISION;
+    Dmar->Header.CreatorId        = ACPI_DMAR_OEM_CREATOR_ID;
+    Dmar->Header.CreatorRevision  = ACPI_DMAR_OEM_CREATOR_REVISION;
+    Dmar->HostAddressWidth        = MAX_BUS_ADDR_WIDTH;
+
+    TempOemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+
+    CopyMem (Dmar->Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Dmar->Header.OemId));
+    CopyMem (&Dmar->Header.OemTableId, &TempOemTableId, sizeof (Dmar->Header.OemTableId));
+
+    Status = gBS->InstallProtocolInterface (
+                    &mPrivateData.Handle,
+                    &gDmaRemapProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &mPrivateData.DmaRemapProt
+                    );
+  } else {
+
+    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
+    Status = EFI_OUT_OF_RESOURCES;
+  }
+
+  if (FixedPcdGetBool (PcdConditionallyExtendPcr7)) {
+    if (!VTdSupport || !DmaCtrlOptIn || (ControlIommu == 0)) {
+      //
+      // Inform OS by TPM PCR7 when VTd/DMA protection is disabled.
+      //
+      RegisterExtendPCR7CallBack ();
+    }
+  }
+
+  return Status;
+}

+ 66 - 0
Platform/Intel/WhitleyOpenBoardPkg/Features/AcpiVtd/AcpiVtd.inf

@@ -0,0 +1,66 @@
+## @file
+#
+# @copyright
+# Copyright 2009 - 2021 Intel Corporation. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = AcpiVtd
+  FILE_GUID                      = 64A11188-5B86-4f59-A702-73365896E65E
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = VtdTableEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  AcpiVtd.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  WhitleyOpenBoardPkg/PlatformPkg.dec
+  WhitleySiliconPkg/SiliconPkg.dec
+  WhitleySiliconPkg/CpRcPkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  IoLib
+  BaseMemoryLib
+  DebugLib
+  UefiRuntimeServicesTableLib
+  UefiBootServicesTableLib
+  DevicePathLib
+  HobLib
+  SetupLib
+  TpmMeasurementLib
+
+[Protocols]
+  gDmaRemapProtocolGuid                         ## CONSUMES
+
+[Guids]
+  gEfiHobListGuid                               ## CONSUMES
+  gEfiSocketIioVariableGuid                     ## CONSUMES
+  gEfiEndOfDxeEventGroupGuid                    ## CONSUMES
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId
+  gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId
+  gPlatformTokenSpaceGuid.PcdConditionallyExtendPcr7
+
+[FixedPcd]
+  gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuSocketCount
+  gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuCoreCount
+
+[Depex]
+  gEfiVariableArchProtocolGuid AND
+  gEfiIioUdsProtocolGuid AND
+  gEfiIioSystemProtocolGuid
+

+ 53 - 0
Platform/Intel/WhitleyOpenBoardPkg/Include/AcpiVtd.h

@@ -0,0 +1,53 @@
+/** @file
+  This file describes the contents of the VTD ACPI Support
+
+  @copyright
+  Copyright 1996 - 2021 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _ACPI_VTD_H
+#define _ACPI_VTD_H
+
+//
+// Statements that include other files
+//
+#include <PiDxe.h>
+#include <Library/UefiLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HobLib.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/DmaRemappingReportingTable.h>
+#include <Protocol/DmaRemap.h>
+#include <Guid/HobList.h>
+#include <Guid/PlatformInfo.h>
+#include <Guid/SocketVariable.h>
+
+//
+// equates used in DMAR Table.
+//
+#define ACPI_DMAR_OEM_REVISION          0x01
+#define ACPI_DMAR_OEM_CREATOR_ID        0x01
+#define ACPI_DMAR_OEM_CREATOR_REVISION  0x01
+
+#define TABLE_SIZE                      4 * 1024
+
+typedef struct {
+  UINT32                                Signature;
+  EFI_HANDLE                            Handle;
+  DMA_REMAP_PROTOCOL                    DmaRemapProt;
+  EFI_ACPI_DMAR_HEADER                  *Dmar;
+  EFI_ACPI_DMAR_HEADER                  *DmarOrder;
+} VTD_SUPPORT_INSTANCE;
+
+#endif

+ 109 - 0
Platform/Intel/WhitleyOpenBoardPkg/Include/Protocol/DmaRemap.h

@@ -0,0 +1,109 @@
+/** @file
+  Protocol used to support ACPI VT-d DMA remapping reporting
+
+  @copyright
+  Copyright 2006 - 2021 Intel Corporation. <BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef __DMA_REMAP_H__
+#define __DMA_REMAP_H__
+
+//
+// Protocol for GUID.
+//
+typedef struct _DMA_REMAP_PROTOCOL DMA_REMAP_PROTOCOL;
+
+#define  DRHD_SIGNATURE  (('D'<<24) + ('R'<<16) + ('H'<<8) + 'D')
+#define  RMRR_SIGNATURE  (('R'<<24) + ('M'<<16) + ('R'<<8) + 'R')
+#define  ATSR_SIGNATURE  (('A'<<24) + ('T'<<16) + ('S'<<8) + 'R')
+#define  RHSA_SIGNATURE  (('A'<<24) + ('S'<<16) + ('H'<<8) + 'R')
+#define  ANDD_SIGNATURE  (('A'<<24) + ('N'<<16) + ('D'<<8) + 'D')
+
+typedef enum {
+  DrhdType,
+  RmrrType,
+  AtsrType,
+  RhsaType
+} REMAP_TYPE;
+
+typedef enum {
+  PciEndpoint = 1,
+  PciBridge   = 2
+} PCI_DEV_TYPE;
+
+typedef struct {
+  UINT8         Device;
+  UINT8         Function;
+} PCI_NODE;
+
+typedef struct {
+  UINT8         DeviceType;
+  UINT8         EnumerationID;
+  UINT8         StartBusNumber;
+  PCI_NODE      *PciNode;
+} DEVICE_SCOPE;
+
+typedef struct {
+  UINT32        Signature;
+  UINT8         Flags;
+  UINT16        SegmentNumber;
+  UINT64        RegisterBase;
+  UINTN         DeviceScopeNumber;
+  DEVICE_SCOPE  *DeviceScope;
+} DMAR_DRHD;
+
+typedef struct {
+  UINT32        Signature;
+  UINT16        SegmentNumber;
+  UINT64        RsvdMemBase;
+  UINT64        RsvdMemLimit;
+  UINTN         DeviceScopeNumber;
+  DEVICE_SCOPE  *DeviceScope;
+} DMAR_RMRR;
+
+typedef struct {
+  UINT32        Signature;
+  UINT8         Flags;
+  UINT16        SegmentNumber;
+  UINTN         DeviceScopeNumber;
+  UINT32        ATSRPresentBit;
+  DEVICE_SCOPE  *DeviceScope;
+} DMAR_ATSR;
+
+typedef struct {
+  UINT32        Signature;
+  UINT64        RegisterBase;
+  UINT32        Domian;
+  UINT16        RhsaCount;
+} DMAR_RHSA;
+
+typedef
+EFI_STATUS
+(EFIAPI *INSERT_DMA_REMAP) (
+  IN  DMA_REMAP_PROTOCOL                                        *This,
+  IN  REMAP_TYPE                                                RemapType,
+  IN  VOID                                                      *RemapEntry
+  );
+
+typedef
+EFI_STATUS
+(EFIAPI *GET_DMAR_TABLE) (
+  IN  DMA_REMAP_PROTOCOL                                        *This,
+  IN  VOID                                                      **DmarTable
+  );
+
+typedef struct _DMA_REMAP_PROTOCOL {
+  BOOLEAN                   VTdSupport;
+  BOOLEAN                   DmaCtrlOptIn;
+  BOOLEAN                   InterruptRemap;
+  BOOLEAN                   X2ApicOptOut;
+  BOOLEAN                   ATS;
+  INSERT_DMA_REMAP          InsertDmaRemap;
+  GET_DMAR_TABLE            GetDmarTable;
+} DMA_REMAP_PROTOCOL;
+
+extern EFI_GUID gDmaRemapProtocolGuid;
+
+#endif

+ 4 - 0
Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec

@@ -153,6 +153,7 @@
   gEfiIpmiBootGuid                                    = { 0x5c9b75ec, 0x8ec7, 0x45f2, { 0x8f, 0x8f, 0xc1, 0xd8, 0x8f, 0x3b, 0x93, 0x45 } }
   gEfiGenericIpmiDriverInstalledGuid                  = { 0x7cdad61a, 0x3df8, 0x4425, { 0x96, 0x8c, 0x66, 0x28, 0xc8, 0x35, 0xff, 0xce } }
 
+  gDmaRemapProtocolGuid                            = { 0x4e873773, 0x8391, 0x4e47, { 0xb7, 0xf4, 0xca, 0xfb, 0xdc, 0xc4, 0xb2, 0x04 } }
 
 [PcdsFixedAtBuild]
 
@@ -211,6 +212,9 @@
   gCpPlatFlashTokenSpaceGuid.PcdFlashCfrRegionSize|0x01000000|UINT32|0xF00000B0
   gCpPlatFlashTokenSpaceGuid.PcdFlashCfrRegionBase|0xFF900000|UINT32|0xF00000B1
 
+  #If True, extend PCR7 when VT-d disabled.
+  gPlatformTokenSpaceGuid.PcdConditionallyExtendPcr7|FALSE|BOOLEAN|0xE0000045
+
 [PcdsFixedAtBuild, PcdsPatchableInModule]
   gPlatformTokenSpaceGuid.PcdShellFile|{ 0xB7, 0xD6, 0x7A, 0xC5, 0x15, 0x05, 0xA8, 0x40, 0x9D, 0x21, 0x55, 0x16, 0x52, 0x85, 0x4E, 0x37 }|VOID*|0x40000004
   ## Specify memory size with page number for a pre-allocated reserved memory to be used

+ 1 - 0
Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dsc

@@ -741,6 +741,7 @@
 
   $(RP_PKG)/Features/Pci/Dxe/PciPlatform/PciPlatform.inf
 
+  $(RP_PKG)/Features/AcpiVtd/AcpiVtd.inf
 
   $(PLATFORM_PKG)/Acpi/AcpiSmm/AcpiSmm.inf {
     <LibraryClasses>

+ 1 - 0
Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.fdf

@@ -672,6 +672,7 @@ SET gMinPlatformPkgTokenSpaceGuid.PcdFlashAreaSize         = 0x01000000
   INF  BoardModulePkg/LegacySioDxe/LegacySioDxe.inf
   INF  MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf
 
+  INF  WhitleyOpenBoardPkg/Features/AcpiVtd/AcpiVtd.inf
   INF  MinPlatformPkg/Acpi/AcpiSmm/AcpiSmm.inf
 
 [FV.FvOsBoot]

+ 4 - 0
Silicon/Intel/WhitleySiliconPkg/Include/IioSetupDefinitions.h

@@ -57,4 +57,8 @@
 #define IIO_BIFURCATE_x2x2x2x2x2x2x2x2  0x19
 #define IIO_BIFURCATE_AUTO              0xFF
 
+#define IIO_OPTION_AUTO    2
+#define IIO_OPTION_ENABLE  1
+#define IIO_OPTION_DISABLE 0
+
 #endif /* _IIOSETUPDEFINITIONS_H_ */