diff --git a/0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch b/0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch new file mode 100644 index 0000000000000000000000000000000000000000..98cea5f8412b4ef9caed58e5b568b17754efd840 --- /dev/null +++ b/0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch @@ -0,0 +1,4912 @@ +From 6b83755a46db898016d51a3d0d8f44e4a656747c Mon Sep 17 00:00:00 2001 +From: z00570632 +Date: Mon, 17 Feb 2025 19:17:07 +0800 +Subject: [PATCH] enable cc measurement and sha256 in cc measurement + +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 2235 +++++++++++++++++ + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf | 86 + + ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c | 407 +++ + ArmVirtPkg/ArmVirtPkg.dec | 2 + + ArmVirtPkg/ArmVirtQemu.dsc | 127 +- + ArmVirtPkg/ArmVirtQemu.fdf | 25 +- + ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc | 10 + + ArmVirtPkg/Include/Library/ArmCcaRsiLib.h | 373 +++ + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c | 13 + + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf | 1 + + ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h | 59 + + .../Library/ArmCcaRsiLib/ArmCcaRsiLib.c | 730 ++++++ + .../Library/ArmCcaRsiLib/ArmCcaRsiLib.inf | 29 + + ArmVirtPkg/Library/HashLibCca/HashLibCca.c | 209 ++ + ArmVirtPkg/Library/HashLibCca/HashLibCca.inf | 39 + + .../RealmApertureManagementProtocolDxe.c | 7 +- + .../RealmApertureManagementProtocolDxe.inf | 1 + + MdeModulePkg/MdeModulePkg.dec | 2 +- + .../IndustryStandard/UefiTcgPlatform.h | 1 + + MdePkg/Include/Protocol/CcMeasurement.h | 5 +- + .../DxeTpm2MeasureBootLib.c | 96 +- + .../HashInstanceLibSha256.c | 1 - + .../HashInstanceLibSha256.inf | 1 - + 23 files changed, 4334 insertions(+), 125 deletions(-) + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c + create mode 100644 ArmVirtPkg/Include/Library/ArmCcaRsiLib.h + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf + create mode 100644 ArmVirtPkg/Library/HashLibCca/HashLibCca.c + create mode 100644 ArmVirtPkg/Library/HashLibCca/HashLibCca.inf + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +new file mode 100644 +index 00000000..a4881ad5 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -0,0 +1,2235 @@ ++#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 ++#define CC_MR_INDEX_0_RIM 0 ++#define CC_MR_INDEX_1_REM0 1 ++#define CC_MR_INDEX_2_REM1 2 ++#define CC_MR_INDEX_3_REM2 3 ++#define CC_MR_INDEX_INVALID 4 ++ ++typedef struct { ++ CHAR16 *VariableName; ++ EFI_GUID *VendorGuid; ++} VARIABLE_TYPE; ++ ++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 _CCA_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]; ++} CCA_DXE_DATA; ++ ++typedef struct { ++ TPMI_ALG_HASH HashAlgo; ++ UINT16 HashSize; ++ UINT32 HashMask; ++} CCA_HASH_INFO; ++ ++CCA_DXE_DATA mCcaDxeData = { ++ { ++ sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY), // Size ++ { 1, 1 }, // StructureVersion ++ { 1, 1 }, // ProtocolVersion ++ EFI_CC_BOOT_HASH_ALG_SHA256, // 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 mCcaEventlogAcpiTemplate = { ++ { ++ EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE, ++ sizeof (mCcaEventlogAcpiTemplate), ++ EFI_CC_EVENTLOG_ACPI_TABLE_REVISION, ++ // ++ // Compiler initializes the remaining bytes to 0 ++ // These fields should be filled in production ++ // ++ }, ++ { EFI_CC_TYPE_CCA, 0 }, // CcType ++ 0, // rsvd ++ 0, // laml ++ 0, // lasa ++}; ++ ++// ++// Supported Hash list in Td guest. ++// Currently SHA256 is supported. ++// ++CCA_HASH_INFO mHashInfo[] = { ++ { TPM_ALG_SHA256, SHA256_DIGEST_SIZE, HASH_ALG_SHA256 } ++}; ++ ++/** ++ 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; ++} ++ ++/** ++ 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: CCA 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] RemIndex REM 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 RemIndex, ++ 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 TD_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 ((mCcaDxeData.BsCap.HashAlgorithmBitmap & EFI_CC_BOOT_HASH_ALG_SHA256) != 0) { ++ HashAlgId = TPM_ALG_SHA256; ++ 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); ++} ++ ++/** ++ 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 ++CcaGetCapability ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN OUT EFI_CC_BOOT_SERVICE_CAPABILITY *ProtocolCapability ++ ) ++{ ++ DEBUG ((DEBUG_VERBOSE, "CcaGetCapability\n")); ++ ++ if ((This == NULL) || (ProtocolCapability == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ CopyMem (ProtocolCapability, &mCcaDxeData.BsCap, sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY)); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function dump PCR event. ++ TD 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 TD 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 CCA Event (including the Digests). ++ ++ @param[in] CcEvent CCA 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 Td Table event. ++ ++ @param[in] CcEvent Td Table event structure. ++ ++ @return size of Td 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. ++ TDVF 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 ++CcaGetEventLog ( ++ 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, "CcaGetEventLog ... (0x%x)\n", EventLogFormat)); ++ ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2); ++ ++ if (EventLogLocation != NULL) { ++ *EventLogLocation = mCcaDxeData.EventLogAreaStruct[Index].Lasa; ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogLocation - %x)\n", *EventLogLocation)); ++ } ++ ++ if (EventLogLastEntry != NULL) { ++ if (!mCcaDxeData.EventLogAreaStruct[Index].EventLogStarted) { ++ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; ++ } else { ++ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mCcaDxeData.EventLogAreaStruct[Index].LastEvent; ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry)); ++ } ++ ++ if (EventLogTruncated != NULL) { ++ *EventLogTruncated = mCcaDxeData.EventLogAreaStruct[Index].EventLogTruncated; ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated)); ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog - %r\n", EFI_SUCCESS)); ++ ++ // Dump Event Log for debug purpose ++ if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) { ++ DumpCcEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mCcaDxeData.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. ++ // ++ mCcaDxeData.GetEventLogCalled[Index] = TRUE; ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Return if this is a Tcg800155PlatformIdEvent. ++ ++ @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 TRUE This is a Tcg800155PlatformIdEvent. ++ @retval FALSE This is NOT a Tcg800155PlatformIdEvent. ++ ++**/ ++BOOLEAN ++Is800155Event ( ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ if ((((TCG_PCR_EVENT2_HDR *)NewEventHdr)->EventType == EV_NO_ACTION) && ++ (NewEventSize >= sizeof (TCG_Sp800_155_PlatformId_Event2)) && ++ ((CompareMem ( ++ NewEventData, ++ TCG_Sp800_155_PlatformId_Event2_SIGNATURE, ++ sizeof (TCG_Sp800_155_PlatformId_Event2_SIGNATURE) - 1 ++ ) == 0) || ++ (CompareMem ( ++ NewEventData, ++ TCG_Sp800_155_PlatformId_Event3_SIGNATURE, ++ sizeof (TCG_Sp800_155_PlatformId_Event3_SIGNATURE) - 1 ++ ) == 0))) ++ { ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/** ++ 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; ++ BOOLEAN Record800155Event; ++ CC_EVENT_HDR *CcEventHdr; ++ ++ CcEventHdr = (CC_EVENT_HDR *)NewEventHdr; ++ DEBUG ((DEBUG_INFO, "Cca: Try to log event. Index = %d, EventType = 0x%x\n", CcEventHdr->MrIndex, CcEventHdr->EventType)); ++ ++ 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; ++ } ++ ++ // ++ // Check 800-155 event ++ // Record to 800-155 event offset only. ++ // If the offset is 0, no need to record. ++ // ++ Record800155Event = Is800155Event (NewEventHdr, NewEventHdrSize, NewEventData, NewEventSize); ++ if (Record800155Event) { ++ DEBUG ((DEBUG_INFO, "It is 800155Event.\n")); ++ ++ if (EventLogAreaStruct->Next800155EventOffset != 0) { ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewLogSize, ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, ++ EventLogAreaStruct->EventLogSize - EventLogAreaStruct->Next800155EventOffset ++ ); ++ ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, ++ NewEventHdr, ++ NewEventHdrSize ++ ); ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ EventLogAreaStruct->Next800155EventOffset += NewLogSize; ++ EventLogAreaStruct->LastEvent += NewLogSize; ++ EventLogAreaStruct->EventLogSize += NewLogSize; ++ } ++ ++ return EFI_SUCCESS; ++ } ++ ++ 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; ++} ++ ++/** ++ 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 ARM CCA, where RIM means Realm Initial Measurement ++ and REM means Realm Extensive Measurement ++ ++ // TPM PCR Index | CC Measurement Register Index | CCA-measurement register ++ // ------------------------------------------------------------------------ ++ // 0 | 0 | RIM ++ // 1, 7 | 1 | REM[0] ++ // 2~6 | 2 | REM[1] ++ // 8~15 | 3 | REM[2] ++ ++ @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 ++MapPcrToMrIndex ( ++ 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_RIM; ++ } else if ((PCRIndex == 1) || (PCRIndex == 7)) { ++ MrIndex = CC_MR_INDEX_1_REM0; ++ } else if ((PCRIndex >= 2) && (PCRIndex <= 6)) { ++ MrIndex = CC_MR_INDEX_2_REM1; ++ } else if ((PCRIndex >= 8) && (PCRIndex <= 15)) { ++ MrIndex = CC_MR_INDEX_3_REM2; ++ } ++ ++ return MrIndex; ++} ++ ++EFI_STATUS ++EFIAPI ++CcaMapPcrToMrIndex ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN UINT32 PCRIndex, ++ OUT UINT32 *MrIndex ++ ) ++{ ++ if (MrIndex == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ *MrIndex = MapPcrToMrIndex (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 ++CcaDxeLogEvent ( ++ 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 = &mCcaDxeData.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 (mCcaDxeData.GetEventLogCalled[Index]) { ++ if (mCcaDxeData.FinalEventsTable[Index] == NULL) { ++ // ++ // no need for FinalEventsTable ++ // ++ return EFI_SUCCESS; ++ } ++ ++ EventLogAreaStruct = &mCcaDxeData.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 ++ // ++ (mCcaDxeData.FinalEventsTable[Index])->NumberOfEvents++; ++ DEBUG ((DEBUG_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mCcaDxeData.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; ++} ++ ++/** ++ Add a new entry to the Event Log. The call chain is like below: ++ CcaDxeLogHashEvent -> CcaDxeLogEvent -> 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 TD_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 ++CcaDxeLogHashEvent ( ++ 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_SHA256); ++ CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize)); ++ ++ // ++ // Enter critical region ++ // ++ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); ++ Status = CcaDxeLogEvent ( ++ 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 REM 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 TD_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 ++CcaDxeHashLogExtendEvent ( ++ 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 REM extend for EV_NO_ACTION ++ // ++ Status = EFI_SUCCESS; ++ InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize); ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData); ++ } ++ ++ return Status; ++ } ++ ++ // ++ // According to UEFI Spec 2.10 Section 38.4.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // Only the REM registers can be extended in EDK2 by HashAndExtend. ++ // ++ Status = HashAndExtend ( ++ NewEventHdr->MrIndex, ++ HashData, ++ (UINTN)HashDataLen, ++ &DigestList ++ ); ++ if (!EFI_ERROR (Status)) { ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&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 ++CcaHashLogExtendEvent ( ++ 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, "CcaHashLogExtendEvent ...\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_0_RIM) { ++ DEBUG ((DEBUG_ERROR, "%a: RIM cannot be extended.\n", __func__)); ++ 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.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // Only the REM registers can be extended in EDK2 by HashAndExtend. ++ // ++ Status = MeasurePeImageAndExtend ( ++ NewEventHdr.MrIndex, ++ DataToHash, ++ (UINTN)DataToHashLen, ++ &DigestList ++ ); ++ if (!EFI_ERROR (Status)) { ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&DigestList, &NewEventHdr, CcEvent->Event); ++ } ++ } ++ } else { ++ Status = CcaDxeHashLogExtendEvent ( ++ Flags, ++ (UINT8 *)(UINTN)DataToHash, ++ DataToHashLen, ++ &NewEventHdr, ++ CcEvent->Event ++ ); ++ } ++ ++ DEBUG ((DEBUG_VERBOSE, "CcaHashLogExtendEvent - %r\n", Status)); ++ return Status; ++} ++ ++EFI_CC_MEASUREMENT_PROTOCOL mCcaProtocol = { ++ CcaGetCapability, ++ CcaGetEventLog, ++ CcaHashLogExtendEvent, ++ CcaMapPcrToMrIndex ++}; ++ ++#define CCA_HASH_COUNT 1 ++#define TEMP_BUF_LEN (sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32) \ ++ + (CCA_HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8)) ++ ++/** ++ Initialize the Realm 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 ++ // ++ mCcaDxeData.EventLogAreaStruct[Index].EventLogFormat = LogFormat; ++ ++ // allocate pages for Realm Event log ++ Status = gBS->AllocatePages ( ++ AllocateAnyPages, ++ EfiACPIMemoryNVS, ++ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), ++ &Lasa ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ mCcaDxeData.EventLogAreaStruct[Index].Lasa = Lasa; ++ mCcaDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); ++ mCcaDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0; ++ ++ // ++ // Report Realm event log address and length, so that they can be reported in ++ // Realm ACPI table. Ignore the return status, because those fields are optional. ++ // ++ PcdSet32S (PcdCcEventlogAcpiTableLaml, (UINT32)mCcaDxeData.EventLogAreaStruct[Index].Laml); ++ PcdSet64S (PcdCcEventlogAcpiTableLasa, mCcaDxeData.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_SHA256; ++ TempDigestSize->digestSize = SHA256_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); ++ ++ // ++ // Realm 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 = CcaDxeLogEvent ( ++ 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. ++ // ++ mCcaDxeData.EventLogAreaStruct[Index].Next800155EventOffset = mCcaDxeData.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 = CcaDxeLogEvent ( ++ 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 ++ // ++ mCcaDxeData.FinalEventsTable[Index] = (VOID *)(UINTN)Lasa; ++ (mCcaDxeData.FinalEventsTable[Index])->Version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION; ++ (mCcaDxeData.FinalEventsTable[Index])->NumberOfEvents = 0; ++ ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = LogFormat; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof (EFI_CC_FINAL_EVENTS_TABLE); ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_CC_FINAL_EVENTS_TABLE); ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mCcaDxeData.FinalEventLogAreaStruct[Index].Lasa; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; ++ ++ // ++ // Install to configuration table for EFI_CC_EVENT_LOG_FORMAT_TCG_2 ++ // ++ Status = gBS->InstallConfigurationTable (&gEfiCcFinalEventsTableGuid, (VOID *)mCcaDxeData.FinalEventsTable[Index]); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ return Status; ++} ++ ++/** ++ Measure and log an action string, and extend the measurement result into REM. ++ ++ @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 ++CcaMeasureAction ( ++ IN UINT32 MrIndex, ++ IN CHAR8 *String ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EV_EFI_ACTION; ++ CcEvent.EventSize = (UINT32)AsciiStrLen (String); ++ return CcaDxeHashLogExtendEvent ( ++ 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; ++ Status = EFI_SUCCESS; ++ ++ // TODO: may delete this function ++ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { ++ DEBUG ((DEBUG_ERROR, "MeasureHandoffTables: TCG_PLATFORM_TYPE_SERVER")); ++ } ++ ++ return Status; ++} ++ ++/** ++ Measure and log Separator event, and extend the measurement result into a specific PCR. ++ ++ @param[in] MrIndex REM 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 Rem - %d\n", MrIndex)); ++ ++ EventData = 0; ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EV_SEPARATOR; ++ CcEvent.EventSize = (UINT32)sizeof (EventData); ++ ++ return CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)&EventData, ++ sizeof (EventData), ++ &CcEvent, ++ (UINT8 *)&EventData ++ ); ++} ++ ++/** ++ Measure and log an EFI variable, and extend the measurement result into a specific REM. ++ ++ @param[in] MrIndex REM 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, "CcaTcg2Dxe: MeasureVariable (REM - %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 = CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)VarLog, ++ CcEvent.EventSize, ++ &CcEvent, ++ (UINT8 *)VarLog ++ ); ++ } else { ++ ASSERT (VarData != NULL); ++ Status = CcaDxeHashLogExtendEvent ( ++ 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 REM 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 ( ++ MapPcrToMrIndex (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 ( ++ MapPcrToMrIndex (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 ( ++ MapPcrToMrIndex (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 = MapPcrToMrIndex (7); ++ CcEvent.EventType = EV_EFI_ACTION; ++ CcEvent.EventSize = sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1; ++ return CcaDxeHashLogExtendEvent ( ++ 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 (MapPcrToMrIndex (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", "CcaTcg2Dxe", 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 = CcaMeasureAction ( ++ MapPcrToMrIndex (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.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // REM[0] (i.e. MrIndex 1) is already done. So SepartorEvent shall be extended to ++ // REM[1] (i.e. MrIndex 2) as well. ++ // ++ Status = MeasureSeparatorEvent (CC_MR_INDEX_2_REM1); ++ 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 = CcaMeasureAction ( ++ MapPcrToMrIndex (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 = CcaMeasureAction ( ++ MapPcrToMrIndex (4), ++ EFI_CALLING_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); ++ } ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaTcg2Dxe Measure Data when ReadyToBoot\n")); ++ // ++ // Increase boot attempt counter. ++ // ++ mBootAttempts++; ++ PERF_END_EX (mImageHandle, "EventRec", "CcaTcg2Dxe", 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 = CcaMeasureAction ( ++ MapPcrToMrIndex (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 = CcaMeasureAction ( ++ MapPcrToMrIndex (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 = CcaMeasureAction ( ++ MapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_FAILED ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED)); ++ } ++} ++ ++/** ++ Install TDVF 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, "CCA: AcpiTableProtocol is not installed. %r\n", Status)); ++ return; ++ } ++ ++ mCcaEventlogAcpiTemplate.Laml = (UINT64)PcdGet32 (PcdCcEventlogAcpiTableLaml); ++ mCcaEventlogAcpiTemplate.Lasa = PcdGet64 (PcdCcEventlogAcpiTableLasa); ++ CopyMem (mCcaEventlogAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mCcaEventlogAcpiTemplate.Header.OemId)); ++ mCcaEventlogAcpiTemplate.Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); ++ mCcaEventlogAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); ++ mCcaEventlogAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); ++ mCcaEventlogAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); ++ ++ // ++ // Construct ACPI Table ++ Status = AcpiTable->InstallAcpiTable ( ++ AcpiTable, ++ &mCcaEventlogAcpiTemplate, ++ mCcaEventlogAcpiTemplate.Header.Length, ++ &TableKey ++ ); ++ ASSERT_EFI_ERROR (Status); ++ ++ DEBUG ((DEBUG_INFO, "CCA Eventlog ACPI Table is installed.\n")); ++} ++ ++/** ++ The function install CcaTcg2 protocol. ++ ++ @retval EFI_SUCCESS CcaTcg2 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, ++ &mCcaProtocol, ++ NULL ++ ); ++ DEBUG ((DEBUG_INFO, "CcProtocol: Install %r\n", Status)); ++ return Status; ++} ++ ++EFI_STATUS ++EFIAPI ++DriverEntry ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++) ++{ ++ EFI_STATUS Status; ++ EFI_EVENT Event; ++ VOID *Registration; ++ ++ if (!IsRealm ()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ mImageHandle = ImageHandle; ++ ++ // ++ // Fill information ++ // ++ mCcaDxeData.BsCap.Size = sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY); ++ mCcaDxeData.BsCap.ProtocolVersion.Major = 1; ++ mCcaDxeData.BsCap.ProtocolVersion.Minor = 0; ++ mCcaDxeData.BsCap.StructureVersion.Major = 1; ++ mCcaDxeData.BsCap.StructureVersion.Minor = 0; ++ ++ // ++ // Get supported PCR and current Active PCRs ++ // For Realm gueset HA384 is tested first. ++ // ++ mCcaDxeData.BsCap.HashAlgorithmBitmap = HASH_ALG_SHA256; ++ ++ // Realm guest only supports EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 ++ mCcaDxeData.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 Realm 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; ++} +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf +new file mode 100644 +index 00000000..750c7762 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf +@@ -0,0 +1,86 @@ ++## @file ++# ++# Produces EFI_CC_MEASUREMENT_PROTOCOL and measure boot environment ++# ++# Copyright (C) 2023, Linaro Ltd ++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = CcaTcg2Dxe ++ FILE_GUID = 1788737c-83c4-47b9-899c-b741ab263964 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = DriverEntry ++ ++[Sources] ++ CcaTcg2Dxe.c ++ MeasureBootPeCoff.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ SecurityPkg/SecurityPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ MemoryAllocationLib ++ BaseLib ++ UefiBootServicesTableLib ++ HobLib ++ UefiDriverEntryPoint ++ UefiRuntimeServicesTableLib ++ BaseMemoryLib ++ DebugLib ++ PrintLib ++ UefiLib ++ HashLib ++ PerformanceLib ++ PeCoffLib ++ ArmCcaLib ++ ++[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 ++ ++ gCcEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gTcg800155PlatformIdEventHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gEfiCcFinalEventsTableGuid ## PRODUCES ++ ++[Protocols] ++ gEfiCcMeasurementProtocolGuid ## PRODUCES ++ 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 ++ ++[Depex] ++ gEfiVariableArchProtocolGuid AND gEfiAcpiTableProtocolGuid +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c b/ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c +new file mode 100644 +index 00000000..e01d46d5 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/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) 2015 - 2018, Intel 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] RemIndex Rem 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 RemIndex, ++ 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, RemIndex, NULL, 0, DigestList); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++Finish: ++ if (SectionHeader != NULL) { ++ FreePool (SectionHeader); ++ } ++ ++ return Status; ++} +diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec +index ac1c3ed0..8aed7750 100644 +--- a/ArmVirtPkg/ArmVirtPkg.dec ++++ b/ArmVirtPkg/ArmVirtPkg.dec +@@ -26,6 +26,8 @@ + Include # Root include for the package + + [LibraryClasses] ++ ArmCcaLib|Include/Library/ArmCcaLib.h ++ ArmCcaRsiLib|Include/Library/ArmCcaRsiLib.h + ArmVirtMemInfoLib|Include/Library/ArmVirtMemInfoLib.h + + [Guids.common] +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index b7d34b91..7e91fea2 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -32,6 +32,7 @@ + DEFINE TPM2_ENABLE = FALSE + DEFINE TPM2_CONFIG_ENABLE = FALSE + DEFINE CAVIUM_ERRATUM_27456 = FALSE ++ DEFINE CC_MEASUREMENT_ENABLE = FALSE + + # + # Network definition +@@ -78,13 +79,13 @@ + FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf + PciPcdProducerLib|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf + PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf +- PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf +- PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf +- PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf +- ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +-!if $(TPM2_ENABLE) == TRUE +- Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf +- Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf ++ PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf ++ PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf ++ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf ++ ++!if $(TPM2_ENABLE) == TRUE ++ Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf ++ Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf + TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf + TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLib/PeiDxeTpmPlatformHierarchyLib.inf + !else +@@ -94,16 +95,19 @@ + + [LibraryClasses.AARCH64] + ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf ++ ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf ++ ArmCcaRsiLib|ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf ++ HashLib|ArmVirtPkg/Library/HashLibCca/HashLibCca.inf + + [LibraryClasses.ARM] + ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf +- +-[LibraryClasses.common.PEIM] +- ArmVirtMemInfoLib|ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf +- ArmCcaInitPeiLib|ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf +- +-!if $(TPM2_ENABLE) == TRUE +- BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf ++ ++[LibraryClasses.common.PEIM] ++ ArmVirtMemInfoLib|ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf ++ ArmCcaInitPeiLib|ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf ++ ++!if $(TPM2_ENABLE) == TRUE ++ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf + ResetSystemLib|MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.inf + Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf + !endif +@@ -252,16 +256,16 @@ + + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|0x0 + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|0x0 +- gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0 +- gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0 +- +- # Define PCD for emulating runtime variable storage when CFI flash is absent +- gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|FALSE +- +- +- # +- # ARM General Interrupt Controller +- # ++ gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0 ++ gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0 ++ ++ # Define PCD for emulating runtime variable storage when CFI flash is absent ++ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|FALSE ++ ++ ++ # ++ # ARM General Interrupt Controller ++ # + gArmTokenSpaceGuid.PcdGicDistributorBase|0x0 + gArmTokenSpaceGuid.PcdGicRedistributorsBase|0x0 + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x0 +@@ -396,18 +400,23 @@ + # don't use unaligned CopyMem () on the UEFI varstore NOR flash region + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + } +-!if $(SECURE_BOOT_ENABLE) == TRUE + MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf { + ++!if $(SECURE_BOOT_ENABLE) == TRUE + NULL|SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf +-!if $(TPM2_ENABLE) == TRUE ++!endif ++!if $(TPM2_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 + } ++!if $(SECURE_BOOT_ENABLE) == TRUE + SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf +-!else +- MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf + !endif + MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf + MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf +@@ -444,16 +453,16 @@ + # + MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf + +- # +- # Platform Driver +- # +- ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf { +- +- NULL|ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf +- } +- OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf +- EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf +- OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf ++ # ++ # Platform Driver ++ # ++ ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf { ++ ++ NULL|ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf ++ } ++ OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf ++ EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf ++ OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf + OvmfPkg/VirtioBlkDxe/VirtioBlk.inf + OvmfPkg/VirtioScsiDxe/VirtioScsi.inf + OvmfPkg/VirtioNetDxe/VirtioNet.inf +@@ -585,22 +594,32 @@ + !endif + + # +- # ACPI Support +- # +- OvmfPkg/PlatformHasAcpiDtDxe/PlatformHasAcpiDtDxe.inf +- +- # +- # Realm Aperture Management +- # +- ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +- +- # +- # IoMMU support for Arm CCA +- # +- ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +-[Components.AARCH64] +- MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf +- OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { ++ # ACPI Support ++ # ++ OvmfPkg/PlatformHasAcpiDtDxe/PlatformHasAcpiDtDxe.inf ++[Components.AARCH64] ++ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf ++ OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { + + NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf + } ++ # ++ # Realm Aperture Management ++ # ++ ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf ++ ++ # ++ # Cc Measurement Protocol for Cca guest ++ # ++!if $(CC_MEASUREMENT_ENABLE) == TRUE ++ ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf { ++ ++ HashLib|ArmVirtPkg/Library/HashLibCca/HashLibCca.inf ++ NULL|SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf ++ } ++!endif +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf +index 0a89f24c..f4ef6ee2 100644 +--- a/ArmVirtPkg/ArmVirtQemu.fdf ++++ b/ArmVirtPkg/ArmVirtQemu.fdf +@@ -108,21 +108,16 @@ READ_LOCK_STATUS = TRUE + INF MdeModulePkg/Core/Pei/PeiMain.inf + INF ArmPlatformPkg/PlatformPei/PlatformPeim.inf + INF ArmVirtPkg/MemoryInitPei/MemoryInitPeim.inf +- INF ArmPkg/Drivers/CpuPei/CpuPei.inf +- INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf +- +- # +- # Realm Aperture Management +- # +- INF ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +- +- # +- # IoMMU support for Arm CCA +- # +- INF ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +-!if $(TPM2_ENABLE) == TRUE +- INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf +- INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf ++ INF ArmPkg/Drivers/CpuPei/CpuPei.inf ++ INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf ++ ++!if $(CC_MEASUREMENT_ENABLE) == TRUE ++ INF ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf ++!endif ++ ++!if $(TPM2_ENABLE) == TRUE ++ INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf ++ INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf + INF OvmfPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf + INF SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf + !endif +diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +index bef91421..e89dec81 100644 +--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc ++++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +@@ -148,6 +148,16 @@ READ_LOCK_STATUS = TRUE + INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf + INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf + INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf ++ ++ # ++ # Realm Aperture Management ++ # ++ INF ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ INF ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf + !endif + + # +diff --git a/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h b/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h +new file mode 100644 +index 00000000..b5ad68f3 +--- /dev/null ++++ b/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h +@@ -0,0 +1,373 @@ ++/** @file ++ Library that implements the Arm CCA Realm Service Interface calls. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ - RIM - Realm Initial Measurement ++ - REM - Realm Extensible Measurement ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++**/ ++ ++#ifndef ARM_CCA_RSI_LIB_ ++#define ARM_CCA_RSI_LIB_ ++ ++#include ++ ++/** ++ A macro defining the size of a Realm Granule. ++ See Section A2.2, RMM Specification, version A-bet0 ++ DNBXXX A Granule is a unit of physical memory whose size is 4KB. ++*/ ++#define REALM_GRANULE_SIZE SIZE_4KB ++ ++/** ++ A macro defining the mask for the RSI RIPAS type. ++ See Section B4.4.5 RsiRipas type, RMM Specification, version A-bet0. ++*/ ++#define RIPAS_TYPE_MASK 0xFF ++ ++/* Maximum challenge data size in bits. ++*/ ++#define MAX_CHALLENGE_DATA_SIZE_BITS 512 ++ ++/* Minimum recommended challenge data size in bits. ++*/ ++#define MIN_CHALLENGE_DATA_SIZE_BITS 256 ++ ++/* Maximum measurement data size in bytes. ++ See Section C1.11 RmmRealmMeasurement type, RMM Specification, version A-bet0 ++ The width of the RmmRealmMeasurement type is 512 bits. ++*/ ++#define MAX_MEASUREMENT_DATA_SIZE_BYTES 64 ++ ++/* Minimum and Maximum indices for REMs ++ See Section A2.1.3 Realm attributes, RMM Specification, version A-bet0 ++ IFMPYL - Attributes of a Realm include an array of measurement values. The ++ first entry in this array is a RIM. The remaining entries in this array are ++ REMs. ++*/ ++#define MIN_REM_INDEX 1 ++#define MAX_REM_INDEX 4 ++ ++/* The values of the RsiHashAlgorithm enumeration. ++ SHA-256 (Secure Hash Standard (SHS)) ++*/ ++#define RSI_HASH_SHA_256 0 ++ ++/* The values of the RsiHashAlgorithm enumeration. ++ SHA-512 (Secure Hash Standard (SHS)) ++*/ ++#define RSI_HASH_SHA_512 1 ++ ++/* The RsiRipasChangeFlags fieldset contains flags provided by ++ the Realm when requesting a RIPAS change. ++ See section B4.4.8 RsiRipasChangeFlags type in the ++ RMM Specification, version 1.0-eac2. ++ The following macros prefixed RIPAS_CHANGE_FLAGS_xxx ++ define the values of the RsiRipasChangeFlags fieldset. ++*/ ++ ++/* A RIPAS change from DESTROYED should not be permitted. ++ See section B4.4.7 RsiRipasChangeDestroyed type in the ++ RMM Specification, version 1.0-eac2 ++*/ ++#define RIPAS_CHANGE_FLAGS_RSI_NO_CHANGE_DESTROYED 0 ++ ++/* A RIPAS change from DESTROYED should be permitted. ++ See section B4.4.7 RsiRipasChangeDestroyed type in the ++ RMM Specification, version 1.0-eac2 ++*/ ++#define RIPAS_CHANGE_FLAGS_RSI_CHANGE_DESTROYED 1 ++ ++/* The RsiResponse type is a value returned by the ++ RSI_IPA_STATE_SET command and represents whether ++ the Host accepted or rejected a Realm request. ++ See section B4.4.6 RsiResponse type in the ++ RMM Specification, version 1.0-eac3. ++ The width of the RsiResponse enumeration is 1 bit ++ and the following macros prefixed RIPAS_CHANGE_RESPONSE_xxx ++ define the values of the RsiResponse type. ++*/ ++ ++/* The RIPAS change request to RAM was accepted ++ by the host. ++*/ ++#define RIPAS_CHANGE_RESPONSE_ACCEPT 0 ++ ++/* The RIPAS change request to RAM was rejected ++ by the host. ++*/ ++#define RIPAS_CHANGE_RESPONSE_REJECT 1 ++ ++/* A mask for the RSI Response bit */ ++#define RSI_RESPONSE_MASK BIT0 ++ ++/** An enum describing the RSI RIPAS. ++ See Section A5.2.2 Realm IPA state, RMM Specification, version 1.0-eac2 ++*/ ++typedef enum Ripas { ++ RipasEmpty, ///< Unused IPA location. ++ RipasRam, ///< Private code or data owned by the Realm. ++ RipasDestroyed, ///< An address which is inaccessible to the Realm. ++ RipasMax ///< A valid RIPAS type value is less than RipasMax. ++} RIPAS; ++ ++/** A structure describing the Realm Configuration. ++ See Section B4.4.5 RsiRealmConfig type, RMM Specification, version 1.0-eac2 ++ The width of the RsiRealmConfig structure is 4096 (0x1000) bytes. ++*/ ++typedef struct RealmConfig { ++ // Width of IPA in bits. ++ UINT64 IpaWidth; ++ // Width of the RsiHashAlgorithm enumeration is 8 bits. ++ UINT8 HashAlgorithm; ++ // Unused bits of the RsiRealmConfig structure should be zero. ++ UINT8 Reserved[SIZE_4KB - (sizeof (UINT64) + sizeof (UINT8))]; ++} REALM_CONFIG; ++ ++/** A structure describing the Host Call arguments ++ See Section 4.4.2 RsiHostCall type, RMM Specification, version 1.0-bet2 ++*/ ++typedef struct HostCallArgs { ++ UINT16 Imm; ++ UINT8 Reserved1[6]; ++ ++ UINT64 Gprs0; ++ UINT64 Gprs1; ++ UINT64 Gprs2; ++ UINT64 Gprs3; ++ UINT64 Gprs4; ++ UINT64 Gprs5; ++ UINT64 Gprs6; ++ UINT64 Gprs7; ++ UINT64 Gprs8; ++ UINT64 Gprs9; ++ UINT64 Gprs10; ++ UINT64 Gprs11; ++ UINT64 Gprs12; ++ UINT64 Gprs13; ++ UINT64 Gprs14; ++ UINT64 Gprs15; ++ UINT64 Gprs16; ++ UINT64 Gprs17; ++ UINT64 Gprs18; ++ UINT64 Gprs19; ++ UINT64 Gprs20; ++ UINT64 Gprs21; ++ UINT64 Gprs22; ++ UINT64 Gprs23; ++ UINT64 Gprs24; ++ UINT64 Gprs25; ++ UINT64 Gprs26; ++ UINT64 Gprs27; ++ UINT64 Gprs28; ++ UINT64 Gprs29; ++ UINT64 Gprs30; ++} HOST_CALL_ARGS; ++ ++/** ++ Retrieve an attestation token from the RMM. ++ ++ @param [in] ChallengeData Pointer to the challenge data to be ++ included in the attestation token. ++ @param [in] ChallengeDataSizeBits Size of the challenge data in bits. ++ @param [out] TokenBuffer Pointer to a buffer to store the ++ retrieved attestation token. ++ @param [out] TokenBufferSize Length of token data returned. ++ ++ Note: The TokenBuffer allocated must be freed by the caller ++ using RsiFreeAttestationToken(). ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetAttestationToken ( ++ IN CONST UINT8 *CONST ChallengeData, ++ IN UINT64 ChallengeDataSizeBits, ++ OUT UINT8 **CONST TokenBuffer, ++ OUT UINT64 *CONST TokenBufferSize ++ ); ++ ++/** ++ Free the attestation token buffer. ++ ++ @param [in] TokenBuffer Pointer to the retrieved ++ attestation token. ++ @param [in] TokenBufferSize Size of the token buffer. ++**/ ++VOID ++RsiFreeAttestationToken ( ++ IN UINT8 *CONST TokenBuffer, ++ IN UINT64 CONST TokenBufferSize ++ ); ++ ++/** ++ Returns the IPA state for the page pointed by the address. ++ ++ @param [in] Address Address to retrive IPA state. ++ @param [out] State The RIPAS state for the address specified. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetIpaState ( ++ IN UINT64 *Address, ++ OUT RIPAS *State ++ ); ++ ++/** ++ Sets the IPA state for the pages pointed by the memory range. ++ ++ @param [in] Address Address to the start of the memory range. ++ @param [in] Size Length of the memory range. ++ @param [in] State The RIPAS state to be configured. ++ @param [in] Flags The RIPAS change flags. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ACCESS_DENIED RIPAS change request was rejected. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiSetIpaState ( ++ IN UINT64 *Address, ++ IN UINT64 Size, ++ IN RIPAS State, ++ IN UINT64 Flags ++ ); ++ ++/** ++ Extends a measurement to a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [in] Measurement Pointer to the measurement buffer. ++ @param [in] MeasurementSize Size of the measurement data. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiExtendMeasurement ( ++ IN UINTN MeasurementIndex, ++ IN CONST UINT8 *CONST Measurement, ++ IN UINTN MeasurementSize ++ ); ++ ++/** ++ Read the measurement value from a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [out] MeasurementBuffer Pointer to store the measurement data. ++ @param [in] MeasurementBufferSize Size of the measurement buffer. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiReadMeasurement ( ++ IN UINTN MeasurementIndex, ++ OUT UINT8 *CONST MeasurementBuffer, ++ IN UINTN MeasurementBufferSize ++ ); ++ ++/** ++ Read the Realm Configuration. ++ ++ @param [out] Config Pointer to the address of the buffer to retrieve ++ the Realm configuration. ++ ++ Note: The buffer to retrieve the Realm configuration must be aligned to the ++ Realm granule size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetRealmConfig ( ++ IN REALM_CONFIG *Config ++ ); ++ ++/** ++ Make a Host Call. ++ ++ A Host call can be used by a Realm to make a hypercall. ++ On Realm execution of HVC, an Unknown exception is taken to the Realm. ++ ++ @param [in] Args Pointer to the IPA of the Host call data ++ structure. ++ ++ Note: The IPA of the Host call arguments data structure must be aligned ++ to the Realm granule size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiHostCall ( ++ IN HOST_CALL_ARGS *Args ++ ); ++ ++/** ++ Get the version of the RSI implementation. ++ ++ @param [out] UefiImpl The version of the RSI specification ++ implemented by the UEFI firmware. ++ @param [out] RmmImpl The version of the RSI specification ++ implemented by the RMM. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_UNSUPPORTED The execution context is not a Realm. ++ @retval RETURN_INCOMPATIBLE_VERSION The Firmware and RMM specification ++ revisions are not compatible. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetVersion ( ++ OUT UINT32 *CONST UefiImpl, ++ OUT UINT32 *CONST RmmImpl ++ ); ++ ++/** ++ Get the features supported by the RSI implementation. ++ ++ RMM implementations across different CCA platforms may support ++ disparate features and may offer disparate configuration options ++ for Realms. The features supported by an RSI implementation are ++ discovered by reading feature pseudo-register values using the ++ RSI_FEATURES command. ++ ++ @param [in] FeatureRegIndex The Feature Register Index. ++ @param [out] FeatureRegValue The Feature Register Value. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetFeatures ( ++ IN UINT64 FeatureRegIndex, ++ OUT UINT64 *FeatureRegValue ++ ); ++ ++#endif // ARM_CCA_RSI_LIB_ +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +index 894c6db0..4b974d86 100644 +--- a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +@@ -13,6 +13,7 @@ + + #include + #include ++#include + #include + #include + +@@ -33,7 +34,19 @@ IsRealm ( + VOID + ) + { ++ RETURN_STATUS Status; ++ UINT32 UefiImpl; ++ UINT32 RmmImpl; ++ ++ Status = RsiGetVersion ( ++ &UefiImpl, ++ &RmmImpl ++ ); ++ if (!RETURN_ERROR (Status)) { + return TRUE; ++ } ++ ++ return FALSE; + } + + /** +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +index c0d703b2..2c96d2a5 100644 +--- a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +@@ -25,6 +25,7 @@ + MdePkg/MdePkg.dec + + [LibraryClasses] ++ ArmCcaRsiLib + ArmLib + ArmMmuLib + BaseLib +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h +new file mode 100644 +index 00000000..ce3cb0c3 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h +@@ -0,0 +1,59 @@ ++/** @file ++ Definitions for Arm CCA Realm Service Interface. ++ ++ Copyright (c) 2022 - 2023, ARM Ltd. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++**/ ++ ++#ifndef ARM_CCA_RSI_H_ ++#define ARM_CCA_RSI_H_ ++ ++// FIDs for Realm Service Interface calls. ++#define FID_RSI_ATTESTATION_TOKEN_CONTINUE 0xC4000195 ++#define FID_RSI_ATTESTATION_TOKEN_INIT 0xC4000194 ++#define FID_RSI_FEATURES 0xC4000191 ++#define FID_RSI_HOST_CALL 0xC4000199 ++#define FID_RSI_IPA_STATE_GET 0xC4000198 ++#define FID_RSI_IPA_STATE_SET 0xC4000197 ++#define FID_RSI_MEASUREMENT_EXTEND 0xC4000193 ++#define FID_RSI_MEASUREMENT_READ 0xC4000192 ++#define FID_RSI_REALM_CONFIG 0xC4000196 ++#define FID_RSI_VERSION 0xC4000190 ++ ++/** RSI Command Return codes ++ See Section B4.4.1, RMM Specification, version A-bet0. ++ The width of the RsiCommandReturnCode enumeration is 64 bits. ++*/ ++#define RSI_SUCCESS 0ULL ++#define RSI_ERROR_INPUT 1ULL ++#define RSI_ERROR_STATE 2ULL ++#define RSI_INCOMPLETE 3ULL ++ ++/** RSI interface Version ++ See Section B4.4.3, RMM Specification, version A-bet0. ++ The width of the RsiInterfaceVersion fieldset is 64 bits. ++*/ ++#define RSI_VER_MINOR_MASK 0x0000FFFFULL ++#define RSI_VER_MAJOR_MASK 0x7FFF0000ULL ++#define RSI_VER_MAJOR_SHIFT 16 ++#define RSI_VERSION_MASK (RSI_VER_MAJOR_MASK | RSI_VER_MINOR_MASK) ++ ++#define RMM_VERSION(Major, Minor) ((Minor & RSI_VER_MINOR_MASK) | \ ++ ((Major << RSI_VER_MAJOR_SHIFT) & RSI_VER_MAJOR_MASK)) ++ ++#define GET_MAJOR_REVISION(Rev) \ ++ ((Rev & RSI_VER_MAJOR_MASK) >> RSI_VER_MAJOR_SHIFT) ++ ++#define GET_MINOR_REVISION(Rev) \ ++ ((Rev & RSI_VER_MINOR_MASK)) ++ ++#endif // ARM_CCA_RSI_H_ +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c +new file mode 100644 +index 00000000..76fc761e +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c +@@ -0,0 +1,730 @@ ++/** @file ++ Library that implements the Arm CCA Realm Service Interface calls. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ - REM - Realm Extensible Measurement ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++ ++**/ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ArmCcaRsi.h" ++ ++/** The version of RSI specification implemented by this module. ++*/ ++STATIC CONST UINT32 mRsiImplVersion = RMM_VERSION (1, 0); ++ ++/** ++ Convert the RSI status code to EFI Status code. ++ ++ @param [in] RsiCommandReturnCode RSI status code. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++ **/ ++STATIC ++RETURN_STATUS ++RsiCmdStatusToEfiStatus ( ++ IN UINT64 RsiCommandReturnCode ++ ) ++{ ++ switch (RsiCommandReturnCode) { ++ /* TODO: when running in the host, RSI is not available. Find out how to probe ++ * this reliably. ++ */ ++ case 0xFFFFFFFFFFFFFFFF: ++ return RETURN_ABORTED; ++ case RSI_SUCCESS: ++ return RETURN_SUCCESS; ++ case RSI_ERROR_INPUT: ++ return RETURN_INVALID_PARAMETER; ++ case RSI_ERROR_STATE: ++ return RETURN_ABORTED; ++ case RSI_INCOMPLETE: ++ return RETURN_NOT_READY; ++ default: ++ // Unknown error code. ++ ASSERT (0); ++ break; ++ } // switch ++ ++ return RETURN_ABORTED; ++} ++ ++/** ++ Check if the address is aligned to the size of the Realm granule. ++ ++ @param [in] Address Address to check granule alignment. ++ ++ @retval TRUE Address is aligned to the Realm granule size. ++ @retval FALSE Address is not aligned to the Realm granule size. ++**/ ++STATIC ++BOOLEAN ++EFIAPI ++AddrIsGranuleAligned ( ++ IN UINT64 *Address ++ ) ++{ ++ if (((UINT64)Address & (REALM_GRANULE_SIZE - 1)) != 0) { ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/** ++ Continue the operation to retrieve an attestation token. ++ ++ @param [out] TokenBuffer Pointer to a buffer to store the ++ retrieved attestation token. ++ @param [in] Offset Offset within Token buffer granule ++ to start of buffer in bytes. ++ @param [in,out] TokenSize On input size of the token buffer, ++ and on output size of the token ++ returned if operation is successful, ++ otherwise 0. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++ **/ ++STATIC ++RETURN_STATUS ++EFIAPI ++RsiAttestationTokenContinue ( ++ OUT UINT8 *CONST TokenBuffer, ++ IN UINT64 CONST Offset, ++ IN OUT UINT64 *CONST TokenSize ++ ) ++{ ++ RETURN_STATUS Status; ++ ARM_SMC_ARGS SmcCmd; ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_ATTESTATION_TOKEN_CONTINUE; ++ // Set the IPA of the Granule to which the token will be written. ++ SmcCmd.Arg1 = (UINTN)TokenBuffer; ++ // Set the Offset within Granule to start of buffer in bytes ++ SmcCmd.Arg2 = (UINTN)Offset; ++ // Set the size of the buffer in bytes ++ SmcCmd.Arg3 = (UINTN)*TokenSize; ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (!RETURN_ERROR (Status)) { ++ // Update the token size ++ *TokenSize = SmcCmd.Arg1; ++ } else { ++ // Clear the TokenBuffer on error. ++ ZeroMem (TokenBuffer, *TokenSize); ++ *TokenSize = 0; ++ } ++ ++ return Status; ++} ++ ++/** ++ Initialize the operation to retrieve an attestation token. ++ ++ @param [in] ChallengeData Pointer to the challenge data to be ++ included in the attestation token. ++ @param [in] ChallengeDataSizeBits Size of the challenge data in bits. ++ @param [out] MaxTokenSize Pointer to an integer to retrieve ++ the maximum attestation token size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ **/ ++STATIC ++RETURN_STATUS ++EFIAPI ++RsiAttestationTokenInit ( ++ IN CONST UINT8 *CONST ChallengeData, ++ IN UINT64 ChallengeDataSizeBits, ++ OUT UINT64 *CONST MaxTokenSize ++ ) ++{ ++ RETURN_STATUS Status; ++ ARM_SMC_ARGS SmcCmd; ++ UINT8 *Buffer8; ++ CONST UINT8 *Data8; ++ UINT64 Count; ++ UINT8 TailBits; ++ ++ /* See A7.2.2 Attestation token generation, RMM Specification, version A-bet0 ++ IWTKDD - If the size of the challenge provided by the relying party is less ++ than 64 bytes, it should be zero-padded prior to calling ++ RSI_ATTESTATION_TOKEN_INIT. ++ ++ Therefore, zero out the SmcCmd memory before coping the ChallengeData ++ bits. ++ */ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_ATTESTATION_TOKEN_INIT; ++ // Copy challenge data. ++ Buffer8 = (UINT8 *)&SmcCmd.Arg1; ++ Data8 = ChallengeData; ++ ++ // First copy whole bytes ++ Count = ChallengeDataSizeBits >> 3; ++ CopyMem (Buffer8, Data8, Count); ++ ++ // Now copy any remaining tail bits. ++ TailBits = ChallengeDataSizeBits & (8 - 1); ++ if (TailBits > 0) { ++ // Advance buffer pointers. ++ Buffer8 += Count; ++ Data8 += Count; ++ ++ // Copy tail byte. ++ *Buffer8 = *Data8; ++ ++ // Clear unused tail bits. ++ *Buffer8 &= ~(0xFF << TailBits); ++ } ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (RETURN_ERROR (Status)) { ++ // Set the max token size to zero ++ *MaxTokenSize = 0; ++ } else { ++ *MaxTokenSize = SmcCmd.Arg1; ++ } ++ ++ return Status; ++} ++ ++/** ++ Free the attestation token buffer. ++ ++ @param [in] TokenBuffer Pointer to the retrieved ++ attestation token. ++ @param [in] TokenBufferSize Size of the token buffer. ++**/ ++VOID ++RsiFreeAttestationToken ( ++ IN UINT8 *CONST TokenBuffer, ++ IN UINT64 CONST TokenBufferSize ++ ) ++{ ++ if (TokenBuffer != NULL) { ++ if (TokenBufferSize > 0) { ++ // Scrub the token buffer ++ ZeroMem (TokenBuffer, TokenBufferSize); ++ } ++ ++ FreePool (TokenBuffer); ++ } ++} ++ ++/** ++ Retrieve an attestation token from the RMM. ++ ++ @param [in] ChallengeData Pointer to the challenge data to be ++ included in the attestation token. ++ @param [in] ChallengeDataSizeBits Size of the challenge data in bits. ++ @param [out] TokenBuffer Pointer to a buffer to store the ++ retrieved attestation token. ++ @param [out] TokenBufferSize Length of token data returned. ++ ++ Note: The TokenBuffer allocated must be freed by the caller ++ using RsiFreeAttestationToken(). ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetAttestationToken ( ++ IN CONST UINT8 *CONST ChallengeData, ++ IN UINT64 ChallengeDataSizeBits, ++ OUT UINT8 **CONST TokenBuffer, ++ OUT UINT64 *CONST TokenBufferSize ++ ) ++{ ++ RETURN_STATUS Status; ++ UINT8 *Granule; ++ UINT64 GranuleSize; ++ UINT64 Offset; ++ UINT8 *Token; ++ UINT64 TokenSize; ++ UINT64 MaxTokenSize; ++ ++ if ((TokenBuffer == NULL) || ++ (TokenBufferSize == NULL) || ++ (ChallengeData == NULL)) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ if (ChallengeDataSizeBits > MAX_CHALLENGE_DATA_SIZE_BITS) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ /* See A7.2.2 Attestation token generation, RMM Specification, version A-bet0 ++ IWTKDD - Arm recommends that the challenge should contain at least 32 bytes ++ of unique data. ++ */ ++ if (ChallengeDataSizeBits < MIN_CHALLENGE_DATA_SIZE_BITS) { ++ DEBUG ((DEBUG_WARN, "Minimum Challenge data size should be 32 bytes\n")); ++ } ++ ++ Status = RsiAttestationTokenInit ( ++ ChallengeData, ++ ChallengeDataSizeBits, ++ &MaxTokenSize ++ ); ++ if (RETURN_ERROR (Status)) { ++ ASSERT (0); ++ return Status; ++ } ++ ++ // Allocate a granule to retrieve the attestation token chunk. ++ Granule = (UINT8 *)AllocateAlignedPages ( ++ EFI_SIZE_TO_PAGES (REALM_GRANULE_SIZE), ++ REALM_GRANULE_SIZE ++ ); ++ if (Granule == NULL) { ++ ASSERT (0); ++ return RETURN_OUT_OF_RESOURCES; ++ } ++ ++ // Alloate a buffer to store the retrieved attestation token. ++ Token = AllocateZeroPool (MaxTokenSize); ++ if (Token == NULL) { ++ ASSERT (0); ++ Status = RETURN_OUT_OF_RESOURCES; ++ goto exit_handler; ++ } ++ ++ TokenSize = 0; ++ do { ++ // Retrieve one Granule of data per loop iteration ++ ZeroMem (Granule, REALM_GRANULE_SIZE); ++ Offset = 0; ++ do { ++ // Retrieve sub-Granule chunk of data per loop iteration ++ GranuleSize = REALM_GRANULE_SIZE - Offset; ++ Status = RsiAttestationTokenContinue ( ++ Granule, ++ Offset, ++ &GranuleSize ++ ); ++ Offset += GranuleSize; ++ } while ((Status == RETURN_NOT_READY) && (Offset < REALM_GRANULE_SIZE)); ++ ++ if (RETURN_ERROR (Status) && (Status != RETURN_NOT_READY)) { ++ ASSERT (0); ++ goto exit_handler1; ++ } ++ ++ // "Offset" bytes of data are now ready for consumption from "Granule" ++ // Copy the new token data from the Granule. ++ CopyMem (&Token[TokenSize], Granule, Offset); ++ TokenSize += Offset; ++ } while ((Status == RETURN_NOT_READY) && (TokenSize < MaxTokenSize)); ++ ++ *TokenBuffer = Token; ++ *TokenBufferSize = TokenSize; ++ goto exit_handler; ++ ++exit_handler1: ++ if (Token != NULL) { ++ // Scrub the old Token ++ ZeroMem (Token, TokenSize); ++ FreePool (Token); ++ } ++ ++ *TokenBuffer = NULL; ++ *TokenBufferSize = 0; ++ ++exit_handler: ++ // Scrub the Granule buffer ++ ZeroMem (Granule, REALM_GRANULE_SIZE); ++ FreePages (Granule, EFI_SIZE_TO_PAGES (REALM_GRANULE_SIZE)); ++ ++ return Status; ++} ++ ++/** ++ Returns the IPA state for the page pointed by the address. ++ ++ @param [in] Address Address to retrive IPA state. ++ @param [out] State The RIPAS state for the address specified. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetIpaState ( ++ IN UINT64 *Address, ++ OUT RIPAS *State ++ ) ++{ ++ RETURN_STATUS Status; ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((State == NULL) || (!AddrIsGranuleAligned (Address))) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_IPA_STATE_GET; ++ SmcCmd.Arg1 = (UINTN)Address; ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (!RETURN_ERROR (Status)) { ++ *State = (RIPAS)(SmcCmd.Arg1 & RIPAS_TYPE_MASK); ++ } ++ ++ return Status; ++} ++ ++/** ++ Sets the IPA state for the pages pointed by the memory range. ++ ++ @param [in] Address Address to the start of the memory range. ++ @param [in] Size Length of the memory range. ++ @param [in] State The RIPAS state to be configured. ++ @param [in] Flags The RIPAS change flags. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ACCESS_DENIED RIPAS change request was rejected. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiSetIpaState ( ++ IN UINT64 *Address, ++ IN UINT64 Size, ++ IN RIPAS State, ++ IN UINT64 Flags ++ ) ++{ ++ RETURN_STATUS Status; ++ UINT64 *BaseAddress; ++ UINT64 *EndAddress; ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((Size == 0) || ++ ((Size & (REALM_GRANULE_SIZE - 1)) != 0) || ++ (!AddrIsGranuleAligned (Address))) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ BaseAddress = Address; ++ // Divide Size by 8 for the pointer arithmetic ++ // to work, as we are adding to UINT64*. ++ EndAddress = Address + (Size >> 3); ++ ++ while (Size > 0) { ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_IPA_STATE_SET; ++ SmcCmd.Arg1 = (UINTN)BaseAddress; ++ SmcCmd.Arg2 = (UINTN)EndAddress; ++ SmcCmd.Arg3 = (UINTN)State; ++ SmcCmd.Arg4 = Flags; ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (RETURN_ERROR (Status)) { ++ break; ++ } ++ ++ BaseAddress = (UINT64 *)SmcCmd.Arg1; ++ Size = EndAddress - BaseAddress; ++ ++ if ((SmcCmd.Arg2 & RSI_RESPONSE_MASK) == RIPAS_CHANGE_RESPONSE_REJECT) { ++ Status = RETURN_ACCESS_DENIED; ++ break; ++ } ++ } // while ++ ++ return Status; ++} ++ ++/** ++ Extends a measurement to a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [in] Measurement Pointer to the measurement buffer. ++ @param [in] MeasurementSize Size of the measurement data. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiExtendMeasurement ( ++ IN UINTN MeasurementIndex, ++ IN CONST UINT8 *CONST Measurement, ++ IN UINTN MeasurementSize ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((MeasurementIndex < MIN_REM_INDEX) || ++ (MeasurementIndex > MAX_REM_INDEX) || ++ (Measurement == NULL) || ++ (MeasurementSize == 0) || ++ (MeasurementSize > MAX_MEASUREMENT_DATA_SIZE_BYTES)) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ ++ SmcCmd.Arg0 = FID_RSI_MEASUREMENT_EXTEND; ++ SmcCmd.Arg1 = MeasurementIndex; ++ SmcCmd.Arg2 = MeasurementSize; ++ ++ SmcCmd.Arg3 = (UINTN) Measurement; ++ ++ ArmCallSmc (&SmcCmd); ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} ++ ++/** ++ Read the measurement value from a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [out] MeasurementBuffer Pointer to store the measurement data. ++ @param [in] MeasurementBufferSize Size of the measurement buffer. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiReadMeasurement ( ++ IN UINTN MeasurementIndex, ++ OUT UINT8 *CONST MeasurementBuffer, ++ IN UINTN MeasurementBufferSize ++ ) ++{ ++ RETURN_STATUS Status; ++ ARM_SMC_ARGS SmcCmd; ++ UINT64 *Data64; ++ ++ if ((MeasurementIndex < MIN_REM_INDEX) || ++ (MeasurementIndex > MAX_REM_INDEX) || ++ (MeasurementBuffer == NULL)) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ if (MeasurementBufferSize < MAX_MEASUREMENT_DATA_SIZE_BYTES) { ++ return RETURN_BUFFER_TOO_SMALL; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_MEASUREMENT_READ; ++ SmcCmd.Arg1 = MeasurementIndex; ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (!RETURN_ERROR (Status)) { ++ Data64 = &SmcCmd.Arg1; ++ CopyMem (MeasurementBuffer, Data64, MAX_MEASUREMENT_DATA_SIZE_BYTES); ++ } ++ ++ return Status; ++} ++ ++/** ++ Read the Realm Configuration. ++ ++ @param [out] Config Pointer to the address of the buffer to retrieve ++ the Realm configuration. ++ ++ Note: The buffer to retrieve the Realm configuration must be aligned to the ++ Realm granule size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetRealmConfig ( ++ OUT REALM_CONFIG *Config ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((Config == NULL) || (!AddrIsGranuleAligned ((UINT64 *)Config))) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_REALM_CONFIG; ++ SmcCmd.Arg1 = (UINTN)Config; ++ ++ ArmCallSmc (&SmcCmd); ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} ++ ++/** ++ Make a Host Call. ++ ++ A Host call can be used by a Realm to make a hypercall. ++ On Realm execution of HVC, an Unknown exception is taken to the Realm. ++ ++ @param [in] Args Pointer to the IPA of the Host call data ++ structure. ++ ++ Note: The IPA of the Host call arguments data structure must be aligned ++ to the Realm granule size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiHostCall ( ++ IN HOST_CALL_ARGS *Args ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ // The RMM specification, version 1.0-eac1, relaxes the alignment ++ // requirement for RSI_HOST_CALL from 4KB to 256B. Also see RMM ++ // specification, sections B4.3.3 RSI_HOST_CALL command and ++ // section B4.3.3.2 Failure conditions. ++ if ((Args == NULL) || (((UINT64)Args & (0x100 - 1)) != 0)) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ // See RMM specification, version 1.0-bet1, Section B4.4.2 RsiHostCall type ++ // The width of the RsiHostCall structure is 256 (0x100) bytes. ++ STATIC_ASSERT (sizeof (HOST_CALL_ARGS) == 0x100); ++ ++ // Clear the reserved fields ++ ZeroMem (&Args->Reserved1, sizeof (Args->Reserved1)); ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_HOST_CALL; ++ SmcCmd.Arg1 = (UINTN)Args; ++ ++ ArmCallSmc (&SmcCmd); ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} ++ ++/** ++ Get the version of the RSI implementation. ++ ++ @param [out] UefiImpl The version of the RSI specification ++ implemented by the UEFI firmware. ++ @param [out] RmmImpl The version of the RSI specification ++ implemented by the RMM. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_UNSUPPORTED The execution context is not a Realm. ++ @retval RETURN_INCOMPATIBLE_VERSION The Firmware and RMM specification ++ revisions are not compatible. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetVersion ( ++ OUT UINT32 *CONST UefiImpl, ++ OUT UINT32 *CONST RmmImpl ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((UefiImpl == NULL) || (RmmImpl == NULL)) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_VERSION; ++ ArmCallSmc (&SmcCmd); ++ if (SmcCmd.Arg0 == MAX_UINT64) { ++ // This FID is not implemented, which means ++ // we are not running in a Realm, therefore ++ // return the error code as unsupported. ++ return RETURN_UNSUPPORTED; ++ } ++ ++ *RmmImpl = (SmcCmd.Arg0 & RSI_VERSION_MASK); ++ *UefiImpl = mRsiImplVersion; ++ if (*RmmImpl != *UefiImpl) { ++ // The RSI version implemented by UEFI ++ // firmware and RMM dose not match, return ++ // the status code as RETURN_INCOMPATIBLE_VERSION. ++ return RETURN_INCOMPATIBLE_VERSION; ++ } ++ ++ return RETURN_SUCCESS; ++} ++ ++/** ++ Get the features supported by the RSI implementation. ++ ++ RMM implementations across different CCA platforms may support ++ disparate features and may offer disparate configuration options ++ for Realms. The features supported by an RSI implementation are ++ discovered by reading feature pseudo-register values using the ++ RSI_FEATURES command. ++ ++ @param [in] FeatureRegIndex The Feature Register Index. ++ @param [out] FeatureRegValue The Feature Register Value. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetFeatures ( ++ IN UINT64 FeatureRegIndex, ++ OUT UINT64 *FeatureRegValue ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if (FeatureRegValue == NULL) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_FEATURES; ++ SmcCmd.Arg1 = FeatureRegIndex; ++ ++ ArmCallSmc (&SmcCmd); ++ *FeatureRegValue = SmcCmd.Arg1; ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf +new file mode 100644 +index 00000000..1e2b72f3 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf +@@ -0,0 +1,29 @@ ++## @file ++# Library that implements the Arm CCA Realm Service Interface calls. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = ArmCcaRsiLib ++ FILE_GUID = 5EF34A0A-28B5-4E57-A999-CC1528FC629A ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmCcaRsiLib ++ ++[Sources] ++ ArmCcaRsiLib.c ++ ArmCcaRsi.h ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmLib ++ ArmSmcLib +diff --git a/ArmVirtPkg/Library/HashLibCca/HashLibCca.c b/ArmVirtPkg/Library/HashLibCca/HashLibCca.c +new file mode 100644 +index 00000000..3d0a133d +--- /dev/null ++++ b/ArmVirtPkg/Library/HashLibCca/HashLibCca.c +@@ -0,0 +1,209 @@ ++/** @file ++ This library is HashLib for Cca. ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++EFI_GUID mSha256Guid = HASH_ALGORITHM_SHA256_GUID; ++ ++// ++// Currently CCA supports SHA256. ++// ++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_SHA256); ++ ++ Status = RsiExtendMeasurement ( ++ (UINTN)PcrIndex, ++ (UINT8 *)DigestList->digests[0].digest.sha256, ++ SHA256_DIGEST_SIZE ++ ); ++ ++ 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 (IsRealm ()); ++ ++ 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 ++ ) ++{ ++ // ++ // HashLibCca is designed for Cca guest. So if it is not Cca guest, ++ // return EFI_UNSUPPORTED. ++ // ++ if (!IsRealm ()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ // ++ // Only SHA256 is allowed. ++ // ++ if (!CompareGuid (&mSha256Guid, &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/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf b/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf +new file mode 100644 +index 00000000..7d23792d +--- /dev/null ++++ b/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf +@@ -0,0 +1,39 @@ ++## @file ++# Provides hash service by registered hash handler in Tdx. ++# ++# This library is HashLib for Cca. Currently only SHA384 is supported. ++# ++# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = HashLibCca ++ FILE_GUID = 60a6d467-4f75-4089-8c8e-52a74af1e068 ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = HashLib|DXE_DRIVER ++ ++# ++# The following information is for reference only and not required by the build tools. ++# ++# VALID_ARCHITECTURES = AARCH64 ++# ++ ++[Sources] ++ HashLibCca.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ SecurityPkg/SecurityPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ BaseMemoryLib ++ DebugLib ++ PcdLib ++ ArmCcaLib ++ ArmCcaRsiLib +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +index 58ea4c66..82ae9571 100644 +--- a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +@@ -201,7 +201,6 @@ RampOpenAperture ( + )); + return Status; + } +- DEBUG ((DEBUG_INFO, "RampOpenAperture set 0x%p NS 1.\n", Memory)); + + // Allocate a APERTURE_INFO structure to remember the apertures opened. + ApertInfo = AllocateZeroPool (sizeof (APERTURE_INFO)); +@@ -523,7 +522,7 @@ RealmApertureManagementProtocolDxeInitialize ( + EFI_EVENT CloseAllAperturesEvent; + EFI_EVENT ExitBootEvent; + VOID *Registration; +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 1.\n")); ++ + // When the execution context is a Realm, install the Realm Aperture + // Management protocol otherwise return success so that other modules + // can run. +@@ -579,7 +578,7 @@ RealmApertureManagementProtocolDxeInitialize ( + NULL, + &Registration + ); +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 2.\n")); ++ + return Status; + } + +@@ -588,6 +587,6 @@ RealmApertureManagementProtocolDxeInitialize ( + + error_handler1: + gBS->CloseEvent (CloseAllAperturesEvent); +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 3.\n")); ++ + return Status; + } +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +index 029e933e..8f8e7585 100644 +--- a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +@@ -31,6 +31,7 @@ + + [LibraryClasses] + ArmCcaLib ++ ArmCcaRsiLib + BaseLib + DxeServicesTableLib + MemoryAllocationLib +diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec +index 0ff058b0..9c66c292 100644 +--- a/MdeModulePkg/MdeModulePkg.dec ++++ b/MdeModulePkg/MdeModulePkg.dec +@@ -1984,7 +1984,7 @@ + + ## Default OEM ID for ACPI table creation, its length must be 0x6 bytes to follow ACPI specification. + # @Prompt Default OEM ID for ACPI table creation. +- gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"INTEL "|VOID*|0x30001034 ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"Huawei "|VOID*|0x30001034 + + ## Default OEM Table ID for ACPI table creation, it is "EDK2 ". + # According to ACPI specification, this field is particularly useful when +diff --git a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h +index e07840c9..ee99897b 100644 +--- a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h ++++ b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h +@@ -438,6 +438,7 @@ typedef struct tdTCG_PCClientTaggedEvent { + + #define TCG_Sp800_155_PlatformId_Event_SIGNATURE "SP800-155 Event" + #define TCG_Sp800_155_PlatformId_Event2_SIGNATURE "SP800-155 Event2" ++#define TCG_Sp800_155_PlatformId_Event3_SIGNATURE "SP800-155 Event3" + + typedef struct tdTCG_Sp800_155_PlatformId_Event2 { + UINT8 Signature[16]; +diff --git a/MdePkg/Include/Protocol/CcMeasurement.h b/MdePkg/Include/Protocol/CcMeasurement.h +index 4bf21fc4..23681a3a 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_CCA 3 + + typedef struct { + UINT8 Type; +@@ -57,7 +58,9 @@ typedef UINT32 EFI_CC_MR_INDEX; + #define TDX_MR_INDEX_RTMR3 4 + + #define EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 +-#define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define EFI_CC_BOOT_HASH_ALG_SHA256 0x00000002 ++#define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define EFI_CC_BOOT_HASH_ALG_SHA512 0x00000008 + + // + // This bit is shall be set when an event shall be extended but not logged. +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +index cc58b8bf..73719f3b 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +@@ -20,8 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +-Copyright (c) Microsoft Corporation.
+-SPDX-License-Identifier: BSD-2-Clause-Patent ++Copyright (c) Microsoft Corporation.
++SPDX-License-Identifier: BSD-2-Clause-Patent + **/ + + #include +@@ -46,8 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + +-#include "DxeTpm2MeasureBootLibSanitization.h" +- ++#include "DxeTpm2MeasureBootLibSanitization.h" ++ + typedef struct { + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; +@@ -148,11 +148,11 @@ Tcg2MeasureGptTable ( + EFI_TCG2_EVENT *Tcg2Event; + EFI_CC_EVENT *CcEvent; + EFI_GPT_DATA *GptData; +- UINT32 TcgEventSize; ++ UINT32 TcgEventSize; + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; + EFI_CC_MR_INDEX MrIndex; +- UINT32 AllocSize; ++ UINT32 AllocSize; + + if (mTcg2MeasureGptCount > 0) { + return EFI_SUCCESS; +@@ -200,22 +200,22 @@ Tcg2MeasureGptTable ( + BlockIo->Media->BlockSize, + (UINT8 *)PrimaryHeader + ); +- if (EFI_ERROR (Status) || EFI_ERROR (Tpm2SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { +- DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); ++ if (EFI_ERROR (Status) || EFI_ERROR (Tpm2SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); + FreePool (PrimaryHeader); + return EFI_DEVICE_ERROR; + } + + // +- // Read the partition entry. ++ // Read the partition entry. + // +- Status = Tpm2SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); +- if (EFI_ERROR (Status)) { ++ Status = Tpm2SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); ++ if (EFI_ERROR (Status)) { + FreePool (PrimaryHeader); + return EFI_BAD_BUFFER_SIZE; + } + +- EntryPtr = (UINT8 *)AllocatePool (AllocSize); ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); + if (EntryPtr == NULL) { + FreePool (PrimaryHeader); + return EFI_OUT_OF_RESOURCES; +@@ -225,7 +225,7 @@ Tcg2MeasureGptTable ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), +- AllocSize, ++ AllocSize, + EntryPtr + ); + if (EFI_ERROR (Status)) { +@@ -250,21 +250,21 @@ Tcg2MeasureGptTable ( + // + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol) + // +- Status = Tpm2SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); +- if (EFI_ERROR (Status)) { +- FreePool (PrimaryHeader); +- FreePool (EntryPtr); +- return EFI_DEVICE_ERROR; +- } +- +- EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); ++ Status = Tpm2SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); ++ if (EFI_ERROR (Status)) { ++ FreePool (PrimaryHeader); ++ FreePool (EntryPtr); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); + if (EventPtr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; +- Tcg2Event->Size = TcgEventSize; ++ Tcg2Event->Size = TcgEventSize; + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + Tcg2Event->Header.PCRIndex = 5; +@@ -317,7 +317,7 @@ Tcg2MeasureGptTable ( + CcProtocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, +- (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), + CcEvent + ); + if (!EFI_ERROR (Status)) { +@@ -333,7 +333,7 @@ Tcg2MeasureGptTable ( + Tcg2Protocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, +- (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), + Tcg2Event + ); + if (!EFI_ERROR (Status)) { +@@ -404,7 +404,7 @@ Tcg2MeasurePeImage ( + Status = EFI_UNSUPPORTED; + ImageLoad = NULL; + EventPtr = NULL; +- Tcg2Event = NULL; ++ Tcg2Event = NULL; + + Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol; + CcProtocol = MeasureBootProtocols->CcProtocol; +@@ -420,22 +420,22 @@ Tcg2MeasurePeImage ( + } + + FilePathSize = (UINT32)GetDevicePathSize (FilePath); +- Status = Tpm2SanitizePeImageEventSize (FilePathSize, &EventSize); +- if (EFI_ERROR (Status)) { +- return EFI_UNSUPPORTED; +- } ++ Status = Tpm2SanitizePeImageEventSize (FilePathSize, &EventSize); ++ if (EFI_ERROR (Status)) { ++ return EFI_UNSUPPORTED; ++ } + + // + // Determine destination PCR by BootPolicy + // +- // from a malicious GPT disk partition +- EventPtr = AllocateZeroPool (EventSize); ++ // from a malicious GPT disk partition ++ EventPtr = AllocateZeroPool (EventSize); + if (EventPtr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; +- Tcg2Event->Size = EventSize; ++ Tcg2Event->Size = EventSize; + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + ImageLoad = (EFI_IMAGE_LOAD_EVENT *)Tcg2Event->Event; +@@ -454,13 +454,13 @@ Tcg2MeasurePeImage ( + Tcg2Event->Header.PCRIndex = 2; + break; + default: +- DEBUG ( +- ( +- DEBUG_ERROR, +- "Tcg2MeasurePeImage: Unknown subsystem type %d", +- ImageType +- ) +- ); ++ DEBUG ( ++ ( ++ DEBUG_ERROR, ++ "Tcg2MeasurePeImage: Unknown subsystem type %d", ++ ImageType ++ ) ++ ); + goto Finish; + } + +@@ -528,7 +528,7 @@ Finish: + + @param MeasureBootProtocols Pointer to the located measure boot protocol instances. + +- @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). + @retval EFI_UNSUPPORTED Measure boot is not supported. + **/ + EFI_STATUS +@@ -659,14 +659,14 @@ DxeTpm2MeasureBootHandler ( + return EFI_SUCCESS; + } + +- DEBUG ( +- ( +- DEBUG_INFO, +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", +- MeasureBootProtocols.Tcg2Protocol, +- MeasureBootProtocols.CcProtocol +- ) +- ); ++ DEBUG ( ++ ( ++ DEBUG_INFO, ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", ++ MeasureBootProtocols.Tcg2Protocol, ++ MeasureBootProtocols.CcProtocol ++ ) ++ ); + + // + // Copy File Device Path +diff --git a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c +index 43877400..f06c7028 100644 +--- a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c ++++ b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c +@@ -10,7 +10,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + #include +-#include + #include + #include + #include +diff --git a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf +index a7d1f162..72fd1b44 100644 +--- a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf ++++ b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf +@@ -36,6 +36,5 @@ + BaseLib + BaseMemoryLib + DebugLib +- Tpm2CommandLib + MemoryAllocationLib + BaseCryptLib +-- +2.33.0 + diff --git a/edk2.spec b/edk2.spec index f37c23d161f7d760dec3de6208be68813238cf6f..fe5f64e8b226447090409d16ea8b98cc7a1f46df 100644 --- a/edk2.spec +++ b/edk2.spec @@ -135,6 +135,9 @@ patch82: 0082-fixup-fdt-parse-error.patch # Support virtCCA patch83: 0083-edk2-1219-support-virtCCA.patch +# enable cc measurement and sha256 in cc measurement +patch84: 0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -404,6 +407,10 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Tue Feb 18 2025 z00570632 - 202308-19 +- enable cc measurement and sha256 in cc measurement +- 0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch + * Thu Jan 9 2025 z00570632 - 202308-18 - Support virtCCA - 0083-edk2-1219-support-virtCCA.patch