From nobody Mon Feb 9 01:48:10 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+89758+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+89758+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1652686986; cv=none; d=zohomail.com; s=zohoarc; b=KhNegT+5D0EfiIdHnDWFJCGOhBqOZLEsUFJRZB9lXh1BZCUPdgmyKcpnRNXtXh1oPHGtASkr5izdawNSQc5E7fB3XppwF9tw5V51I5l7ci8k5S+6fUaJ5Ex2ALjrvfbrv6//Z8Ac7gz2NI5zwFW/8I3zDNqxd2DWGzipIDqL42c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1652686986; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=BoSvUipzZDWMg2AhEv8MuygIJVNAFU+iwwYF/KqdmDc=; b=Ys9uQqIVW2UhfKwoieOJ/Vgb4+MKLeqmecRtNklrXvMg/WxXHvhJaGrhhfVMTqFyNXplxQYlWWB4d+UOA20w/ImxOF3qi/6sSIBZmThlVcZ70GhqBVZQKdEz0nmDaNZnngsboaS0ZtDwTHv2qk/Eg87ecCkDTWBeezROdQxPgV8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+89758+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1652686986337867.4459572487074; Mon, 16 May 2022 00:43:06 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id Szh1YY1788612xLGgrpr34pd; Mon, 16 May 2022 00:43:05 -0700 X-Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by mx.groups.io with SMTP id smtpd.web12.26123.1652686980416689942 for ; Mon, 16 May 2022 00:43:05 -0700 X-IronPort-AV: E=McAfee;i="6400,9594,10348"; a="252830544" X-IronPort-AV: E=Sophos;i="5.91,229,1647327600"; d="scan'208";a="252830544" X-Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 May 2022 00:43:04 -0700 X-IronPort-AV: E=Sophos;i="5.91,229,1647327600"; d="scan'208";a="699419058" X-Received: from mxu9-mobl1.ccr.corp.intel.com ([10.249.170.79]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 May 2022 00:43:00 -0700 From: "Min Xu" To: devel@edk2.groups.io Cc: Min Xu , Brijesh Singh , Erdem Aktas , James Bottomley , Jiewen Yao , Tom Lendacky , Ken Lu , Sami Mujawar , Gerd Hoffmann Subject: [edk2-devel] [PATCH V4 8/9] OvmfPkg/IntelTdx: Add TdTcg2Dxe Date: Mon, 16 May 2022 15:42:22 +0800 Message-Id: <56ce786fc58cae5110a68734183c0a930bc54fb3.1652686674.git.min.m.xu@intel.com> In-Reply-To: References: MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,min.m.xu@intel.com X-Gm-Message-State: iPzPh50Ko4N7IXDVsuAqKi8Sx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1652686985; bh=/hE3/i/hoYBsz3Gsc+UGA6YNCVAzv9dv1ObQkTyxhr0=; h=Cc:Date:From:Reply-To:Subject:To; b=ZOVfg3ygzn6hN9ba02mj3MsGO67mzMMf2BS1aANjKtaor92B6P83tzxsiCMENwmTx8t VUKHW+U7hizVEOJEps+3MMaYlo5ZcJOwp5Lz19zjwwJT8kd+15bWrRpQxuV8wPaz/rXY4 Mt3ekJa6dAvqiNNHIISGdkKWUiY6F/DMQ6Q= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1652686987855100011 Content-Type: text/plain; charset="utf-8" RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3853 TdTcg2Dxe mimics the Security/Tcg/Tcg2Dxe. It does below tasks: - Set up and install CC_EVENTLOG ACPI table - Parse the GUIDed HOB (gCcEventEntryHobGuid) and create CC event log - Measure handoff tables, Boot##### variables etc - Measure Exit Boot Service failed - Install CcMeasurement Protocol Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Cc: Ken Lu Cc: Sami Mujawar Cc: Gerd Hoffmann Reviewed-by: Jiewen Yao Signed-off-by: Min Xu --- .../IntelTdx/TdTcg2Dxe/MeasureBootPeCoff.c | 407 +++ OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c | 2489 +++++++++++++++++ OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf | 101 + 3 files changed, 2997 insertions(+) create mode 100644 OvmfPkg/IntelTdx/TdTcg2Dxe/MeasureBootPeCoff.c create mode 100644 OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c create mode 100644 OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf diff --git a/OvmfPkg/IntelTdx/TdTcg2Dxe/MeasureBootPeCoff.c b/OvmfPkg/Intel= Tdx/TdTcg2Dxe/MeasureBootPeCoff.c new file mode 100644 index 000000000000..4d542156badd --- /dev/null +++ b/OvmfPkg/IntelTdx/TdTcg2Dxe/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 =3D 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 i= mage. + @param FileOffset Offset into the PE/COFF image to begin the read = operation. + @param ReadSize On input, the size in bytes of the requested rea= d operation. + On output, the number of bytes actually read. + @param Buffer Output buffer that contains the data read from t= he PE/COFF image. + + @retval EFI_SUCCESS The specified portion of the PE/COFF image was r= ead and the size +**/ +EFI_STATUS +EFIAPI +Tcg2DxeImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + UINTN EndPosition; + + if ((FileHandle =3D=3D NULL) || (ReadSize =3D=3D NULL) || (Buffer =3D=3D= NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (MAX_ADDRESS - FileOffset < *ReadSize) { + return EFI_INVALID_PARAMETER; + } + + EndPosition =3D FileOffset + *ReadSize; + if (EndPosition > mTcg2DxeImageSize) { + *ReadSize =3D (UINT32)(mTcg2DxeImageSize - FileOffset); + } + + if (FileOffset >=3D mTcg2DxeImageSize) { + *ReadSize =3D 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 PeCoffLoaderGetImageInf= o(). + + @param[in] RtmrIndex Rtmr index + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[out] DigestList Digest list of this image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval other error value +**/ +EFI_STATUS +MeasurePeImageAndExtend ( + IN UINT32 RtmrIndex, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + EFI_STATUS Status; + EFI_IMAGE_DOS_HEADER *DosHdr; + UINT32 PeCoffHeaderOffset; + EFI_IMAGE_SECTION_HEADER *Section; + UINT8 *HashBase; + UINTN HashSize; + UINTN SumOfBytesHashed; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN Index; + UINTN Pos; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + UINT32 NumberOfRvaAndSizes; + UINT32 CertSize; + HASH_HANDLE HashHandle; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + HashHandle =3D 0xFFFFFFFF; // Know bad value + + Status =3D EFI_UNSUPPORTED; + SectionHeader =3D NULL; + + // + // Check PE/COFF image + // + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle =3D (VOID *)(UINTN)ImageAddress; + mTcg2DxeImageSize =3D ImageSize; + ImageContext.ImageRead =3D (PE_COFF_LOADER_READ_FILE)Tcg2DxeImageRead; + + // + // Get information about the image being loaded + // + Status =3D 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 i= nformation.\n")); + goto Finish; + } + + DosHdr =3D (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress; + PeCoffHeaderOffset =3D 0; + if (DosHdr->e_magic =3D=3D EFI_IMAGE_DOS_SIGNATURE) { + PeCoffHeaderOffset =3D DosHdr->e_lfanew; + } + + Hdr.Pe32 =3D (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + P= eCoffHeaderOffset); + if (Hdr.Pe32->Signature !=3D EFI_IMAGE_NT_SIGNATURE) { + Status =3D EFI_UNSUPPORTED; + goto Finish; + } + + // + // PE/COFF Image Measurement + // + // NOTE: The following codes/steps are based upon the authenticode im= age hashing in + // PE/COFF Specification 8.0 Appendix A. + // + // + + // 1. Load the image header into memory. + + // 2. Initialize a SHA hash context. + + Status =3D HashStart (&HashHandle); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // Measuring PE/COFF Image Header; + // But CheckSum field and SECURITY data directory (certificate) are excl= uded + // + + // + // 3. Calculate the distance from the base of the image header to the i= mage checksum address. + // 4. Hash the image header from its base to beginning of the image che= cksum. + // + HashBase =3D (UINT8 *)(UINTN)ImageAddress; + if (Hdr.Pe32->OptionalHeader.Magic =3D=3D EFI_IMAGE_NT_OPTIONAL_HDR32_MA= GIC) { + // + // Use PE32 offset + // + NumberOfRvaAndSizes =3D Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + HashSize =3D (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - = (UINTN)HashBase; + } else { + // + // Use PE32+ offset + // + NumberOfRvaAndSizes =3D Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSiz= es; + HashSize =3D (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum= ) - (UINTN)HashBase; + } + + Status =3D HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // 5. Skip over the image checksum (it occupies a single ULONG). + // + if (NumberOfRvaAndSizes <=3D EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + // + // 6. Since there is no Cert Directory in optional header, hash every= thing + // from the end of the checksum to the end of image header. + // + if (Hdr.Pe32->OptionalHeader.Magic =3D=3D EFI_IMAGE_NT_OPTIONAL_HDR32_= MAGIC) { + // + // Use PE32 offset. + // + HashBase =3D (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (U= INT32); + HashSize =3D Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBa= se - ImageAddress); + } else { + // + // Use PE32+ offset. + // + HashBase =3D (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeo= f (UINT32); + HashSize =3D Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(Ha= shBase - ImageAddress); + } + + if (HashSize !=3D 0) { + Status =3D HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } + } else { + // + // 7. Hash everything from the end of the checksum to the start of th= e Cert Directory. + // + if (Hdr.Pe32->OptionalHeader.Magic =3D=3D EFI_IMAGE_NT_OPTIONAL_HDR32_= MAGIC) { + // + // Use PE32 offset + // + HashBase =3D (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (U= INT32); + HashSize =3D (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMA= GE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; + } else { + // + // Use PE32+ offset + // + HashBase =3D (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeo= f (UINT32); + HashSize =3D (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI= _IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; + } + + if (HashSize !=3D 0) { + Status =3D HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } + + // + // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTOR= Y) bytes.) + // 9. Hash everything from the end of the Cert Directory to the end o= f image header. + // + if (Hdr.Pe32->OptionalHeader.Magic =3D=3D EFI_IMAGE_NT_OPTIONAL_HDR32_= MAGIC) { + // + // Use PE32 offset + // + HashBase =3D (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IM= AGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize =3D Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBa= se - ImageAddress); + } else { + // + // Use PE32+ offset + // + HashBase =3D (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EF= I_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize =3D Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(Ha= shBase - ImageAddress); + } + + if (HashSize !=3D 0) { + Status =3D 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 =3D=3D EFI_IMAGE_NT_OPTIONAL_HDR32_MA= GIC) { + // + // Use PE32 offset + // + SumOfBytesHashed =3D Hdr.Pe32->OptionalHeader.SizeOfHeaders; + } else { + // + // Use PE32+ offset + // + SumOfBytesHashed =3D Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; + } + + // + // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEAD= ER + // 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 =3D (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (= EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); + if (SectionHeader =3D=3D NULL) { + Status =3D 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 offse= t of + // the section. + // + Section =3D (EFI_IMAGE_SECTION_HEADER *)( + (UINT8 *)(UINTN)ImageAddress + + PeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + Hdr.Pe32->FileHeader.SizeOfOption= alHeader + ); + for (Index =3D 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++= ) { + Pos =3D Index; + while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1= ].PointerToRawData)) { + CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_I= MAGE_SECTION_HEADER)); + Pos--; + } + + CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADE= R)); + Section +=3D 1; + } + + // + // 13. Walk through the sorted table, bring the corresponding section + // into memory, and hash the entire section (using the 'SizeOfRawDa= ta' + // field in the section header to determine the amount of data to h= ash). + // 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 =3D 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++= ) { + Section =3D (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index]; + if (Section->SizeOfRawData =3D=3D 0) { + continue; + } + + HashBase =3D (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData; + HashSize =3D (UINTN)Section->SizeOfRawData; + + Status =3D HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + + SumOfBytesHashed +=3D HashSize; + } + + // + // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is e= xtra + // data in the file that needs to be added to the hash. This data b= egins + // at file offset SUM_OF_BYTES_HASHED and its length is: + // FileSize - (CertDirectory->Size) + // + if (ImageSize > SumOfBytesHashed) { + HashBase =3D (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed; + + if (NumberOfRvaAndSizes <=3D EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + CertSize =3D 0; + } else { + if (Hdr.Pe32->OptionalHeader.Magic =3D=3D EFI_IMAGE_NT_OPTIONAL_HDR3= 2_MAGIC) { + // + // Use PE32 offset. + // + CertSize =3D Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRE= CTORY_ENTRY_SECURITY].Size; + } else { + // + // Use PE32+ offset. + // + CertSize =3D Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_= DIRECTORY_ENTRY_SECURITY].Size; + } + } + + if (ImageSize > CertSize + SumOfBytesHashed) { + HashSize =3D (UINTN)(ImageSize - CertSize - SumOfBytesHashed); + + Status =3D HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } else if (ImageSize < CertSize + SumOfBytesHashed) { + Status =3D EFI_UNSUPPORTED; + goto Finish; + } + } + + // + // 17. Finalize the SHA hash. + // + Status =3D HashCompleteAndExtend (HashHandle, RtmrIndex, NULL, 0, Digest= List); + if (EFI_ERROR (Status)) { + goto Finish; + } + +Finish: + if (SectionHeader !=3D NULL) { + FreePool (SectionHeader); + } + + return Status; +} diff --git a/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c b/OvmfPkg/IntelTdx/TdTc= g2Dxe/TdTcg2Dxe.c new file mode 100644 index 000000000000..e9315ecda17b --- /dev/null +++ b/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.c @@ -0,0 +1,2489 @@ +/** @file + This module implements EFI TD Protocol. + + Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PERF_ID_CC_TCG2_DXE 0x3130 + +#define CC_EVENT_LOG_AREA_COUNT_MAX 1 +#define INVALID_RTMR_INDEX 4 + +typedef struct { + CHAR16 *VariableName; + EFI_GUID *VendorGuid; +} VARIABLE_TYPE; + +typedef struct { + EFI_GUID *EventGuid; + EFI_CC_EVENT_LOG_FORMAT LogFormat; +} CC_EVENT_INFO_STRUCT; + +typedef struct { + EFI_CC_EVENT_LOG_FORMAT EventLogFormat; + EFI_PHYSICAL_ADDRESS Lasa; + UINT64 Laml; + UINTN EventLogSize; + UINT8 *LastEvent; + BOOLEAN EventLogStarted; + BOOLEAN EventLogTruncated; + UINTN Next800155EventOffset; +} CC_EVENT_LOG_AREA_STRUCT; + +typedef struct _TDX_DXE_DATA { + EFI_CC_BOOT_SERVICE_CAPABILITY BsCap; + CC_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[CC_EVENT_LOG_AREA_C= OUNT_MAX]; + BOOLEAN GetEventLogCalled[CC_EVENT_LOG_AREA_CO= UNT_MAX]; + CC_EVENT_LOG_AREA_STRUCT FinalEventLogAreaStruct[CC_EVENT_LOG_A= REA_COUNT_MAX]; + EFI_CC_FINAL_EVENTS_TABLE *FinalEventsTable[CC_EVENT_LOG_AREA_CO= UNT_MAX]; +} TDX_DXE_DATA; + +typedef struct { + TPMI_ALG_HASH HashAlgo; + UINT16 HashSize; + UINT32 HashMask; +} TDX_HASH_INFO; + +// +// +CC_EVENT_INFO_STRUCT mCcEventInfo[] =3D { + { &gCcEventEntryHobGuid, EFI_CC_EVENT_LOG_FORMAT_TCG_2 }, +}; + +TDX_DXE_DATA mTdxDxeData =3D { + { + sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY), // Size + { 1, 1 }, // StructureVersion + { 1, 1 }, // ProtocolVersion + EFI_CC_BOOT_HASH_ALG_SHA384, // HashAlgorithmBitmap + EFI_CC_EVENT_LOG_FORMAT_TCG_2, // SupportedEventLogs + { 2, 0 } // {CC_TYPE, CC_SUBTYPE} + }, +}; + +UINTN mBootAttempts =3D 0; +CHAR16 mBootVarName[] =3D L"BootOrder"; + +VARIABLE_TYPE mVariableType[] =3D { + { 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 mTdxEventlogAcpiTemplate =3D { + { + EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE, + sizeof (mTdxEventlogAcpiTemplate), + EFI_CC_EVENTLOG_ACPI_TABLE_REVISION, + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in production + // + }, + { EFI_CC_TYPE_TDX, 0 }, // CcType + 0, // rsvd + 0, // laml + 0, // lasa +}; + +// +// Supported Hash list in Td guest. +// Currently SHA384 is supported. +// +TDX_HASH_INFO mHashInfo[] =3D { + { TPM_ALG_SHA384, SHA384_DIGEST_SIZE, HASH_ALG_SHA384 } +}; + +/** + 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 =3D 0; Index < sizeof (mHashInfo)/sizeof (mHashInfo[0]); Inde= x++) { + if (mHashInfo[Index].HashAlgo =3D=3D HashAlgo) { + return mHashInfo[Index].HashSize; + } + } + + return 0; +} + +/** + Get hash mask based on Algo + + @param[in] HashAlgo Hash Algorithm Id. + + @return Hash mask. +**/ +UINT32 +GetHashMaskFromAlgo ( + IN TPMI_ALG_HASH HashAlgo + ) +{ + UINTN Index; + + for (Index =3D 0; Index < ARRAY_SIZE (mHashInfo); Index++) { + if (mHashInfo[Index].HashAlgo =3D=3D HashAlgo) { + return mHashInfo[Index].HashMask; + } + } + + ASSERT (FALSE); + return 0; +} + +/** + Copy TPML_DIGEST_VALUES into a buffer + + @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALU= ES 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 =3D (UINT32 *)Buffer; + DigestListCount =3D 0; + Buffer =3D (UINT8 *)Buffer + sizeof (DigestList->count); + for (Index =3D 0; Index < DigestList->count; Index++) { + if ((DigestList->digests[Index].hashAlg & HashAlgorithmMask) =3D=3D 0)= { + DEBUG ((DEBUG_ERROR, "WARNING: TD Event log has HashAlg unsupported = (0x%x)\n", DigestList->digests[Index].hashAlg)); + continue; + } + + CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof (DigestLi= st->digests[Index].hashAlg)); + Buffer =3D (UINT8 *)Buffer + sizeof (DigestList->digests[Index].ha= shAlg); + DigestSize =3D GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg= ); + CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize); + Buffer =3D (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 PeCoffLoaderGetImageInf= o(). + + @param[in] MrIndex RTMR index + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[out] DigestList Digest list of this image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval other error value +**/ +EFI_STATUS +MeasurePeImageAndExtend ( + IN UINT32 MrIndex, + 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 =3D 0; Index < Size; Index++) { + DEBUG ((DEBUG_INFO, Index =3D=3D 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 =3D Size / COLUME_SIZE; + Left =3D Size % COLUME_SIZE; + for (Index =3D 0; Index < Count; Index++) { + DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); + InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); + DEBUG ((DEBUG_INFO, "\n")); + } + + if (Left !=3D 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 =3D (UINT8 *)NoActionEvent->Digests.digests; + DigestListCount =3D 0; + + NoActionEvent->MrIndex =3D 0; + NoActionEvent->EventType =3D EV_NO_ACTION; + + // + // Set Hash count & hashAlg accordingly, while Digest.digests[n].digest = to all 0 + // + ZeroMem (&NoActionEvent->Digests, sizeof (NoActionEvent->Digests)); + + if ((mTdxDxeData.BsCap.HashAlgorithmBitmap & EFI_CC_BOOT_HASH_ALG_SHA384= ) !=3D 0) { + HashAlgId =3D TPM_ALG_SHA384; + CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); + DigestBuffer +=3D sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAl= gId); + DigestListCount++; + } + + // + // Set Digests Count + // + WriteUnaligned32 ((UINT32 *)&NoActionEvent->Digests.count, DigestListCou= nt); + + // + // Set Event Size + // + WriteUnaligned32 ((UINT32 *)DigestBuffer, EventSize); +} + +/** + Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated = inside the function + Caller is responsible to free LocationBuf. + + @param[out] LocationBuf Returns Processor Location Buffer. + @param[out] Num Returns processor number. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED MpService protocol not found. + +**/ +EFI_STATUS +GetProcessorsCpuLocation ( + OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf, + OUT UINTN *Num + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpProtocol; + UINTN ProcessorNum; + UINTN EnabledProcessorNum; + EFI_PROCESSOR_INFORMATION ProcessorInfo; + EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; + UINTN Index; + + Status =3D gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID = **)&MpProtocol); + if (EFI_ERROR (Status)) { + // + // MP protocol is not installed + // + return EFI_UNSUPPORTED; + } + + Status =3D MpProtocol->GetNumberOfProcessors ( + MpProtocol, + &ProcessorNum, + &EnabledProcessorNum + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->AllocatePool ( + EfiBootServicesData, + sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, + (VOID **)&ProcessorLocBuf + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get each processor Location info + // + for (Index =3D 0; Index < ProcessorNum; Index++) { + Status =3D MpProtocol->GetProcessorInfo ( + MpProtocol, + Index, + &ProcessorInfo + ); + if (EFI_ERROR (Status)) { + FreePool (ProcessorLocBuf); + return Status; + } + + // + // Get all Processor Location info & measure + // + CopyMem ( + &ProcessorLocBuf[Index], + &ProcessorInfo.Location, + sizeof (EFI_CPU_PHYSICAL_LOCATION) + ); + } + + *LocationBuf =3D ProcessorLocBuf; + *Num =3D ProcessorNum; + + return Status; +} + +/** + The EFI_CC_MEASUREMENT_PROTOCOL GetCapability function call provides pro= tocol + 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 t= he EFI protocol capability information + and the current EFI TCG2 state inform= ation 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 incorre= ct. + The ProtocolCapability variable will not = be populated. + @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too sm= all to hold the full response. + It will be partially populated (required = Size field will be set). +**/ +EFI_STATUS +EFIAPI +TdGetCapability ( + IN EFI_CC_MEASUREMENT_PROTOCOL *This, + IN OUT EFI_CC_BOOT_SERVICE_CAPABILITY *ProtocolCapability + ) +{ + DEBUG ((DEBUG_VERBOSE, "TdGetCapability\n")); + + if ((This =3D=3D NULL) || (ProtocolCapability =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (ProtocolCapability, &mTdxDxeData.BsCap, sizeof (EFI_CC_BOOT_SER= VICE_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 =3D 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_EfiSpecIDEventS= truct. +**/ +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 =3D 0; Index < sizeof (TcgEfiSpecIdEventStruct->signature); I= ndex++) { + DEBUG ((DEBUG_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index])); + } + + DEBUG ((DEBUG_INFO, "'\n")); + DEBUG ((DEBUG_INFO, " platformClass - 0x%08x\n", TcgEfiSpecIdEve= ntStruct->platformClass)); + DEBUG ((DEBUG_INFO, " specVersion - %d.%d%d\n", TcgEfiSpecIdEv= entStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, Tcg= EfiSpecIdEventStruct->specErrata)); + DEBUG ((DEBUG_INFO, " uintnSize - 0x%02x\n", TcgEfiSpecIdEve= ntStruct->uintnSize)); + + CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (Numbe= rOfAlgorithms)); + DEBUG ((DEBUG_INFO, " NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorit= hms)); + + DigestSize =3D (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecId= EventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithm= s)); + for (Index =3D 0; Index < NumberOfAlgorithms; Index++) { + DEBUG ((DEBUG_INFO, " digest(%d)\n", Index)); + DEBUG ((DEBUG_INFO, " algorithmId - 0x%04x\n", DigestSize[In= dex].algorithmId)); + DEBUG ((DEBUG_INFO, " digestSize - 0x%04x\n", DigestSize[In= dex].digestSize)); + } + + VendorInfoSize =3D (UINT8 *)&DigestSize[NumberOfAlgorithms]; + DEBUG ((DEBUG_INFO, " VendorInfoSize - 0x%02x\n", *VendorInfoSize= )); + VendorInfo =3D VendorInfoSize + 1; + DEBUG ((DEBUG_INFO, " VendorInfo - ")); + for (Index =3D 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_EfiSpecIDEventS= truct. +**/ +UINTN +GetTcgEfiSpecIdEventStructSize ( + IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct + ) +{ + TCG_EfiSpecIdEventAlgorithmSize *DigestSize; + UINT8 *VendorInfoSize; + UINT32 NumberOfAlgorithms; + + CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (Numbe= rOfAlgorithms)); + + DigestSize =3D (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSp= ecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgor= ithms)); + VendorInfoSize =3D (UINT8 *)&DigestSize[NumberOfAlgorithms]; + return sizeof (TCG_EfiSpecIDEventStruct) + sizeof (UINT32) + (NumberOfAl= gorithms * sizeof (TCG_EfiSpecIdEventAlgorithmSize)) + sizeof (UINT8) + (*V= endorInfoSize); +} + +/** + This function dump TD Event (including the Digests). + + @param[in] CcEvent TD 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 =3D CcEvent->Digests.count; + HashAlgo =3D CcEvent->Digests.digests[0].hashAlg; + DigestBuffer =3D (UINT8 *)&CcEvent->Digests.digests[0].digest; + for (DigestIndex =3D 0; DigestIndex < DigestCount; DigestIndex++) { + DEBUG ((DEBUG_INFO, " HashAlgo : 0x%04x\n", HashAlgo)); + DEBUG ((DEBUG_INFO, " Digest(%d): \n", DigestIndex)); + DigestSize =3D GetHashSizeFromAlgo (HashAlgo); + InternalDumpHex (DigestBuffer, DigestSize); + // + // Prepare next + // + CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); + DigestBuffer =3D DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); + } + + DigestBuffer =3D DigestBuffer - sizeof (TPMI_ALG_HASH); + + CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize)); + DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventSize)); + EventBuffer =3D 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 =3D CcEvent->Digests.count; + HashAlgo =3D CcEvent->Digests.digests[0].hashAlg; + DigestBuffer =3D (UINT8 *)&CcEvent->Digests.digests[0].digest; + for (DigestIndex =3D 0; DigestIndex < DigestCount; DigestIndex++) { + DigestSize =3D GetHashSizeFromAlgo (HashAlgo); + // + // Prepare next + // + CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); + DigestBuffer =3D DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); + } + + DigestBuffer =3D DigestBuffer - sizeof (TPMI_ALG_HASH); + + CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize)); + EventBuffer =3D 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 i= nformation is requested. + @param[in] EventLogLocation A pointer to the memory address of the ev= ent log. + @param[in] EventLogLastEntry If the Event Log contains more than one e= ntry, 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 fi= nal 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 =3D=3D 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 =3D (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; + DumpPcrEvent (EventHdr); + + TcgEfiSpecIdEventStruct =3D (TCG_EfiSpecIDEventStruct *)(EventHdr + 1); + DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct); + + // + // Then the CcEvent (Its structure is similar to TCG_PCR_EVENT2) + // + CcEvent =3D (CC_EVENT *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecI= dEventStructSize (TcgEfiSpecIdEventStruct)); + while ((UINTN)CcEvent <=3D EventLogLastEntry) { + DumpCcEvent (CcEvent); + CcEvent =3D (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent)); + } + + if (FinalEventsTable =3D=3D 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 =3D (CC_EVENT *)(UINTN)(FinalEventsTable + 1); + for (NumberOfEvents =3D 0; NumberOfEvents < FinalEventsTable->NumberOf= Events; NumberOfEvents++) { + DumpCcEvent (CcEvent); + CcEvent =3D (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent)); + } + } + + return; +} + +/** + The EFI_CC_MEASUREMENT_PROTOCOL Get Event Log function call allows a cal= ler 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 i= nformation is requested. + @param[out] EventLogLocation A pointer to the memory address of the ev= ent log. + @param[out] EventLogLastEntry If the Event Log contains more than one e= ntry, 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 even= ts, this value is set to TRUE. + Otherwise, the value will be FALSE and th= e Event Log will be complete. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorre= ct + (e.g. asking for an event log whose forma= t is not supported). +**/ +EFI_STATUS +EFIAPI +TdGetEventLog ( + 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 =3D 0; + + DEBUG ((DEBUG_INFO, "TdGetEventLog ... (0x%x)\n", EventLogFormat)); + ASSERT (EventLogFormat =3D=3D EFI_CC_EVENT_LOG_FORMAT_TCG_2); + + if (EventLogLocation !=3D NULL) { + *EventLogLocation =3D mTdxDxeData.EventLogAreaStruct[Index].Lasa; + DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogLocation - %x)\n", *EventL= ogLocation)); + } + + if (EventLogLastEntry !=3D NULL) { + if (!mTdxDxeData.EventLogAreaStruct[Index].EventLogStarted) { + *EventLogLastEntry =3D (EFI_PHYSICAL_ADDRESS)(UINTN)0; + } else { + *EventLogLastEntry =3D (EFI_PHYSICAL_ADDRESS)(UINTN)mTdxDxeData.Even= tLogAreaStruct[Index].LastEvent; + } + + DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogLastEntry - %x)\n", *Event= LogLastEntry)); + } + + if (EventLogTruncated !=3D NULL) { + *EventLogTruncated =3D mTdxDxeData.EventLogAreaStruct[Index].EventLogT= runcated; + DEBUG ((DEBUG_INFO, "TdGetEventLog (EventLogTruncated - %x)\n", *Event= LogTruncated)); + } + + DEBUG ((DEBUG_INFO, "TdGetEventLog - %r\n", EFI_SUCCESS)); + + // Dump Event Log for debug purpose + if ((EventLogLocation !=3D NULL) && (EventLogLastEntry !=3D NULL)) { + DumpCcEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry,= mTdxDxeData.FinalEventsTable[Index]); + } + + // + // All events generated after the invocation of EFI_TCG2_GET_EVENT_LOG S= HALL be stored + // in an instance of an EFI_CONFIGURATION_TABLE named by the VendorGuid = of EFI_TCG2_FINAL_EVENTS_TABLE_GUID. + // + mTdxDxeData.GetEventLogCalled[Index] =3D TRUE; + + return EFI_SUCCESS; +} + +/** + Return if this is a Tcg800155PlatformIdEvent. + + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_P= CR_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 =3D=3D EV_NO_ACTION)= && + (NewEventSize >=3D sizeof (TCG_Sp800_155_PlatformId_Event2)) && + (CompareMem ( + NewEventData, + TCG_Sp800_155_PlatformId_Event2_SIGNATURE, + sizeof (TCG_Sp800_155_PlatformId_Event2_SIGNATURE) - 1 + ) =3D=3D 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_P= CR_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 =3D (CC_EVENT_HDR *)NewEventHdr; + DEBUG ((DEBUG_VERBOSE, "Td: Try to log event. Index =3D %d, EventType = =3D 0x%x\n", CcEventHdr->MrIndex, CcEventHdr->EventType)); + + if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { + return EFI_OUT_OF_RESOURCES; + } + + NewLogSize =3D 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->Event= LogSize)); + 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 =3D Is800155Event (NewEventHdr, NewEventHdrSize, NewEv= entData, NewEventSize); + if (Record800155Event) { + DEBUG ((DEBUG_INFO, "It is 800155Event.\n")); + + if (EventLogAreaStruct->Next800155EventOffset !=3D 0) { + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Nex= t800155EventOffset + NewLogSize, + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Nex= t800155EventOffset, + EventLogAreaStruct->EventLogSize - EventLogAreaStruct->Next800155E= ventOffset + ); + + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Nex= t800155EventOffset, + NewEventHdr, + NewEventHdrSize + ); + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Nex= t800155EventOffset + NewEventHdrSize, + NewEventData, + NewEventSize + ); + + EventLogAreaStruct->Next800155EventOffset +=3D NewLogSize; + EventLogAreaStruct->LastEvent +=3D NewLogSize; + EventLogAreaStruct->EventLogSize +=3D NewLogSize; + } + + return EFI_SUCCESS; + } + + EventLogAreaStruct->LastEvent =3D (UINT8 *)(UINTN)EventLogAreaStruct= ->Lasa + EventLogAreaStruct->EventLogSize; + EventLogAreaStruct->EventLogSize +=3D NewLogSize; + + CopyMem (EventLogAreaStruct->LastEvent, NewEventHdr, NewEventHdrSize); + CopyMem ( + EventLogAreaStruct->LastEvent + NewEventHdrSize, + NewEventData, + NewEventSize + ); + + return EFI_SUCCESS; +} + +/** + RTMR[0] =3D> PCR[1,7] + RTMR[1] =3D> PCR[2,3,4,5] + RTMR[2] =3D> PCR[8~15] + RTMR[3] =3D> NA +**/ +UINT32 +EFIAPI +MapPcrToMrIndex ( + IN UINT32 PCRIndex + ) +{ + UINT32 MrIndex; + + if ((PCRIndex > 16) || (PCRIndex =3D=3D 6) || (PCRIndex =3D=3D 0)) { + ASSERT (FALSE); + return INVALID_RTMR_INDEX; + } + + MrIndex =3D 0; + if ((PCRIndex =3D=3D 1) || (PCRIndex =3D=3D 7)) { + MrIndex =3D 0; + } else if ((PCRIndex > 1) && (PCRIndex < 6)) { + MrIndex =3D 1; + } else if ((PCRIndex > 7) && (PCRIndex < 16)) { + MrIndex =3D 2; + } + + return MrIndex; +} + +EFI_STATUS +EFIAPI +TdMapPcrToMrIndex ( + IN EFI_CC_MEASUREMENT_PROTOCOL *This, + IN UINT32 PCRIndex, + OUT UINT32 *MrIndex + ) +{ + if (MrIndex =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((PCRIndex > 16) || (PCRIndex =3D=3D 0) || (PCRIndex =3D=3D 6)) { + return EFI_INVALID_PARAMETER; + } + + *MrIndex =3D MapPcrToMrIndex (PCRIndex); + + return *MrIndex =3D=3D INVALID_RTMR_INDEX ? 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 infor= mation 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 +TdxDxeLogEvent ( + 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 !=3D EFI_CC_EVENT_LOG_FORMAT_TCG_2) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Index =3D 0; + + // + // Record to normal event log + // + EventLogAreaStruct =3D &mTdxDxeData.EventLogAreaStruct[Index]; + + if (EventLogAreaStruct->EventLogTruncated) { + return EFI_VOLUME_FULL; + } + + Status =3D TcgCommLogEvent ( + EventLogAreaStruct, + NewEventHdr, + NewEventHdrSize, + NewEventData, + NewEventSize + ); + + if (Status =3D=3D EFI_OUT_OF_RESOURCES) { + EventLogAreaStruct->EventLogTruncated =3D TRUE; + return EFI_VOLUME_FULL; + } else if (Status =3D=3D EFI_SUCCESS) { + EventLogAreaStruct->EventLogStarted =3D TRUE; + } + + // + // If GetEventLog is called, record to FinalEventsTable, too. + // + if (mTdxDxeData.GetEventLogCalled[Index]) { + if (mTdxDxeData.FinalEventsTable[Index] =3D=3D NULL) { + // + // no need for FinalEventsTable + // + return EFI_SUCCESS; + } + + EventLogAreaStruct =3D &mTdxDxeData.FinalEventLogAreaStruct[Index]; + + if (EventLogAreaStruct->EventLogTruncated) { + return EFI_VOLUME_FULL; + } + + Status =3D TcgCommLogEvent ( + EventLogAreaStruct, + NewEventHdr, + NewEventHdrSize, + NewEventData, + NewEventSize + ); + if (Status =3D=3D EFI_OUT_OF_RESOURCES) { + EventLogAreaStruct->EventLogTruncated =3D TRUE; + return EFI_VOLUME_FULL; + } else if (Status =3D=3D EFI_SUCCESS) { + EventLogAreaStruct->EventLogStarted =3D TRUE; + // + // Increase the NumberOfEvents in FinalEventsTable + // + (mTdxDxeData.FinalEventsTable[Index])->NumberOfEvents++; + DEBUG ((DEBUG_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mT= dxDxeData.FinalEventsTable[Index])->NumberOfEvents)); + DEBUG ((DEBUG_INFO, " Size - 0x%x\n", (UINTN)EventLogAreaStruct->Ev= entLogSize)); + } + } + + 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 =3D ReadUnaligned32 (DigestListBin); + TotalSize =3D sizeof (Count); + DigestListBin =3D (UINT8 *)DigestListBin + sizeof (Count); + for (Index =3D 0; Index < Count; Index++) { + HashAlg =3D ReadUnaligned16 (DigestListBin); + TotalSize +=3D sizeof (HashAlg); + DigestListBin =3D (UINT8 *)DigestListBin + sizeof (HashAlg); + + DigestSize =3D GetHashSizeFromAlgo (HashAlg); + TotalSize +=3D DigestSize; + DigestListBin =3D (UINT8 *)DigestListBin + DigestSize; + } + + return TotalSize; +} + +/** + Copy TPML_DIGEST_VALUES compact binary into a buffer + + @param[in,out] Buffer Buffer to hold copied TPML_DIG= EST_VALUES compact binary. + @param[in] DigestListBin TPML_DIGEST_VALUES compact bin= ary buffer. + @param[in] HashAlgorithmMask HASH bits corresponding to the= desired digests to copy. + @param[out] HashAlgorithmMaskCopied Pointer to HASH bits correspon= ding to the digests copied. + + @return The end of buffer to hold TPML_DIGEST_VALUES compact binary. +**/ +VOID * +CopyDigestListBinToBuffer ( + IN OUT VOID *Buffer, + IN VOID *DigestListBin, + IN UINT32 HashAlgorithmMask, + OUT UINT32 *HashAlgorithmMaskCopied + ) +{ + UINTN Index; + UINT16 DigestSize; + UINT32 Count; + TPMI_ALG_HASH HashAlg; + UINT32 DigestListCount; + UINT32 *DigestListCountPtr; + + DigestListCountPtr =3D (UINT32 *)Buffer; + DigestListCount =3D 0; + *HashAlgorithmMaskCopied =3D 0; + + Count =3D ReadUnaligned32 (DigestListBin); + Buffer =3D (UINT8 *)Buffer + sizeof (Count); + DigestListBin =3D (UINT8 *)DigestListBin + sizeof (Count); + for (Index =3D 0; Index < Count; Index++) { + HashAlg =3D ReadUnaligned16 (DigestListBin); + DigestListBin =3D (UINT8 *)DigestListBin + sizeof (HashAlg); + DigestSize =3D GetHashSizeFromAlgo (HashAlg); + + if ((HashAlg & HashAlgorithmMask) !=3D 0) { + CopyMem (Buffer, &HashAlg, sizeof (HashAlg)); + Buffer =3D (UINT8 *)Buffer + sizeof (HashAlg); + CopyMem (Buffer, DigestListBin, DigestSize); + Buffer =3D (UINT8 *)Buffer + DigestSize; + DigestListCount++; + (*HashAlgorithmMaskCopied) |=3D GetHashMaskFromAlgo (HashAlg); + } else { + DEBUG ((DEBUG_ERROR, "WARNING: CopyDigestListBinToBuffer Event log h= as HashAlg unsupported by PCR bank (0x%x)\n", HashAlg)); + } + + DigestListBin =3D (UINT8 *)DigestListBin + DigestSize; + } + + WriteUnaligned32 (DigestListCountPtr, DigestListCount); + + return Buffer; +} + +/** + Add a new entry to the Event Log. The call chain is like below: + TdxDxeLogHashEvent -> TdxDxeLogEvent -> TcgCommonLogEvent + + Before this function is called, the event information (including the dig= est) + 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 +TdxDxeLogHashEvent ( + 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 =3D EFI_SUCCESS; + LogFormat =3D EFI_CC_EVENT_LOG_FORMAT_TCG_2; + + ZeroMem (&CcEvent, sizeof (CcEvent)); + // + // The index of event log is designed as below: + // 0 : MRTD + // 1-4: RTMR[0-3] + // + CcEvent.MrIndex =3D NewEventHdr->MrIndex + 1; + CcEvent.EventType =3D NewEventHdr->EventType; + DigestBuffer =3D (UINT8 *)&CcEvent.Digests; + EventSizePtr =3D CopyDigestListToBuffer (DigestBuffer, DigestList, = HASH_ALG_SHA384); + CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->Eve= ntSize)); + + // + // Enter critical region + // + OldTpl =3D gBS->RaiseTPL (TPL_HIGH_LEVEL); + Status =3D TdxDxeLogEvent ( + LogFormat, + &CcEvent, + sizeof (CcEvent.MrIndex) + sizeof (CcEvent.EventType) + GetDi= gestListBinSize (DigestBuffer) + sizeof (CcEvent.EventSize), + NewEventData, + NewEventHdr->EventSize + ); + if (Status !=3D EFI_SUCCESS) { + RetStatus =3D Status; + } + + gBS->RestoreTPL (OldTpl); + + return RetStatus; +} + +/** + Do a hash operation on a data buffer, extend a specific RTMR with the ha= sh 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 refere= nced 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 +TdxDxeHashLogExtendEvent ( + 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 =3D=3D EV_NO_ACTION) { + // + // Do not do RTMR extend for EV_NO_ACTION + // + Status =3D EFI_SUCCESS; + InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize); + if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) =3D=3D 0) { + Status =3D TdxDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr= , NewEventData); + } + + return Status; + } + + Status =3D HashAndExtend ( + NewEventHdr->MrIndex, + HashData, + (UINTN)HashDataLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) =3D=3D 0) { + Status =3D TdxDxeLogHashEvent (&DigestList, NewEventHdr, NewEventDat= a); + } + } + + return Status; +} + +/** + The EFI_CC_MEASUREMENT_PROTOCOL HashLogExtendEvent function call provide= s 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 e= vent + 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 referen= ced by DataToHash. + @param[in] Event Pointer to data buffer containing informa= tion 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 ev= ent could not be written to one or more event logs. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorre= ct. + @retval EFI_UNSUPPORTED The PE/COFF image type is not supported. +**/ +EFI_STATUS +EFIAPI +TdHashLogExtendEvent ( + 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, "TdHashLogExtendEvent ...\n")); + + if ((This =3D=3D NULL) || (CcEvent =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Do not check hash data size for EV_NO_ACTION event. + // + if ((CcEvent->Header.EventType !=3D EV_NO_ACTION) && (DataToHash =3D=3D = 0)) { + return EFI_INVALID_PARAMETER; + } + + if (CcEvent->Size < CcEvent->Header.HeaderSize + sizeof (UINT32)) { + return EFI_INVALID_PARAMETER; + } + + if (CcEvent->Header.MrIndex > 4) { + return EFI_INVALID_PARAMETER; + } + + NewEventHdr.MrIndex =3D CcEvent->Header.MrIndex; + NewEventHdr.EventType =3D CcEvent->Header.EventType; + NewEventHdr.EventSize =3D CcEvent->Size - sizeof (UINT32) - CcEvent->Hea= der.HeaderSize; + if ((Flags & EFI_CC_FLAG_PE_COFF_IMAGE) !=3D 0) { + Status =3D MeasurePeImageAndExtend ( + NewEventHdr.MrIndex, + DataToHash, + (UINTN)DataToHashLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) =3D=3D 0) { + Status =3D TdxDxeLogHashEvent (&DigestList, &NewEventHdr, CcEvent-= >Event); + } + } + } else { + Status =3D TdxDxeHashLogExtendEvent ( + Flags, + (UINT8 *)(UINTN)DataToHash, + DataToHashLen, + &NewEventHdr, + CcEvent->Event + ); + } + + DEBUG ((DEBUG_VERBOSE, "TdHashLogExtendEvent - %r\n", Status)); + return Status; +} + +EFI_CC_MEASUREMENT_PROTOCOL mTdProtocol =3D { + TdGetCapability, + TdGetEventLog, + TdHashLogExtendEvent, + TdMapPcrToMrIndex, +}; + +#define TD_HASH_COUNT 1 +#define TEMP_BUF_LEN (sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32)= \ + + (TD_HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithm= Size)) + sizeof(UINT8)) + +/** + Initialize the TD 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 =3D EFI_SUCCESS; + DEBUG ((DEBUG_INFO, "SetupCcEventLog\n")); + + Index =3D 0; + LogFormat =3D EFI_CC_EVENT_LOG_FORMAT_TCG_2; + + // + // 1. Create Log Area + // + mTdxDxeData.EventLogAreaStruct[Index].EventLogFormat =3D LogFormat; + + // allocate pages for TD Event log + Status =3D gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), + &Lasa + ); + if (EFI_ERROR (Status)) { + return Status; + } + + mTdxDxeData.EventLogAreaStruct[Index].Lasa =3D Lasa; + mTdxDxeData.EventLogAreaStruct[Index].Laml =3D PcdGet32= (PcdTcgLogAreaMinLen); + mTdxDxeData.EventLogAreaStruct[Index].Next800155EventOffset =3D 0; + + // + // Report TD event log address and length, so that they can be reported = in + // TD ACPI table. Ignore the return status, because those fields are opt= ional. + // + PcdSet32S (PcdCcEventlogAcpiTableLaml, (UINT32)mTdxDxeData.EventLogAreaS= truct[Index].Laml); + PcdSet64S (PcdCcEventlogAcpiTableLasa, mTdxDxeData.EventLogAreaStruct[In= dex].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 =3D (TCG_EfiSpecIDEventStruct *)TempBuf; + CopyMem (TcgEfiSpecIdEventStruct->signature, TCG_EfiSpecIDEventStruct_SI= GNATURE_03, sizeof (TcgEfiSpecIdEventStruct->signature)); + + TcgEfiSpecIdEventStruct->platformClass =3D PcdGet8 (PcdTpmPlatformClass); + + TcgEfiSpecIdEventStruct->specVersionMajor =3D TCG_EfiSpecIDEventStruct_S= PEC_VERSION_MAJOR_TPM2; + TcgEfiSpecIdEventStruct->specVersionMinor =3D TCG_EfiSpecIDEventStruct_S= PEC_VERSION_MINOR_TPM2; + TcgEfiSpecIdEventStruct->specErrata =3D TCG_EfiSpecIDEventStruct_S= PEC_ERRATA_TPM2; + TcgEfiSpecIdEventStruct->uintnSize =3D sizeof (UINTN)/sizeof (UIN= T32); + NumberOfAlgorithms =3D 0; + DigestSize =3D (TCG_EfiSpecIdEventAlgorit= hmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + = + sizeof (*TcgEfiSpecIdEventStruct) + = + sizeof (NumberOfAlgorithms)); + + TempDigestSize =3D DigestSize; + TempDigestSize +=3D NumberOfAlgorithms; + TempDigestSize->algorithmId =3D TPM_ALG_SHA384; + TempDigestSize->digestSize =3D SHA384_DIGEST_SIZE; + NumberOfAlgorithms++; + + CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof (Numbe= rOfAlgorithms)); + TempDigestSize =3D DigestSize; + TempDigestSize +=3D NumberOfAlgorithms; + VendorInfoSize =3D (UINT8 *)TempDigestSize; + *VendorInfoSize =3D 0; + + SpecIdEvent.PCRIndex =3D 1; // PCRIndex 0 maps to MrIndex 1 + SpecIdEvent.EventType =3D EV_NO_ACTION; + ZeroMem (&SpecIdEvent.Digest, sizeof (SpecIdEvent.Digest)); + SpecIdEvent.EventSize =3D (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfi= SpecIdEventStruct); + + // + // TD Event log re-use the spec of TCG2 Event log. + // Log TcgEfiSpecIdEventStruct as the first Event. Event format is TCG_P= CR_EVENT. + // TCG EFI Protocol Spec. Section 5.3 Event Log Header + // TCG PC Client PFP spec. Section 9.2 Measurement Event Entries and L= og + // + Status =3D TdxDxeLogEvent ( + 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. + // + mTdxDxeData.EventLogAreaStruct[Index].Next800155EventOffset =3D mTdxDxeD= ata.EventLogAreaStruct[Index].EventLogSize; + + // + // Tcg800155PlatformIdEvent. Event format is TCG_PCR_EVENT2 + // + GuidHob.Guid =3D GetFirstGuidHob (&gTcg800155PlatformIdEventHobGuid); + while (GuidHob.Guid !=3D NULL) { + InitNoActionEvent (&NoActionEvent, GET_GUID_HOB_DATA_SIZE (GuidHob.Gui= d)); + + Status =3D TdxDxeLogEvent ( + LogFormat, + &NoActionEvent, + sizeof (NoActionEvent.MrIndex) + sizeof (NoActionEvent.Even= tType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof (NoActionEv= ent.EventSize), + GET_GUID_HOB_DATA (GuidHob.Guid), + GET_GUID_HOB_DATA_SIZE (GuidHob.Guid) + ); + + GuidHob.Guid =3D GET_NEXT_HOB (GuidHob); + GuidHob.Guid =3D GetNextGuidHob (&gTcg800155PlatformIdEventHobGuid, Gu= idHob.Guid); + } + + // + // 2. Create Final Log Area + // + Status =3D 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 + // + mTdxDxeData.FinalEventsTable[Index] =3D (VOID *)(UINTN= )Lasa; + (mTdxDxeData.FinalEventsTable[Index])->Version =3D EFI_TCG2_FINAL= _EVENTS_TABLE_VERSION; + (mTdxDxeData.FinalEventsTable[Index])->NumberOfEvents =3D 0; + + mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogFormat =3D Log= Format; + mTdxDxeData.FinalEventLogAreaStruct[Index].Lasa =3D Las= a + sizeof (EFI_CC_FINAL_EVENTS_TABLE); + mTdxDxeData.FinalEventLogAreaStruct[Index].Laml =3D Pcd= Get32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_CC_FINAL_EVENTS_TABLE); + mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogSize =3D 0; + mTdxDxeData.FinalEventLogAreaStruct[Index].LastEvent =3D (VO= ID *)(UINTN)mTdxDxeData.FinalEventLogAreaStruct[Index].Lasa; + mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogStarted =3D FAL= SE; + mTdxDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated =3D FAL= SE; + mTdxDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset =3D 0; + + // + // Install to configuration table for EFI_CC_EVENT_LOG_FORMAT_TCG_2 + // + Status =3D gBS->InstallConfigurationTable (&gEfiCcFinalEventsTableGuid, = (VOID *)mTdxDxeData.FinalEventsTable[Index]); + if (EFI_ERROR (Status)) { + return Status; + } + + return Status; +} + +/** + Measure and log an action string, and extend the measurement result into= RTMR. + + @param[in] MrIndex MrIndex to extend + @param[in] String A specific string that indicates an Action e= vent. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +TdMeasureAction ( + IN UINT32 MrIndex, + IN CHAR8 *String + ) +{ + CC_EVENT_HDR CcEvent; + + CcEvent.MrIndex =3D MrIndex; + CcEvent.EventType =3D EV_EFI_ACTION; + CcEvent.EventSize =3D (UINT32)AsciiStrLen (String); + return TdxDxeHashLogExtendEvent ( + 0, + (UINT8 *)String, + CcEvent.EventSize, + &CcEvent, + (UINT8 *)String + ); +} + +/** + Measure and log EFI handoff tables, and extend the measurement result in= to PCR[1]. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureHandoffTables ( + VOID + ) +{ + EFI_STATUS Status; + CC_EVENT_HDR CcEvent; + EFI_HANDOFF_TABLE_POINTERS HandoffTables; + UINTN ProcessorNum; + EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; + + ProcessorLocBuf =3D NULL; + Status =3D EFI_SUCCESS; + + if (PcdGet8 (PcdTpmPlatformClass) =3D=3D TCG_PLATFORM_TYPE_SERVER) { + // + // Tcg Server spec. + // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_D= EVICES to PCR[1] + // + Status =3D GetProcessorsCpuLocation (&ProcessorLocBuf, &ProcessorNum); + + if (!EFI_ERROR (Status)) { + CcEvent.MrIndex =3D MapPcrToMrIndex (1); + CcEvent.EventType =3D EV_TABLE_OF_DEVICES; + CcEvent.EventSize =3D sizeof (HandoffTables); + + HandoffTables.NumberOfTables =3D 1; + HandoffTables.TableEntry[0].VendorGuid =3D gEfiMpServiceProtocolGui= d; + HandoffTables.TableEntry[0].VendorTable =3D ProcessorLocBuf; + + Status =3D TdxDxeHashLogExtendEvent ( + 0, + (UINT8 *)(UINTN)ProcessorLocBuf, + sizeof (EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, + &CcEvent, + (UINT8 *)&HandoffTables + ); + + FreePool (ProcessorLocBuf); + } + } + + return Status; +} + +/** + Measure and log Separator event, and extend the measurement result into = a specific PCR. + + @param[in] PCRIndex PCR index. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureSeparatorEvent ( + IN UINT32 MrIndex + ) +{ + CC_EVENT_HDR CcEvent; + UINT32 EventData; + + DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent to Rtmr - %d\n", MrIndex)); + + EventData =3D 0; + CcEvent.MrIndex =3D MrIndex; + CcEvent.EventType =3D EV_SEPARATOR; + CcEvent.EventSize =3D (UINT32)sizeof (EventData); + + return TdxDxeHashLogExtendEvent ( + 0, + (UINT8 *)&EventData, + sizeof (EventData), + &CcEvent, + (UINT8 *)&EventData + ); +} + +/** + Measure and log an EFI variable, and extend the measurement result into = a specific RTMR. + + @param[in] MrIndex RTMR Index. + @param[in] EventType Event type. + @param[in] VarName A Null-terminated string that is the name = of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] VarData The content of the variable data. + @param[in] VarSize The size of the variable data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureVariable ( + IN UINT32 MrIndex, + IN TCG_EVENTTYPE EventType, + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *VarData, + IN UINTN VarSize + ) +{ + EFI_STATUS Status; + CC_EVENT_HDR CcEvent; + UINTN VarNameLength; + UEFI_VARIABLE_DATA *VarLog; + + DEBUG ((DEBUG_INFO, "TdTcg2Dxe: MeasureVariable (Rtmr - %x, EventType - = %x, ", (UINTN)MrIndex, (UINTN)EventType)); + DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, Ve= ndorGuid)); + + VarNameLength =3D StrLen (VarName); + CcEvent.MrIndex =3D MrIndex; + CcEvent.EventType =3D EventType; + + CcEvent.EventSize =3D (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof= (*VarName) + VarSize + - sizeof (VarLog->UnicodeName) - sizeof (Va= rLog->VariableData)); + + VarLog =3D (UEFI_VARIABLE_DATA *)AllocatePool (CcEvent.EventSize); + if (VarLog =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VarLog->VariableName =3D *VendorGuid; + VarLog->UnicodeNameLength =3D VarNameLength; + VarLog->VariableDataLength =3D VarSize; + CopyMem ( + VarLog->UnicodeName, + VarName, + VarNameLength * sizeof (*VarName) + ); + if ((VarSize !=3D 0) && (VarData !=3D NULL)) { + CopyMem ( + (CHAR16 *)VarLog->UnicodeName + VarNameLength, + VarData, + VarSize + ); + } + + if (EventType =3D=3D EV_EFI_VARIABLE_DRIVER_CONFIG) { + // + // Digest is the event data (UEFI_VARIABLE_DATA) + // + Status =3D TdxDxeHashLogExtendEvent ( + 0, + (UINT8 *)VarLog, + CcEvent.EventSize, + &CcEvent, + (UINT8 *)VarLog + ); + } else { + ASSERT (VarData !=3D NULL); + Status =3D TdxDxeHashLogExtendEvent ( + 0, + (UINT8 *)VarData, + VarSize, + &CcEvent, + (UINT8 *)VarLog + ); + } + + FreePool (VarLog); + return Status; +} + +/** + Read then Measure and log an EFI variable, and extend the measurement re= sult into a specific RTMR. + + @param[in] MrIndex RTMR Index. + @param[in] EventType Event type. + @param[in] VarName A Null-terminated string that is the name = of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +ReadAndMeasureVariable ( + IN UINT32 MrIndex, + IN TCG_EVENTTYPE EventType, + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + EFI_STATUS Status; + + Status =3D GetVariable2 (VarName, VendorGuid, VarData, VarSize); + if (EventType =3D=3D EV_EFI_VARIABLE_DRIVER_CONFIG) { + if (EFI_ERROR (Status)) { + // + // It is valid case, so we need handle it. + // + *VarData =3D NULL; + *VarSize =3D 0; + } + } else { + // + // if status error, VarData is freed and set NULL by GetVariable2 + // + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + } + + Status =3D MeasureVariable ( + MrIndex, + EventType, + VarName, + VendorGuid, + *VarData, + *VarSize + ); + return Status; +} + +/** + Read then Measure and log an EFI boot variable, and extend the measureme= nt 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 + ) +{ + // + // Boot variables are measured into (PCR[5]) RTMR[1], + // details in section 8.1 of TDVF design guide. + // + return ReadAndMeasureVariable ( + MapPcrToMrIndex (5), + EV_EFI_VARIABLE_BOOT, + VarName, + VendorGuid, + VarSize, + VarData + ); +} + +/** + Read then Measure and log an EFI Secure variable, and extend the measure= ment 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 resul= t 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 =3D ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &BootCount, + (VOID **)&BootOrder + ); + if ((Status =3D=3D EFI_NOT_FOUND) || (BootOrder =3D=3D 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 /=3D sizeof (*BootOrder); + for (Index =3D 0; Index < BootCount; Index++) { + UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootO= rder[Index]); + Status =3D 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 res= ult 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 =3D EFI_NOT_FOUND; + for (Index =3D 0; Index < sizeof (mVariableType)/sizeof (mVariableType[0= ]); Index++) { + Status =3D ReadAndMeasureSecureVariable ( + mVariableType[Index].VariableName, + mVariableType[Index].VendorGuid, + &DataSize, + &Data + ); + if (!EFI_ERROR (Status)) { + if (Data !=3D NULL) { + FreePool (Data); + } + } + } + + // + // Measure DBT if present and not empty + // + Status =3D GetVariable2 (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurit= yDatabaseGuid, &Data, &DataSize); + if (!EFI_ERROR (Status)) { + Status =3D 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 r= esult 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 =3D MapPcrToMrIndex (7); + CcEvent.EventType =3D EV_EFI_ACTION; + CcEvent.EventSize =3D sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1; + return TdxDxeHashLogExtendEvent ( + 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 resul= t into a specific PCR. + + Platform firmware adhering to the policy must therefore measure the foll= owing 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_D= ATABASE, + EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into P= CR[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 =3D gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL= , (VOID **)&Protocol); + if (EFI_ERROR (Status)) { + return; + } + + if (PcdGetBool (PcdFirmwareDebuggerInitialized)) { + Status =3D MeasureLaunchOfFirmwareDebugger (); + DEBUG ((DEBUG_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status)); + } + + Status =3D 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 DriverOrde= r, besides BootOrder. So + // the Authority measurement happen before ReadToBoot event. + // + Status =3D 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 handle= r. + + @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", "TdTcg2Dxe", 0, PERF_ID_CC_TCG2= _DXE); + if (mBootAttempts =3D=3D 0) { + // + // Measure handoff tables. + // + Status =3D MeasureHandoffTables (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "HOBs not Measured. Error!\n")); + } + + // + // Measure BootOrder & Boot#### variables. + // + Status =3D MeasureAllBootVariables (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Boot Variables not Measured. Error!\n")); + } + + // + // 1. This is the first boot attempt. + // + Status =3D TdMeasureAction ( + MapPcrToMrIndex (4), + EFI_CALLING_EFI_APPLICATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_AP= PLICATION)); + } + + // + // 2. Draw a line between pre-boot env and entering post-boot env. + // PCR[7] (is RTMR[0]) is already done. + // + Status =3D MeasureSeparatorEvent (1); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Separator Event not Measured. 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 =3D TdMeasureAction ( + 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 Op= tion" again + // TCG PC Client PFP spec Section 2.4.4.5 Step 4 + // + Status =3D TdMeasureAction ( + MapPcrToMrIndex (4), + EFI_CALLING_EFI_APPLICATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_AP= PLICATION)); + } + } + + DEBUG ((DEBUG_INFO, "TdTcg2Dxe Measure Data when ReadyToBoot\n")); + // + // Increase boot attempt counter. + // + mBootAttempts++; + PERF_END_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_CC_TCG2_DXE= + 1); +} + +/** + Exit Boot Services Event notification handler. + + Measure invocation and success of ExitBootServices. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Measure invocation of ExitBootServices, + // + Status =3D TdMeasureAction ( + MapPcrToMrIndex (5), + EFI_EXIT_BOOT_SERVICES_INVOCATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVIC= ES_INVOCATION)); + } + + // + // Measure success of ExitBootServices + // + Status =3D TdMeasureAction ( + MapPcrToMrIndex (5), + EFI_EXIT_BOOT_SERVICES_SUCCEEDED + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVIC= ES_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 =3D TdMeasureAction ( + MapPcrToMrIndex (5), + EFI_EXIT_BOOT_SERVICES_FAILED + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVIC= ES_FAILED)); + } +} + +EFI_STATUS +SyncCcEvent ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS GuidHob; + VOID *CcEvent; + VOID *DigestListBin; + UINT32 DigestListBinSize; + UINT8 *Event; + UINT32 EventSize; + EFI_CC_EVENT_LOG_FORMAT LogFormat; + + DEBUG ((DEBUG_INFO, "Sync Cc event from SEC\n")); + + Status =3D EFI_SUCCESS; + LogFormat =3D EFI_CC_EVENT_LOG_FORMAT_TCG_2; + GuidHob.Guid =3D GetFirstGuidHob (&gCcEventEntryHobGuid); + + while (!EFI_ERROR (Status) && GuidHob.Guid !=3D NULL) { + CcEvent =3D AllocateCopyPool (GET_GUID_HOB_DATA_SIZE (GuidHob.Guid), G= ET_GUID_HOB_DATA (GuidHob.Guid)); + if (CcEvent =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + GuidHob.Guid =3D GET_NEXT_HOB (GuidHob); + GuidHob.Guid =3D GetNextGuidHob (&gCcEventEntryHobGuid, GuidHob.Guid); + + DigestListBin =3D (UINT8 *)CcEvent + sizeof (UINT32) + sizeof (TCG= _EVENTTYPE); + DigestListBinSize =3D GetDigestListBinSize (DigestListBin); + + // + // Event size. + // + EventSize =3D *(UINT32 *)((UINT8 *)DigestListBin + DigestListBinSize); + Event =3D (UINT8 *)DigestListBin + DigestListBinSize + sizeof (UIN= T32); + + // + // Log the event + // + Status =3D TdxDxeLogEvent ( + LogFormat, + CcEvent, + sizeof (UINT32) + sizeof (TCG_EVENTTYPE) + DigestListBinSiz= e + sizeof (UINT32), + Event, + EventSize + ); + + DumpCcEvent ((CC_EVENT *)CcEvent); + FreePool (CcEvent); + } + + return Status; +} + +/** + 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; + UINT64 OemTableId; + + Status =3D gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID = **)&AcpiTable); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "TD: AcpiTableProtocol is not installed. %r\n", S= tatus)); + return; + } + + mTdxEventlogAcpiTemplate.Laml =3D (UINT64)PcdGet32 (PcdCcEventlogAcpiTab= leLaml); + mTdxEventlogAcpiTemplate.Lasa =3D PcdGet64 (PcdCcEventlogAcpiTableLasa); + CopyMem (mTdxEventlogAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaul= tOemId), sizeof (mTdxEventlogAcpiTemplate.Header.OemId)); + OemTableId =3D PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mTdxEventlogAcpiTemplate.Header.OemTableId, &OemTableId, sizeo= f (UINT64)); + mTdxEventlogAcpiTemplate.Header.OemRevision =3D PcdGet32 (PcdAcpiDef= aultOemRevision); + mTdxEventlogAcpiTemplate.Header.CreatorId =3D PcdGet32 (PcdAcpiDef= aultCreatorId); + mTdxEventlogAcpiTemplate.Header.CreatorRevision =3D PcdGet32 (PcdAcpiDef= aultCreatorRevision); + + // + // Construct ACPI Table + Status =3D AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTdxEventlogAcpiTemplate, + mTdxEventlogAcpiTemplate.Header.Length, + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((DEBUG_INFO, "TDVF Eventlog ACPI Table is installed.\n")); +} + +/** + The function install TdTcg2 protocol. + + @retval EFI_SUCCESS TdTcg2 protocol is installed. + @retval other Some error occurs. +**/ +EFI_STATUS +InstallCcMeasurementProtocol ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle =3D NULL; + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiCcMeasurementProtocolGuid, + &mTdProtocol, + NULL + ); + DEBUG ((DEBUG_INFO, "CcProtocol: Install %r\n", Status)); + return Status; +} + +/** + The driver's entry point. It publishes EFI Tcg2 Protocol. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry poin= t. +**/ +EFI_STATUS +EFIAPI +DriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + VOID *Registration; + + if (!TdIsEnabled ()) { + return EFI_UNSUPPORTED; + } + + mImageHandle =3D ImageHandle; + + // + // Fill information + // + // ASSERT (TD_EVENT_LOG_AREA_COUNT_MAX =3D=3D sizeof(mTEventInfo)/sizeo= f(mTcg2EventInfo[0])); + + mTdxDxeData.BsCap.Size =3D sizeof (EFI_CC_BOOT_SERVICE= _CAPABILITY); + mTdxDxeData.BsCap.ProtocolVersion.Major =3D 1; + mTdxDxeData.BsCap.ProtocolVersion.Minor =3D 1; + mTdxDxeData.BsCap.StructureVersion.Major =3D 1; + mTdxDxeData.BsCap.StructureVersion.Minor =3D 1; + + // + // Get supported PCR and current Active PCRs + // For TD gueset HA384 is supported. + // + mTdxDxeData.BsCap.HashAlgorithmBitmap =3D HASH_ALG_SHA384; + + // TD guest only supports EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 + mTdxDxeData.BsCap.SupportedEventLogs =3D EFI_CC_EVENT_LOG_FORMAT_TCG_2; + + // + // Setup the log area and copy event log from hob list to it + // + Status =3D SetupCcEventLog (); + ASSERT_EFI_ERROR (Status); + + if (!EFI_ERROR (Status)) { + Status =3D SyncCcEvent (); + ASSERT_EFI_ERROR (Status); + } + + // + // Measure handoff tables, Boot#### variables etc. + // + Status =3D EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + OnReadyToBoot, + NULL, + &Event + ); + + Status =3D gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServices, + NULL, + &gEfiEventExitBootServicesGuid, + &Event + ); + + // + // Measure Exit Boot Service failed + // + Status =3D gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServicesFailed, + NULL, + &gEventExitBootServicesFailedGuid, + &Event + ); + + // + // Create event callback, because we need access variable on SecureBootP= olicyVariable + // We should use VariableWriteArch instead of VariableArch, because Vari= able driver + // may update SecureBoot value based on last setting. + // + EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CA= LLBACK, MeasureSecureBootPolicy, NULL, &Registration); + + // + // Install CcMeasurementProtocol + // + Status =3D InstallCcMeasurementProtocol (); + DEBUG ((DEBUG_INFO, "InstallCcMeasurementProtocol - %r\n", Status)); + + if (Status =3D=3D EFI_SUCCESS) { + // + // Create event callback to install CC EventLog ACPI Table + EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK= , InstallAcpiTable, NULL, &Registration); + } + + return Status; +} diff --git a/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf b/OvmfPkg/IntelTdx/Td= Tcg2Dxe/TdTcg2Dxe.inf new file mode 100644 index 000000000000..5efe7ef479f1 --- /dev/null +++ b/OvmfPkg/IntelTdx/TdTcg2Dxe/TdTcg2Dxe.inf @@ -0,0 +1,101 @@ +## @file +# +# Produces EFI_CC_MEASUREMENT_PROTOCOL and measure boot environment +# +# +# Copyright (c) 2020 - 2022, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D TdTcg2Dxe + FILE_GUID =3D F062221E-C607-44C2-B0B4-C3886331D351 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D DriverEntry + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D X64 +# + +[Sources] + TdTcg2Dxe.c + MeasureBootPeCoff.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiBootServicesTableLib + HobLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + PrintLib + UefiLib + HashLib + PerformanceLib + ReportStatusCodeLib + PeCoffLib + TpmMeasurementLib + TdxLib + +[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_CONSUM= ES ## HOB + gEfiEventExitBootServicesGuid ## CONSUMES = ## Event + gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES= ## Event + + gCcEventEntryHobGuid ## SOMETIMES_CONSUMES= ## HOB + gTcg800155PlatformIdEventHobGuid ## SOMETIMES_CONSUMES= ## HOB + gEfiCcFinalEventsTableGuid ## PRODUCES + +[Protocols] + gEfiCcMeasurementProtocolGuid ## PRODUCES + gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES + gEfiVariableWriteArchProtocolGuid ## NOTIFY + gEfiResetNotificationProtocolGuid ## CONSUMES + 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 + gUefiOvmfPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLaml = ## PRODUCES + gUefiOvmfPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLasa = ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId = ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId = ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision = ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId = ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision = ## CONSUMES + +[Depex] + # According to PcdTpm2AcpiTableRev definition in SecurityPkg.dec + # This PCD should be configured at DynamicHii or DynamicHiiEx. + # So, this PCD read operation depends on GetVariable service. + # Add VariableArch protocol dependency to make sure PCD read works. + gEfiVariableArchProtocolGuid AND gEfiAcpiTableProtocolGuid --=20 2.29.2.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#89758): https://edk2.groups.io/g/devel/message/89758 Mute This Topic: https://groups.io/mt/91135118/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-