REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2303

This driver is to do the PCI device authentication
based upon Intel PCIe Security Specification.

Cc: Ray Ni <ray...@intel.com>
Cc: Rangasai V Chaganty <rangasai.v.chaga...@intel.com>
Cc: Yun Lou <yun....@intel.com>
Signed-off-by: Jiewen Yao <jiewen....@intel.com>
Signed-off-by: Yun Lou <yun....@intel.com>
---
 .../IntelPciDeviceSecurityDxe.c               | 697 ++++++++++++++++++
 .../IntelPciDeviceSecurityDxe.inf             |  45 ++
 .../TcgDeviceEvent.h                          | 178 +++++
 3 files changed, 920 insertions(+)
 create mode 100644 
Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.c
 create mode 100644 
Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.inf
 create mode 100644 
Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/TcgDeviceEvent.h

diff --git 
a/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.c
 
b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.c
new file mode 100644
index 0000000000..8838d5635a
--- /dev/null
+++ 
b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.c
@@ -0,0 +1,697 @@
+/** @file
+  EDKII Device Security library for PCI device.
+  It follows the Intel PCIe Security Specification.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <IndustryStandard/Spdm.h>
+#include <IndustryStandard/IntelPciSecurity.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Tpm20.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/TpmMeasurementLib.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DeviceSecurity.h>
+#include <Protocol/PlatformDeviceSecurityPolicy.h>
+#include "TcgDeviceEvent.h"
+
+typedef struct {
+  EDKII_DEVICE_SECURITY_EVENT_DATA_HEADER       EventData;
+  SPDM_MEASUREMENT_BLOCK_COMMON_HEADER          CommonHeader;
+  SPDM_MEASUREMENT_BLOCK_DMTF_HEADER            DmtfHeader;
+  UINT8                                         Digest[SHA256_DIGEST_SIZE];
+  EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT  PciContext;
+} EDKII_DEVICE_SECURITY_PCI_EVENT_DATA;
+
+typedef struct {
+  UINTN         Signature;
+  LIST_ENTRY    Link;
+  UINTN         PciSegment;
+  UINTN         PciBus;
+  UINTN         PciDevice;
+  UINTN         PciFunction;
+} PCI_DEVICE_INSTANCE;
+
+#define PCI_DEVICE_INSTANCE_SIGNATURE  SIGNATURE_32 ('P', 'D', 'I', 'S')
+#define PCI_DEVICE_INSTANCE_FROM_LINK(a)  CR (a, PCI_DEVICE_INSTANCE, Link, 
PCI_DEVICE_INSTANCE_SIGNATURE)
+
+LIST_ENTRY mSecurityEventMeasurementDeviceList = 
INITIALIZE_LIST_HEAD_VARIABLE(mSecurityEventMeasurementDeviceList);;
+EDKII_DEVICE_SECURITY_POLICY_PROTOCOL  *mDeviceSecurityPolicy;
+
+/**
+  Record a PCI device into device list.
+
+  @param PciIo            PciIo instance of the device
+  @param PciDeviceList    The list to record the the device
+**/
+VOID
+RecordPciDeviceInList(
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,
+  IN LIST_ENTRY                   *PciDeviceList
+  )
+{
+  UINTN                 PciSegment;
+  UINTN                 PciBus;
+  UINTN                 PciDevice;
+  UINTN                 PciFunction;
+  EFI_STATUS            Status;
+  PCI_DEVICE_INSTANCE   *NewPciDevice;
+
+  Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBus, &PciDevice, 
&PciFunction);
+  ASSERT_EFI_ERROR(Status);
+
+  NewPciDevice = AllocateZeroPool(sizeof(*NewPciDevice));
+  ASSERT_EFI_ERROR(NewPciDevice != NULL);
+
+  NewPciDevice->Signature   = PCI_DEVICE_INSTANCE_SIGNATURE;
+  NewPciDevice->PciSegment  = PciSegment;
+  NewPciDevice->PciBus      = PciBus;
+  NewPciDevice->PciDevice   = PciDevice;
+  NewPciDevice->PciFunction = PciFunction;
+
+  InsertTailList(PciDeviceList, &NewPciDevice->Link);
+}
+
+/**
+  Check if a PCI device is recorded in device list.
+
+  @param PciIo            PciIo instance of the device
+  @param PciDeviceList    The list to record the the device
+
+  @retval TRUE  The PCI device is in the list.
+  @retval FALSE The PCI device is NOT in the list.
+**/
+BOOLEAN
+IsPciDeviceInList(
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,
+  IN LIST_ENTRY                   *PciDeviceList
+  )
+{
+  UINTN                 PciSegment;
+  UINTN                 PciBus;
+  UINTN                 PciDevice;
+  UINTN                 PciFunction;
+  EFI_STATUS            Status;
+  LIST_ENTRY            *Link;
+  PCI_DEVICE_INSTANCE   *CurrentPciDevice;
+
+  Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBus, &PciDevice, 
&PciFunction);
+  ASSERT_EFI_ERROR(Status);
+
+  Link = GetFirstNode(PciDeviceList);
+  while (!IsNull(PciDeviceList, Link)) {
+    CurrentPciDevice = PCI_DEVICE_INSTANCE_FROM_LINK(Link);
+
+    if (CurrentPciDevice->PciSegment == PciSegment && CurrentPciDevice->PciBus 
== PciBus &&
+        CurrentPciDevice->PciDevice == PciDevice && 
CurrentPciDevice->PciFunction == PciFunction) {
+      DEBUG((DEBUG_INFO, "PCI device duplicated (Loc - 
%04x:%02x:%02x:%02x)\n", PciSegment, PciBus, PciDevice, PciFunction));
+      return TRUE;
+    }
+
+    Link = GetNextNode(PciDeviceList, Link);
+  }
+
+  return FALSE;
+}
+
+/*
+  return Offset of the PCI Cap ID.
+
+  @param PciIo            PciIo instance of the device
+  @param CapId            The Capability ID of the Pci device
+
+  @return The PCI Capability ID Offset
+*/
+UINT32
+GetPciCapId (
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,
+  IN UINT8                        CapId
+  )
+{
+  EFI_PCI_CAPABILITY_HDR                    PciCapIdHdr;
+  UINT32                                    PciCapIdOffset;
+  EFI_STATUS                                Status;
+
+  PciCapIdHdr.CapabilityID = ~CapId;
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 
PCI_CAPBILITY_POINTER_OFFSET, 1, &PciCapIdHdr.NextItemPtr);
+  ASSERT_EFI_ERROR(Status);
+  if (PciCapIdHdr.NextItemPtr == 0 || PciCapIdHdr.NextItemPtr == 0xFF) {
+    return 0;
+  }
+  PciCapIdOffset = 0;
+  do {
+    if (PciCapIdHdr.CapabilityID == CapId) {
+      break;
+    }
+    PciCapIdOffset = PciCapIdHdr.NextItemPtr;
+    Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PciCapIdOffset, 1, 
&PciCapIdHdr);
+    ASSERT_EFI_ERROR(Status);
+  } while (PciCapIdHdr.NextItemPtr != 0 && PciCapIdHdr.NextItemPtr != 0xFF);
+
+  if (PciCapIdHdr.CapabilityID == CapId) {
+    return PciCapIdOffset;
+  } else {
+    return 0;
+  }
+}
+
+/*
+  return Offset of the PCIe Ext Cap ID.
+
+  @param PciIo            PciIo instance of the device
+  @param CapId            The Ext Capability ID of the Pci device
+
+  @return The PCIe Ext Capability ID Offset
+*/
+UINT32
+GetPciExpressExtCapId (
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,
+  IN UINT16                       CapId
+  )
+{
+  UINT32                                    PcieCapIdOffset;
+  PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER  PciExpressExtCapIdHdr;
+  EFI_STATUS                                Status;
+
+  PcieCapIdOffset = GetPciCapId (PciIo, EFI_PCI_CAPABILITY_ID_PCIEXP);
+  if (PcieCapIdOffset == 0) {
+    return 0;
+  }
+
+  PciExpressExtCapIdHdr.CapabilityId = ~CapId;
+  PciExpressExtCapIdHdr.CapabilityVersion = 0xF;
+  PciExpressExtCapIdHdr.NextCapabilityOffset = 0x100;
+  PcieCapIdOffset = 0;
+  do {
+    if (PciExpressExtCapIdHdr.CapabilityId == CapId) {
+      break;
+    }
+    PcieCapIdOffset = PciExpressExtCapIdHdr.NextCapabilityOffset;
+    Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, PcieCapIdOffset, 1, 
&PciExpressExtCapIdHdr);
+    ASSERT_EFI_ERROR(Status);
+  } while (PciExpressExtCapIdHdr.NextCapabilityOffset != 0 && 
PciExpressExtCapIdHdr.NextCapabilityOffset != 0xFFF);
+
+  if (PciExpressExtCapIdHdr.CapabilityId == CapId) {
+    return PcieCapIdOffset;
+  } else {
+    return 0;
+  }
+}
+
+/**
+  Read byte of the PCI device configuration space.
+
+  @param PciIo            PciIo instance of the device
+  @param Offset           The offset of the Pci device configuration space
+
+  @return Byte value of the PCI device configuration space.
+**/
+UINT8
+DvSecPciRead8 (
+  IN EFI_PCI_IO_PROTOCOL *PciIo,
+  IN UINT32              Offset
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       Data;
+
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, Offset, 1, &Data);
+  ASSERT_EFI_ERROR(Status);
+
+  return Data;
+}
+
+/**
+  Write byte of the PCI device configuration space.
+
+  @param PciIo            PciIo instance of the device
+  @param Offset           The offset of the Pci device configuration space
+  @param Data             Byte value of the PCI device configuration space.
+**/
+VOID
+DvSecPciWrite8 (
+  IN EFI_PCI_IO_PROTOCOL *PciIo,
+  IN UINT32              Offset,
+  IN UINT8               Data
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, Offset, 1, &Data);
+  ASSERT_EFI_ERROR(Status);
+}
+
+/**
+  Get the Digest size from the TCG hash Algorithm ID.
+
+  @param TcgAlgId            TCG hash Algorithm ID
+
+  @return Digest size of the TCG hash Algorithm ID
+**/
+UINTN
+DigestSizeFromTcgAlgId (
+  IN UINT16                                    TcgAlgId
+  )
+{
+  switch (TcgAlgId) {
+  case TPM_ALG_SHA256:
+    return SHA256_DIGEST_SIZE;
+  case TPM_ALG_SHA384:
+  case TPM_ALG_SHA512:
+  case TPM_ALG_SM3_256:
+  default:
+    break;
+  }
+  return 0;
+}
+
+/**
+  Convert the SPDM hash algo ID from the TCG hash Algorithm ID.
+
+  @param TcgAlgId            TCG hash Algorithm ID
+
+  @return SPDM hash algo ID
+**/
+UINT32
+TcgAlgIdToSpdmHashAlgo (
+  IN UINT16                                    TcgAlgId
+  )
+{
+  switch (TcgAlgId) {
+  case TPM_ALG_SHA256:
+    return SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256;
+  case TPM_ALG_SHA384:
+  case TPM_ALG_SHA512:
+  case TPM_ALG_SM3_256:
+  default:
+    break;
+  }
+  return 0;
+}
+
+/**
+  This function extend the PCI digest from the DvSec register.
+
+  @param[in]  PciIo                  The PciIo of the device.
+  @param[in]  DeviceSecurityPolicy   The Device Security Policy associated 
with the device.
+  @param[in]  TcgAlgId               TCG hash Algorithm ID
+  @param[in]  DigestSel              The digest selector
+  @param[in]  Digest                 The digest buffer
+  @param[out] DeviceSecurityState    The Device Security state associated with 
the device.
+**/
+VOID
+ExtendDigestRegister (
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,
+  IN EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy,
+  IN UINT16                       TcgAlgId,
+  IN UINT8                        DigestSel,
+  IN UINT8                        *Digest,
+  OUT EDKII_DEVICE_SECURITY_STATE *DeviceSecurityState
+  )
+{
+  UINT32                                                   PcrIndex;
+  UINT32                                                   EventType;
+  EDKII_DEVICE_SECURITY_PCI_EVENT_DATA                     EventLog;
+  EFI_STATUS                                               Status;
+  PCI_TYPE00                                               PciData;
+
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof(PciData), 
&PciData);
+  ASSERT_EFI_ERROR(Status);
+
+  PcrIndex = EDKII_DEVICE_MEASUREMENT_COMPONENT_PCR_INDEX;
+  EventType = EDKII_DEVICE_MEASUREMENT_COMPONENT_EVENT_TYPE;
+
+  CopyMem (EventLog.EventData.Signature, 
EDKII_DEVICE_SECURITY_EVENT_DATA_SIGNATURE, 
sizeof(EventLog.EventData.Signature));
+  EventLog.EventData.Version                  = 
EDKII_DEVICE_SECURITY_EVENT_DATA_VERSION;
+  EventLog.EventData.Length                   = 
sizeof(EDKII_DEVICE_SECURITY_PCI_EVENT_DATA);
+  EventLog.EventData.SpdmHashAlgo             = TcgAlgIdToSpdmHashAlgo 
(TcgAlgId);
+  EventLog.EventData.DeviceType               = 
EDKII_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_PCI;
+
+  EventLog.CommonHeader.Index                      = DigestSel;
+  EventLog.CommonHeader.MeasurementSpecification   = 
SPDM_MEASUREMENT_BLOCK_HEADER_SPECIFICATION_DMTF;
+  EventLog.CommonHeader.MeasurementSize            = 
sizeof(SPDM_MEASUREMENT_BLOCK_DMTF_HEADER) + SHA256_DIGEST_SIZE;
+  EventLog.DmtfHeader.DMTFSpecMeasurementValueType = 
SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_MUTABLE_FIRMWARE;
+  EventLog.DmtfHeader.DMTFSpecMeasurementValueSize = SHA256_DIGEST_SIZE;
+  CopyMem (&EventLog.Digest, Digest, SHA256_DIGEST_SIZE);
+
+  EventLog.PciContext.Version           = 
EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT_VERSION;
+  EventLog.PciContext.Length            = 
sizeof(EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT);
+  EventLog.PciContext.VendorId          = PciData.Hdr.VendorId;
+  EventLog.PciContext.DeviceId          = PciData.Hdr.DeviceId;
+  EventLog.PciContext.RevisionID        = PciData.Hdr.RevisionID;
+  EventLog.PciContext.ClassCode[0]      = PciData.Hdr.ClassCode[0];
+  EventLog.PciContext.ClassCode[1]      = PciData.Hdr.ClassCode[1];
+  EventLog.PciContext.ClassCode[2]      = PciData.Hdr.ClassCode[2];
+  if ((PciData.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
+    EventLog.PciContext.SubsystemVendorID = PciData.Device.SubsystemVendorID;
+    EventLog.PciContext.SubsystemID       = PciData.Device.SubsystemID;
+  } else {
+    EventLog.PciContext.SubsystemVendorID = 0;
+    EventLog.PciContext.SubsystemID       = 0;
+  }
+
+  Status = TpmMeasureAndLogData (
+             PcrIndex,
+             EventType,
+             &EventLog,
+             EventLog.EventData.Length,
+             Digest,
+             SHA256_DIGEST_SIZE
+             );
+  DEBUG((DEBUG_INFO, "TpmMeasureAndLogData - %r\n", Status));
+  if (EFI_ERROR(Status)) {
+    DeviceSecurityState->MeasurementState = 
EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR;
+  } else {
+    RecordPciDeviceInList (PciIo, &mSecurityEventMeasurementDeviceList);
+  }
+}
+
+/**
+  This function reads the PCI digest from the DvSec register and extend to TPM.
+
+  @param[in]  PciIo                  The PciIo of the device.
+  @param[in]  DvSecOffset            The DvSec register offset of the device.
+  @param[in]  DeviceSecurityPolicy   The Device Security Policy associated 
with the device.
+  @param[out] DeviceSecurityState    The Device Security state associated with 
the device.
+**/
+VOID
+DoMeasurementsFromDigestRegister (
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,
+  IN UINT32                       DvSecOffset,
+  IN EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy,
+  OUT EDKII_DEVICE_SECURITY_STATE *DeviceSecurityState
+  )
+{
+  UINT8                                     Modified;
+  UINT8                                     Valid;
+  UINT16                                    TcgAlgId;
+  UINT8                                     NumDigest;
+  UINT8                                     DigestSel;
+  UINT8                                     Digest[SHA256_DIGEST_SIZE];
+  UINTN                                     DigestSize;
+  EFI_STATUS                                Status;
+
+  TcgAlgId = DvSecPciRead8 (
+               PciIo,
+               DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + 
OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, TcgAlgId)
+               );
+  DEBUG((DEBUG_INFO, "  TcgAlgId      - 0x%04x\n", TcgAlgId));
+  DigestSize = DigestSizeFromTcgAlgId (TcgAlgId);
+  if (DigestSize == 0) {
+    DEBUG((DEBUG_INFO, "Unsupported Algorithm - 0x%04x\n", TcgAlgId));
+    DeviceSecurityState->MeasurementState = 
EDKII_DEVICE_SECURITY_STATE_ERROR_PCI_NO_CAPABILITIES;
+    return ;
+  }
+  DEBUG((DEBUG_INFO, "  (DigestSize: 0x%x)\n", DigestSize));
+
+  DeviceSecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_SUCCESS;
+
+  NumDigest = DvSecPciRead8 (
+                PciIo,
+                DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + 
OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, FirmwareID)
+                );
+  DEBUG((DEBUG_INFO, "  NumDigest     - 0x%02x\n", NumDigest));
+
+  Valid = DvSecPciRead8 (
+            PciIo,
+            DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + 
OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, Valid)
+            );
+  DEBUG((DEBUG_INFO, "  Valid         - 0x%02x\n", Valid));
+
+  //
+  // Only 2 are supported as maximum.
+  // But hardware may report 3.
+  //
+  if (NumDigest > 2) {
+    NumDigest = 2;
+  }
+
+  for (DigestSel = 0; DigestSel < NumDigest; DigestSel++) {
+    DEBUG((DEBUG_INFO, "  DigestSel     - 0x%02x\n", DigestSel));
+    if ((DigestSel == 0) && ((Valid & INTEL_PCI_DIGEST_0_VALID) == 0)) {
+      continue;
+    }
+    if ((DigestSel == 1) && ((Valid & INTEL_PCI_DIGEST_1_VALID) == 0)) {
+      continue;
+    }
+    while (TRUE) {
+      //
+      // Host MUST clear DIGEST_MODIFIED before read DIGEST.
+      //
+      DvSecPciWrite8 (
+        PciIo,
+        DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + 
OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, Modified),
+        INTEL_PCI_DIGEST_MODIFIED
+        );
+
+      Status = PciIo->Pci.Read (
+                            PciIo,
+                            EfiPciIoWidthUint8,
+                            (UINT32)(DvSecOffset + 
sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + 
sizeof(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE) + DigestSize * DigestSel),
+                            DigestSize,
+                            Digest
+                            );
+      ASSERT_EFI_ERROR(Status);
+
+      //
+      // After read DIGEST, Host MUST consult DIGEST_MODIFIED.
+      //
+      Modified = DvSecPciRead8 (
+                   PciIo,
+                   DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + 
OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, Modified)
+                   );
+      if ((Modified & INTEL_PCI_DIGEST_MODIFIED) == 0) {
+        break;
+      }
+    }
+
+    //
+    // Dump Digest
+    //
+    {
+      UINTN  Index;
+      DEBUG((DEBUG_INFO, "  Digest        - "));
+      for (Index = 0; Index < DigestSize; Index++) {
+        DEBUG((DEBUG_INFO, "%02x", *(Digest + Index)));
+      }
+      DEBUG((DEBUG_INFO, "\n"));
+    }
+
+    DEBUG((DEBUG_INFO, "ExtendDigestRegister...\n", ExtendDigestRegister));
+    ExtendDigestRegister (PciIo, DeviceSecurityPolicy, TcgAlgId, DigestSel, 
Digest, DeviceSecurityState);
+  }
+}
+
+/**
+  The device driver uses this service to measure a PCI device.
+
+  @param[in]  PciIo                  The PciIo of the device.
+  @param[in]  DeviceSecurityPolicy   The Device Security Policy associated 
with the device.
+  @param[out] DeviceSecurityState    The Device Security state associated with 
the device.
+**/
+VOID
+DoDeviceMeasurement (
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,
+  IN EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy,
+  OUT EDKII_DEVICE_SECURITY_STATE *DeviceSecurityState
+  )
+{
+  UINT32                                    DvSecOffset;
+  INTEL_PCI_DIGEST_CAPABILITY_HEADER        DvSecHdr;
+  EFI_STATUS                                Status;
+
+  if (IsPciDeviceInList (PciIo, &mSecurityEventMeasurementDeviceList)) {
+    DeviceSecurityState->MeasurementState = 
EDKII_DEVICE_SECURITY_STATE_SUCCESS;
+    return ;
+  }
+
+  DvSecOffset = GetPciExpressExtCapId (PciIo, INTEL_PCI_CAPID_DVSEC);
+  DEBUG((DEBUG_INFO, "DvSec Capability - 0x%x\n", DvSecOffset));
+  if (DvSecOffset == 0) {
+    DeviceSecurityState->MeasurementState = 
EDKII_DEVICE_SECURITY_STATE_ERROR_PCI_NO_CAPABILITIES;
+    return ;
+  }
+  Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, DvSecOffset, 
sizeof(DvSecHdr)/sizeof(UINT16), &DvSecHdr);
+  ASSERT_EFI_ERROR(Status);
+  DEBUG((DEBUG_INFO, "  CapId         - 0x%04x\n", DvSecHdr.CapId));
+  DEBUG((DEBUG_INFO, "  CapVersion    - 0x%01x\n", DvSecHdr.CapVersion));
+  DEBUG((DEBUG_INFO, "  NextOffset    - 0x%03x\n", DvSecHdr.NextOffset));
+  DEBUG((DEBUG_INFO, "  DvSecVendorId - 0x%04x\n", DvSecHdr.DvSecVendorId));
+  DEBUG((DEBUG_INFO, "  DvSecRevision - 0x%01x\n", DvSecHdr.DvSecRevision));
+  DEBUG((DEBUG_INFO, "  DvSecLength   - 0x%03x\n", DvSecHdr.DvSecLength));
+  DEBUG((DEBUG_INFO, "  DvSecId       - 0x%04x\n", DvSecHdr.DvSecId));
+  if ((DvSecHdr.DvSecVendorId != INTEL_PCI_DVSEC_VENDORID_INTEL) &&
+      (DvSecHdr.DvSecId != INTEL_PCI_DVSEC_DVSECID_MEASUREMENT)) {
+    DeviceSecurityState->MeasurementState = 
EDKII_DEVICE_SECURITY_STATE_ERROR_PCI_NO_CAPABILITIES;
+    return ;
+  }
+
+  DoMeasurementsFromDigestRegister (PciIo, DvSecOffset, DeviceSecurityPolicy, 
DeviceSecurityState);
+}
+
+/**
+  The device driver uses this service to verify a PCI device.
+
+  @param[in]  PciIo                  The PciIo of the device.
+  @param[in]  DeviceSecurityPolicy   The Device Security Policy associated 
with the device.
+  @param[out] DeviceSecurityState    The Device Security state associated with 
the device.
+**/
+VOID
+DoDeviceAuthentication (
+  IN EFI_PCI_IO_PROTOCOL          *PciIo,
+  IN EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy,
+  OUT EDKII_DEVICE_SECURITY_STATE *DeviceSecurityState
+  )
+{
+  DeviceSecurityState->AuthenticationState = 
EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_UNSUPPORTED;
+}
+
+/**
+  The device driver uses this service to measure and/or verify a device.
+
+  The flow in device driver is:
+  1) Device driver discovers a new device.
+  2) Device driver creates an EFI_DEVICE_PATH_PROTOCOL.
+  3) Device driver creates a device access protocol. e.g.
+     EFI_PCI_IO_PROTOCOL for PCI device.
+     EFI_USB_IO_PROTOCOL for USB device.
+     EFI_EXT_SCSI_PASS_THRU_PROTOCOL for SCSI device.
+     EFI_ATA_PASS_THRU_PROTOCOL for ATA device.
+     EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL for NVMe device.
+     EFI_SD_MMC_PASS_THRU_PROTOCOL for SD/MMC device.
+  4) Device driver installs the EFI_DEVICE_PATH_PROTOCOL with 
EFI_DEVICE_PATH_PROTOCOL_GUID,
+     and the device access protocol with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID.
+     Once it is done, a DeviceHandle is returned.
+  5) Device driver creates EDKII_DEVICE_IDENTIFIER with 
EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID
+     and the DeviceHandle.
+  6) Device driver calls DeviceAuthenticate().
+  7) If DeviceAuthenticate() returns EFI_SECURITY_VIOLATION, the device driver 
uninstalls
+     all protocols on this handle.
+  8) If DeviceAuthenticate() returns EFI_SUCCESS, the device driver installs 
the device access
+     protocol with a real protocol GUID. e.g.
+     EFI_PCI_IO_PROTOCOL with EFI_PCI_IO_PROTOCOL_GUID.
+     EFI_USB_IO_PROTOCOL with EFI_USB_IO_PROTOCOL_GUID.
+
+  @param[in]  This              The protocol instance pointer.
+  @param[in]  DeviceId          The Identifier for the device.
+
+  @retval EFI_SUCCESS              The device specified by the DeviceId passed 
the measurement
+                                   and/or authentication based upon the 
platform policy.
+                                   If TCG measurement is required, the 
measurement is extended to TPM PCR.
+  @retval EFI_SECURITY_VIOLATION   The device fails to return the measurement 
data.
+  @retval EFI_SECURITY_VIOLATION   The device fails to response the 
authentication request.
+  @retval EFI_SECURITY_VIOLATION   The system fails to verify the device based 
upon the authentication response.
+  @retval EFI_SECURITY_VIOLATION   The system fails to extend the measurement 
to TPM PCR.
+**/
+EFI_STATUS
+EFIAPI
+DeviceAuthentication (
+  IN EDKII_DEVICE_SECURITY_PROTOCOL  *This,
+  IN EDKII_DEVICE_IDENTIFIER         *DeviceId
+  )
+{
+  EDKII_DEVICE_SECURITY_POLICY           DeviceSecurityPolicy;
+  EDKII_DEVICE_SECURITY_STATE            DeviceSecurityState;
+  EFI_PCI_IO_PROTOCOL                    *PciIo;
+  EFI_STATUS                             Status;
+
+  if (mDeviceSecurityPolicy == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  if (!CompareGuid (&DeviceId->DeviceType, 
&gEdkiiDeviceIdentifierTypePciGuid)) {
+    return EFI_SUCCESS;
+  }
+
+  Status = gBS->HandleProtocol (
+                  DeviceId->DeviceHandle,
+                  &gEdkiiDeviceIdentifierTypePciGuid,
+                  (VOID **)&PciIo
+                  );
+  if (EFI_ERROR(Status)) {
+    DEBUG ((DEBUG_ERROR, "Locate - DeviceIdentifierTypePci - %r\n", Status));
+    return EFI_SUCCESS;
+  }
+
+  DeviceSecurityState.Version = EDKII_DEVICE_SECURITY_STATE_REVISION;
+  DeviceSecurityState.MeasurementState = 0x0;
+  DeviceSecurityState.AuthenticationState = 0x0;
+
+  Status = mDeviceSecurityPolicy->GetDevicePolicy (mDeviceSecurityPolicy, 
DeviceId, &DeviceSecurityPolicy);
+  if (EFI_ERROR(Status)) {
+    DEBUG((DEBUG_ERROR, "mDeviceSecurityPolicy->GetDevicePolicy - %r\n", 
Status));
+    DeviceSecurityState.MeasurementState = 
EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_GET_POLICY_PROTOCOL;
+    DeviceSecurityState.AuthenticationState = 
EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_GET_POLICY_PROTOCOL;
+  } else {
+    if ((DeviceSecurityPolicy.MeasurementPolicy & 
EDKII_DEVICE_MEASUREMENT_REQUIRED) != 0) {
+      DoDeviceMeasurement (PciIo, &DeviceSecurityPolicy, &DeviceSecurityState);
+      DEBUG((DEBUG_ERROR, "MeasurementState - 0x%08x\n", 
DeviceSecurityState.MeasurementState));
+    }
+    if ((DeviceSecurityPolicy.AuthenticationPolicy & 
EDKII_DEVICE_AUTHENTICATION_REQUIRED) != 0) {
+      DoDeviceAuthentication (PciIo, &DeviceSecurityPolicy, 
&DeviceSecurityState);
+      DEBUG((DEBUG_ERROR, "AuthenticationState - 0x%08x\n", 
DeviceSecurityState.AuthenticationState));
+    }
+  }
+
+  Status = mDeviceSecurityPolicy->NotifyDeviceState (mDeviceSecurityPolicy, 
DeviceId, &DeviceSecurityState);
+  if (EFI_ERROR(Status)) {
+    DEBUG((DEBUG_ERROR, "mDeviceSecurityPolicy->NotifyDeviceState - %r\n", 
Status));
+  }
+
+  if ((DeviceSecurityState.MeasurementState == 0) &&
+      (DeviceSecurityState.AuthenticationState == 0)) {
+    return EFI_SUCCESS;
+  } else {
+    return EFI_SECURITY_VIOLATION;
+  }
+}
+
+EDKII_DEVICE_SECURITY_PROTOCOL mDeviceSecurity = {
+  EDKII_DEVICE_SECURITY_PROTOCOL_REVISION,
+  DeviceAuthentication
+};
+
+/**
+  Entrypoint of the device security driver.
+
+  @param[in]  ImageHandle  ImageHandle of the loaded driver
+  @param[in]  SystemTable  Pointer to the System Table
+
+  @retval  EFI_SUCCESS           The Protocol is installed.
+  @retval  EFI_OUT_OF_RESOURCES  Not enough resources available to initialize 
driver.
+  @retval  EFI_DEVICE_ERROR      A device error occurred attempting to 
initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+MainEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_HANDLE  Handle;
+  EFI_STATUS  Status;
+
+  Status = gBS->LocateProtocol (&gEdkiiDeviceSecurityPolicyProtocolGuid, NULL, 
(VOID **)&mDeviceSecurityPolicy);
+  ASSERT_EFI_ERROR(Status);
+
+  Handle = NULL;
+  Status = gBS->InstallProtocolInterface (
+                  &Handle,
+                  &gEdkiiDeviceSecurityProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  (VOID **)&mDeviceSecurity
+                  );
+  ASSERT_EFI_ERROR(Status);
+
+  return Status;
+}
diff --git 
a/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.inf
 
b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.inf
new file mode 100644
index 0000000000..89a4c8fadd
--- /dev/null
+++ 
b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.inf
@@ -0,0 +1,45 @@
+## @file
+#  EDKII Device Security library for PCI device
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = IntelPciDeviceSecurityDxe
+  FILE_GUID                      = D9569195-ED94-47D2-9523-38BF2D201371
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = MainEntryPoint
+
+[Sources]
+  IntelPciDeviceSecurityDxe.c
+  TcgDeviceEvent.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  IntelSiliconPkg/IntelSiliconPkg.dec
+
+[LibraryClasses]
+  UefiRuntimeServicesTableLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  MemoryAllocationLib
+  DevicePathLib
+  BaseMemoryLib
+  PrintLib
+  DebugLib
+  UefiLib
+  PcdLib
+  TpmMeasurementLib
+
+[Protocols]
+  gEdkiiDeviceSecurityPolicyProtocolGuid  ## CONSUMES
+  gEdkiiDeviceSecurityProtocolGuid        ## PRODUCES
+  gEdkiiDeviceIdentifierTypePciGuid       ## COMSUMES
+
+[Depex]
+  gEdkiiDeviceSecurityPolicyProtocolGuid
diff --git 
a/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/TcgDeviceEvent.h
 
b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/TcgDeviceEvent.h
new file mode 100644
index 0000000000..5b642b3ecc
--- /dev/null
+++ 
b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/TcgDeviceEvent.h
@@ -0,0 +1,178 @@
+/** @file
+  TCG Device Event data structure
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+
+#ifndef __TCG_EVENT_DATA_H__
+#define __TCG_EVENT_DATA_H__
+
+#include <IndustryStandard/Spdm.h>
+
+#pragma pack(1)
+
+// -------------------------------------------
+// TCG Measurement for SPDM Device Measurement
+// -------------------------------------------
+
+//
+// Device Firmware Component (including immutable ROM or mutable firmware)
+//
+#define EDKII_DEVICE_MEASUREMENT_COMPONENT_PCR_INDEX        2
+#define EDKII_DEVICE_MEASUREMENT_COMPONENT_EVENT_TYPE       0x800000E1
+//
+// Device Firmware Configuration (including hardware configuration or firmware 
configuration)
+//
+#define EDKII_DEVICE_MEASUREMENT_CONFIGURATION_PCR_INDEX    4
+#define EDKII_DEVICE_MEASUREMENT_CONFIGURATION_EVENT_TYPE   0x800000E2
+
+//
+// Device Firmware Measurement Measurement Data
+// The measurement data is the device firmware measurement.
+//
+// In order to support crypto agile, the firmware will hash the 
DeviceMeasurement again.
+// As such the device measurement algo might be different with host firmware 
measurement algo.
+//
+
+//
+// Device Firmware Measurement Event Data
+//
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_SIGNATURE "SPDM Device Sec\0"
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_VERSION  0
+
+//
+// Device Type
+// 0x03 ~ 0xDF reserved by TCG.
+// 0xE0 ~ 0xFF reserved by OEM.
+//
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_NULL  0
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_PCI   1
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_USB   2
+
+//
+// Device Firmware Measurement Event Data Common Part
+// The device specific part should follow this data structure.
+//
+typedef struct {
+  //
+  // It must be EDKII_DEVICE_SECURITY_EVENT_DATA_SIGNATURE.
+  //
+  UINT8                          Signature[16];
+  //
+  // It must be EDKII_DEVICE_SECURITY_EVENT_DATA_VERSION.
+  //
+  UINT16                         Version;
+  //
+  // The length of whole data structure, including Device Context.
+  //
+  UINT16                         Length;
+  //
+  // The SpdmHashAlgo
+  //
+  UINT32                         SpdmHashAlgo;
+  //
+  // The type of device. This field is to determine the Device Context 
followed by.
+  //
+  UINT32                         DeviceType;
+  //
+  // The SPDM measurement block.
+  //
+//SPDM_MEASUREMENT_BLOCK         SpdmMeasurementBlock;
+} EDKII_DEVICE_SECURITY_EVENT_DATA_HEADER;
+
+//
+// PCI device specific context
+//
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT_VERSION  0
+typedef struct {
+  UINT16  Version;
+  UINT16  Length;
+  UINT16  VendorId;
+  UINT16  DeviceId;
+  UINT8   RevisionID;
+  UINT8   ClassCode[3];
+  UINT16  SubsystemVendorID;
+  UINT16  SubsystemID;
+} EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT;
+
+//
+// USB device specific context
+//
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT_VERSION  0
+typedef struct {
+  UINT16  Version;
+  UINT16  Length;
+//UINT8   DeviceDescriptor[DescLen];
+//UINT8   BodDescriptor[DescLen];
+//UINT8   ConfigurationDescriptor[DescLen][NumOfConfiguration];
+} EDKII_DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT;
+
+// ----------------------------------------------
+// TCG Measurement for SPDM Device Authentication
+// ----------------------------------------------
+
+//
+// Device Root cert is stored into a UEFI authenticated variable.
+// It is non-volatile, boot service, runtime service, and time based 
authenticated variable.
+// The "devdb" includes a list of allowed device root cert.
+// The "devdbx" includes a list of forbidden device root cert.
+// The usage of "devdb" and "devdbx" is same as "db" and "dbx" in UEFI secure 
boot.
+//
+// NOTE: We choose not to mix "db"/"dbx" for better management purpose.
+//
+
+#define EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME    L"devdb"
+#define EDKII_DEVICE_ROOT_CERT_VARAIBLE2_NAME   L"devdbx"
+
+#define EDKII_DEVICE_SIGNATURE_DATABASE_GUID \
+  {0xb9c2b4f4, 0xbf5f, 0x462d, 0x8a, 0xdf, 0xc5, 0xc7, 0xa, 0xc3, 0x5d, 0xad}
+
+//
+// Platform Firmware adhering to the policy MUST therefore measure the 
following values into PCR[7]:
+// 1. The content of the 
EDKII_DEVICE_SIGNATURE_DATABASE_GUID/EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME 
variable.
+// 2. The content of the 
EDKII_DEVICE_SIGNATURE_DATABASE_GUID/EDKII_DEVICE_ROOT_CERT_VARAIBLE2_NAME 
variable.
+// 3. Entries in the 
EDKII_DEVICE_SIGNATURE_DATABASE_GUID/EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME 
variable to
+//    authenticate the device.
+//
+// For all UEFI variable value events, the eventType SHALL be 
EV_EFI_VARIABLE_DRIVER_CONFIG and the Event
+// value SHALL be the value of the UEFI_VARIABLE_DATA structure (this 
structure SHALL be considered byte-aligned).
+// The measurement digest MUST be tagged Hash for each supported PCR bank of 
the event data which is the
+// UEFI_VARIABLE_DATA structure. The UEFI_VARIABLE_DATA.UnicodeNameLength 
value is the number of CHAR16
+// characters (not the number of bytes). The UEFI_VARIABLE_DATA.UnicodeName 
contents MUST NOT include a NUL.
+// If reading a UEFI variable returns UEFI_NOT_FOUND, the 
UEFI_VARIABLE_DATA.VariableDataLength field MUST
+// be set to zero and UEFI_VARIABLE_DATA.VariableData field will have a size 
of zero.
+//
+
+//
+// Entities that MUST be measured if the TPM is enabled:
+// 1. Before executing any code not cryptographically authenticated as being 
provided by the Platform Manufacturer,
+//    the Platform Manufacturer firmware MUST measure the following values, in 
the order listed using the
+//    EV_EFI_VARIABLE_DRIVER_CONFIG event type to PCR[7]:
+//    a) The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ 
EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME variable.
+//    b) The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ 
EDKII_DEVICE_ROOT_CERT_VARAIBLE2_NAME variable.
+// 2. If the platform supports changing any of the following UEFI policy 
variables after they are initially measured
+//    in PCR[7] and before ExitBootServices() has completed, the platform MAY 
be restarted OR the variables MUST be
+//    remeasured into PCR[7]. Additionally the normal update process for 
setting any of the UEFI variables below SHOULD
+//    occur before the initial measurement in PCR[7] or after the call to 
ExitBootServices() has completed.
+//    a) The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ 
EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME variable.
+//    b) The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ 
EDKII_DEVICE_ROOT_CERT_VARAIBLE2_NAME variable.
+// 3. The system SHALL measure the EV_SEPARATOR event in PCR[7]. (This occurs 
at the same time the separator is
+//    measured to PCR[0-7].)
+//    Before setting up a device, the UEFI firmware SHALL determine if the 
entry in the
+//    EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ 
EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME variable that was used to validate
+//    the device has previously been measured in PCR[7]. If it has not been, 
it MUST be measured into PCR[7] as follows.
+//    If it has been measured previously, it MUST NOT be measured again. The 
measurement SHALL occur in conjunction
+//    with device setup.
+//    a) The eventType SHALL be EV_EFI_VARIABLE_AUTHORITY.
+//    b) The event value SHALL be the value of the UEFI_VARIABLE_DATA 
structure.
+//       i.   The UEFI_VARIABLE_DATA.VariableData value SHALL be the 
UEFI_SIGNATURE_DATA value from the
+//            UEFI_SIGNATURE_LIST that contained the authority that was used 
to validate the image.
+//       ii.  The UEFI_VARIABLE_DATA.VariableName SHALL be set to 
UEFI_IMAGE_SECURITY_DATABASE_GUID.
+//       iii. The UEFI_VARIABLE_DATA.UnicodeName SHALL be set to the value of 
UEFI_IMAGE_SECURITY_DATABASE.
+//            The value MUST NOT include the terminating NUL.
+//
+
+#pragma pack()
+
+#endif
-- 
2.19.2.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#50223): https://edk2.groups.io/g/devel/message/50223
Mute This Topic: https://groups.io/mt/46028011/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to