From c3001cb744f7b2e5d91a5803814f50e0607d592d Mon Sep 17 00:00:00 2001 From: Min Xu Date: Fri, 16 Jul 2021 16:25:50 +0800 Subject: [PATCH] MdePkg: Add TdxLib to wrap Tdx operations RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 TdxLib is created with functions to perform the related Tdx operation. This includes functions for: - TdAcceptPages : Accept pending private pages and initialize the pages to all-0 using the TD ephemeral private key. - TdExtendRtmr : Extend measurement to one of the RTMR registers. - TdSharedPageMask: Get the Td guest shared page mask which indicates it is a Shared or Private page. - TdMaxVCpuNum : Get the maximum number of virtual CPUs. - TdVCpuNum : Get the number of virtual CPUs. Cc: Michael D Kinney Cc: Liming Gao Cc: Zhiguang Liu Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Cc: Gerd Hoffmann Acked-by: Gerd Hoffmann Reviewed-by: Liming Gao Reviewed-by: Jiewen Yao Signed-off-by: Min Xu --- MdePkg/Include/Library/TdxLib.h | 92 ++++++++++++++ MdePkg/Library/TdxLib/AcceptPages.c | 181 ++++++++++++++++++++++++++++ MdePkg/Library/TdxLib/Rtmr.c | 84 +++++++++++++ MdePkg/Library/TdxLib/TdInfo.c | 115 ++++++++++++++++++ MdePkg/Library/TdxLib/TdxLib.inf | 37 ++++++ MdePkg/Library/TdxLib/TdxLibNull.c | 106 ++++++++++++++++ MdePkg/MdePkg.dec | 3 + MdePkg/MdePkg.dsc | 1 + 8 files changed, 619 insertions(+) create mode 100644 MdePkg/Include/Library/TdxLib.h create mode 100644 MdePkg/Library/TdxLib/AcceptPages.c create mode 100644 MdePkg/Library/TdxLib/Rtmr.c create mode 100644 MdePkg/Library/TdxLib/TdInfo.c create mode 100644 MdePkg/Library/TdxLib/TdxLib.inf create mode 100644 MdePkg/Library/TdxLib/TdxLibNull.c diff --git a/MdePkg/Include/Library/TdxLib.h b/MdePkg/Include/Library/TdxLib.h new file mode 100644 index 0000000000..55f0436cca --- /dev/null +++ b/MdePkg/Include/Library/TdxLib.h @@ -0,0 +1,92 @@ +/** @file + TdxLib definitions + + Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef TDX_LIB_H_ +#define TDX_LIB_H_ + +/** + This function accepts a pending private page, and initialize the page to + all-0 using the TD ephemeral private key. + + @param[in] StartAddress Guest physical address of the private page + to accept. [63:52] and [11:0] must be 0. + @param[in] NumberOfPages Number of the pages to be accepted. + @param[in] PageSize GPA page size. Accept 2M/4K page size. + + @return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +TdAcceptPages ( + IN UINT64 StartAddress, + IN UINT64 NumberOfPages, + IN UINT32 PageSize + ); + +/** + This function extends one of the RTMR measurement register + in TDCS with the provided extension data in memory. + RTMR extending supports SHA384 which length is 48 bytes. + + @param[in] Data Point to the data to be extended + @param[in] DataLen Length of the data. Must be 48 + @param[in] Index RTMR index + + @return EFI_SUCCESS + @return EFI_INVALID_PARAMETER + @return EFI_DEVICE_ERROR + +**/ +EFI_STATUS +EFIAPI +TdExtendRtmr ( + IN UINT32 *Data, + IN UINT32 DataLen, + IN UINT8 Index + ); + +/** + This function gets the Td guest shared page mask. + + The guest indicates if a page is shared using the Guest Physical Address + (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47. + If the GPAW is 52, the S-bit is bit-51. + + @return Shared page bit mask +**/ +UINT64 +EFIAPI +TdSharedPageMask ( + VOID + ); + +/** + This function gets the maximum number of Virtual CPUs that are usable for + Td Guest. + + @return maximum Virtual CPUs number +**/ +UINT32 +EFIAPI +TdMaxVCpuNum ( + VOID + ); + +/** + This function gets the number of Virtual CPUs that are usable for Td + Guest. + + @return Virtual CPUs number +**/ +UINT32 +EFIAPI +TdVCpuNum ( + VOID + ); + +#endif diff --git a/MdePkg/Library/TdxLib/AcceptPages.c b/MdePkg/Library/TdxLib/AcceptPages.c new file mode 100644 index 0000000000..3a2182e95f --- /dev/null +++ b/MdePkg/Library/TdxLib/AcceptPages.c @@ -0,0 +1,181 @@ +/** @file + + Unaccepted memory is a special type of private memory. In Td guest + TDCALL [TDG.MEM.PAGE.ACCEPT] is invoked to accept the unaccepted + memory before use it. + + Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +UINT64 mNumberOfDuplicatedAcceptedPages; + +#define TDX_ACCEPTPAGE_MAX_RETRIED 3 + +// PageSize is mapped to PageLevel like below: +// 4KB - 0, 2MB - 1 +UINT32 mTdxAcceptPageLevelMap[2] = { + SIZE_4KB, + SIZE_2MB +}; + +#define INVALID_ACCEPT_PAGELEVEL ARRAY_SIZE(mTdxAcceptPageLevelMap) + +/** + This function gets the PageLevel according to the input page size. + + @param[in] PageSize Page size + + @return UINT32 The mapped page level +**/ +UINT32 +GetGpaPageLevel ( + UINT32 PageSize + ) +{ + UINT32 Index; + + for (Index = 0; Index < ARRAY_SIZE (mTdxAcceptPageLevelMap); Index++) { + if (mTdxAcceptPageLevelMap[Index] == PageSize) { + break; + } + } + + return Index; +} + +/** + This function accept a pending private page, and initialize the page to + all-0 using the TD ephemeral private key. + + Sometimes TDCALL [TDG.MEM.PAGE.ACCEPT] may return + TDX_EXIT_REASON_PAGE_SIZE_MISMATCH. It indicates the input PageLevel is + not workable. In this case we need to try to fallback to a smaller + PageLevel if possible. + + @param[in] StartAddress Guest physical address of the private + page to accept. [63:52] and [11:0] must be 0. + @param[in] NumberOfPages Number of the pages to be accepted. + @param[in] PageSize GPA page size. Only accept 2M/4K size. + + @return EFI_SUCCESS Accept successfully + @return others Indicate other errors +**/ +EFI_STATUS +EFIAPI +TdAcceptPages ( + IN UINT64 StartAddress, + IN UINT64 NumberOfPages, + IN UINT32 PageSize + ) +{ + EFI_STATUS Status; + UINT64 Address; + UINT64 TdxStatus; + UINT64 Index; + UINT32 GpaPageLevel; + UINT32 PageSize2; + UINTN Retried; + + Retried = 0; + + if ((StartAddress & ~0xFFFFFFFFFF000ULL) != 0) { + ASSERT (FALSE); + DEBUG ((DEBUG_ERROR, "Accept page address(0x%llx) is not valid. [63:52] and [11:0] must be 0\n", StartAddress)); + return EFI_INVALID_PARAMETER; + } + + Address = StartAddress; + + GpaPageLevel = GetGpaPageLevel (PageSize); + if (GpaPageLevel == INVALID_ACCEPT_PAGELEVEL) { + ASSERT (FALSE); + DEBUG ((DEBUG_ERROR, "Accept page size must be 4K/2M. Invalid page size - 0x%llx\n", PageSize)); + return EFI_INVALID_PARAMETER; + } + + Status = EFI_SUCCESS; + for (Index = 0; Index < NumberOfPages; Index++) { + Retried = 0; + +DoAcceptPage: + TdxStatus = TdCall (TDCALL_TDACCEPTPAGE, Address | GpaPageLevel, 0, 0, 0); + if (TdxStatus != TDX_EXIT_REASON_SUCCESS) { + if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_PAGE_ALREADY_ACCEPTED) { + // + // Already accepted + // + mNumberOfDuplicatedAcceptedPages++; + DEBUG ((DEBUG_WARN, "Page at Address (0x%llx) has already been accepted. - %d\n", Address, mNumberOfDuplicatedAcceptedPages)); + } else if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_PAGE_SIZE_MISMATCH) { + // + // GpaPageLevel is mismatch, fall back to a smaller GpaPageLevel if possible + // + DEBUG ((DEBUG_VERBOSE, "Address %llx cannot be accepted in PageLevel of %d\n", Address, GpaPageLevel)); + + if (GpaPageLevel == 0) { + // + // Cannot fall back to smaller page level + // + DEBUG ((DEBUG_ERROR, "AcceptPage cannot fallback from PageLevel %d\n", GpaPageLevel)); + Status = EFI_INVALID_PARAMETER; + break; + } else { + // + // Fall back to a smaller page size + // + PageSize2 = mTdxAcceptPageLevelMap[GpaPageLevel - 1]; + Status = TdAcceptPages (Address, 512, PageSize2); + if (EFI_ERROR (Status)) { + break; + } + } + } else if ((TdxStatus & ~0xFFFFULL) == TDX_EXIT_REASON_OPERAND_BUSY) { + // + // Concurrent TDG.MEM.PAGE.ACCEPT is using the same Secure EPT entry + // So try it again. There is a max retried count. If Retried exceeds the max count, + // report the error and quit. + // + Retried += 1; + if (Retried > TDX_ACCEPTPAGE_MAX_RETRIED) { + DEBUG (( + DEBUG_ERROR, + "Address %llx (%d) failed to be accepted because of OPERAND_BUSY. Retried %d time.\n", + Address, + Index, + Retried + )); + Status = EFI_INVALID_PARAMETER; + break; + } else { + goto DoAcceptPage; + } + } else { + // + // Other errors + // + DEBUG (( + DEBUG_ERROR, + "Address %llx (%d) failed to be accepted. Error = 0x%llx\n", + Address, + Index, + TdxStatus + )); + Status = EFI_INVALID_PARAMETER; + break; + } + } + + Address += PageSize; + } + + return Status; +} diff --git a/MdePkg/Library/TdxLib/Rtmr.c b/MdePkg/Library/TdxLib/Rtmr.c new file mode 100644 index 0000000000..a0283966b3 --- /dev/null +++ b/MdePkg/Library/TdxLib/Rtmr.c @@ -0,0 +1,84 @@ +/** @file + + Extends one of the RTMR measurement registers in TDCS with the provided + extension data in memory. + + Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include + +#define RTMR_COUNT 4 +#define TD_EXTEND_BUFFER_LEN (64 + 48) + +UINT8 mExtendBuffer[TD_EXTEND_BUFFER_LEN]; + +/** + This function extends one of the RTMR measurement register + in TDCS with the provided extension data in memory. + RTMR extending supports SHA384 which length is 48 bytes. + + @param[in] Data Point to the data to be extended + @param[in] DataLen Length of the data. Must be 48 + @param[in] Index RTMR index + + @return EFI_SUCCESS + @return EFI_INVALID_PARAMETER + @return EFI_DEVICE_ERROR + +**/ +EFI_STATUS +EFIAPI +TdExtendRtmr ( + IN UINT32 *Data, + IN UINT32 DataLen, + IN UINT8 Index + ) +{ + EFI_STATUS Status; + UINT64 TdCallStatus; + UINT8 *ExtendBuffer; + + Status = EFI_SUCCESS; + + ASSERT (Data != NULL); + ASSERT (DataLen == SHA384_DIGEST_SIZE); + ASSERT (Index >= 0 && Index < RTMR_COUNT); + + if ((Data == NULL) || (DataLen != SHA384_DIGEST_SIZE) || (Index >= RTMR_COUNT)) { + return EFI_INVALID_PARAMETER; + } + + // TD.RTMR.EXTEND requires 64B-aligned guest physical address of + // 48B-extension data. We use ALIGN_POINTER(Pointer, 64) to get + // the 64B-aligned guest physical address. + ExtendBuffer = ALIGN_POINTER (mExtendBuffer, 64); + ASSERT (((UINTN)ExtendBuffer & 0x3f) == 0); + + ZeroMem (ExtendBuffer, SHA384_DIGEST_SIZE); + CopyMem (ExtendBuffer, Data, SHA384_DIGEST_SIZE); + + TdCallStatus = TdCall (TDCALL_TDEXTENDRTMR, (UINT64)(UINTN)ExtendBuffer, Index, 0, 0); + + if (TdCallStatus == TDX_EXIT_REASON_SUCCESS) { + Status = EFI_SUCCESS; + } else if (TdCallStatus == TDX_EXIT_REASON_OPERAND_INVALID) { + Status = EFI_INVALID_PARAMETER; + } else { + Status = EFI_DEVICE_ERROR; + } + + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Error returned from TdExtendRtmr call - 0x%lx\n", TdCallStatus)); + } + + return Status; +} diff --git a/MdePkg/Library/TdxLib/TdInfo.c b/MdePkg/Library/TdxLib/TdInfo.c new file mode 100644 index 0000000000..3c5689f1d8 --- /dev/null +++ b/MdePkg/Library/TdxLib/TdInfo.c @@ -0,0 +1,115 @@ +/** @file + + Fetch the Tdx info. + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include + +UINT64 mTdSharedPageMask = 0; +UINT32 mTdMaxVCpuNum = 0; +UINT32 mTdVCpuNum = 0; +BOOLEAN mTdDataReturned = FALSE; + +/** + This function call TDCALL_TDINFO to get the TD_RETURN_DATA. + If the TDCALL is successful, populate below variables: + - mTdSharedPageMask + - mTdMaxVCpunum + - mTdVCpuNum + - mTdDataReturned + + @return TRUE The TDCALL is successful and above variables are populated. + @return FALSE The TDCALL is failed. Above variables are not set. +**/ +BOOLEAN +GetTdInfo ( + VOID + ) +{ + UINT64 Status; + TD_RETURN_DATA TdReturnData; + UINT8 Gpaw; + + Status = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData); + if (Status == TDX_EXIT_REASON_SUCCESS) { + Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f); + mTdSharedPageMask = 1ULL << (Gpaw - 1); + mTdMaxVCpuNum = TdReturnData.TdInfo.MaxVcpus; + mTdVCpuNum = TdReturnData.TdInfo.NumVcpus; + mTdDataReturned = TRUE; + } else { + DEBUG ((DEBUG_ERROR, "Failed call TDCALL_TDINFO. %llx\n", Status)); + mTdDataReturned = FALSE; + } + + return mTdDataReturned; +} + +/** + This function gets the Td guest shared page mask. + + The guest indicates if a page is shared using the Guest Physical Address + (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47. + If the GPAW is 52, the S-bit is bit-51. + + @return Shared page bit mask +**/ +UINT64 +EFIAPI +TdSharedPageMask ( + VOID + ) +{ + if (mTdDataReturned) { + return mTdSharedPageMask; + } + + return GetTdInfo () ? mTdSharedPageMask : 0; +} + +/** + This function gets the maximum number of Virtual CPUs that are usable for + Td Guest. + + @return maximum Virtual CPUs number +**/ +UINT32 +EFIAPI +TdMaxVCpuNum ( + VOID + ) +{ + if (mTdDataReturned) { + return mTdMaxVCpuNum; + } + + return GetTdInfo () ? mTdMaxVCpuNum : 0; +} + +/** + This function gets the number of Virtual CPUs that are usable for Td + Guest. + + @return Virtual CPUs number +**/ +UINT32 +EFIAPI +TdVCpuNum ( + VOID + ) +{ + if (mTdDataReturned) { + return mTdVCpuNum; + } + + return GetTdInfo () ? mTdVCpuNum : 0; +} diff --git a/MdePkg/Library/TdxLib/TdxLib.inf b/MdePkg/Library/TdxLib/TdxLib.inf new file mode 100644 index 0000000000..442e63d079 --- /dev/null +++ b/MdePkg/Library/TdxLib/TdxLib.inf @@ -0,0 +1,37 @@ +## @file +# Tdx library +# +# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TdxLib + FILE_GUID = 032A8E0D-0C27-40C0-9CAA-23B731C1B223 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TdxLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.IA32] + TdxLibNull.c + +[Sources.X64] + AcceptPages.c + Rtmr.c + TdInfo.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib diff --git a/MdePkg/Library/TdxLib/TdxLibNull.c b/MdePkg/Library/TdxLib/TdxLibNull.c new file mode 100644 index 0000000000..29b2fe7ae7 --- /dev/null +++ b/MdePkg/Library/TdxLib/TdxLibNull.c @@ -0,0 +1,106 @@ +/** @file + + Null stub of TdxLib + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +/** + This function accepts a pending private page, and initialize the page to + all-0 using the TD ephemeral private key. + + @param[in] StartAddress Guest physical address of the private page + to accept. + @param[in] NumberOfPages Number of the pages to be accepted. + @param[in] PageSize GPA page size. Accept 1G/2M/4K page size. + + @return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +TdAcceptPages ( + IN UINT64 StartAddress, + IN UINT64 NumberOfPages, + IN UINT32 PageSize + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function extends one of the RTMR measurement register + in TDCS with the provided extension data in memory. + RTMR extending supports SHA384 which length is 48 bytes. + + @param[in] Data Point to the data to be extended + @param[in] DataLen Length of the data. Must be 48 + @param[in] Index RTMR index + + @return EFI_SUCCESS + @return EFI_INVALID_PARAMETER + @return EFI_DEVICE_ERROR + +**/ +EFI_STATUS +EFIAPI +TdExtendRtmr ( + IN UINT32 *Data, + IN UINT32 DataLen, + IN UINT8 Index + ) +{ + return EFI_UNSUPPORTED; +} + +/** + This function gets the Td guest shared page mask. + + The guest indicates if a page is shared using the Guest Physical Address + (GPA) Shared (S) bit. If the GPA Width(GPAW) is 48, the S-bit is bit-47. + If the GPAW is 52, the S-bit is bit-51. + + @return Shared page bit mask +**/ +UINT64 +EFIAPI +TdSharedPageMask ( + VOID + ) +{ + return 0; +} + +/** + This function gets the maximum number of Virtual CPUs that are usable for + Td Guest. + + @return maximum Virtual CPUs number +**/ +UINT32 +EFIAPI +TdMaxVCpuNum ( + VOID + ) +{ + return 0; +} + +/** + This function gets the number of Virtual CPUs that are usable for Td + Guest. + + @return Virtual CPUs number +**/ +UINT32 +EFIAPI +TdVCpuNum ( + VOID + ) +{ + return 0; +} diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index 59b405928b..1934c98404 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -296,6 +296,9 @@ ## @libraryclass Provides services to log the SMI handler registration. SmiHandlerProfileLib|Include/Library/SmiHandlerProfileLib.h + ## @libraryclass Provides function to support TDX processing. + TdxLib|Include/Library/TdxLib.h + [Guids] # # GUID defined in UEFI2.1/UEFI2.0/EFI1.1 diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index a94959169b..d6a7af412b 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -175,6 +175,7 @@ MdePkg/Library/SmiHandlerProfileLibNull/SmiHandlerProfileLibNull.inf MdePkg/Library/MmServicesTableLib/MmServicesTableLib.inf MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf + MdePkg/Library/TdxLib/TdxLib.inf [Components.EBC] MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf -- 2.39.2