diff --git a/0053-SecurityPkg-Removing-unused-library-dependencies-in-.patch b/0053-SecurityPkg-Removing-unused-library-dependencies-in-.patch new file mode 100644 index 0000000000000000000000000000000000000000..95b06e461a2b19738e4fb8514e267d8423f91662 --- /dev/null +++ b/0053-SecurityPkg-Removing-unused-library-dependencies-in-.patch @@ -0,0 +1,29 @@ +From: Ge Yang +Date: Mon, 23 Jun 2025 20:30:10 +0800 +Subject: [PATCH 1/4] SecurityPkg: Removing unused library dependencies in INF + [LibraryClasses] Section + +The SM3 digest algorithm does not use Tpm2CommandLib, so the Tpm2CommandLib +should be removed from the [LibraryClasses] section in the INF file. Otherwise, +if TPM2 is not enabled but the SM3 digest algorithm is required, the build will +fail with an error. + +Signed-off-by: Ge Yang +--- + SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf b/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf +index 781164d..e1e30b5 100644 +--- a/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf ++++ b/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf +@@ -36,6 +36,5 @@ + BaseLib + BaseMemoryLib + DebugLib +- Tpm2CommandLib + MemoryAllocationLib + BaseCryptLib +-- +2.34.1 + diff --git a/0054-OvmfPkg-Add-RTMR-functions-in-CsvLib-for-CSV3-virtua.patch b/0054-OvmfPkg-Add-RTMR-functions-in-CsvLib-for-CSV3-virtua.patch new file mode 100644 index 0000000000000000000000000000000000000000..92af55f4e36786958023e68a4368cdc7750e6a2c --- /dev/null +++ b/0054-OvmfPkg-Add-RTMR-functions-in-CsvLib-for-CSV3-virtua.patch @@ -0,0 +1,714 @@ +From: Ge Yang +Date: Tue, 24 Jun 2025 10:16:17 +0800 +Subject: [PATCH 2/4] OvmfPkg: Add RTMR functions in CsvLib for CSV3 virtual + machine + +The Hygon Secure Processor maintains 5 RTMRs (Runtime Extendable Measurement +Registers) for each CSV3 virtual machine, which are accessible to EDK2 for +measuring additional logic and data loaded into the CSV3 virtual machine at +runtime. + +When launching CSV3 virtual machine, during the execution process of EDK2, it +is necessary to use the funcitons we provide to perform measurement operations. +This include functions for: + - CsvExtendRtmr : Extend measurement to one of the RTMR registers. + - CsvStartRtmr : Init the RTMR registers. + +Signed-off-by: Ge Yang +--- + OvmfPkg/Include/Library/CsvLib.h | 131 +++++++++++- + OvmfPkg/Library/CsvLib/CsvLib.inf | 3 + + OvmfPkg/Library/CsvLib/CsvSecureCall.h | 43 ++++ + OvmfPkg/Library/CsvLib/Ia32/CsvSecureCall.c | 46 +++++ + OvmfPkg/Library/CsvLib/Rtmr.c | 112 ++++++++++ + OvmfPkg/Library/CsvLib/X64/CsvSecureCall.c | 194 ++++++++++++++++++ + .../Library/CsvLib/X64/UpdateMemoryCsvLib.c | 64 +----- + 7 files changed, 529 insertions(+), 64 deletions(-) + create mode 100644 OvmfPkg/Library/CsvLib/CsvSecureCall.h + create mode 100644 OvmfPkg/Library/CsvLib/Ia32/CsvSecureCall.c + create mode 100644 OvmfPkg/Library/CsvLib/Rtmr.c + create mode 100644 OvmfPkg/Library/CsvLib/X64/CsvSecureCall.c + +diff --git a/OvmfPkg/Include/Library/CsvLib.h b/OvmfPkg/Include/Library/CsvLib.h +index 0cb6218..6c37b24 100644 +--- a/OvmfPkg/Include/Library/CsvLib.h ++++ b/OvmfPkg/Include/Library/CsvLib.h +@@ -18,6 +18,7 @@ + #define _CSV_LIB_H_ + + #include ++#include + + typedef struct { + IN UINT64 BaseAddress; +@@ -30,9 +31,94 @@ typedef enum { + CsvSecureCmdReset, + CsvSecureCmdUpdateSecureCallTable, + CsvSecureCmdMapLowerMemory, //secure memory range below 4G +- CsvSecureCmdMapUpperMemory //secure memory range above 4G ++ CsvSecureCmdMapUpperMemory, //secure memory range above 4G ++ CsvSecureCmdRtmr = 8 + } CSV_SECURE_COMMAND_TYPE; + ++/* The sub command of the RTMR secure call command */ ++typedef enum { ++ SecureCmdRtmrStatus = 0x1, // return RTMR status info ++ SecureCmdRtmrStart = 0x2, // negotiage and start RTMR ++ SecureCmdRtmrRead = 0x3, // read the value of RTMR registers specified in bitmap ++ SecureCmdRtmrExtend = 0x4, // extend a specific RTMR register ++} SECURE_CMD_RTMR_SUBTYPE; ++ ++/** ++ * struct RTMR_SUBCMD_HDR - Common header structure for RTMR sub commands ++ * ++ * @SubcmdId: ID of the sub command ++ * @SubcmdSize: the size of the sub command buffer ++ * @FwErrorCode: the return code of sub command ++ */ ++typedef struct { ++ UINT16 SubcmdId; /* In */ ++ UINT16 SubcmdSize; /* In,Out */ ++ UINT32 FwErrorCode; /* Out */ ++} RTMR_SUBCMD_HDR; ++ ++/** ++ * struct RTMR_SUBCMD_STATUS - RTMR_STATUS sub command parameters ++ * ++ * @Hdr: common structure used for RTMR sub commands ++ * @Version: the RTMR version used in the guest. When in state ++ * RTMR_STATE_INIT, it will be fixed. ++ * @State: the state of the guest's RTMR. ++ * @Reserved: reserved ++ */ ++typedef struct { ++ RTMR_SUBCMD_HDR Hdr; /* In,Out */ ++ UINT16 Version; /* Out */ ++ UINT8 State; /* Out */ ++ UINT8 Reserved[21]; /* reserved */ ++} RTMR_SUBCMD_STATUS; ++ ++/** ++ * struct RTMR_SUBCMD_START - RTMR_START sub command parameters ++ * ++ * @Hdr: common structure used for RTMR sub commands ++ * @Version: the RTMR version requested by the guest ++ * @Reserved: reserved ++ */ ++typedef struct { ++ RTMR_SUBCMD_HDR Hdr; /* In,Out */ ++ UINT16 Version; /* In,Out */ ++ UINT8 Reserved[22]; /* reserved */ ++} RTMR_SUBCMD_START; ++ ++/** ++ * struct RTMR_SUBCMD_READ - RTMR_READ sub command parameters ++ * ++ * @Hdr: common structure used for RTMR sub commands ++ * @RtmrRegBitmap: the bitmap specified the RTMR registers to read ++ * @Reserved: reserved ++ * @Digest: save the values of the specified RTMR registers ++ */ ++typedef struct { ++ RTMR_SUBCMD_HDR Hdr; /* In,Out */ ++ UINT32 RtmrRegBitmap; /* In,Out */ ++ UINT8 Reserved[20]; /* reserved */ ++ UINT8 Digest[32]; /* Out */ ++} RTMR_SUBCMD_READ; ++ ++/** ++ * struct RTMR_SUBCMD_EXTEND - RTMR_EXTEND sub command parameters ++ * ++ * @Hdr: common structure used for RTMR sub commands ++ * @RtmrRegIndex: the index for extending the RTMR register ++ * @Reserved1: reserved ++ * @DataLength: the length of the data to be extended ++ * @Reserved2: reserved ++ * @Data: the data to be extended to the RTMR register ++ */ ++typedef struct { ++ RTMR_SUBCMD_HDR Hdr; /* In,Out */ ++ UINT8 RtmrRegIndex; /* In,Out */ ++ UINT8 Reserved1; /* reserved */ ++ UINT16 DataLength; /* In,Out */ ++ UINT8 Reserved2[20]; /* reserved */ ++ UINT8 Data[32]; /* In */ ++} RTMR_SUBCMD_EXTEND; ++ + /** + Returns a boolean to indicate whether CSV is enabled + +@@ -81,4 +167,47 @@ CsvUpdateMapUpperMemory ( + IN PHYSICAL_ADDRESS BaseAddress, + IN UINTN NumPages + ); ++ ++/** ++ This function extends one of the RTMR measurement register ++ in hygon secure processor with the provided extension data ++ in memory. RTMR extending supports SM3 which length is 32 ++ bytes. ++ ++ @param[in] Data Point to the data to be extended ++ @param[in] DataLen Length of the data. Must be 32 ++ @param[in] Index RTMR index ++ ++ @return EFI_SUCCESS ++ @return EFI_DEVICE_ERROR ++ ++**/ ++ ++EFI_STATUS ++EFIAPI ++CsvExtendRtmr ( ++ IN UINT32 *Data, ++ IN UINT32 DataLen, ++ IN UINT8 Index ++); ++ ++/** ++ This function is used to initialize the guest's RTMR. We need ++ to provide the version of the RTMR that we intended to use. ++ If the secure call return code is SECURE_CALL_CMD_ACK and the ++ return code of the CSV_RTMR_START is 0, it means the RTMR is ++ successfully initialized by the firmware. Then we can read the ++ RTMR registers or extend data to the RTMR registers. ++ ++ @return EFI_SUCCESS ++ @return EFI_DEVICE_ERROR ++ ++**/ ++ ++EFI_STATUS ++EFIAPI ++CsvStartRtmr ( ++ VOID ++); ++ + #endif // _CSV_LIB_H_ +diff --git a/OvmfPkg/Library/CsvLib/CsvLib.inf b/OvmfPkg/Library/CsvLib/CsvLib.inf +index 25859c3..f2c0990 100644 +--- a/OvmfPkg/Library/CsvLib/CsvLib.inf ++++ b/OvmfPkg/Library/CsvLib/CsvLib.inf +@@ -37,11 +37,14 @@ + + [Sources] + CsvLib.c ++ Rtmr.c + + [Sources.X64] + X64/UpdateMemoryCsvLib.c ++ X64/CsvSecureCall.c + [Sources.IA32] + Ia32/UpdateMemoryCsvLib.c ++ Ia32/CsvSecureCall.c + + [LibraryClasses] + BaseLib +diff --git a/OvmfPkg/Library/CsvLib/CsvSecureCall.h b/OvmfPkg/Library/CsvLib/CsvSecureCall.h +new file mode 100644 +index 0000000..bc509f7 +--- /dev/null ++++ b/OvmfPkg/Library/CsvLib/CsvSecureCall.h +@@ -0,0 +1,43 @@ ++/** @file ++ ++ CSV base library helper function ++ ++ Copyright (c) 2025, HYGON. All rights reserved.
++ ++ This program and the accompanying materials are licensed and made available ++ under the terms and conditions of the BSD License which accompanies this ++ distribution. The full text of the license may be found at ++ http://opensource.org/licenses/bsd-license.php ++ ++ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, ++ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. ++ ++**/ ++ ++VOID ++EFIAPI ++CsvSecureCall( ++ IN PHYSICAL_ADDRESS BaseAddress, ++ IN UINTN NumPages, ++ IN CSV_SECURE_COMMAND_TYPE CmdType ++); ++ ++UINT32 ++EFIAPI ++CsvSecureCallExtendRtmr ( ++ IN UINT32 *Data, ++ IN UINT32 DataLen, ++ IN UINT8 Index ++); ++ ++UINT32 ++EFIAPI ++CsvSecureCallStartRtmr ( ++VOID ++); ++ ++UINT32 ++EFIAPI ++CsvSecureCallReadRtmr ( ++ IN UINT8 Index ++); +diff --git a/OvmfPkg/Library/CsvLib/Ia32/CsvSecureCall.c b/OvmfPkg/Library/CsvLib/Ia32/CsvSecureCall.c +new file mode 100644 +index 0000000..79ec34f +--- /dev/null ++++ b/OvmfPkg/Library/CsvLib/Ia32/CsvSecureCall.c +@@ -0,0 +1,46 @@ ++/** @file ++ ++ CSV library helper function ++ ++ Copyright (c) 2025, HYGON. All rights reserved.
++ ++ This program and the accompanying materials are licensed and made available ++ under the terms and conditions of the BSD License which accompanies this ++ distribution. The full text of the license may be found at ++ http://opensource.org/licenses/bsd-license.php ++ ++ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, ++ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. ++ ++**/ ++ ++#include ++ ++UINT32 ++EFIAPI ++CsvSecureCallExtendRtmr ( ++ IN UINT32 *Data, ++ IN UINT32 DataLen, ++ IN UINT8 Index ++) ++{ ++ return 0; ++} ++ ++UINT32 ++EFIAPI ++CsvSecureCallReadRtmr ( ++ IN UINT8 Index ++) ++{ ++ return 0; ++} ++ ++UINT32 ++EFIAPI ++CsvSecureCallStartRtmr ( ++ VOID ++) ++{ ++ return 0; ++} +diff --git a/OvmfPkg/Library/CsvLib/Rtmr.c b/OvmfPkg/Library/CsvLib/Rtmr.c +new file mode 100644 +index 0000000..9109419 +--- /dev/null ++++ b/OvmfPkg/Library/CsvLib/Rtmr.c +@@ -0,0 +1,112 @@ ++/** @file ++ ++ Extends one of the RTMR measurement registers in hygon secure processor ++ with the provided extension data in memory. ++ ++ Copyright (c) 2025, Hygon Corporation. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "CsvSecureCall.h" ++ ++#define RTMR_COUNT 4 ++ ++/** ++ This function extends one of the RTMR measurement register ++ in hygon secure processor with the provided extension data ++ in memory. RTMR extending supports SM3 which length is 32 ++ bytes. ++ ++ @param[in] Data Point to the data to be extended ++ @param[in] DataLen Length of the data. Must be 32 ++ @param[in] Index RTMR index ++ ++ @return EFI_SUCCESS ++ @return EFI_DEVICE_ERROR ++ ++**/ ++EFI_STATUS ++EFIAPI ++CsvExtendRtmr ( ++ IN UINT32 *Data, ++ IN UINT32 DataLen, ++ IN UINT8 Index ++ ) ++{ ++ EFI_STATUS Status; ++ UINT64 CsvCallStatus; ++ ++ Status = EFI_SUCCESS; ++ ++ ASSERT (Data != NULL); ++ ASSERT (DataLen == SM3_256_DIGEST_SIZE); ++ ASSERT (Index < RTMR_COUNT); ++ ++ if ((Data == NULL) || (DataLen != SM3_256_DIGEST_SIZE) || (Index >= RTMR_COUNT)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ CsvCallStatus = CsvSecureCallExtendRtmr (Data, DataLen, Index); ++ ++ if (CsvCallStatus == 0) { ++ Status = EFI_SUCCESS; ++ } else { ++ Status = EFI_DEVICE_ERROR; ++ } ++ ++ if (Status != EFI_SUCCESS) { ++ DEBUG ((DEBUG_ERROR, "Error returned from CsvSecureCallExtendRtmr call - 0x%lx\n", CsvCallStatus)); ++ } ++ ++ return Status; ++} ++ ++/** ++ This function is used to initialize the guest's RTMR. We need ++ to provide the version of the RTMR that we intended to use. ++ If the secure call return code is SECURE_CALL_CMD_ACK and the ++ return code of the CSV_RTMR_START is 0, it means the RTMR is ++ successfully initialized by the firmware. Then we can read the ++ RTMR registers or extend data to the RTMR registers. ++ ++ @param[in] Data Point to the data to be extended ++ @param[in] DataLen Length of the data. Must be 32 ++ @param[in] Index RTMR index ++ ++ @return EFI_SUCCESS ++ @return EFI_DEVICE_ERROR ++ ++**/ ++EFI_STATUS ++EFIAPI ++CsvStartRtmr ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UINT64 CsvCallStatus; ++ ++ Status = EFI_SUCCESS; ++ ++ CsvCallStatus = CsvSecureCallStartRtmr (); ++ ++ if (CsvCallStatus == 0) { ++ Status = EFI_SUCCESS; ++ } else { ++ Status = EFI_DEVICE_ERROR; ++ } ++ ++ if (Status != EFI_SUCCESS) { ++ DEBUG ((DEBUG_ERROR, "Error returned from CsvSecureCallStartRtmr call - 0x%lx\n", CsvCallStatus)); ++ } ++ ++ return Status; ++} +diff --git a/OvmfPkg/Library/CsvLib/X64/CsvSecureCall.c b/OvmfPkg/Library/CsvLib/X64/CsvSecureCall.c +new file mode 100644 +index 0000000..5fe8e84 +--- /dev/null ++++ b/OvmfPkg/Library/CsvLib/X64/CsvSecureCall.c +@@ -0,0 +1,194 @@ ++/** @file ++ ++ CSV library helper function ++ ++ Copyright (c) 2025, HYGON. All rights reserved.
++ ++ This program and the accompanying materials are licensed and made available ++ under the terms and conditions of the BSD License which accompanies this ++ distribution. The full text of the license may be found at ++ http://opensource.org/licenses/bsd-license.php ++ ++ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, ++ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. ++ ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define SECURE_CALL_ENTRY_MAX (254) ++ ++ ++typedef struct { ++ union { ++ UINT8 Guid[16]; ++ UINT64 Guid64[2]; ++ }; ++ UINT32 CmdType; ++ UINT32 Nums; ++ UINT64 Unused; ++ union { ++ struct { ++ UINT64 BaseAddress; ++ UINT64 Size; ++ } Entry[SECURE_CALL_ENTRY_MAX]; ++ union { ++ RTMR_SUBCMD_HDR Hdr; ++ RTMR_SUBCMD_STATUS StatusCmd; ++ RTMR_SUBCMD_START StartCmd; ++ RTMR_SUBCMD_READ ReadCmd; ++ RTMR_SUBCMD_EXTEND ExtendCmd; ++ } RtmrSubcmd; ++ }; ++} CSV_SECURE_CALL_CMD; ++ ++STATIC UINT32 SecureCallPageIdx = 0; ++ ++VOID ++EFIAPI ++CsvSecureCall( ++ IN PHYSICAL_ADDRESS BaseAddress, ++ IN UINTN NumPages, ++ IN CSV_SECURE_COMMAND_TYPE CmdType ++) ++{ ++ volatile CSV_SECURE_COMMAND_TYPE CmdAck = 0; ++ ++ CSV_SECURE_CALL_CMD *SecureCallPageRead; ++ CSV_SECURE_CALL_CMD *SecureCallPageWrite; ++ UINTN SecureCallBase = 0; ++ ++ if (CsvIsEnabled () == FALSE) { ++ return ; ++ } ++ ++ SecureCallBase = FixedPcdGet32 (PcdCsvDefaultSecureCallBase); ++ ++ SecureCallPageRead = ++ (CSV_SECURE_CALL_CMD *)(UINT64) ++ (EFI_PAGE_SIZE * SecureCallPageIdx + SecureCallBase); ++ ++ SecureCallPageWrite = ++ (CSV_SECURE_CALL_CMD *) ++ (UINT64)(EFI_PAGE_SIZE * (1 - SecureCallPageIdx) + SecureCallBase); ++ ++ while(1) { ++ SecureCallPageWrite->CmdType = (UINT32)CmdType; ++ SecureCallPageWrite->Nums = 1; ++ SecureCallPageWrite->Entry[0].BaseAddress = (UINT64)BaseAddress; ++ SecureCallPageWrite->Entry[0].Size = (UINT64)NumPages << EFI_PAGE_SHIFT; ++ ++ MemoryFence (); ++ ++ CmdAck = SecureCallPageRead->CmdType; ++ if (CmdAck != CmdType) ++ break; ++ } ++ SecureCallPageIdx = 1 - SecureCallPageIdx; ++} ++ ++STATIC ++VOID ++EFIAPI ++CsvSecureCallRtmr( ++ IN VOID *Buffer, ++ IN UINTN Size ++) ++{ ++ volatile CSV_SECURE_COMMAND_TYPE CmdAck = 0; ++ ++ CSV_SECURE_CALL_CMD *SecureCallPageRead; ++ CSV_SECURE_CALL_CMD *SecureCallPageWrite; ++ UINTN SecureCallBase = 0; ++ ++ if (CsvIsEnabled () == FALSE) { ++ return ; ++ } ++ ++ SecureCallBase = FixedPcdGet32 (PcdCsvDefaultSecureCallBase); ++ ++ SecureCallPageRead = ++ (CSV_SECURE_CALL_CMD *)(UINT64) ++ (EFI_PAGE_SIZE * SecureCallPageIdx + SecureCallBase); ++ ++ SecureCallPageWrite = ++ (CSV_SECURE_CALL_CMD *) ++ (UINT64)(EFI_PAGE_SIZE * (1 - SecureCallPageIdx) + SecureCallBase); ++ ++ while(1) { ++ SecureCallPageWrite->CmdType = CsvSecureCmdRtmr; ++ SecureCallPageWrite->Nums = 1; ++ SecureCallPageWrite->Unused = 0; ++ CopyMem((VOID *)&SecureCallPageWrite->RtmrSubcmd, Buffer, Size); ++ ++ MemoryFence (); ++ ++ CmdAck = SecureCallPageRead->CmdType; ++ if (CmdAck != CsvSecureCmdRtmr) ++ break; ++ } ++ ++ CopyMem(Buffer, (VOID *)&SecureCallPageRead->RtmrSubcmd, Size); ++ ++ SecureCallPageIdx = 1 - SecureCallPageIdx; ++} ++ ++UINT32 ++EFIAPI ++CsvSecureCallExtendRtmr ( ++ IN UINT32 *Data, ++ IN UINT32 DataLen, ++ IN UINT8 Index ++) ++{ ++ RTMR_SUBCMD_EXTEND ExtendSubcmd; ++ ++ ExtendSubcmd.RtmrRegIndex = Index; ++ ExtendSubcmd.DataLength = DataLen; ++ CopyMem((VOID *)&ExtendSubcmd.Data, Data, DataLen); ++ ExtendSubcmd.Hdr.SubcmdId = SecureCmdRtmrExtend; ++ ExtendSubcmd.Hdr.SubcmdSize = sizeof (ExtendSubcmd); ++ ++ CsvSecureCallRtmr(&ExtendSubcmd, sizeof (ExtendSubcmd)); ++ ++ return ExtendSubcmd.Hdr.FwErrorCode; ++} ++ ++UINT32 ++EFIAPI ++CsvSecureCallStartRtmr ( ++) ++{ ++ RTMR_SUBCMD_START StartSubcmd; ++ ++ StartSubcmd.Version = 1; ++ StartSubcmd.Hdr.SubcmdId = SecureCmdRtmrStart; ++ StartSubcmd.Hdr.SubcmdSize = sizeof (StartSubcmd); ++ ++ CsvSecureCallRtmr(&StartSubcmd, sizeof (StartSubcmd)); ++ ++ return StartSubcmd.Hdr.FwErrorCode; ++} ++ ++UINT32 ++EFIAPI ++CsvSecureCallReadRtmr ( ++ IN UINT8 Index ++) ++{ ++ RTMR_SUBCMD_READ ReadSubcmd; ++ ++ ReadSubcmd.Hdr.SubcmdId = SecureCmdRtmrRead; ++ ReadSubcmd.Hdr.SubcmdSize = sizeof (ReadSubcmd); ++ ++ ReadSubcmd.RtmrRegBitmap = 1 << Index; ++ ++ CsvSecureCallRtmr(&ReadSubcmd, sizeof (ReadSubcmd)); ++ ++ return ReadSubcmd.Hdr.FwErrorCode; ++} +diff --git a/OvmfPkg/Library/CsvLib/X64/UpdateMemoryCsvLib.c b/OvmfPkg/Library/CsvLib/X64/UpdateMemoryCsvLib.c +index 13d06d7..51f31d1 100644 +--- a/OvmfPkg/Library/CsvLib/X64/UpdateMemoryCsvLib.c ++++ b/OvmfPkg/Library/CsvLib/X64/UpdateMemoryCsvLib.c +@@ -21,72 +21,11 @@ + #include + #include + +-#define SECURE_CALL_ENTRY_MAX (254) +- +- +-typedef struct { +- union { +- UINT8 Guid[16]; +- UINT64 Guid64[2]; +- }; +- UINT32 CmdType; +- UINT32 Nums; +- UINT64 Unused; +- struct { +- UINT64 BaseAddress; +- UINT64 Size; +- } Entry[SECURE_CALL_ENTRY_MAX]; +-} CSV_SECURE_CALL_CMD; +- +-STATIC UINT32 SecureCallPageIdx = 0; ++#include "CsvSecureCall.h" + + STATIC UINTN MemorySizeBelow4G = (UINTN)-1; + STATIC UINTN MemorySizeAbove4G = (UINTN)-1; + +-STATIC +-VOID +-EFIAPI +-CsvSecureCall( +- IN PHYSICAL_ADDRESS BaseAddress, +- IN UINTN NumPages, +- IN CSV_SECURE_COMMAND_TYPE CmdType +-) +-{ +- volatile CSV_SECURE_COMMAND_TYPE CmdAck = 0; +- +- CSV_SECURE_CALL_CMD *SecureCallPageRead; +- CSV_SECURE_CALL_CMD *SecureCallPageWrite; +- UINTN SecureCallBase = 0; +- +- if (CsvIsEnabled () == FALSE) { +- return ; +- } +- +- SecureCallBase = FixedPcdGet32 (PcdCsvDefaultSecureCallBase); +- +- SecureCallPageRead = +- (CSV_SECURE_CALL_CMD *)(UINT64) +- (EFI_PAGE_SIZE * SecureCallPageIdx + SecureCallBase); +- +- SecureCallPageWrite = +- (CSV_SECURE_CALL_CMD *) +- (UINT64)(EFI_PAGE_SIZE * (1 - SecureCallPageIdx) + SecureCallBase); +- +- while(1) { +- SecureCallPageWrite->CmdType = (UINT32)CmdType; +- SecureCallPageWrite->Nums = 1; +- SecureCallPageWrite->Entry[0].BaseAddress = (UINT64)BaseAddress; +- SecureCallPageWrite->Entry[0].Size = (UINT64)NumPages << EFI_PAGE_SHIFT; +- +- MemoryFence (); +- +- CmdAck = SecureCallPageRead->CmdType; +- if (CmdAck != CmdType) +- break; +- } +- SecureCallPageIdx = 1 - SecureCallPageIdx; +-} +- + STATIC + UINT8 + CmosRead8 ( +@@ -97,7 +36,6 @@ CmosRead8 ( + return IoRead8 (0x71); + } + +- + STATIC + VOID + EFIAPI +-- +2.34.1 + diff --git a/0055-OmvfPkg-HashLibCsv-Add-HashLibCsv.patch b/0055-OmvfPkg-HashLibCsv-Add-HashLibCsv.patch new file mode 100644 index 0000000000000000000000000000000000000000..76587453a33929675d1b0219e5b2a39965a36c33 --- /dev/null +++ b/0055-OmvfPkg-HashLibCsv-Add-HashLibCsv.patch @@ -0,0 +1,285 @@ +From: Ge Yang +Date: Tue, 24 Jun 2025 10:45:59 +0800 +Subject: [PATCH 3/4] OmvfPkg/HashLibCsv: Add HashLibCsv + +HashLibCsv mimics the OvmfPkg/Library/HashLibTdx. The library provides +hash services by registering hash handlers in the CSV3 guest. Currently, +it only supports the SM3 algorithm. Subsequently, the hash values are +extended into the CSV3 RTMR registers, which are analogous to the TPM's +PCR registers. + +Signed-off-by: Ge Yang +--- + OvmfPkg/Library/HashLibCsv/HashLibCsv.c | 214 ++++++++++++++++++++++ + OvmfPkg/Library/HashLibCsv/HashLibCsv.inf | 38 ++++ + 2 files changed, 252 insertions(+) + create mode 100644 OvmfPkg/Library/HashLibCsv/HashLibCsv.c + create mode 100644 OvmfPkg/Library/HashLibCsv/HashLibCsv.inf + +diff --git a/OvmfPkg/Library/HashLibCsv/HashLibCsv.c b/OvmfPkg/Library/HashLibCsv/HashLibCsv.c +new file mode 100644 +index 0000000..79e2226 +--- /dev/null ++++ b/OvmfPkg/Library/HashLibCsv/HashLibCsv.c +@@ -0,0 +1,214 @@ ++/** @file ++ This library is HashLib for Csv. ++ ++Copyright (c) 2025, Hygon Corporation. All rights reserved.
++SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++EFI_GUID mSm3Guid = HASH_ALGORITHM_SM3_256_GUID; ++ ++// ++// Currently CSV supports SM3. ++// ++HASH_INTERFACE mHashInterface = { ++ { 0 }, NULL, NULL, NULL ++}; ++ ++UINTN mHashInterfaceCount = 0; ++ ++/** ++ Start hash sequence. ++ ++ @param HashHandle Hash handle. ++ ++ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. ++**/ ++EFI_STATUS ++EFIAPI ++HashStart ( ++ OUT HASH_HANDLE *HashHandle ++ ) ++{ ++ HASH_HANDLE HashCtx; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ HashCtx = 0; ++ mHashInterface.HashInit (&HashCtx); ++ ++ *HashHandle = HashCtx; ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Update hash sequence data. ++ ++ @param HashHandle Hash handle. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ ++ @retval EFI_SUCCESS Hash sequence updated. ++**/ ++EFI_STATUS ++EFIAPI ++HashUpdate ( ++ IN HASH_HANDLE HashHandle, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen ++ ) ++{ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ mHashInterface.HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Hash sequence complete and extend to PCR. ++ ++ @param HashHandle Hash handle. ++ @param PcrIndex PCR to be extended. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ @param DigestList Digest list. ++ ++ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. ++**/ ++EFI_STATUS ++EFIAPI ++HashCompleteAndExtend ( ++ IN HASH_HANDLE HashHandle, ++ IN TPMI_DH_PCR PcrIndex, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ TPML_DIGEST_VALUES Digest; ++ EFI_STATUS Status; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ ZeroMem (DigestList, sizeof (*DigestList)); ++ ++ mHashInterface.HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ mHashInterface.HashFinal (HashHandle, &Digest); ++ ++ CopyMem ( ++ &DigestList->digests[0], ++ &Digest.digests[0], ++ sizeof (Digest.digests[0]) ++ ); ++ DigestList->count++; ++ ++ ASSERT (DigestList->count == 1 && DigestList->digests[0].hashAlg == TPM_ALG_SM3_256); ++ ++ Status = CsvExtendRtmr ( ++ (UINT32 *)DigestList->digests[0].digest.sm3_256, ++ SM3_256_DIGEST_SIZE, ++ (UINT8)PcrIndex ++ ); ++ ++ ASSERT (!EFI_ERROR (Status)); ++ return Status; ++} ++ ++/** ++ Hash data and extend to RTMR. ++ ++ @param PcrIndex PCR to be extended. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ @param DigestList Digest list. ++ ++ @retval EFI_SUCCESS Hash data and DigestList is returned. ++**/ ++EFI_STATUS ++EFIAPI ++HashAndExtend ( ++ IN TPMI_DH_PCR PcrIndex, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ HASH_HANDLE HashHandle; ++ EFI_STATUS Status; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ ASSERT (CsvIsEnabled ()); ++ ++ HashStart (&HashHandle); ++ HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ Status = HashCompleteAndExtend (HashHandle, PcrIndex, NULL, 0, DigestList); ++ ++ return Status; ++} ++ ++/** ++ This service register Hash. ++ ++ @param HashInterface Hash interface ++ ++ @retval EFI_SUCCESS This hash interface is registered successfully. ++ @retval EFI_UNSUPPORTED System does not support register this interface. ++ @retval EFI_ALREADY_STARTED System already register this interface. ++**/ ++EFI_STATUS ++EFIAPI ++RegisterHashInterfaceLib ( ++ IN HASH_INTERFACE *HashInterface ++ ) ++{ ++ // ++ // HashLibCsv is designed for Csv guest. So if it is not Csv guest, ++ // return EFI_UNSUPPORTED. ++ // ++ if (!CsvIsEnabled ()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ ++ // ++ // Only SM3 is allowed. ++ // ++ if (!CompareGuid (&mSm3Guid, &HashInterface->HashGuid)) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ if (mHashInterfaceCount != 0) { ++ ASSERT (FALSE); ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ CopyMem (&mHashInterface, HashInterface, sizeof (*HashInterface)); ++ mHashInterfaceCount++; ++ ++ return EFI_SUCCESS; ++} +diff --git a/OvmfPkg/Library/HashLibCsv/HashLibCsv.inf b/OvmfPkg/Library/HashLibCsv/HashLibCsv.inf +new file mode 100644 +index 0000000..9b242cc +--- /dev/null ++++ b/OvmfPkg/Library/HashLibCsv/HashLibCsv.inf +@@ -0,0 +1,38 @@ ++## @file ++# Provides hash service by registered hash handler in Csv. ++# ++# This library is HashLib for Csv. Currently only Sm3 is supported. ++# ++# Copyright (c) 2025, Hygon Corporation. All rights reserved.
++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = HashLibCsv ++ FILE_GUID = A9729AF5-145A-4A05-BEAC-9B62C45D8D61 ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = HashLib|SEC DXE_DRIVER ++ ++# ++# The following information is for reference only and not required by the build tools. ++# ++# VALID_ARCHITECTURES = X64 ++# ++ ++[Sources] ++ HashLibCsv.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ SecurityPkg/SecurityPkg.dec ++ OvmfPkg/OvmfPkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ BaseMemoryLib ++ DebugLib ++ PcdLib ++ CsvLib +-- +2.34.1 + diff --git a/0056-OvmfPkg-CsvTcg2Dxe-Add-CsvTcg2Dxe.patch b/0056-OvmfPkg-CsvTcg2Dxe-Add-CsvTcg2Dxe.patch new file mode 100644 index 0000000000000000000000000000000000000000..8131deba9f0aaedadd6162bd2e618cd28b3e6e50 --- /dev/null +++ b/0056-OvmfPkg-CsvTcg2Dxe-Add-CsvTcg2Dxe.patch @@ -0,0 +1,3052 @@ +From: Ge Yang +Date: Tue, 24 Jun 2025 10:58:28 +0800 +Subject: [PATCH 4/4] OvmfPkg/CsvTcg2Dxe: Add CsvTcg2Dxe + +CsvTcg2Dxe mimics the Ovmfpkg/Tcg/TdTcg2Dxe. It does below tasks: + - Set up and install CC_EVENTLOG ACPI table + - Measure handoff tables, Boot##### variables etc + - Measure Exit Boot Service failed + - Install CcMeasurement Protocol + +Signed-off-by: Ge Yang +--- + MdePkg/Include/Protocol/CcMeasurement.h | 23 + + OvmfPkg/OvmfPkgX64.dsc | 19 + + OvmfPkg/OvmfPkgX64.fdf | 7 + + OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.c | 2377 ++++++++++++++++++++ + OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.inf | 99 + + OvmfPkg/Tcg/CsvTcg2Dxe/MeasureBootPeCoff.c | 407 ++++ + SecurityPkg/SecurityPkg.dec | 6 + + 7 files changed, 2938 insertions(+) + create mode 100644 OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.c + create mode 100644 OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.inf + create mode 100644 OvmfPkg/Tcg/CsvTcg2Dxe/MeasureBootPeCoff.c + +diff --git a/MdePkg/Include/Protocol/CcMeasurement.h b/MdePkg/Include/Protocol/CcMeasurement.h +index 68029e9..53edba1 100644 +--- a/MdePkg/Include/Protocol/CcMeasurement.h ++++ b/MdePkg/Include/Protocol/CcMeasurement.h +@@ -36,6 +36,7 @@ typedef struct { + #define EFI_CC_TYPE_NONE 0 + #define EFI_CC_TYPE_SEV 1 + #define EFI_CC_TYPE_TDX 2 ++#define EFI_CC_TYPE_CSV 20 + + typedef struct { + UINT8 Type; +@@ -58,6 +59,7 @@ typedef UINT32 EFI_CC_MR_INDEX; + + #define EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 + #define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define EFI_CC_BOOT_HASH_ALG_SM3 0x00000008 + + // + // This bit is shall be set when an event shall be extended but not logged. +@@ -299,4 +301,25 @@ typedef struct { + + extern EFI_GUID gEfiCcFinalEventsTableGuid; + ++// ++// Define the CC Measure EventLog ACPI Table ++// ++#pragma pack(1) ++ ++typedef struct { ++ EFI_ACPI_DESCRIPTION_HEADER Header; ++ EFI_CC_TYPE CcType; ++ UINT16 Rsvd; ++ UINT64 Laml; ++ UINT64 Lasa; ++} EFI_CC_EVENTLOG_ACPI_TABLE; ++ ++#pragma pack() ++ ++// ++// Define the signature and revision of CC Measurement EventLog ACPI Table ++// ++#define EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE SIGNATURE_32('C', 'C', 'E', 'L') ++#define EFI_CC_EVENTLOG_ACPI_TABLE_REVISION 1 ++ + #endif +diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc +index 0b192cc..515cef5 100644 +--- a/OvmfPkg/OvmfPkgX64.dsc ++++ b/OvmfPkg/OvmfPkgX64.dsc +@@ -34,6 +34,7 @@ + DEFINE SOURCE_DEBUG_ENABLE = FALSE + DEFINE TPM_ENABLE = FALSE + DEFINE TPM_CONFIG_ENABLE = FALSE ++ DEFINE CC_MEASUREMENT_ENABLE = TRUE + + # + # Network definition +@@ -761,6 +762,13 @@ + !endif + !if $(TPM_ENABLE) == TRUE + NULL|SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf ++!endif ++!if $(TPM_ENABLE) == TRUE || $(CC_MEASUREMENT_ENABLE) == TRUE ++ # ++ # DxeTpm2MeasureBootLib provides security service of TPM2 measure boot and ++ # Confidential Computing (CC) measure boot. It should be controlled by ++ # TPM2_ENABLE and CC_MEASUREMENT_ENABLE ++ # + NULL|SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf + !endif + } +@@ -1045,6 +1053,17 @@ + } + !endif + ++ # ++ # Cc Measurement Protocol for Csv guest ++ # ++!if $(CC_MEASUREMENT_ENABLE) == TRUE ++ OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.inf { ++ ++ HashLib|OvmfPkg/Library/HashLibCsv/HashLibCsv.inf ++ NULL|SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf ++ } ++!endif ++ + # + # TPM support + # +diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf +index 9d96e89..ea5efc4 100644 +--- a/OvmfPkg/OvmfPkgX64.fdf ++++ b/OvmfPkg/OvmfPkgX64.fdf +@@ -400,6 +400,13 @@ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf + INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + !endif + ++# ++# EFI_CC_MEASUREMENT_PROTOCOL ++# ++!if $(CC_MEASUREMENT_ENABLE) == TRUE ++INF OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.inf ++!endif ++ + # + # TPM support + # +diff --git a/OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.c b/OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.c +new file mode 100644 +index 0000000..8e90720 +--- /dev/null ++++ b/OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.c +@@ -0,0 +1,2377 @@ ++/** @file ++ This module implements EFI CSV Protocol. ++ ++ Copyright (c) 2025, Hygon Corporation. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define PERF_ID_CC_TCG2_DXE 0x3130 ++ ++#define CC_EVENT_LOG_AREA_COUNT_MAX 1 ++ ++typedef struct { ++ CHAR16 *VariableName; ++ EFI_GUID *VendorGuid; ++} VARIABLE_TYPE; ++ ++typedef struct { ++ EFI_GUID *EventGuid; ++ EFI_CC_EVENT_LOG_FORMAT LogFormat; ++} CC_EVENT_INFO_STRUCT; ++ ++typedef struct { ++ EFI_CC_EVENT_LOG_FORMAT EventLogFormat; ++ EFI_PHYSICAL_ADDRESS Lasa; ++ UINT64 Laml; ++ UINTN EventLogSize; ++ UINT8 *LastEvent; ++ BOOLEAN EventLogStarted; ++ BOOLEAN EventLogTruncated; ++ UINTN Next800155EventOffset; ++} CC_EVENT_LOG_AREA_STRUCT; ++ ++typedef struct _CSV_DXE_DATA { ++ EFI_CC_BOOT_SERVICE_CAPABILITY BsCap; ++ CC_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ BOOLEAN GetEventLogCalled[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ CC_EVENT_LOG_AREA_STRUCT FinalEventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ EFI_CC_FINAL_EVENTS_TABLE *FinalEventsTable[CC_EVENT_LOG_AREA_COUNT_MAX]; ++} CSV_DXE_DATA; ++ ++typedef struct { ++ TPMI_ALG_HASH HashAlgo; ++ UINT16 HashSize; ++ UINT32 HashMask; ++} CSV_HASH_INFO; ++ ++CSV_DXE_DATA mCsvDxeData = { ++ { ++ sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY), // Size ++ { 1, 1 }, // StructureVersion ++ { 1, 1 }, // ProtocolVersion ++ EFI_CC_BOOT_HASH_ALG_SM3, // HashAlgorithmBitmap ++ EFI_CC_EVENT_LOG_FORMAT_TCG_2, // SupportedEventLogs ++ { 2, 0 } // {CC_TYPE, CC_SUBTYPE} ++ }, ++}; ++ ++UINTN mBootAttempts = 0; ++CHAR16 mBootVarName[] = L"BootOrder"; ++ ++VARIABLE_TYPE mVariableType[] = { ++ { EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid }, ++ { EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid }, ++}; ++ ++EFI_CC_EVENTLOG_ACPI_TABLE mCsvEventlogAcpiTemplate = { ++ { ++ EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE, ++ sizeof (mCsvEventlogAcpiTemplate), ++ EFI_CC_EVENTLOG_ACPI_TABLE_REVISION, ++ // ++ // Compiler initializes the remaining bytes to 0 ++ // These fields should be filled in production ++ // ++ }, ++ { EFI_CC_TYPE_CSV, 0 }, // CcType ++ 0, // rsvd ++ 0, // laml ++ 0, // lasa ++}; ++ ++// ++// Supported Hash list in Csv guest. ++// Currently SM3 is supported. ++// ++CSV_HASH_INFO mHashInfo[] = { ++ { TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE, HASH_ALG_SM3_256 } ++}; ++ ++/** ++ Get hash size based on Algo ++ ++ @param[in] HashAlgo Hash Algorithm Id. ++ ++ @return Size of the hash. ++**/ ++UINT16 ++GetHashSizeFromAlgo ( ++ IN TPMI_ALG_HASH HashAlgo ++ ) ++{ ++ UINTN Index; ++ ++ for (Index = 0; Index < sizeof (mHashInfo)/sizeof (mHashInfo[0]); Index++) { ++ if (mHashInfo[Index].HashAlgo == HashAlgo) { ++ return mHashInfo[Index].HashSize; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ Get hash mask based on Algo ++ ++ @param[in] HashAlgo Hash Algorithm Id. ++ ++ @return Hash mask. ++**/ ++UINT32 ++GetHashMaskFromAlgo ( ++ IN TPMI_ALG_HASH HashAlgo ++ ) ++{ ++ UINTN Index; ++ ++ for (Index = 0; Index < ARRAY_SIZE (mHashInfo); Index++) { ++ if (mHashInfo[Index].HashAlgo == HashAlgo) { ++ return mHashInfo[Index].HashMask; ++ } ++ } ++ ++ ASSERT (FALSE); ++ return 0; ++} ++ ++/** ++ Copy TPML_DIGEST_VALUES into a buffer ++ ++ @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary. ++ @param[in] DigestList TPML_DIGEST_VALUES to be copied. ++ @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy. ++ ++ @return The end of buffer to hold TPML_DIGEST_VALUES. ++**/ ++VOID * ++CopyDigestListToBuffer ( ++ IN OUT VOID *Buffer, ++ IN TPML_DIGEST_VALUES *DigestList, ++ IN UINT32 HashAlgorithmMask ++ ) ++{ ++ UINTN Index; ++ UINT16 DigestSize; ++ UINT32 DigestListCount; ++ UINT32 *DigestListCountPtr; ++ ++ DigestListCountPtr = (UINT32 *)Buffer; ++ DigestListCount = 0; ++ Buffer = (UINT8 *)Buffer + sizeof (DigestList->count); ++ for (Index = 0; Index < DigestList->count; Index++) { ++ if ((DigestList->digests[Index].hashAlg & HashAlgorithmMask) == 0) { ++ DEBUG ((DEBUG_ERROR, "WARNING: CSV Event log has HashAlg unsupported (0x%x)\n", DigestList->digests[Index].hashAlg)); ++ continue; ++ } ++ ++ CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof (DigestList->digests[Index].hashAlg)); ++ Buffer = (UINT8 *)Buffer + sizeof (DigestList->digests[Index].hashAlg); ++ DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg); ++ CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize); ++ Buffer = (UINT8 *)Buffer + DigestSize; ++ DigestListCount++; ++ } ++ ++ WriteUnaligned32 (DigestListCountPtr, DigestListCount); ++ ++ return Buffer; ++} ++ ++EFI_HANDLE mImageHandle; ++ ++/** ++ Measure PE image into TPM log based on the authenticode image hashing in ++ PE/COFF Specification 8.0 Appendix A. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will validate its data structure ++ within this image buffer before use. ++ ++ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). ++ ++ @param[in] RtmrIndex RTMR index ++ @param[in] ImageAddress Start address of image buffer. ++ @param[in] ImageSize Image size ++ @param[out] DigestList Digest list of this image. ++ ++ @retval EFI_SUCCESS Successfully measure image. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. ++ @retval other error value ++**/ ++EFI_STATUS ++MeasurePeImageAndExtend ( ++ IN UINT32 RtmrIndex, ++ IN EFI_PHYSICAL_ADDRESS ImageAddress, ++ IN UINTN ImageSize, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ); ++ ++#define COLUME_SIZE (16 * 2) ++ ++/** ++ ++ This function dump raw data. ++ ++ @param Data raw data ++ @param Size raw data size ++ ++**/ ++VOID ++InternalDumpData ( ++ IN UINT8 *Data, ++ IN UINTN Size ++ ) ++{ ++ UINTN Index; ++ ++ for (Index = 0; Index < Size; Index++) { ++ DEBUG ((DEBUG_INFO, Index == COLUME_SIZE/2 ? " | %02x" : " %02x", (UINTN)Data[Index])); ++ } ++} ++ ++/** ++ ++ This function dump raw data with colume format. ++ ++ @param Data raw data ++ @param Size raw data size ++ ++**/ ++VOID ++InternalDumpHex ( ++ IN UINT8 *Data, ++ IN UINTN Size ++ ) ++{ ++ UINTN Index; ++ UINTN Count; ++ UINTN Left; ++ ++ Count = Size / COLUME_SIZE; ++ Left = Size % COLUME_SIZE; ++ for (Index = 0; Index < Count; Index++) { ++ DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); ++ InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); ++ DEBUG ((DEBUG_INFO, "\n")); ++ } ++ ++ if (Left != 0) { ++ DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); ++ InternalDumpData (Data + Index * COLUME_SIZE, Left); ++ DEBUG ((DEBUG_INFO, "\n")); ++ } ++} ++ ++/** ++ ++ This function initialize CC_EVENT_HDR for EV_NO_ACTION ++ Event Type other than EFI Specification ID event. The behavior is defined ++ by TCG PC Client PFP Spec. Section 9.3.4 EV_NO_ACTION Event Types ++ ++ @param[in, out] NoActionEvent Event Header of EV_NO_ACTION Event ++ @param[in] EventSize Event Size of the EV_NO_ACTION Event ++ ++**/ ++VOID ++InitNoActionEvent ( ++ IN OUT CC_EVENT_HDR *NoActionEvent, ++ IN UINT32 EventSize ++ ) ++{ ++ UINT32 DigestListCount; ++ TPMI_ALG_HASH HashAlgId; ++ UINT8 *DigestBuffer; ++ ++ DigestBuffer = (UINT8 *)NoActionEvent->Digests.digests; ++ DigestListCount = 0; ++ ++ NoActionEvent->MrIndex = 0; ++ NoActionEvent->EventType = EV_NO_ACTION; ++ ++ // ++ // Set Hash count & hashAlg accordingly, while Digest.digests[n].digest to all 0 ++ // ++ ZeroMem (&NoActionEvent->Digests, sizeof (NoActionEvent->Digests)); ++ ++ if ((mCsvDxeData.BsCap.HashAlgorithmBitmap & EFI_CC_BOOT_HASH_ALG_SM3) != 0) { ++ HashAlgId = TPM_ALG_SM3_256; ++ CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); ++ DigestListCount++; ++ } ++ ++ // ++ // Set Digests Count ++ // ++ WriteUnaligned32 ((UINT32 *)&NoActionEvent->Digests.count, DigestListCount); ++ ++ // ++ // Set Event Size ++ // ++ WriteUnaligned32 ((UINT32 *)DigestBuffer, EventSize); ++} ++ ++/** ++ Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function ++ Caller is responsible to free LocationBuf. ++ ++ @param[out] LocationBuf Returns Processor Location Buffer. ++ @param[out] Num Returns processor number. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_UNSUPPORTED MpService protocol not found. ++ ++**/ ++EFI_STATUS ++GetProcessorsCpuLocation ( ++ OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf, ++ OUT UINTN *Num ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_MP_SERVICES_PROTOCOL *MpProtocol; ++ UINTN ProcessorNum; ++ UINTN EnabledProcessorNum; ++ EFI_PROCESSOR_INFORMATION ProcessorInfo; ++ EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; ++ UINTN Index; ++ ++ Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpProtocol); ++ if (EFI_ERROR (Status)) { ++ // ++ // MP protocol is not installed ++ // ++ return EFI_UNSUPPORTED; ++ } ++ ++ Status = MpProtocol->GetNumberOfProcessors ( ++ MpProtocol, ++ &ProcessorNum, ++ &EnabledProcessorNum ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ Status = gBS->AllocatePool ( ++ EfiBootServicesData, ++ sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, ++ (VOID **)&ProcessorLocBuf ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ // ++ // Get each processor Location info ++ // ++ for (Index = 0; Index < ProcessorNum; Index++) { ++ Status = MpProtocol->GetProcessorInfo ( ++ MpProtocol, ++ Index, ++ &ProcessorInfo ++ ); ++ if (EFI_ERROR (Status)) { ++ FreePool (ProcessorLocBuf); ++ return Status; ++ } ++ ++ // ++ // Get all Processor Location info & measure ++ // ++ CopyMem ( ++ &ProcessorLocBuf[Index], ++ &ProcessorInfo.Location, ++ sizeof (EFI_CPU_PHYSICAL_LOCATION) ++ ); ++ } ++ ++ *LocationBuf = ProcessorLocBuf; ++ *Num = ProcessorNum; ++ ++ return Status; ++} ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL GetCapability function call provides protocol ++ capability information and state information. ++ ++ @param[in] This Indicates the calling context ++ @param[in, out] ProtocolCapability The caller allocates memory for a EFI_CC_BOOT_SERVICE_CAPABILITY ++ structure and sets the size field to the size of the structure allocated. ++ The callee fills in the fields with the EFI protocol capability information ++ and the current EFI TCG2 state information up to the number of fields which ++ fit within the size of the structure passed in. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ The ProtocolCapability variable will not be populated. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. ++ The ProtocolCapability variable will not be populated. ++ @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response. ++ It will be partially populated (required Size field will be set). ++**/ ++EFI_STATUS ++EFIAPI ++CsvGetCapability ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN OUT EFI_CC_BOOT_SERVICE_CAPABILITY *ProtocolCapability ++ ) ++{ ++ DEBUG ((DEBUG_VERBOSE, "CsvGetCapability\n")); ++ ++ if ((This == NULL) || (ProtocolCapability == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ CopyMem (ProtocolCapability, &mCsvDxeData.BsCap, sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY)); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function dump PCR event. ++ CSV Event log reuse the TCG PCR Event spec. ++ The first event in the event log is the SHA1 log format. ++ There is only ONE TCG_PCR_EVENT in CSV Event log. ++ ++ @param[in] EventHdr TCG PCR event structure. ++**/ ++VOID ++DumpPcrEvent ( ++ IN TCG_PCR_EVENT_HDR *EventHdr ++ ) ++{ ++ UINTN Index; ++ ++ DEBUG ((DEBUG_INFO, " Event:\n")); ++ DEBUG ((DEBUG_INFO, " MrIndex - %d\n", EventHdr->PCRIndex)); ++ DEBUG ((DEBUG_INFO, " EventType - 0x%08x\n", EventHdr->EventType)); ++ DEBUG ((DEBUG_INFO, " Digest - ")); ++ for (Index = 0; Index < sizeof (TCG_DIGEST); Index++) { ++ DEBUG ((DEBUG_INFO, "%02x ", EventHdr->Digest.digest[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "\n")); ++ DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventHdr->EventSize)); ++ InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize); ++} ++ ++/** ++ This function dump TCG_EfiSpecIDEventStruct. ++ ++ @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. ++**/ ++VOID ++DumpTcgEfiSpecIdEventStruct ( ++ IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct ++ ) ++{ ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ UINTN Index; ++ UINT8 *VendorInfoSize; ++ UINT8 *VendorInfo; ++ UINT32 NumberOfAlgorithms; ++ ++ DEBUG ((DEBUG_INFO, " TCG_EfiSpecIDEventStruct:\n")); ++ DEBUG ((DEBUG_INFO, " signature - '")); ++ for (Index = 0; Index < sizeof (TcgEfiSpecIdEventStruct->signature); Index++) { ++ DEBUG ((DEBUG_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "'\n")); ++ DEBUG ((DEBUG_INFO, " platformClass - 0x%08x\n", TcgEfiSpecIdEventStruct->platformClass)); ++ DEBUG ((DEBUG_INFO, " specVersion - %d.%d%d\n", TcgEfiSpecIdEventStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, TcgEfiSpecIdEventStruct->specErrata)); ++ DEBUG ((DEBUG_INFO, " uintnSize - 0x%02x\n", TcgEfiSpecIdEventStruct->uintnSize)); ++ ++ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms)); ++ DEBUG ((DEBUG_INFO, " NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorithms)); ++ ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); ++ for (Index = 0; Index < NumberOfAlgorithms; Index++) { ++ DEBUG ((DEBUG_INFO, " digest(%d)\n", Index)); ++ DEBUG ((DEBUG_INFO, " algorithmId - 0x%04x\n", DigestSize[Index].algorithmId)); ++ DEBUG ((DEBUG_INFO, " digestSize - 0x%04x\n", DigestSize[Index].digestSize)); ++ } ++ ++ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; ++ DEBUG ((DEBUG_INFO, " VendorInfoSize - 0x%02x\n", *VendorInfoSize)); ++ VendorInfo = VendorInfoSize + 1; ++ DEBUG ((DEBUG_INFO, " VendorInfo - ")); ++ for (Index = 0; Index < *VendorInfoSize; Index++) { ++ DEBUG ((DEBUG_INFO, "%02x ", VendorInfo[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "\n")); ++} ++ ++/** ++ This function get size of TCG_EfiSpecIDEventStruct. ++ ++ @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. ++**/ ++UINTN ++GetTcgEfiSpecIdEventStructSize ( ++ IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct ++ ) ++{ ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ UINT8 *VendorInfoSize; ++ UINT32 NumberOfAlgorithms; ++ ++ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms)); ++ ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); ++ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; ++ return sizeof (TCG_EfiSpecIDEventStruct) + sizeof (UINT32) + (NumberOfAlgorithms * sizeof (TCG_EfiSpecIdEventAlgorithmSize)) + sizeof (UINT8) + (*VendorInfoSize); ++} ++ ++/** ++ This function dump CSV Event (including the Digests). ++ ++ @param[in] CcEvent CSV Event structure. ++**/ ++VOID ++DumpCcEvent ( ++ IN CC_EVENT *CcEvent ++ ) ++{ ++ UINT32 DigestIndex; ++ UINT32 DigestCount; ++ TPMI_ALG_HASH HashAlgo; ++ UINT32 DigestSize; ++ UINT8 *DigestBuffer; ++ UINT32 EventSize; ++ UINT8 *EventBuffer; ++ ++ DEBUG ((DEBUG_INFO, "Cc Event:\n")); ++ DEBUG ((DEBUG_INFO, " MrIndex - %d\n", CcEvent->MrIndex)); ++ DEBUG ((DEBUG_INFO, " EventType - 0x%08x\n", CcEvent->EventType)); ++ DEBUG ((DEBUG_INFO, " DigestCount: 0x%08x\n", CcEvent->Digests.count)); ++ ++ DigestCount = CcEvent->Digests.count; ++ HashAlgo = CcEvent->Digests.digests[0].hashAlg; ++ DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest; ++ for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { ++ DEBUG ((DEBUG_INFO, " HashAlgo : 0x%04x\n", HashAlgo)); ++ DEBUG ((DEBUG_INFO, " Digest(%d): \n", DigestIndex)); ++ DigestSize = GetHashSizeFromAlgo (HashAlgo); ++ InternalDumpHex (DigestBuffer, DigestSize); ++ // ++ // Prepare next ++ // ++ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); ++ } ++ ++ DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH); ++ ++ CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize)); ++ DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventSize)); ++ EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize); ++ InternalDumpHex (EventBuffer, EventSize); ++ DEBUG ((DEBUG_INFO, "\n")); ++} ++ ++/** ++ This function returns size of Csv Table event. ++ ++ @param[in] CcEvent Csv Table event structure. ++ ++ @return size of Csv event. ++**/ ++UINTN ++GetCcEventSize ( ++ IN CC_EVENT *CcEvent ++ ) ++{ ++ UINT32 DigestIndex; ++ UINT32 DigestCount; ++ TPMI_ALG_HASH HashAlgo; ++ UINT32 DigestSize; ++ UINT8 *DigestBuffer; ++ UINT32 EventSize; ++ UINT8 *EventBuffer; ++ ++ DigestCount = CcEvent->Digests.count; ++ HashAlgo = CcEvent->Digests.digests[0].hashAlg; ++ DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest; ++ for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { ++ DigestSize = GetHashSizeFromAlgo (HashAlgo); ++ // ++ // Prepare next ++ // ++ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); ++ } ++ ++ DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH); ++ ++ CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize)); ++ EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize); ++ ++ return (UINTN)EventBuffer + EventSize - (UINTN)CcEvent; ++} ++ ++/** ++ This function dump CC event log. ++ CSV only supports EFI_CC_EVENT_LOG_FORMAT_TCG_2 ++ ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[in] EventLogLocation A pointer to the memory address of the event log. ++ @param[in] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the ++ address of the start of the last entry in the event log in memory. ++ @param[in] FinalEventsTable A pointer to the memory address of the final event table. ++**/ ++VOID ++DumpCcEventLog ( ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ IN EFI_PHYSICAL_ADDRESS EventLogLocation, ++ IN EFI_PHYSICAL_ADDRESS EventLogLastEntry, ++ IN EFI_CC_FINAL_EVENTS_TABLE *FinalEventsTable ++ ) ++{ ++ TCG_PCR_EVENT_HDR *EventHdr; ++ CC_EVENT *CcEvent; ++ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; ++ UINTN NumberOfEvents; ++ ++ DEBUG ((DEBUG_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat)); ++ ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2); ++ ++ // ++ // Dump first event. ++ // The first event is always the TCG_PCR_EVENT_HDR ++ // After this event is a TCG_EfiSpecIDEventStruct ++ // ++ EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; ++ DumpPcrEvent (EventHdr); ++ ++ TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)(EventHdr + 1); ++ DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct); ++ ++ // ++ // Then the CcEvent (Its structure is similar to TCG_PCR_EVENT2) ++ // ++ CcEvent = (CC_EVENT *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct)); ++ while ((UINTN)CcEvent <= EventLogLastEntry) { ++ DumpCcEvent (CcEvent); ++ CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent)); ++ } ++ ++ if (FinalEventsTable == NULL) { ++ DEBUG ((DEBUG_INFO, "FinalEventsTable: NOT FOUND\n")); ++ } else { ++ DEBUG ((DEBUG_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable)); ++ DEBUG ((DEBUG_INFO, " Version: (0x%x)\n", FinalEventsTable->Version)); ++ DEBUG ((DEBUG_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents)); ++ ++ CcEvent = (CC_EVENT *)(UINTN)(FinalEventsTable + 1); ++ for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) { ++ DumpCcEvent (CcEvent); ++ CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent)); ++ } ++ } ++ ++ return; ++} ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL Get Event Log function call allows a caller to ++ retrieve the address of a given event log and its last entry. ++ ++ @param[in] This Indicates the calling context ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[out] EventLogLocation A pointer to the memory address of the event log. ++ @param[out] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the ++ address of the start of the last entry in the event log in memory. ++ @param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would ++ have exceeded the area allocated for events, this value is set to TRUE. ++ Otherwise, the value will be FALSE and the Event Log will be complete. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect ++ (e.g. asking for an event log whose format is not supported). ++**/ ++EFI_STATUS ++EFIAPI ++CsvGetEventLog ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, ++ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry, ++ OUT BOOLEAN *EventLogTruncated ++ ) ++{ ++ UINTN Index = 0; ++ ++ DEBUG ((DEBUG_INFO, "CsvGetEventLog ... (0x%x)\n", EventLogFormat)); ++ ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2); ++ ++ if (EventLogLocation != NULL) { ++ *EventLogLocation = mCsvDxeData.EventLogAreaStruct[Index].Lasa; ++ DEBUG ((DEBUG_INFO, "CsvGetEventLog (EventLogLocation - %x)\n", *EventLogLocation)); ++ } ++ ++ if (EventLogLastEntry != NULL) { ++ if (!mCsvDxeData.EventLogAreaStruct[Index].EventLogStarted) { ++ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; ++ } else { ++ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mCsvDxeData.EventLogAreaStruct[Index].LastEvent; ++ } ++ ++ DEBUG ((DEBUG_INFO, "CsvGetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry)); ++ } ++ ++ if (EventLogTruncated != NULL) { ++ *EventLogTruncated = mCsvDxeData.EventLogAreaStruct[Index].EventLogTruncated; ++ DEBUG ((DEBUG_INFO, "CsvGetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated)); ++ } ++ ++ DEBUG ((DEBUG_INFO, "CsvGetEventLog - %r\n", EFI_SUCCESS)); ++ ++ // Dump Event Log for debug purpose ++ if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) { ++ DumpCcEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mCsvDxeData.FinalEventsTable[Index]); ++ } ++ ++ // ++ // All events generated after the invocation of EFI_TCG2_GET_EVENT_LOG SHALL be stored ++ // in an instance of an EFI_CONFIGURATION_TABLE named by the VendorGuid of EFI_TCG2_FINAL_EVENTS_TABLE_GUID. ++ // ++ mCsvDxeData.GetEventLogCalled[Index] = TRUE; ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Add a new entry to the Event Log. ++ ++ @param[in, out] EventLogAreaStruct The event log area data structure ++ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. ++ @param[in] NewEventHdrSize New event header size. ++ @param[in] NewEventData Pointer to the new event data. ++ @param[in] NewEventSize New event data size. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ ++**/ ++EFI_STATUS ++TcgCommLogEvent ( ++ IN OUT CC_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct, ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ UINTN NewLogSize; ++ CC_EVENT_HDR *CcEventHdr; ++ ++ CcEventHdr = (CC_EVENT_HDR *)NewEventHdr; ++ DEBUG ((DEBUG_VERBOSE, "Csv: Try to log event. Index = %d, EventType = 0x%x, NewEventHdrSize=0x%x, NewEventSize=0x%x\n", CcEventHdr->MrIndex, CcEventHdr->EventType, NewEventHdrSize, NewEventSize)); ++ ++ if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ NewLogSize = NewEventHdrSize + NewEventSize; ++ ++ if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ if (NewLogSize + EventLogAreaStruct->EventLogSize > EventLogAreaStruct->Laml) { ++ DEBUG ((DEBUG_INFO, " Laml - 0x%x\n", EventLogAreaStruct->Laml)); ++ DEBUG ((DEBUG_INFO, " NewLogSize - 0x%x\n", NewLogSize)); ++ DEBUG ((DEBUG_INFO, " LogSize - 0x%x\n", EventLogAreaStruct->EventLogSize)); ++ DEBUG ((DEBUG_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ EventLogAreaStruct->LastEvent = (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->EventLogSize; ++ EventLogAreaStruct->EventLogSize += NewLogSize; ++ ++ CopyMem (EventLogAreaStruct->LastEvent, NewEventHdr, NewEventHdrSize); ++ CopyMem ( ++ EventLogAreaStruct->LastEvent + NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ return EFI_SUCCESS; ++} ++ ++#define CC_MR_INDEX_0_RTMR0 0 ++#define CC_MR_INDEX_1_RTMR1 1 ++#define CC_MR_INDEX_2_RTMR2 2 ++#define CC_MR_INDEX_3_RTMR3 3 ++#define CC_MR_INDEX_INVALID 4 ++ ++/** ++ According to UEFI Spec 2.10 Section 38.4.1: ++ The following table shows the TPM PCR index mapping and CC event log measurement ++ register index interpretation for Hygon CSV, where RTMR means Runtime Measurement ++ Register ++ // TPM PCR Index | CC Measurement Register Index | CSV-measurement register ++ // ------------------------------------------------------------------------ ++ // 0 | 0 | RTMR[0] ++ // 1, 7 | 1 | RTMR[1] ++ // 2~6 | 2 | RTMR[2] ++ // 8~15 | 3 | RTMR[3] ++ @param[in] PCRIndex Index of the TPM PCR ++ @retval UINT32 Index of the CC Event Log Measurement Register Index ++ @retval CC_MR_INDEX_INVALID Invalid MR Index ++**/ ++UINT32 ++EFIAPI ++CsvMeasurementMapPcrToMrIndex ( ++ IN UINT32 PCRIndex ++ ) ++{ ++ UINT32 MrIndex; ++ ++ if (PCRIndex > 15) { ++ ASSERT (FALSE); ++ return CC_MR_INDEX_INVALID; ++ } ++ ++ MrIndex = 0; ++ if (PCRIndex == 0) { ++ MrIndex = CC_MR_INDEX_0_RTMR0; ++ } else if ((PCRIndex == 1) || (PCRIndex == 7)) { ++ MrIndex = CC_MR_INDEX_1_RTMR1; ++ } else if ((PCRIndex >= 2) && (PCRIndex <= 6)) { ++ MrIndex = CC_MR_INDEX_2_RTMR2; ++ } else if ((PCRIndex >= 8) && (PCRIndex <= 15)) { ++ MrIndex = CC_MR_INDEX_3_RTMR3; ++ } ++ ++ return MrIndex; ++} ++ ++EFI_STATUS ++EFIAPI ++CsvMapPcrToMrIndex ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN UINT32 PCRIndex, ++ OUT UINT32 *MrIndex ++ ) ++{ ++ if (MrIndex == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ *MrIndex = CsvMeasurementMapPcrToMrIndex (PCRIndex); ++ ++ return *MrIndex == CC_MR_INDEX_INVALID ? EFI_INVALID_PARAMETER : EFI_SUCCESS; ++} ++ ++/** ++ Add a new entry to the Event Log. ++ ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. ++ @param[in] NewEventHdrSize New event header size. ++ @param[in] NewEventData Pointer to the new event data. ++ @param[in] NewEventSize New event data size. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ ++**/ ++EFI_STATUS ++CsvDxeLogEvent ( ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ EFI_STATUS Status; ++ UINTN Index; ++ CC_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct; ++ ++ if (EventLogFormat != EFI_CC_EVENT_LOG_FORMAT_TCG_2) { ++ ASSERT (FALSE); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ Index = 0; ++ ++ // ++ // Record to normal event log ++ // ++ EventLogAreaStruct = &mCsvDxeData.EventLogAreaStruct[Index]; ++ ++ if (EventLogAreaStruct->EventLogTruncated) { ++ return EFI_VOLUME_FULL; ++ } ++ ++ Status = TcgCommLogEvent ( ++ EventLogAreaStruct, ++ NewEventHdr, ++ NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ if (Status == EFI_OUT_OF_RESOURCES) { ++ EventLogAreaStruct->EventLogTruncated = TRUE; ++ return EFI_VOLUME_FULL; ++ } else if (Status == EFI_SUCCESS) { ++ EventLogAreaStruct->EventLogStarted = TRUE; ++ } ++ ++ // ++ // If GetEventLog is called, record to FinalEventsTable, too. ++ // ++ if (mCsvDxeData.GetEventLogCalled[Index]) { ++ if (mCsvDxeData.FinalEventsTable[Index] == NULL) { ++ // ++ // no need for FinalEventsTable ++ // ++ return EFI_SUCCESS; ++ } ++ ++ EventLogAreaStruct = &mCsvDxeData.FinalEventLogAreaStruct[Index]; ++ ++ if (EventLogAreaStruct->EventLogTruncated) { ++ return EFI_VOLUME_FULL; ++ } ++ ++ Status = TcgCommLogEvent ( ++ EventLogAreaStruct, ++ NewEventHdr, ++ NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ if (Status == EFI_OUT_OF_RESOURCES) { ++ EventLogAreaStruct->EventLogTruncated = TRUE; ++ return EFI_VOLUME_FULL; ++ } else if (Status == EFI_SUCCESS) { ++ EventLogAreaStruct->EventLogStarted = TRUE; ++ // ++ // Increase the NumberOfEvents in FinalEventsTable ++ // ++ (mCsvDxeData.FinalEventsTable[Index])->NumberOfEvents++; ++ DEBUG ((DEBUG_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mCsvDxeData.FinalEventsTable[Index])->NumberOfEvents)); ++ DEBUG ((DEBUG_INFO, " Size - 0x%x\n", (UINTN)EventLogAreaStruct->EventLogSize)); ++ } ++ } ++ ++ return Status; ++} ++ ++/** ++ Get TPML_DIGEST_VALUES compact binary buffer size. ++ ++ @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. ++ ++ @return TPML_DIGEST_VALUES compact binary buffer size. ++**/ ++UINT32 ++GetDigestListBinSize ( ++ IN VOID *DigestListBin ++ ) ++{ ++ UINTN Index; ++ UINT16 DigestSize; ++ UINT32 TotalSize; ++ UINT32 Count; ++ TPMI_ALG_HASH HashAlg; ++ ++ Count = ReadUnaligned32 (DigestListBin); ++ TotalSize = sizeof (Count); ++ DigestListBin = (UINT8 *)DigestListBin + sizeof (Count); ++ for (Index = 0; Index < Count; Index++) { ++ HashAlg = ReadUnaligned16 (DigestListBin); ++ TotalSize += sizeof (HashAlg); ++ DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg); ++ ++ DigestSize = GetHashSizeFromAlgo (HashAlg); ++ TotalSize += DigestSize; ++ DigestListBin = (UINT8 *)DigestListBin + DigestSize; ++ } ++ ++ return TotalSize; ++} ++ ++/** ++ Copy TPML_DIGEST_VALUES compact binary into a buffer ++ ++ @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary. ++ @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. ++ @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy. ++ @param[out] HashAlgorithmMaskCopied Pointer to HASH bits corresponding to the digests copied. ++ ++ @return The end of buffer to hold TPML_DIGEST_VALUES compact binary. ++**/ ++VOID * ++CopyDigestListBinToBuffer ( ++ IN OUT VOID *Buffer, ++ IN VOID *DigestListBin, ++ IN UINT32 HashAlgorithmMask, ++ OUT UINT32 *HashAlgorithmMaskCopied ++ ) ++{ ++ UINTN Index; ++ UINT16 DigestSize; ++ UINT32 Count; ++ TPMI_ALG_HASH HashAlg; ++ UINT32 DigestListCount; ++ UINT32 *DigestListCountPtr; ++ ++ DigestListCountPtr = (UINT32 *)Buffer; ++ DigestListCount = 0; ++ *HashAlgorithmMaskCopied = 0; ++ ++ Count = ReadUnaligned32 (DigestListBin); ++ Buffer = (UINT8 *)Buffer + sizeof (Count); ++ DigestListBin = (UINT8 *)DigestListBin + sizeof (Count); ++ for (Index = 0; Index < Count; Index++) { ++ HashAlg = ReadUnaligned16 (DigestListBin); ++ DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg); ++ DigestSize = GetHashSizeFromAlgo (HashAlg); ++ ++ if ((HashAlg & HashAlgorithmMask) != 0) { ++ CopyMem (Buffer, &HashAlg, sizeof (HashAlg)); ++ Buffer = (UINT8 *)Buffer + sizeof (HashAlg); ++ CopyMem (Buffer, DigestListBin, DigestSize); ++ Buffer = (UINT8 *)Buffer + DigestSize; ++ DigestListCount++; ++ (*HashAlgorithmMaskCopied) |= GetHashMaskFromAlgo (HashAlg); ++ } else { ++ DEBUG ((DEBUG_ERROR, "WARNING: CopyDigestListBinToBuffer Event log has HashAlg unsupported by PCR bank (0x%x)\n", HashAlg)); ++ } ++ ++ DigestListBin = (UINT8 *)DigestListBin + DigestSize; ++ } ++ ++ WriteUnaligned32 (DigestListCountPtr, DigestListCount); ++ ++ return Buffer; ++} ++ ++/** ++ Add a new entry to the Event Log. The call chain is like below: ++ CsvDxeLogHashEvent -> CsvDxeLogEvent -> TcgCommonLogEvent ++ ++ Before this function is called, the event information (including the digest) ++ is ready. ++ ++ @param[in] DigestList A list of digest. ++ @param[in,out] NewEventHdr Pointer to a CC_EVENT_HDR data structure. ++ @param[in] NewEventData Pointer to the new event data. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++**/ ++EFI_STATUS ++CsvDxeLogHashEvent ( ++ IN TPML_DIGEST_VALUES *DigestList, ++ IN OUT CC_EVENT_HDR *NewEventHdr, ++ IN UINT8 *NewEventData ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_TPL OldTpl; ++ EFI_STATUS RetStatus; ++ CC_EVENT CcEvent; ++ UINT8 *DigestBuffer; ++ UINT32 *EventSizePtr; ++ EFI_CC_EVENT_LOG_FORMAT LogFormat; ++ ++ RetStatus = EFI_SUCCESS; ++ LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ ZeroMem (&CcEvent, sizeof (CcEvent)); ++ CcEvent.MrIndex = NewEventHdr->MrIndex; ++ CcEvent.EventType = NewEventHdr->EventType; ++ DigestBuffer = (UINT8 *)&CcEvent.Digests; ++ EventSizePtr = CopyDigestListToBuffer (DigestBuffer, DigestList, HASH_ALG_SM3_256); ++ CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize)); ++ ++ // ++ // Enter critical region ++ // ++ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); ++ Status = CsvDxeLogEvent ( ++ LogFormat, ++ &CcEvent, ++ sizeof (CcEvent.MrIndex) + sizeof (CcEvent.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (CcEvent.EventSize), ++ NewEventData, ++ NewEventHdr->EventSize ++ ); ++ if (Status != EFI_SUCCESS) { ++ RetStatus = Status; ++ } ++ ++ gBS->RestoreTPL (OldTpl); ++ ++ return RetStatus; ++} ++ ++/** ++ Do a hash operation on a data buffer, extend a specific RTMR with the hash result, ++ and add an entry to the Event Log. ++ ++ @param[in] Flags Bitmap providing additional information. ++ @param[in] HashData Physical address of the start of the data buffer ++ to be hashed, extended, and logged. ++ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData ++ @param[in, out] NewEventHdr Pointer to a CC_EVENT_HDR data structure. ++ @param[in] NewEventData Pointer to the new event data. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ ++**/ ++EFI_STATUS ++CsvDxeHashLogExtendEvent ( ++ IN UINT64 Flags, ++ IN UINT8 *HashData, ++ IN UINT64 HashDataLen, ++ IN OUT CC_EVENT_HDR *NewEventHdr, ++ IN UINT8 *NewEventData ++ ) ++{ ++ EFI_STATUS Status; ++ TPML_DIGEST_VALUES DigestList; ++ CC_EVENT_HDR NoActionEvent; ++ ++ if (NewEventHdr->EventType == EV_NO_ACTION) { ++ // ++ // Do not do RTMR extend for EV_NO_ACTION ++ // ++ Status = EFI_SUCCESS; ++ InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize); ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CsvDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData); ++ } ++ ++ return Status; ++ } ++ ++ // ++ // According to UEFI Spec 2.10 Section 38.4.1 the mapping between MrIndex and Hygon ++ // CSV Measurement Register is: ++ // MrIndex 0-3 <--> RTMR[0-3] ++ // ++ Status = HashAndExtend ( ++ NewEventHdr->MrIndex, ++ HashData, ++ (UINTN)HashDataLen, ++ &DigestList ++ ); ++ if (!EFI_ERROR (Status)) { ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CsvDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData); ++ } ++ } ++ ++ return Status; ++} ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL HashLogExtendEvent function call provides callers with ++ an opportunity to extend and optionally log events without requiring ++ knowledge of actual TPM commands. ++ The extend operation will occur even if this function cannot create an event ++ log entry (e.g. due to the event log being full). ++ ++ @param[in] This Indicates the calling context ++ @param[in] Flags Bitmap providing additional information. ++ @param[in] DataToHash Physical address of the start of the data buffer to be hashed. ++ @param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash. ++ @param[in] Event Pointer to data buffer containing information about the event. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ @retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. ++ @retval EFI_UNSUPPORTED The PE/COFF image type is not supported. ++**/ ++EFI_STATUS ++EFIAPI ++CsvHashLogExtendEvent ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN UINT64 Flags, ++ IN EFI_PHYSICAL_ADDRESS DataToHash, ++ IN UINT64 DataToHashLen, ++ IN EFI_CC_EVENT *CcEvent ++ ) ++{ ++ EFI_STATUS Status; ++ CC_EVENT_HDR NewEventHdr; ++ TPML_DIGEST_VALUES DigestList; ++ ++ DEBUG ((DEBUG_VERBOSE, "CsvHashLogExtendEvent ...\n")); ++ ++ if ((This == NULL) || (CcEvent == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Do not check hash data size for EV_NO_ACTION event. ++ // ++ if ((CcEvent->Header.EventType != EV_NO_ACTION) && (DataToHash == 0)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (CcEvent->Size < CcEvent->Header.HeaderSize + sizeof (UINT32)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (CcEvent->Header.MrIndex >= CC_MR_INDEX_INVALID) { ++ DEBUG ((DEBUG_ERROR, "%a: MrIndex is invalid. (%d)\n", __func__, CcEvent->Header.MrIndex)); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ NewEventHdr.MrIndex = CcEvent->Header.MrIndex; ++ NewEventHdr.EventType = CcEvent->Header.EventType; ++ NewEventHdr.EventSize = CcEvent->Size - sizeof (UINT32) - CcEvent->Header.HeaderSize; ++ if ((Flags & EFI_CC_FLAG_PE_COFF_IMAGE) != 0) { ++ // ++ // According to UEFI Spec 2.10 Section 38.4.1 the mapping between MrIndex and Hygon ++ // CSV Measurement Register is: ++ // MrIndex 0-3 <--> RTMR[0-3] ++ // ++ Status = MeasurePeImageAndExtend ( ++ NewEventHdr.MrIndex, ++ DataToHash, ++ (UINTN)DataToHashLen, ++ &DigestList ++ ); ++ if (!EFI_ERROR (Status)) { ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CsvDxeLogHashEvent (&DigestList, &NewEventHdr, CcEvent->Event); ++ } ++ } ++ } else { ++ Status = CsvDxeHashLogExtendEvent ( ++ Flags, ++ (UINT8 *)(UINTN)DataToHash, ++ DataToHashLen, ++ &NewEventHdr, ++ CcEvent->Event ++ ); ++ } ++ ++ DEBUG ((DEBUG_VERBOSE, "CsvHashLogExtendEvent - %r\n", Status)); ++ return Status; ++} ++ ++EFI_CC_MEASUREMENT_PROTOCOL mCsvProtocol = { ++ CsvGetCapability, ++ CsvGetEventLog, ++ CsvHashLogExtendEvent, ++ CsvMapPcrToMrIndex, ++}; ++ ++#define CSV_HASH_COUNT 1 ++#define TEMP_BUF_LEN (sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32) \ ++ + (CSV_HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8)) ++ ++/** ++ Initialize the CSV Event Log and log events passed from the PEI phase. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ ++**/ ++EFI_STATUS ++SetupCcEventLog ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PHYSICAL_ADDRESS Lasa; ++ UINTN Index; ++ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; ++ UINT8 TempBuf[TEMP_BUF_LEN]; ++ TCG_PCR_EVENT_HDR SpecIdEvent; ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ TCG_EfiSpecIdEventAlgorithmSize *TempDigestSize; ++ UINT8 *VendorInfoSize; ++ UINT32 NumberOfAlgorithms; ++ EFI_CC_EVENT_LOG_FORMAT LogFormat; ++ EFI_PEI_HOB_POINTERS GuidHob; ++ CC_EVENT_HDR NoActionEvent; ++ ++ Status = EFI_SUCCESS; ++ DEBUG ((DEBUG_INFO, "SetupCcEventLog\n")); ++ ++ Index = 0; ++ LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ // ++ // 1. Create Log Area ++ // ++ mCsvDxeData.EventLogAreaStruct[Index].EventLogFormat = LogFormat; ++ ++ // allocate pages for CSV Event log ++ Status = gBS->AllocatePages ( ++ AllocateAnyPages, ++ EfiACPIMemoryNVS, ++ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), ++ &Lasa ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ mCsvDxeData.EventLogAreaStruct[Index].Lasa = Lasa; ++ mCsvDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); ++ mCsvDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0; ++ ++ // ++ // Report CSV event log address and length, so that they can be reported in ++ // CSV ACPI table. Ignore the return status, because those fields are optional. ++ // ++ PcdSet32S (PcdCcEventlogAcpiTableLaml, (UINT32)mCsvDxeData.EventLogAreaStruct[Index].Laml); ++ PcdSet64S (PcdCcEventlogAcpiTableLasa, mCsvDxeData.EventLogAreaStruct[Index].Lasa); ++ ++ // ++ // To initialize them as 0xFF is recommended ++ // because the OS can know the last entry for that. ++ // ++ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); ++ ++ // ++ // Create first entry for Log Header Entry Data ++ // ++ ++ // ++ // TcgEfiSpecIdEventStruct ++ // ++ TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)TempBuf; ++ CopyMem (TcgEfiSpecIdEventStruct->signature, TCG_EfiSpecIDEventStruct_SIGNATURE_03, sizeof (TcgEfiSpecIdEventStruct->signature)); ++ ++ TcgEfiSpecIdEventStruct->platformClass = PcdGet8 (PcdTpmPlatformClass); ++ ++ TcgEfiSpecIdEventStruct->specVersionMajor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MAJOR_TPM2; ++ TcgEfiSpecIdEventStruct->specVersionMinor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MINOR_TPM2; ++ TcgEfiSpecIdEventStruct->specErrata = TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2; ++ TcgEfiSpecIdEventStruct->uintnSize = sizeof (UINTN)/sizeof (UINT32); ++ NumberOfAlgorithms = 0; ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct ++ + sizeof (*TcgEfiSpecIdEventStruct) ++ + sizeof (NumberOfAlgorithms)); ++ ++ TempDigestSize = DigestSize; ++ TempDigestSize += NumberOfAlgorithms; ++ TempDigestSize->algorithmId = TPM_ALG_SM3_256; ++ TempDigestSize->digestSize = SM3_256_DIGEST_SIZE; ++ NumberOfAlgorithms++; ++ ++ CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof (NumberOfAlgorithms)); ++ TempDigestSize = DigestSize; ++ TempDigestSize += NumberOfAlgorithms; ++ VendorInfoSize = (UINT8 *)TempDigestSize; ++ *VendorInfoSize = 0; ++ ++ SpecIdEvent.PCRIndex = 1; // PCRIndex 0 maps to MrIndex 1 ++ SpecIdEvent.EventType = EV_NO_ACTION; ++ ZeroMem (&SpecIdEvent.Digest, sizeof (SpecIdEvent.Digest)); ++ SpecIdEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct); ++ ++ // ++ // CSV Event log re-use the spec of TCG2 Event log. ++ // Log TcgEfiSpecIdEventStruct as the first Event. Event format is TCG_PCR_EVENT. ++ // TCG EFI Protocol Spec. Section 5.3 Event Log Header ++ // TCG PC Client PFP spec. Section 9.2 Measurement Event Entries and Log ++ // ++ Status = CsvDxeLogEvent ( ++ LogFormat, ++ &SpecIdEvent, ++ sizeof (SpecIdEvent), ++ (UINT8 *)TcgEfiSpecIdEventStruct, ++ SpecIdEvent.EventSize ++ ); ++ // ++ // record the offset at the end of 800-155 event. ++ // the future 800-155 event can be inserted here. ++ // ++ mCsvDxeData.EventLogAreaStruct[Index].Next800155EventOffset = mCsvDxeData.EventLogAreaStruct[Index].EventLogSize; ++ ++ // ++ // Tcg800155PlatformIdEvent. Event format is TCG_PCR_EVENT2 ++ // ++ GuidHob.Guid = GetFirstGuidHob (&gTcg800155PlatformIdEventHobGuid); ++ while (GuidHob.Guid != NULL) { ++ InitNoActionEvent (&NoActionEvent, GET_GUID_HOB_DATA_SIZE (GuidHob.Guid)); ++ ++ Status = CsvDxeLogEvent ( ++ LogFormat, ++ &NoActionEvent, ++ sizeof (NoActionEvent.MrIndex) + sizeof (NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof (NoActionEvent.EventSize), ++ GET_GUID_HOB_DATA (GuidHob.Guid), ++ GET_GUID_HOB_DATA_SIZE (GuidHob.Guid) ++ ); ++ ++ GuidHob.Guid = GET_NEXT_HOB (GuidHob); ++ GuidHob.Guid = GetNextGuidHob (&gTcg800155PlatformIdEventHobGuid, GuidHob.Guid); ++ } ++ ++ // ++ // 2. Create Final Log Area ++ // ++ Status = gBS->AllocatePages ( ++ AllocateAnyPages, ++ EfiACPIMemoryNVS, ++ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcg2FinalLogAreaLen)), ++ &Lasa ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcg2FinalLogAreaLen), 0xFF); ++ ++ // ++ // Initialize ++ // ++ mCsvDxeData.FinalEventsTable[Index] = (VOID *)(UINTN)Lasa; ++ (mCsvDxeData.FinalEventsTable[Index])->Version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION; ++ (mCsvDxeData.FinalEventsTable[Index])->NumberOfEvents = 0; ++ ++ mCsvDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = LogFormat; ++ mCsvDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof (EFI_CC_FINAL_EVENTS_TABLE); ++ mCsvDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_CC_FINAL_EVENTS_TABLE); ++ mCsvDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; ++ mCsvDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mCsvDxeData.FinalEventLogAreaStruct[Index].Lasa; ++ mCsvDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; ++ mCsvDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; ++ mCsvDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; ++ ++ // ++ // Install to configuration table for EFI_CC_EVENT_LOG_FORMAT_TCG_2 ++ // ++ Status = gBS->InstallConfigurationTable (&gEfiCcFinalEventsTableGuid, (VOID *)mCsvDxeData.FinalEventsTable[Index]); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ return Status; ++} ++ ++/** ++ Measure and log an action string, and extend the measurement result into RTMR. ++ ++ @param[in] MrIndex MrIndex to extend ++ @param[in] String A specific string that indicates an Action event. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++CsvMeasureAction ( ++ IN UINT32 MrIndex, ++ IN CHAR8 *String ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EV_EFI_ACTION; ++ CcEvent.EventSize = (UINT32)AsciiStrLen (String); ++ return CsvDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)String, ++ CcEvent.EventSize, ++ &CcEvent, ++ (UINT8 *)String ++ ); ++} ++ ++/** ++ Measure and log EFI handoff tables, and extend the measurement result into PCR[1]. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureHandoffTables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ CC_EVENT_HDR CcEvent; ++ EFI_HANDOFF_TABLE_POINTERS HandoffTables; ++ UINTN ProcessorNum; ++ EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; ++ ++ ProcessorLocBuf = NULL; ++ Status = EFI_SUCCESS; ++ ++ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { ++ // ++ // Tcg Server spec. ++ // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1] ++ // ++ Status = GetProcessorsCpuLocation (&ProcessorLocBuf, &ProcessorNum); ++ ++ if (!EFI_ERROR (Status)) { ++ CcEvent.MrIndex = CsvMeasurementMapPcrToMrIndex (1); ++ CcEvent.EventType = EV_TABLE_OF_DEVICES; ++ CcEvent.EventSize = sizeof (HandoffTables); ++ ++ HandoffTables.NumberOfTables = 1; ++ HandoffTables.TableEntry[0].VendorGuid = gEfiMpServiceProtocolGuid; ++ HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf; ++ ++ Status = CsvDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)(UINTN)ProcessorLocBuf, ++ sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, ++ &CcEvent, ++ (UINT8 *)&HandoffTables ++ ); ++ ++ FreePool (ProcessorLocBuf); ++ } ++ } ++ ++ return Status; ++} ++ ++/** ++ Measure and log Separator event, and extend the measurement result into a specific PCR. ++ ++ @param[in] PCRIndex PCR index. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureSeparatorEvent ( ++ IN UINT32 MrIndex ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ UINT32 EventData; ++ ++ DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent to Rtmr - %d\n", MrIndex)); ++ ++ EventData = 0; ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EV_SEPARATOR; ++ CcEvent.EventSize = (UINT32)sizeof (EventData); ++ ++ return CsvDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)&EventData, ++ sizeof (EventData), ++ &CcEvent, ++ (UINT8 *)&EventData ++ ); ++} ++ ++/** ++ Measure and log an EFI variable, and extend the measurement result into a specific RTMR. ++ ++ @param[in] MrIndex RTMR Index. ++ @param[in] EventType Event type. ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[in] VarData The content of the variable data. ++ @param[in] VarSize The size of the variable data. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureVariable ( ++ IN UINT32 MrIndex, ++ IN TCG_EVENTTYPE EventType, ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ IN VOID *VarData, ++ IN UINTN VarSize ++ ) ++{ ++ EFI_STATUS Status; ++ CC_EVENT_HDR CcEvent; ++ UINTN VarNameLength; ++ UEFI_VARIABLE_DATA *VarLog; ++ ++ DEBUG ((DEBUG_INFO, "CsvTcg2Dxe: MeasureVariable (Rtmr - %x, EventType - %x, ", (UINTN)MrIndex, (UINTN)EventType)); ++ DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); ++ ++ VarNameLength = StrLen (VarName); ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EventType; ++ ++ CcEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize ++ - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); ++ ++ VarLog = (UEFI_VARIABLE_DATA *)AllocatePool (CcEvent.EventSize); ++ if (VarLog == NULL) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ VarLog->VariableName = *VendorGuid; ++ VarLog->UnicodeNameLength = VarNameLength; ++ VarLog->VariableDataLength = VarSize; ++ CopyMem ( ++ VarLog->UnicodeName, ++ VarName, ++ VarNameLength * sizeof (*VarName) ++ ); ++ if ((VarSize != 0) && (VarData != NULL)) { ++ CopyMem ( ++ (CHAR16 *)VarLog->UnicodeName + VarNameLength, ++ VarData, ++ VarSize ++ ); ++ } ++ ++ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { ++ // ++ // Digest is the event data (UEFI_VARIABLE_DATA) ++ // ++ Status = CsvDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)VarLog, ++ CcEvent.EventSize, ++ &CcEvent, ++ (UINT8 *)VarLog ++ ); ++ } else { ++ ASSERT (VarData != NULL); ++ Status = CsvDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)VarData, ++ VarSize, ++ &CcEvent, ++ (UINT8 *)VarLog ++ ); ++ } ++ ++ FreePool (VarLog); ++ return Status; ++} ++ ++/** ++ Read then Measure and log an EFI variable, and extend the measurement result into a specific RTMR. ++ ++ @param[in] MrIndex RTMR Index. ++ @param[in] EventType Event type. ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureVariable ( ++ IN UINT32 MrIndex, ++ IN TCG_EVENTTYPE EventType, ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ EFI_STATUS Status; ++ ++ Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize); ++ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { ++ if (EFI_ERROR (Status)) { ++ // ++ // It is valid case, so we need handle it. ++ // ++ *VarData = NULL; ++ *VarSize = 0; ++ } ++ } else { ++ // ++ // if status error, VarData is freed and set NULL by GetVariable2 ++ // ++ if (EFI_ERROR (Status)) { ++ return EFI_NOT_FOUND; ++ } ++ } ++ ++ Status = MeasureVariable ( ++ MrIndex, ++ EventType, ++ VarName, ++ VendorGuid, ++ *VarData, ++ *VarSize ++ ); ++ return Status; ++} ++ ++/** ++ Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[1]. ++according to TCG PC Client PFP spec 0021 Section 2.4.4.2 ++ ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureBootVariable ( ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ return ReadAndMeasureVariable ( ++ CsvMeasurementMapPcrToMrIndex (1), ++ EV_EFI_VARIABLE_BOOT, ++ VarName, ++ VendorGuid, ++ VarSize, ++ VarData ++ ); ++} ++ ++/** ++ Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7]. ++ ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureSecureVariable ( ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ return ReadAndMeasureVariable ( ++ CsvMeasurementMapPcrToMrIndex (7), ++ EV_EFI_VARIABLE_DRIVER_CONFIG, ++ VarName, ++ VendorGuid, ++ VarSize, ++ VarData ++ ); ++} ++ ++/** ++ Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. ++ ++ The EFI boot variables are BootOrder and Boot#### variables. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureAllBootVariables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UINT16 *BootOrder; ++ UINTN BootCount; ++ UINTN Index; ++ VOID *BootVarData; ++ UINTN Size; ++ ++ Status = ReadAndMeasureBootVariable ( ++ mBootVarName, ++ &gEfiGlobalVariableGuid, ++ &BootCount, ++ (VOID **)&BootOrder ++ ); ++ if ((Status == EFI_NOT_FOUND) || (BootOrder == NULL)) { ++ return EFI_SUCCESS; ++ } ++ ++ if (EFI_ERROR (Status)) { ++ // ++ // BootOrder can't be NULL if status is not EFI_NOT_FOUND ++ // ++ FreePool (BootOrder); ++ return Status; ++ } ++ ++ BootCount /= sizeof (*BootOrder); ++ for (Index = 0; Index < BootCount; Index++) { ++ UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]); ++ Status = ReadAndMeasureBootVariable ( ++ mBootVarName, ++ &gEfiGlobalVariableGuid, ++ &Size, ++ &BootVarData ++ ); ++ if (!EFI_ERROR (Status)) { ++ FreePool (BootVarData); ++ } ++ } ++ ++ FreePool (BootOrder); ++ return EFI_SUCCESS; ++} ++ ++/** ++ Measure and log all EFI Secure variables, and extend the measurement result into a specific PCR. ++ ++ The EFI boot variables are BootOrder and Boot#### variables. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureAllSecureVariables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ VOID *Data; ++ UINTN DataSize; ++ UINTN Index; ++ ++ Status = EFI_NOT_FOUND; ++ for (Index = 0; Index < sizeof (mVariableType)/sizeof (mVariableType[0]); Index++) { ++ Status = ReadAndMeasureSecureVariable ( ++ mVariableType[Index].VariableName, ++ mVariableType[Index].VendorGuid, ++ &DataSize, ++ &Data ++ ); ++ if (!EFI_ERROR (Status)) { ++ if (Data != NULL) { ++ FreePool (Data); ++ } ++ } ++ } ++ ++ // ++ // Measure DBT if present and not empty ++ // ++ Status = GetVariable2 (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, &Data, &DataSize); ++ if (!EFI_ERROR (Status)) { ++ Status = MeasureVariable ( ++ CsvMeasurementMapPcrToMrIndex (7), ++ EV_EFI_VARIABLE_DRIVER_CONFIG, ++ EFI_IMAGE_SECURITY_DATABASE2, ++ &gEfiImageSecurityDatabaseGuid, ++ Data, ++ DataSize ++ ); ++ FreePool (Data); ++ } else { ++ DEBUG ((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2)); ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureLaunchOfFirmwareDebugger ( ++ VOID ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ ++ CcEvent.MrIndex = CsvMeasurementMapPcrToMrIndex (7); ++ CcEvent.EventType = EV_EFI_ACTION; ++ CcEvent.EventSize = sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1; ++ return CsvDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING, ++ sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1, ++ &CcEvent, ++ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING ++ ); ++} ++ ++/** ++ Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR. ++ ++ Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed) ++ - The contents of the SecureBoot variable ++ - The contents of the PK variable ++ - The contents of the KEK variable ++ - The contents of the EFI_IMAGE_SECURITY_DATABASE variable ++ - The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable ++ - Separator ++ - Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path ++ ++ NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE, ++ EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3]. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++**/ ++VOID ++EFIAPI ++MeasureSecureBootPolicy ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ VOID *Protocol; ++ ++ Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol); ++ if (EFI_ERROR (Status)) { ++ return; ++ } ++ ++ if (PcdGetBool (PcdFirmwareDebuggerInitialized)) { ++ Status = MeasureLaunchOfFirmwareDebugger (); ++ DEBUG ((DEBUG_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status)); ++ } ++ ++ Status = MeasureAllSecureVariables (); ++ DEBUG ((DEBUG_INFO, "MeasureAllSecureVariables - %r\n", Status)); ++ ++ // ++ // We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure) ++ // and ImageVerification (Authority) ++ // There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So ++ // the Authority measurement happen before ReadToBoot event. ++ // ++ Status = MeasureSeparatorEvent (CsvMeasurementMapPcrToMrIndex (7)); ++ ++ DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent - %r\n", Status)); ++ return; ++} ++ ++/** ++ Ready to Boot Event notification handler. ++ ++ Sequence of OS boot events is measured in this event notification handler. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnReadyToBoot ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ PERF_START_EX (mImageHandle, "EventRec", "CsvTcg2Dxe", 0, PERF_ID_CC_TCG2_DXE); ++ ++ if (mBootAttempts == 0) { ++ // ++ // Measure handoff tables. ++ // ++ Status = MeasureHandoffTables (); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "HOBs not Measured. Error!\n")); ++ } ++ ++ // ++ // Measure BootOrder & Boot#### variables. ++ // ++ Status = MeasureAllBootVariables (); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Boot Variables not Measured. Error!\n")); ++ } ++ ++ // ++ // 1. This is the first boot attempt. ++ // ++ Status = CsvMeasureAction ( ++ CsvMeasurementMapPcrToMrIndex (4), ++ EFI_CALLING_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); ++ } ++ ++ // ++ // 2. Draw a line between pre-boot env and entering post-boot env. ++ // ++ // According to UEFI Spec 2.10 Section 38.4.1 the mapping between MrIndex and Hygon ++ // CSV Measurement Register is: ++ // MrIndex 0-3 <--> RTMR[0-3] ++ // ++ Status = MeasureSeparatorEvent (CC_MR_INDEX_2_RTMR2); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Separator Event not Measured to RTMR[1]. Error!\n")); ++ } ++ ++ // ++ // 3. Measure GPT. It would be done in SAP driver. ++ // ++ ++ // ++ // 4. Measure PE/COFF OS loader. It would be done in SAP driver. ++ // ++ ++ // ++ // 5. Read & Measure variable. BootOrder already measured. ++ // ++ } else { ++ // ++ // 6. Not first attempt, meaning a return from last attempt ++ // ++ Status = CsvMeasureAction ( ++ CsvMeasurementMapPcrToMrIndex (4), ++ EFI_RETURNING_FROM_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATION)); ++ } ++ ++ // ++ // 7. Next boot attempt, measure "Calling EFI Application from Boot Option" again ++ // TCG PC Client PFP spec Section 2.4.4.5 Step 4 ++ // ++ Status = CsvMeasureAction ( ++ CsvMeasurementMapPcrToMrIndex (4), ++ EFI_CALLING_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); ++ } ++ } ++ ++ DEBUG ((DEBUG_INFO, "CsvTcg2Dxe Measure Data when ReadyToBoot\n")); ++ // ++ // Increase boot attempt counter. ++ // ++ mBootAttempts++; ++ PERF_END_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_CC_TCG2_DXE + 1); ++} ++ ++/** ++ Exit Boot Services Event notification handler. ++ ++ Measure invocation and success of ExitBootServices. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnExitBootServices ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ // ++ // Measure invocation of ExitBootServices, ++ // ++ Status = CsvMeasureAction ( ++ CsvMeasurementMapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_INVOCATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION)); ++ } ++ ++ // ++ // Measure success of ExitBootServices ++ // ++ Status = CsvMeasureAction ( ++ CsvMeasurementMapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_SUCCEEDED ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED)); ++ } ++} ++ ++/** ++ Exit Boot Services Failed Event notification handler. ++ ++ Measure Failure of ExitBootServices. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnExitBootServicesFailed ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ // ++ // Measure Failure of ExitBootServices, ++ // ++ Status = CsvMeasureAction ( ++ CsvMeasurementMapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_FAILED ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED)); ++ } ++} ++ ++/** ++ Install CSV ACPI Table when ACPI Table Protocol is available. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++**/ ++VOID ++EFIAPI ++InstallAcpiTable ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ UINTN TableKey; ++ EFI_STATUS Status; ++ EFI_ACPI_TABLE_PROTOCOL *AcpiTable; ++ ++ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "CSV: AcpiTableProtocol is not installed. %r\n", Status)); ++ return; ++ } ++ ++ mCsvEventlogAcpiTemplate.Laml = (UINT64)PcdGet32 (PcdCcEventlogAcpiTableLaml); ++ mCsvEventlogAcpiTemplate.Lasa = PcdGet64 (PcdCcEventlogAcpiTableLasa); ++ CopyMem (mCsvEventlogAcpiTemplate.Header.OemId, "HYGON ", sizeof (mCsvEventlogAcpiTemplate.Header.OemId)); ++ mCsvEventlogAcpiTemplate.Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); ++ mCsvEventlogAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); ++ mCsvEventlogAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); ++ mCsvEventlogAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); ++ ++ // ++ // Construct ACPI Table ++ Status = AcpiTable->InstallAcpiTable ( ++ AcpiTable, ++ &mCsvEventlogAcpiTemplate, ++ mCsvEventlogAcpiTemplate.Header.Length, ++ &TableKey ++ ); ++ ASSERT_EFI_ERROR (Status); ++ ++ DEBUG ((DEBUG_INFO, "CSV Eventlog ACPI Table is installed.\n")); ++} ++ ++/** ++ The function install CsvTcg2 protocol. ++ ++ @retval EFI_SUCCESS CsvTcg2 protocol is installed. ++ @retval other Some error occurs. ++**/ ++EFI_STATUS ++InstallCcMeasurementProtocol ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_HANDLE Handle; ++ ++ Handle = NULL; ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gEfiCcMeasurementProtocolGuid, ++ &mCsvProtocol, ++ NULL ++ ); ++ DEBUG ((DEBUG_INFO, "CcProtocol: Install %r\n", Status)); ++ return Status; ++} ++ ++/** ++ The driver's entry point. It publishes EFI Tcg2 Protocol. ++ ++ @param[in] ImageHandle The firmware allocated handle for the EFI image. ++ @param[in] SystemTable A pointer to the EFI System Table. ++ ++ @retval EFI_SUCCESS The entry point is executed successfully. ++ @retval other Some error occurs when executing this entry point. ++**/ ++EFI_STATUS ++EFIAPI ++DriverEntry ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_EVENT Event; ++ VOID *Registration; ++ ++ if (!CsvIsEnabled ()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ if (CsvStartRtmr()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ mImageHandle = ImageHandle; ++ ++ // ++ // Fill information ++ // ++ // ASSERT (CSV_EVENT_LOG_AREA_COUNT_MAX == sizeof(mTEventInfo)/sizeof(mTcg2EventInfo[0])); ++ ++ mCsvDxeData.BsCap.Size = sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY); ++ mCsvDxeData.BsCap.ProtocolVersion.Major = 1; ++ mCsvDxeData.BsCap.ProtocolVersion.Minor = 0; ++ mCsvDxeData.BsCap.StructureVersion.Major = 1; ++ mCsvDxeData.BsCap.StructureVersion.Minor = 0; ++ ++ // ++ // Get supported PCR and current Active PCRs ++ // For CSV guest SM3 is supported. ++ // ++ mCsvDxeData.BsCap.HashAlgorithmBitmap = HASH_ALG_SM3_256; ++ ++ // CSV guest only supports EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 ++ mCsvDxeData.BsCap.SupportedEventLogs = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ // ++ // Setup the log area and copy event log from hob list to it ++ // ++ Status = SetupCcEventLog (); ++ ASSERT_EFI_ERROR (Status); ++ ++ // ++ // Measure handoff tables, Boot#### variables etc. ++ // ++ Status = EfiCreateEventReadyToBootEx ( ++ TPL_CALLBACK, ++ OnReadyToBoot, ++ NULL, ++ &Event ++ ); ++ ++ Status = gBS->CreateEventEx ( ++ EVT_NOTIFY_SIGNAL, ++ TPL_NOTIFY, ++ OnExitBootServices, ++ NULL, ++ &gEfiEventExitBootServicesGuid, ++ &Event ++ ); ++ ++ // ++ // Measure Exit Boot Service failed ++ // ++ Status = gBS->CreateEventEx ( ++ EVT_NOTIFY_SIGNAL, ++ TPL_NOTIFY, ++ OnExitBootServicesFailed, ++ NULL, ++ &gEventExitBootServicesFailedGuid, ++ &Event ++ ); ++ ++ // ++ // Create event callback, because we need access variable on SecureBootPolicyVariable ++ // We should use VariableWriteArch instead of VariableArch, because Variable driver ++ // may update SecureBoot value based on last setting. ++ // ++ EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration); ++ ++ // ++ // Install CcMeasurementProtocol ++ // ++ Status = InstallCcMeasurementProtocol (); ++ DEBUG ((DEBUG_INFO, "InstallCcMeasurementProtocol - %r\n", Status)); ++ ++ if (Status == EFI_SUCCESS) { ++ // ++ // Create event callback to install CC EventLog ACPI Table ++ EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration); ++ } else { ++ // ++ // Cc measurement feature is crucial to a csv-guest and it shall stop running immediately ++ // when it is failed to be installed. ++ DEBUG ((DEBUG_ERROR, "%a: CcMeasurement protocol failed to be installed - %r\n", __func__, Status)); ++ CpuDeadLoop (); ++ } ++ ++ return Status; ++} +diff --git a/OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.inf b/OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.inf +new file mode 100644 +index 0000000..a1d541a +--- /dev/null ++++ b/OvmfPkg/Tcg/CsvTcg2Dxe/CsvTcg2Dxe.inf +@@ -0,0 +1,99 @@ ++## @file ++# ++# Produces EFI_CC_MEASUREMENT_PROTOCOL and measure boot environment ++# ++# ++# Copyright (c) 2025, Hygon Corporation. All rights reserved.
++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = CsvTcg2Dxe ++ FILE_GUID = 77797458-DA6D-4403-874A-33BA7E937EB6 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = DriverEntry ++ ++# ++# The following information is for reference only and not required by the build tools. ++# ++# VALID_ARCHITECTURES = X64 ++# ++ ++[Sources] ++ CsvTcg2Dxe.c ++ MeasureBootPeCoff.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ SecurityPkg/SecurityPkg.dec ++ CryptoPkg/CryptoPkg.dec ++ OvmfPkg/OvmfPkg.dec ++ ++[LibraryClasses] ++ MemoryAllocationLib ++ BaseLib ++ UefiBootServicesTableLib ++ HobLib ++ UefiDriverEntryPoint ++ UefiRuntimeServicesTableLib ++ BaseMemoryLib ++ DebugLib ++ PrintLib ++ UefiLib ++ HashLib ++ PerformanceLib ++ ReportStatusCodeLib ++ PeCoffLib ++ TpmMeasurementLib ++ CsvLib ++ ++[Guids] ++ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" ++ ## SOMETIMES_CONSUMES ## Variable:L"PK" ++ ## SOMETIMES_CONSUMES ## Variable:L"KEK" ++ ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" ++ gEfiGlobalVariableGuid ++ ++ ## SOMETIMES_CONSUMES ## Variable:L"db" ++ ## SOMETIMES_CONSUMES ## Variable:L"dbx" ++ gEfiImageSecurityDatabaseGuid ++ ++ # gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gEfiEventExitBootServicesGuid ## CONSUMES ## Event ++ gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event ++ ++ gTcg800155PlatformIdEventHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gEfiCcFinalEventsTableGuid ## PRODUCES ++ ++[Protocols] ++ gEfiCcMeasurementProtocolGuid ## PRODUCES ++ gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES ++ gEfiVariableWriteArchProtocolGuid ## NOTIFY ++ gEfiAcpiTableProtocolGuid ## NOTIFY ++ ++[Pcd] ++ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2NumberOfPCRBanks ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLaml ## PRODUCES ++ gEfiSecurityPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLasa ## PRODUCES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES ++ ++[Depex] ++ # According to PcdTpm2AcpiTableRev definition in SecurityPkg.dec ++ # This PCD should be configured at DynamicHii or DynamicHiiEx. ++ # So, this PCD read operation depends on GetVariable service. ++ # Add VariableArch protocol dependency to make sure PCD read works. ++ gEfiVariableArchProtocolGuid AND gEfiAcpiTableProtocolGuid +diff --git a/OvmfPkg/Tcg/CsvTcg2Dxe/MeasureBootPeCoff.c b/OvmfPkg/Tcg/CsvTcg2Dxe/MeasureBootPeCoff.c +new file mode 100644 +index 0000000..4d54215 +--- /dev/null ++++ b/OvmfPkg/Tcg/CsvTcg2Dxe/MeasureBootPeCoff.c +@@ -0,0 +1,407 @@ ++/** @file ++ This module implements measuring PeCoff image for Tcg2 Protocol. ++ ++ Caution: This file requires additional review when modified. ++ This driver will have external input - PE/COFF image. ++ This external input must be validated carefully to avoid security issue like ++ buffer overflow, integer overflow. ++ ++Copyright (c) 2025, Hygon Corporation. All rights reserved.
++SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++UINTN mTcg2DxeImageSize = 0; ++ ++/** ++ Reads contents of a PE/COFF image in memory buffer. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ @param FileHandle Pointer to the file handle to read the PE/COFF image. ++ @param FileOffset Offset into the PE/COFF image to begin the read operation. ++ @param ReadSize On input, the size in bytes of the requested read operation. ++ On output, the number of bytes actually read. ++ @param Buffer Output buffer that contains the data read from the PE/COFF image. ++ ++ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size ++**/ ++EFI_STATUS ++EFIAPI ++Tcg2DxeImageRead ( ++ IN VOID *FileHandle, ++ IN UINTN FileOffset, ++ IN OUT UINTN *ReadSize, ++ OUT VOID *Buffer ++ ) ++{ ++ UINTN EndPosition; ++ ++ if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (MAX_ADDRESS - FileOffset < *ReadSize) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ EndPosition = FileOffset + *ReadSize; ++ if (EndPosition > mTcg2DxeImageSize) { ++ *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset); ++ } ++ ++ if (FileOffset >= mTcg2DxeImageSize) { ++ *ReadSize = 0; ++ } ++ ++ CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Measure PE image into TPM log based on the authenticode image hashing in ++ PE/COFF Specification 8.0 Appendix A. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will validate its data structure ++ within this image buffer before use. ++ ++ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). ++ ++ @param[in] RtmrIndex Rtmr index ++ @param[in] ImageAddress Start address of image buffer. ++ @param[in] ImageSize Image size ++ @param[out] DigestList Digest list of this image. ++ ++ @retval EFI_SUCCESS Successfully measure image. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. ++ @retval other error value ++**/ ++EFI_STATUS ++MeasurePeImageAndExtend ( ++ IN UINT32 RtmrIndex, ++ IN EFI_PHYSICAL_ADDRESS ImageAddress, ++ IN UINTN ImageSize, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_IMAGE_DOS_HEADER *DosHdr; ++ UINT32 PeCoffHeaderOffset; ++ EFI_IMAGE_SECTION_HEADER *Section; ++ UINT8 *HashBase; ++ UINTN HashSize; ++ UINTN SumOfBytesHashed; ++ EFI_IMAGE_SECTION_HEADER *SectionHeader; ++ UINTN Index; ++ UINTN Pos; ++ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; ++ UINT32 NumberOfRvaAndSizes; ++ UINT32 CertSize; ++ HASH_HANDLE HashHandle; ++ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; ++ ++ HashHandle = 0xFFFFFFFF; // Know bad value ++ ++ Status = EFI_UNSUPPORTED; ++ SectionHeader = NULL; ++ ++ // ++ // Check PE/COFF image ++ // ++ ZeroMem (&ImageContext, sizeof (ImageContext)); ++ ImageContext.Handle = (VOID *)(UINTN)ImageAddress; ++ mTcg2DxeImageSize = ImageSize; ++ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)Tcg2DxeImageRead; ++ ++ // ++ // Get information about the image being loaded ++ // ++ Status = PeCoffLoaderGetImageInfo (&ImageContext); ++ if (EFI_ERROR (Status)) { ++ // ++ // The information can't be got from the invalid PeImage ++ // ++ DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n")); ++ goto Finish; ++ } ++ ++ DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress; ++ PeCoffHeaderOffset = 0; ++ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { ++ PeCoffHeaderOffset = DosHdr->e_lfanew; ++ } ++ ++ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset); ++ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { ++ Status = EFI_UNSUPPORTED; ++ goto Finish; ++ } ++ ++ // ++ // PE/COFF Image Measurement ++ // ++ // NOTE: The following codes/steps are based upon the authenticode image hashing in ++ // PE/COFF Specification 8.0 Appendix A. ++ // ++ // ++ ++ // 1. Load the image header into memory. ++ ++ // 2. Initialize a SHA hash context. ++ ++ Status = HashStart (&HashHandle); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ // ++ // Measuring PE/COFF Image Header; ++ // But CheckSum field and SECURITY data directory (certificate) are excluded ++ // ++ ++ // ++ // 3. Calculate the distance from the base of the image header to the image checksum address. ++ // 4. Hash the image header from its base to beginning of the image checksum. ++ // ++ HashBase = (UINT8 *)(UINTN)ImageAddress; ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; ++ HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; ++ HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase; ++ } ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ // ++ // 5. Skip over the image checksum (it occupies a single ULONG). ++ // ++ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { ++ // ++ // 6. Since there is no Cert Directory in optional header, hash everything ++ // from the end of the checksum to the end of image header. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset. ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } else { ++ // ++ // Use PE32+ offset. ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ } else { ++ // ++ // 7. Hash everything from the end of the checksum to the start of the Cert Directory. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ ++ // ++ // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) ++ // 9. Hash everything from the end of the Cert Directory to the end of image header. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; ++ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; ++ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ } ++ ++ // ++ // 10. Set the SUM_OF_BYTES_HASHED to the size of the header ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; ++ } ++ ++ // ++ // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER ++ // structures in the image. The 'NumberOfSections' field of the image ++ // header indicates how big the table should be. Do not include any ++ // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. ++ // ++ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); ++ if (SectionHeader == NULL) { ++ Status = EFI_OUT_OF_RESOURCES; ++ goto Finish; ++ } ++ ++ // ++ // 12. Using the 'PointerToRawData' in the referenced section headers as ++ // a key, arrange the elements in the table in ascending order. In other ++ // words, sort the section headers according to the disk-file offset of ++ // the section. ++ // ++ Section = (EFI_IMAGE_SECTION_HEADER *)( ++ (UINT8 *)(UINTN)ImageAddress + ++ PeCoffHeaderOffset + ++ sizeof (UINT32) + ++ sizeof (EFI_IMAGE_FILE_HEADER) + ++ Hdr.Pe32->FileHeader.SizeOfOptionalHeader ++ ); ++ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { ++ Pos = Index; ++ while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { ++ CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); ++ Pos--; ++ } ++ ++ CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); ++ Section += 1; ++ } ++ ++ // ++ // 13. Walk through the sorted table, bring the corresponding section ++ // into memory, and hash the entire section (using the 'SizeOfRawData' ++ // field in the section header to determine the amount of data to hash). ++ // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . ++ // 15. Repeat steps 13 and 14 for all the sections in the sorted table. ++ // ++ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { ++ Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index]; ++ if (Section->SizeOfRawData == 0) { ++ continue; ++ } ++ ++ HashBase = (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData; ++ HashSize = (UINTN)Section->SizeOfRawData; ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ SumOfBytesHashed += HashSize; ++ } ++ ++ // ++ // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra ++ // data in the file that needs to be added to the hash. This data begins ++ // at file offset SUM_OF_BYTES_HASHED and its length is: ++ // FileSize - (CertDirectory->Size) ++ // ++ if (ImageSize > SumOfBytesHashed) { ++ HashBase = (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed; ++ ++ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { ++ CertSize = 0; ++ } else { ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset. ++ // ++ CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; ++ } else { ++ // ++ // Use PE32+ offset. ++ // ++ CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; ++ } ++ } ++ ++ if (ImageSize > CertSize + SumOfBytesHashed) { ++ HashSize = (UINTN)(ImageSize - CertSize - SumOfBytesHashed); ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } else if (ImageSize < CertSize + SumOfBytesHashed) { ++ Status = EFI_UNSUPPORTED; ++ goto Finish; ++ } ++ } ++ ++ // ++ // 17. Finalize the SHA hash. ++ // ++ Status = HashCompleteAndExtend (HashHandle, RtmrIndex, NULL, 0, DigestList); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++Finish: ++ if (SectionHeader != NULL) { ++ FreePool (SectionHeader); ++ } ++ ++ return Status; ++} +diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec +index 8cf80b1..d03c1cc 100644 +--- a/SecurityPkg/SecurityPkg.dec ++++ b/SecurityPkg/SecurityPkg.dec +@@ -571,5 +571,11 @@ + # @Prompt Tpm2AcpiTableLasa LASA field in TPM2 ACPI table. + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLasa|0|UINT64|0x00010023 + ++ ## This PCD records LAML field in CC EVENTLOG ACPI table. ++ gEfiSecurityPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLaml|0|UINT32|0x00010025 ++ ++ ## This PCD records LASA field in CC EVENTLOG ACPI table. ++ gEfiSecurityPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLasa|0|UINT64|0x00010026 ++ + [UserExtensions.TianoCore."ExtraFiles"] + SecurityPkgExtra.uni +-- +2.34.1 + diff --git a/edk2.spec b/edk2.spec index 76ccc1114b7dd00ab5d9938ada1b6bb7df4b16c2..d3f7354dd9cf8a5a7c30702907db9872f30f3017 100644 --- a/edk2.spec +++ b/edk2.spec @@ -8,7 +8,7 @@ ExclusiveArch: x86_64 aarch64 Name: edk2 Version: %{GITDATE}git%{GITCOMMIT} -Release: 13%{anolis_release}%{?dist}.7 +Release: 13%{anolis_release}%{?dist}.8 Summary: UEFI firmware for 64-bit virtual machines Group: Applications/Emulators License: BSD-2-Clause-Patent and OpenSSL and MIT @@ -425,6 +425,12 @@ Patch1022: 0051-OvmfPkg-AmdSev-Add-missing-PcdMemEncryptStatus-Base-.patch # Encryption right out of the box. Patch1023: 0052-OvmfPkg-AmdSev-Integrate-grub2-x86_64-efi-modules-fr.patch +#Add coco measurement capabilities for the CSV3 virtual machine +Patch1024: 0053-SecurityPkg-Removing-unused-library-dependencies-in-.patch +Patch1025: 0054-OvmfPkg-Add-RTMR-functions-in-CsvLib-for-CSV3-virtua.patch +Patch1026: 0055-OmvfPkg-HashLibCsv-Add-HashLibCsv.patch +Patch1027: 0056-OvmfPkg-CsvTcg2Dxe-Add-CsvTcg2Dxe.patch + # python3-devel and libuuid-devel are required for building tools. # python3-devel is also needed for varstore template generation and # verification with "ovmf-vars-generator". @@ -883,6 +889,9 @@ true %endif %changelog +* Mon Jun 23 2025 yangge - 20220126gitbb1bba3d77-13.0.1.8 +- Add coco measurement capabilities for the CSV3 virtual machine + * Mon Apr 14 2025 hanliyang - 20220126gitbb1bba3d77-13.0.1.7 - Build OVMF.fd using AmdSevX64.dsc to support Full Disk Encryption