From nobody Mon Feb 9 09:33:38 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+98848+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+98848+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1674098930; cv=none; d=zohomail.com; s=zohoarc; b=IKmEuPBozCuK5EenEY++7cUrvS3g3rw5G9bsX1+Gf0C04LSFoGqh9DeLdd23fhkhcMbF9uht/VLVS7BZngwMECFb6uJn05FzIzA+ycXAmDPQk2L1fXGn1uBBJsXvuge+eMKxhyfJYfEIUbvPpKoQNtP1JS+UaVbp9z67GDJEMZM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1674098930; 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=8Zl141CM4pTJkbQFW+GYFcmwqHJmMhvaYotYarwDXDc=; b=JRRiKpVhFTrhhKA/hI/Z+dmQaAatRoyuw250itoi7OzXVtEIG+Lk39p7EGQTADFp/3hs3XmAiYGiwlwnwF+/PPM2B2IbJSpSJ3LFhpTMgHeaS8agaDMN6fjsZ2EyDId1T5i9Vz1D2QVQyc5ndEPjIgEf8uBrzL8WMTOJqnJLObA= 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+98848+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 1674098930044618.8671603810433; Wed, 18 Jan 2023 19:28:50 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id ooyOYY1788612xsFQuXTgBHo; Wed, 18 Jan 2023 19:28:49 -0800 X-Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by mx.groups.io with SMTP id smtpd.web11.37667.1674098921938942214 for ; Wed, 18 Jan 2023 19:28:49 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10594"; a="387531153" X-IronPort-AV: E=Sophos;i="5.97,226,1669104000"; d="scan'208";a="387531153" X-Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Jan 2023 19:28:48 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10594"; a="692264288" X-IronPort-AV: E=Sophos;i="5.97,226,1669104000"; d="scan'208";a="692264288" X-Received: from mxu9-mobl1.ccr.corp.intel.com ([10.254.211.169]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Jan 2023 19:28:46 -0800 From: "Min Xu" To: devel@edk2.groups.io Cc: Min M Xu , Erdem Aktas , James Bottomley , Jiewen Yao , Gerd Hoffmann , Tom Lendacky , Michael Roth Subject: [edk2-devel] [PATCH V2 03/10] OvmfPkg/IntelTdx: Add SecTdxHelperLib Date: Thu, 19 Jan 2023 11:28:15 +0800 Message-Id: <20230119032822.1406-4-min.m.xu@intel.com> In-Reply-To: <20230119032822.1406-1-min.m.xu@intel.com> References: <20230119032822.1406-1-min.m.xu@intel.com> 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: ypGOW3QyZK4a5GpYXrjR57bIx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1674098929; bh=Lk1YqxJSbQle0OyKafJ9XVtdffKD4a5Qp0J/lCx9Yak=; h=Cc:Date:From:Reply-To:Subject:To; b=F26stU2HwOREOqss8sRRid1swr9urchVZt88Mdq/1Lf42vIMPXbdZmDSLrU3FO8lFCp 7gVaAHGhPj8C5+QKpFN+eVttdXdkmIkF3VEwI1eM4uz+XzE/8/vZG85A9MkodikSRsDcR XuiwE4P6YWdhPIcQ34QBNCol/lBEBwLn3Hk= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1674098930652100014 Content-Type: text/plain; charset="utf-8" From: Min M Xu BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3D4243 TdxHelperLib provides below helper functions for a td-guest. - TdxHelperProcessTdHob - TdxHelperMeasureTdHob - TdxHelperMeasureCfvImage - TdxHelperBuildGuidHobForTdxMeasurement SecTdxHelperLib is the SEC instance of TdxHelperLib. It implements 4 functions for tdx in SEC phase: - TdxHelperProcessTdHob consumes TdHob to accept un-accepted memories. Before the TdHob is consumed, it is first validated. - TdxHelperMeasureTdHob measure/extend TdHob and store the measurement value in workarea. - TdxHelperMeasureCfvImage measure/extend the Configuration FV image and store the measurement value in workarea. - TdxHelperBuildGuidHobForTdxMeasurement builds GuidHob for tdx measurement. In this patch only TdxHelperProcessTdHob is implemented. Other 3 functions are to be implemented in the following patch. This is because the code of TdxHelperProcessTdHob is copied from PlatformInitLib/IntelTdx.c. TdxHelperProcessTdHob is corresponding to ProcessTdxHobList. To make the patch reviewable, we sperate the SecTdxHelperLib into several patches. The duplicated code in PlatformInitLib/IntelTdx.c will be deleted later. This is to prevent the build from broken. Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Gerd Hoffmann Cc: Tom Lendacky Cc: Michael Roth Signed-off-by: Min Xu --- OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c | 845 ++++++++++++++++++ .../IntelTdx/TdxHelperLib/SecTdxHelperLib.inf | 52 ++ 2 files changed, 897 insertions(+) create mode 100644 OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c create mode 100644 OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf diff --git a/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c b/OvmfPkg/IntelTd= x/TdxHelperLib/SecTdxHelper.c new file mode 100644 index 000000000000..4fb2d2a8acad --- /dev/null +++ b/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelper.c @@ -0,0 +1,845 @@ +/** @file + TdxHelper Functions which are used in SEC phase + + Copyright (c) 2022 - 2023, 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 + +#define ALIGNED_2MB_MASK 0x1fffff +#define MEGABYTE_SHIFT 20 + +#define ACCEPT_CHUNK_SIZE SIZE_32MB +#define AP_STACK_SIZE SIZE_16KB +#define APS_STACK_SIZE(CpusNum) (ALIGN_VALUE(CpusNum*AP_STACK_SIZE, SIZE_= 2MB)) + +/** + This function will be called to accept pages. Only BSP accepts pages. + + TDCALL(ACCEPT_PAGE) supports the accept page size of 4k and 2M. To + simplify the implementation, the Memory to be accpeted is splitted + into 3 parts: + ----------------- <-- StartAddress1 (not 2M aligned) + | part 1 | Length1 < 2M + |---------------| <-- StartAddress2 (2M aligned) + | | Length2 =3D Integer multiples of 2M + | part 2 | + | | + |---------------| <-- StartAddress3 + | part 3 | Length3 < 2M + |---------------| + + @param[in] PhysicalAddress Start physical adress + @param[in] PhysicalEnd End physical address + + @retval EFI_SUCCESS Accept memory successfully + @retval Others Other errors as indicated +**/ +STATIC +EFI_STATUS +EFIAPI +BspAcceptMemoryResourceRange ( + IN EFI_PHYSICAL_ADDRESS PhysicalAddress, + IN EFI_PHYSICAL_ADDRESS PhysicalEnd + ) +{ + EFI_STATUS Status; + UINT32 AcceptPageSize; + UINT64 StartAddress1; + UINT64 StartAddress2; + UINT64 StartAddress3; + UINT64 TotalLength; + UINT64 Length1; + UINT64 Length2; + UINT64 Length3; + UINT64 Pages; + + AcceptPageSize =3D FixedPcdGet32 (PcdTdxAcceptPageSize); + TotalLength =3D PhysicalEnd - PhysicalAddress; + StartAddress1 =3D 0; + StartAddress2 =3D 0; + StartAddress3 =3D 0; + Length1 =3D 0; + Length2 =3D 0; + Length3 =3D 0; + + if (TotalLength =3D=3D 0) { + return EFI_SUCCESS; + } + + if (ALIGN_VALUE (PhysicalAddress, SIZE_2MB) !=3D PhysicalAddress) { + StartAddress1 =3D PhysicalAddress; + Length1 =3D ALIGN_VALUE (PhysicalAddress, SIZE_2MB) - PhysicalAd= dress; + if (Length1 >=3D TotalLength) { + Length1 =3D TotalLength; + } + + PhysicalAddress +=3D Length1; + TotalLength -=3D Length1; + } + + if (TotalLength > SIZE_2MB) { + StartAddress2 =3D PhysicalAddress; + Length2 =3D TotalLength & ~(UINT64)ALIGNED_2MB_MASK; + PhysicalAddress +=3D Length2; + TotalLength -=3D Length2; + } + + if (TotalLength) { + StartAddress3 =3D PhysicalAddress; + Length3 =3D TotalLength; + } + + Status =3D EFI_SUCCESS; + if (Length1 > 0) { + Pages =3D Length1 / SIZE_4KB; + Status =3D TdAcceptPages (StartAddress1, Pages, SIZE_4KB); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (Length2 > 0) { + Pages =3D Length2 / AcceptPageSize; + Status =3D TdAcceptPages (StartAddress2, Pages, AcceptPageSize); + if (EFI_ERROR (Status)) { + return Status; + } + } + + if (Length3 > 0) { + Pages =3D Length3 / SIZE_4KB; + Status =3D TdAcceptPages (StartAddress3, Pages, SIZE_4KB); + ASSERT (!EFI_ERROR (Status)); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return Status; +} + +/** + * This function is called by BSP and APs to accept memory. + * Note: + * The input PhysicalStart/PhysicalEnd indicates the whole memory region + * to be accepted. BSP or AP only accepts one piece in the whole memory re= gion. + * + * @param CpuIndex vCPU index + * @param CpusNum Total vCPU number of a Tdx guest + * @param PhysicalStart Start address of a memory region which is to be = accepted + * @param PhysicalEnd End address of a memory region which is to be ac= cepted + * + * @retval EFI_SUCCESS Successfully accept the memory + * @retval Other Other errors as indicated + */ +STATIC +EFI_STATUS +EFIAPI +BspApAcceptMemoryResourceRange ( + UINT32 CpuIndex, + UINT32 CpusNum, + EFI_PHYSICAL_ADDRESS PhysicalStart, + EFI_PHYSICAL_ADDRESS PhysicalEnd + ) +{ + UINT64 Status; + UINT64 Pages; + UINT64 Stride; + UINT64 AcceptPageSize; + EFI_PHYSICAL_ADDRESS PhysicalAddress; + + AcceptPageSize =3D (UINT64)(UINTN)FixedPcdGet32 (PcdTdxAcceptPageSize); + + Status =3D EFI_SUCCESS; + Stride =3D (UINTN)CpusNum * ACCEPT_CHUNK_SIZE; + PhysicalAddress =3D PhysicalStart + ACCEPT_CHUNK_SIZE * (UINTN)CpuIndex; + + while (!EFI_ERROR (Status) && PhysicalAddress < PhysicalEnd) { + Pages =3D MIN (ACCEPT_CHUNK_SIZE, PhysicalEnd - PhysicalAddress) / Ac= ceptPageSize; + Status =3D TdAcceptPages (PhysicalAddress, Pages, (UINT32)(UINTN)Accep= tPageSize); + ASSERT (!EFI_ERROR (Status)); + PhysicalAddress +=3D Stride; + } + + return EFI_SUCCESS; +} + +/** + * This function is called by APs to accept memory. + * + * @param CpuIndex vCPU index of an AP + * @param PhysicalStart Start address of a memory region which is to be = accepted + * @param PhysicalEnd End address of a memory region which is to be ac= cepted + * + * @retval EFI_SUCCESS Successfully accept the memory + * @retval Others Other errors as indicated + */ +STATIC +EFI_STATUS +EFIAPI +ApAcceptMemoryResourceRange ( + UINT32 CpuIndex, + EFI_PHYSICAL_ADDRESS PhysicalStart, + EFI_PHYSICAL_ADDRESS PhysicalEnd + ) +{ + UINT64 Status; + TD_RETURN_DATA TdReturnData; + + Status =3D TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData); + if (Status !=3D TDX_EXIT_REASON_SUCCESS) { + ASSERT (FALSE); + return EFI_ABORTED; + } + + if ((CpuIndex =3D=3D 0) || (CpuIndex >=3D TdReturnData.TdInfo.NumVcpus))= { + ASSERT (FALSE); + return EFI_ABORTED; + } + + return BspApAcceptMemoryResourceRange (CpuIndex, TdReturnData.TdInfo.Num= Vcpus, PhysicalStart, PhysicalEnd); +} + +/** + * This function is called by BSP. It coordinates BSP/APs to accept memory= together. + * + * @param PhysicalStart Start address of a memory region which is to b= e accepted + * @param PhysicalEnd End address of a memory region which is to be = accepted + * @param APsStackAddress APs stack address + * @param CpusNum Total vCPU number of the Tdx guest + * + * @retval EFI_SUCCESS Successfully accept the memory + * @retval Others Other errors as indicated + */ +STATIC +EFI_STATUS +EFIAPI +MpAcceptMemoryResourceRange ( + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN EFI_PHYSICAL_ADDRESS PhysicalEnd, + IN OUT EFI_PHYSICAL_ADDRESS APsStackAddress, + IN UINT32 CpusNum + ) +{ + UINT64 Length; + EFI_STATUS Status; + + Length =3D PhysicalEnd - PhysicalStart; + + DEBUG ((DEBUG_INFO, "MpAccept : 0x%llx - 0x%llx (0x%llx)\n", PhysicalSta= rt, PhysicalEnd, Length)); + + if (Length =3D=3D 0) { + return EFI_SUCCESS; + } + + // + // The start address is not 2M aligned. BSP first accept the part which = is not 2M aligned. + // + if (ALIGN_VALUE (PhysicalStart, SIZE_2MB) !=3D PhysicalStart) { + Length =3D MIN (ALIGN_VALUE (PhysicalStart, SIZE_2MB) - PhysicalStart,= Length); + Status =3D BspAcceptMemoryResourceRange (PhysicalStart, PhysicalStart = + Length); + ASSERT (Status =3D=3D EFI_SUCCESS); + + PhysicalStart +=3D Length; + Length =3D PhysicalEnd - PhysicalStart; + } + + if (Length =3D=3D 0) { + return EFI_SUCCESS; + } + + // + // BSP will accept the memory by itself if the memory is not big enough = compared with a chunk. + // + if (Length <=3D ACCEPT_CHUNK_SIZE) { + return BspAcceptMemoryResourceRange (PhysicalStart, PhysicalEnd); + } + + // + // Now APs are asked to accept the memory together. + // + MpSerializeStart (); + + MpSendWakeupCommand ( + MpProtectedModeWakeupCommandAcceptPages, + (UINT64)(UINTN)ApAcceptMemoryResourceRange, + PhysicalStart, + PhysicalEnd, + APsStackAddress, + AP_STACK_SIZE + ); + + // + // Now BSP does its job. + // + BspApAcceptMemoryResourceRange (0, CpusNum, PhysicalStart, PhysicalEnd); + + MpSerializeEnd (); + + return EFI_SUCCESS; +} + +/** + BSP accept a small piece of memory which will be used as APs stack. + + @param[in] VmmHobList The Hoblist pass the firmware + @param[in] APsStackSize APs stack size + @param[out] PhysicalAddressEnd The physical end address of accepted m= emory in phase-1 + + @retval EFI_SUCCESS Process the HobList successfully + @retval Others Other errors as indicated +**/ +STATIC +EFI_STATUS +EFIAPI +AcceptMemoryForAPsStack ( + IN CONST VOID *VmmHobList, + IN UINT32 APsStackSize, + OUT EFI_PHYSICAL_ADDRESS *PhysicalAddressEnd + ) +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + EFI_PHYSICAL_ADDRESS PhysicalEnd; + EFI_PHYSICAL_ADDRESS PhysicalStart; + UINT64 ResourceLength; + BOOLEAN MemoryRegionFound; + + ASSERT (VmmHobList !=3D NULL); + + Status =3D EFI_SUCCESS; + Hob.Raw =3D (UINT8 *)VmmHobList; + MemoryRegionFound =3D FALSE; + + DEBUG ((DEBUG_INFO, "AcceptMemoryForAPsStack with APsStackSize=3D0x%x\n"= , APsStackSize)); + + // + // Parse the HOB list until end of list or matching type is found. + // + while (!END_OF_HOB_LIST (Hob) && !MemoryRegionFound) { + if (Hob.Header->HobType =3D=3D EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + DEBUG ((DEBUG_INFO, "\nResourceType: 0x%x\n", Hob.ResourceDescriptor= ->ResourceType)); + + if (Hob.ResourceDescriptor->ResourceType =3D=3D BZ3937_EFI_RESOURCE_= MEMORY_UNACCEPTED) { + ResourceLength =3D Hob.ResourceDescriptor->ResourceLength; + PhysicalStart =3D Hob.ResourceDescriptor->PhysicalStart; + PhysicalEnd =3D PhysicalStart + ResourceLength; + + DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescr= iptor->ResourceAttribute)); + DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", PhysicalStart)); + DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", ResourceLength)); + DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owne= r)); + + if (ResourceLength >=3D APsStackSize) { + MemoryRegionFound =3D TRUE; + if (ResourceLength > ACCEPT_CHUNK_SIZE) { + PhysicalEnd =3D Hob.ResourceDescriptor->PhysicalStart + APsSta= ckSize; + } + } + + Status =3D BspAcceptMemoryResourceRange ( + Hob.ResourceDescriptor->PhysicalStart, + PhysicalEnd + ); + if (EFI_ERROR (Status)) { + break; + } + } + } + + Hob.Raw =3D GET_NEXT_HOB (Hob); + } + + ASSERT (MemoryRegionFound); + *PhysicalAddressEnd =3D PhysicalEnd; + + return Status; +} + +/** + BSP and APs work togeter to accept memory which is under the address of = 4G. + + @param[in] VmmHobList The Hoblist pass the firmware + @param[in] CpusNum Number of vCPUs + @param[in] APsStackStartAddres Start address of APs stack + @param[in] PhysicalAddressStart Start physical address which to be accep= ted + + @retval EFI_SUCCESS Process the HobList successfully + @retval Others Other errors as indicated +**/ +STATIC +EFI_STATUS +EFIAPI +AcceptMemory ( + IN CONST VOID *VmmHobList, + IN UINT32 CpusNum, + IN EFI_PHYSICAL_ADDRESS APsStackStartAddress, + IN EFI_PHYSICAL_ADDRESS PhysicalAddressStart + ) +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + EFI_PHYSICAL_ADDRESS PhysicalStart; + EFI_PHYSICAL_ADDRESS PhysicalEnd; + EFI_PHYSICAL_ADDRESS AcceptMemoryEndAddress; + + Status =3D EFI_SUCCESS; + AcceptMemoryEndAddress =3D BASE_4GB; + + ASSERT (VmmHobList !=3D NULL); + Hob.Raw =3D (UINT8 *)VmmHobList; + + DEBUG ((DEBUG_INFO, "AcceptMemory under address of 4G\n")); + + // + // Parse the HOB list until end of list or matching type is found. + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType =3D=3D EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + if (Hob.ResourceDescriptor->ResourceType =3D=3D BZ3937_EFI_RESOURCE_= MEMORY_UNACCEPTED) { + PhysicalStart =3D Hob.ResourceDescriptor->PhysicalStart; + PhysicalEnd =3D PhysicalStart + Hob.ResourceDescriptor->Resource= Length; + + if (PhysicalEnd <=3D PhysicalAddressStart) { + // this memory region has been accepted. Skipped it. + Hob.Raw =3D GET_NEXT_HOB (Hob); + continue; + } + + if (PhysicalStart >=3D AcceptMemoryEndAddress) { + // this memory region is not to be accepted. And we're done. + break; + } + + if (PhysicalStart >=3D PhysicalAddressStart) { + // this memory region has not been acceted. + } else if ((PhysicalStart < PhysicalAddressStart) && (PhysicalEnd = > PhysicalAddressStart)) { + // part of the memory region has been accepted. + PhysicalStart =3D PhysicalAddressStart; + } + + // then compare the PhysicalEnd with AcceptMemoryEndAddress + if (PhysicalEnd >=3D AcceptMemoryEndAddress) { + PhysicalEnd =3D AcceptMemoryEndAddress; + } + + DEBUG ((DEBUG_INFO, "ResourceAttribute: 0x%x\n", Hob.ResourceDescr= iptor->ResourceAttribute)); + DEBUG ((DEBUG_INFO, "PhysicalStart: 0x%llx\n", Hob.ResourceDescrip= tor->PhysicalStart)); + DEBUG ((DEBUG_INFO, "ResourceLength: 0x%llx\n", Hob.ResourceDescri= ptor->ResourceLength)); + DEBUG ((DEBUG_INFO, "Owner: %g\n\n", &Hob.ResourceDescriptor->Owne= r)); + + // Now we're ready to accept memory [PhysicalStart, PhysicalEnd) + if (CpusNum =3D=3D 1) { + Status =3D BspAcceptMemoryResourceRange (PhysicalStart, Physical= End); + } else { + Status =3D MpAcceptMemoryResourceRange ( + PhysicalStart, + PhysicalEnd, + APsStackStartAddress, + CpusNum + ); + } + + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + break; + } + + if (PhysicalEnd =3D=3D AcceptMemoryEndAddress) { + break; + } + } + } + + Hob.Raw =3D GET_NEXT_HOB (Hob); + } + + return Status; +} + +/** + Check the value whether in the valid list. + + @param[in] Value A value + @param[in] ValidList A pointer to valid list + @param[in] ValidListLength Length of valid list + + @retval TRUE The value is in valid list. + @retval FALSE The value is not in valid list. + +**/ +STATIC +BOOLEAN +EFIAPI +IsInValidList ( + IN UINT32 Value, + IN UINT32 *ValidList, + IN UINT32 ValidListLength + ) +{ + UINT32 index; + + if (ValidList =3D=3D NULL) { + return FALSE; + } + + for (index =3D 0; index < ValidListLength; index++) { + if (ValidList[index] =3D=3D Value) { + return TRUE; + } + } + + return FALSE; +} + +/** + Check the integrity of VMM Hob List. + + @param[in] VmmHobList A pointer to Hob List + + @retval TRUE The Hob List is valid. + @retval FALSE The Hob List is invalid. + +**/ +STATIC +BOOLEAN +EFIAPI +ValidateHobList ( + IN CONST VOID *VmmHobList + ) +{ + EFI_PEI_HOB_POINTERS Hob; + UINT32 EFI_BOOT_MODE_LIST[] =3D { + BOOT_WITH_FULL_CONFIGURATION, + BOOT_WITH_MINIMAL_CONFIGURATION, + BOOT_ASSUMING_NO_CONFIGURATION_CHANGES, + BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS, + BOOT_WITH_DEFAULT_SETTINGS, + BOOT_ON_S4_RESUME, + BOOT_ON_S5_RESUME, + BOOT_WITH_MFG_MODE_SETTINGS, + BOOT_ON_S2_RESUME, + BOOT_ON_S3_RESUME, + BOOT_ON_FLASH_UPDATE, + BOOT_IN_RECOVERY_MODE + }; + + UINT32 EFI_RESOURCE_TYPE_LIST[] =3D { + EFI_RESOURCE_SYSTEM_MEMORY, + EFI_RESOURCE_MEMORY_MAPPED_IO, + EFI_RESOURCE_IO, + EFI_RESOURCE_FIRMWARE_DEVICE, + EFI_RESOURCE_MEMORY_MAPPED_IO_PORT, + EFI_RESOURCE_MEMORY_RESERVED, + EFI_RESOURCE_IO_RESERVED, + BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED + }; + + if (VmmHobList =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "HOB: HOB data pointer is NULL\n")); + return FALSE; + } + + Hob.Raw =3D (UINT8 *)VmmHobList; + + // + // Parse the HOB list until end of list or matching type is found. + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->Reserved !=3D (UINT32)0) { + DEBUG ((DEBUG_ERROR, "HOB: Hob header Reserved filed should be zero\= n")); + return FALSE; + } + + if (Hob.Header->HobLength =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "HOB: Hob header LEANGTH should not be zero\n")= ); + return FALSE; + } + + switch (Hob.Header->HobType) { + case EFI_HOB_TYPE_HANDOFF: + if (Hob.Header->HobLength !=3D sizeof (EFI_HOB_HANDOFF_INFO_TABLE)= ) { + DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding= hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_HANDOFF)); + return FALSE; + } + + if (IsInValidList (Hob.HandoffInformationTable->BootMode, EFI_BOOT= _MODE_LIST, ARRAY_SIZE (EFI_BOOT_MODE_LIST)) =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "HOB: Unknow HandoffInformationTable BootMo= de type. Type: 0x%08x\n", Hob.HandoffInformationTable->BootMode)); + return FALSE; + } + + if ((Hob.HandoffInformationTable->EfiFreeMemoryTop % 4096) !=3D 0)= { + DEBUG ((DEBUG_ERROR, "HOB: HandoffInformationTable EfiFreeMemory= Top address must be 4-KB aligned to meet page restrictions of UEFI.\ + Address: 0x%016lx\n", Hob.HandoffInformatio= nTable->EfiFreeMemoryTop)); + return FALSE; + } + + break; + + case EFI_HOB_TYPE_RESOURCE_DESCRIPTOR: + if (Hob.Header->HobLength !=3D sizeof (EFI_HOB_RESOURCE_DESCRIPTOR= )) { + DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding= hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_RESOURCE_DESCRIPTOR)); + return FALSE; + } + + if (IsInValidList (Hob.ResourceDescriptor->ResourceType, EFI_RESOU= RCE_TYPE_LIST, ARRAY_SIZE (EFI_RESOURCE_TYPE_LIST)) =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceTyp= e type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceType)); + return FALSE; + } + + if ((Hob.ResourceDescriptor->ResourceAttribute & (~(EFI_RESOURCE_A= TTRIBUTE_PRESENT | + EFI_RESOURCE_A= TTRIBUTE_INITIALIZED | + EFI_RESOURCE_A= TTRIBUTE_TESTED | + EFI_RESOURCE_A= TTRIBUTE_READ_PROTECTED | + EFI_RESOURCE_A= TTRIBUTE_WRITE_PROTECTED | + EFI_RESOURCE_A= TTRIBUTE_EXECUTION_PROTECTED | + EFI_RESOURCE_A= TTRIBUTE_PERSISTENT | + EFI_RESOURCE_A= TTRIBUTE_SINGLE_BIT_ECC | + EFI_RESOURCE_A= TTRIBUTE_MULTIPLE_BIT_ECC | + EFI_RESOURCE_A= TTRIBUTE_ECC_RESERVED_1 | + EFI_RESOURCE_A= TTRIBUTE_ECC_RESERVED_2 | + EFI_RESOURCE_A= TTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_A= TTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_A= TTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_A= TTRIBUTE_WRITE_BACK_CACHEABLE | + EFI_RESOURCE_A= TTRIBUTE_16_BIT_IO | + EFI_RESOURCE_A= TTRIBUTE_32_BIT_IO | + EFI_RESOURCE_A= TTRIBUTE_64_BIT_IO | + EFI_RESOURCE_A= TTRIBUTE_UNCACHED_EXPORTED | + EFI_RESOURCE_A= TTRIBUTE_READ_PROTECTABLE | + EFI_RESOURCE_A= TTRIBUTE_WRITE_PROTECTABLE | + EFI_RESOURCE_A= TTRIBUTE_EXECUTION_PROTECTABLE | + EFI_RESOURCE_A= TTRIBUTE_PERSISTABLE | + EFI_RESOURCE_A= TTRIBUTE_READ_ONLY_PROTECTED | + EFI_RESOURCE_A= TTRIBUTE_READ_ONLY_PROTECTABLE | + EFI_RESOURCE_A= TTRIBUTE_MORE_RELIABLE))) !=3D 0) + { + DEBUG ((DEBUG_ERROR, "HOB: Unknow ResourceDescriptor ResourceAtt= ribute type. Type: 0x%08x\n", Hob.ResourceDescriptor->ResourceAttribute)); + return FALSE; + } + + break; + + // EFI_HOB_GUID_TYPE is variable length data, so skip check + case EFI_HOB_TYPE_GUID_EXTENSION: + break; + + case EFI_HOB_TYPE_FV: + if (Hob.Header->HobLength !=3D sizeof (EFI_HOB_FIRMWARE_VOLUME)) { + DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding= hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV)); + return FALSE; + } + + break; + + case EFI_HOB_TYPE_FV2: + if (Hob.Header->HobLength !=3D sizeof (EFI_HOB_FIRMWARE_VOLUME2)) { + DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding= hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV2)); + return FALSE; + } + + break; + + case EFI_HOB_TYPE_FV3: + if (Hob.Header->HobLength !=3D sizeof (EFI_HOB_FIRMWARE_VOLUME3)) { + DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding= hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_FV3)); + return FALSE; + } + + break; + + case EFI_HOB_TYPE_CPU: + if (Hob.Header->HobLength !=3D sizeof (EFI_HOB_CPU)) { + DEBUG ((DEBUG_ERROR, "HOB: Hob length is not equal corresponding= hob structure. Type: 0x%04x\n", EFI_HOB_TYPE_CPU)); + return FALSE; + } + + for (UINT32 index =3D 0; index < 6; index++) { + if (Hob.Cpu->Reserved[index] !=3D 0) { + DEBUG ((DEBUG_ERROR, "HOB: Cpu Reserved field will always be s= et to zero.\n")); + return FALSE; + } + } + + break; + + default: + DEBUG ((DEBUG_ERROR, "HOB: Hob type is not know. Type: 0x%04x\n", = Hob.Header->HobType)); + return FALSE; + } + + // Get next HOB + Hob.Raw =3D (UINT8 *)(Hob.Raw + Hob.Header->HobLength); + } + + return TRUE; +} + +/** + Processing the incoming HobList for the TDX + + Firmware must parse list, and accept the pages of memory before their ca= n be + use by the guest. + + @param[in] VmmHobList The Hoblist pass the firmware + + @retval EFI_SUCCESS Process the HobList successfully + @retval Others Other errors as indicated + +**/ +STATIC +EFI_STATUS +EFIAPI +ProcessHobList ( + IN CONST VOID *VmmHobList + ) +{ + EFI_STATUS Status; + UINT32 CpusNum; + EFI_PHYSICAL_ADDRESS PhysicalEnd; + EFI_PHYSICAL_ADDRESS APsStackStartAddress; + + CpusNum =3D GetCpusNum (); + + // + // If there are mutli-vCPU in a TDX guest, accept memory is split into 2= phases. + // Phase-1 accepts a small piece of memory by BSP. This piece of memory + // is used to setup AP's stack. + // After that phase-2 accepts a big piece of memory by BSP/APs. + // + // TDVF supports 4K and 2M accept-page-size. The memory which can be acc= peted + // in 2M accept-page-size must be 2M aligned and multiple 2M. So we align + // APsStackSize to 2M size aligned. + // + if (CpusNum > 1) { + Status =3D AcceptMemoryForAPsStack (VmmHobList, APS_STACK_SIZE (CpusNu= m), &PhysicalEnd); + ASSERT (Status =3D=3D EFI_SUCCESS); + APsStackStartAddress =3D PhysicalEnd - APS_STACK_SIZE (CpusNum); + } else { + PhysicalEnd =3D 0; + APsStackStartAddress =3D 0; + } + + Status =3D AcceptMemory (VmmHobList, CpusNum, APsStackStartAddress, Phys= icalEnd); + ASSERT (Status =3D=3D EFI_SUCCESS); + + return Status; +} + +/** + In Tdx guest, some information need to be passed from host VMM to guest + firmware. For example, the memory resource, etc. These information are + prepared by host VMM and put in TdHob which is described in TdxMetadata. + TDVF processes the TdHob to accept memories. + + @retval EFI_SUCCESS Successfully process the TdHob + @retval Others Other error as indicated +**/ +EFI_STATUS +EFIAPI +TdxHelperProcessTdHob ( + VOID + ) +{ + EFI_STATUS Status; + VOID *TdHob; + TD_RETURN_DATA TdReturnData; + + TdHob =3D (VOID *)(UINTN)FixedPcdGet32 (PcdOvmfSecGhcbBase); + Status =3D TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG (( + DEBUG_INFO, + "Intel Tdx Started with (GPAW: %d, Cpus: %d)\n", + TdReturnData.TdInfo.Gpaw, + TdReturnData.TdInfo.NumVcpus + )); + + // + // Validate HobList + // + if (ValidateHobList (TdHob) =3D=3D FALSE) { + return EFI_INVALID_PARAMETER; + } + + // + // Process Hoblist to accept memory + // + Status =3D ProcessHobList (TdHob); + + return Status; +} + +/** + In Tdx guest, TdHob is passed from host VMM to guest firmware and it con= tains + the information of the memory resource. From the security perspective be= fore + it is consumed, it should be measured and extended. + * + * @retval EFI_SUCCESS Successfully measure the TdHob + * @retval Others Other error as indicated + */ +EFI_STATUS +EFIAPI +TdxHelperMeasureTdHob ( + VOID + ) +{ + return EFI_UNSUPPORTED; +} + +/** + * In Tdx guest, Configuration FV (CFV) is treated as external input becau= se it + * may contain the data provided by VMM. From the sucurity perspective Cfv= image + * should be measured before it is consumed. + * + * @retval EFI_SUCCESS Successfully measure the CFV image + * @retval Others Other error as indicated + */ +EFI_STATUS +EFIAPI +TdxHelperMeasureCfvImage ( + VOID + ) +{ + return EFI_UNSUPPORTED; +} + +/** +/** + Build the GuidHob for tdx measurements which were done in SEC phase. + The measurement values are stored in WorkArea. + + @retval EFI_SUCCESS The GuidHob is built successfully + @retval Others Other errors as indicated +**/ +EFI_STATUS +EFIAPI +TdxHelperBuildGuidHobForTdxMeasurement ( + VOID + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf b/OvmfPkg/In= telTdx/TdxHelperLib/SecTdxHelperLib.inf new file mode 100644 index 000000000000..3c6b96f7759a --- /dev/null +++ b/OvmfPkg/IntelTdx/TdxHelperLib/SecTdxHelperLib.inf @@ -0,0 +1,52 @@ +## @file +# TdxHelperLib SEC instance +# +# This module provides Tdx helper functions in SEC phase. +# Copyright (c) 2021 - 2023, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D SecTdxHelperLib + FILE_GUID =3D ba69ac6b-0c59-4472-899d-b684590ec1e9 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D TdxHelperLib|SEC + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D X64 +# + +[Sources] + SecTdxHelper.c + +[Packages] + CryptoPkg/CryptoPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + OvmfPkg/OvmfPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseCryptLib + DebugLib + HobLib + PcdLib + TdxMailboxLib + TdxLib + +[FixedPcd] + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase + gUefiOvmfPkgTokenSpaceGuid.PcdTdxAcceptPageSize + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecGhcbBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFlashNvStorageVariableBase + gUefiOvmfPkgTokenSpaceGuid.PcdCfvRawDataSize + +[Guids] + gCcEventEntryHobGuid --=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 (#98848): https://edk2.groups.io/g/devel/message/98848 Mute This Topic: https://groups.io/mt/96370897/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-