From a92440295367d4bb7e611f476e7cd9451281cab3 Mon Sep 17 00:00:00 2001 From: gongchangsui Date: Thu, 9 Jan 2025 20:11:24 +0800 Subject: [PATCH 1/2] support virtCCA --- 0083-edk2-1219-support-virtCCA.patch | 3689 ++++++++++++++++++++++++++ edk2.spec | 9 +- 2 files changed, 3697 insertions(+), 1 deletion(-) create mode 100644 0083-edk2-1219-support-virtCCA.patch diff --git a/0083-edk2-1219-support-virtCCA.patch b/0083-edk2-1219-support-virtCCA.patch new file mode 100644 index 0000000..a0bc37d --- /dev/null +++ b/0083-edk2-1219-support-virtCCA.patch @@ -0,0 +1,3689 @@ +From b5417ff1cd804818abb18d929abb0741d001bf48 Mon Sep 17 00:00:00 2001 +From: z00570632 +Date: Thu, 9 Jan 2025 21:27:12 +0800 +Subject: [PATCH] support virtCCA + +--- + ArmPkg/Include/Library/ArmMmuLib.h | 42 +- + .../Library/ArmMmuLib/AArch64/ArmMmuLibCore.c | 20 +- + .../Include/Library/ArmCcaInitPeiLib.h | 49 ++ + ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c | 813 ++++++++++++++++++ + ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h | 66 ++ + ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c | 60 ++ + ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf | 45 + + ArmVirtPkg/ArmVirtPkg.dec | 16 +- + ArmVirtPkg/ArmVirtQemu.dsc | 81 +- + ArmVirtPkg/ArmVirtQemu.fdf | 21 +- + ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc | 13 +- + ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h | 49 ++ + ArmVirtPkg/Include/Library/ArmCcaLib.h | 114 +++ + .../Include/Library/ArmVirtMemInfoLib.h | 24 +- + .../RealmApertureManagementProtocol.h | 103 +++ + .../ArmCcaInitPeiLib/ArmCcaInitPeiLib.c | 60 ++ + .../ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf | 38 + + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c | 176 ++++ + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf | 34 + + .../ArmVirtMemoryInitPeiLib.c | 25 +- + .../ArmVirtMemoryInitPeiLib.inf | 13 +- + .../ArmVirtMonitorLib/ArmVirtMonitorLib.c | 119 +++ + .../ArmVirtMonitorLib/ArmVirtMonitorLib.inf | 36 + + .../Library/NorFlashQemuLib/NorFlashQemuLib.c | 199 +++-- + .../NorFlashQemuLib/NorFlashQemuLib.inf | 32 +- + .../QemuVirtMemInfoLib/QemuVirtMemInfoLib.c | 39 +- + .../QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf | 13 +- + .../PrePi/ArmVirtPrePiUniCoreRelocatable.inf | 13 +- + ArmVirtPkg/PrePi/PrePi.c | 15 +- + ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c | 38 + + .../QemuPlatformDxe/QemuPlatformDxe.inf | 39 + + .../RealmApertureManagementProtocolDxe.c | 593 +++++++++++++ + .../RealmApertureManagementProtocolDxe.inf | 47 + + .../Library/QemuFwCfgLib/QemuFwCfgLibMmio.c | 194 +---- + OvmfPkg/OvmfPkg.dec | 13 +- + 35 files changed, 2877 insertions(+), 375 deletions(-) + create mode 100644 ArmPlatformPkg/Include/Library/ArmCcaInitPeiLib.h + create mode 100644 ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c + create mode 100644 ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h + create mode 100644 ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c + create mode 100644 ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf + create mode 100644 ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h + create mode 100644 ArmVirtPkg/Include/Library/ArmCcaLib.h + create mode 100644 ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h + create mode 100644 ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c + create mode 100644 ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf + create mode 100644 ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c + create mode 100644 ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf + create mode 100644 ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c + create mode 100644 ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.inf + create mode 100644 ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c + create mode 100644 ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf + create mode 100644 ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c + create mode 100644 ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf + +diff --git a/ArmPkg/Include/Library/ArmMmuLib.h b/ArmPkg/Include/Library/ArmMmuLib.h +index 2ce948e8..caa158d1 100644 +--- a/ArmPkg/Include/Library/ArmMmuLib.h ++++ b/ArmPkg/Include/Library/ArmMmuLib.h +@@ -61,14 +61,34 @@ ArmReplaceLiveTranslationEntry ( + AttributeMask. + @retval EFI_OUT_OF_RESOURCES Requested attributes cannot be applied due to + lack of system resources. +- +-**/ +-EFI_STATUS +-ArmSetMemoryAttributes ( +- IN EFI_PHYSICAL_ADDRESS BaseAddress, +- IN UINT64 Length, +- IN UINT64 Attributes, +- IN UINT64 AttributeMask +- ); +- +-#endif // ARM_MMU_LIB_H_ ++ ++**/ ++EFI_STATUS ++EFIAPI ++ArmSetMemoryAttributes ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 Attributes, ++ IN UINT64 AttributeMask ++ ); ++ /** ++ Set the attributes for the memory region. ++ ++ @param[in] BaseAddress Start address of the memory region. ++ @param[in] Length Length memory region. ++ @param[in] Attributes Attributes to set for the memory region. ++ @param[in] BlockEntryMask Mask to be used for the block entry. ++ ++ @retval EFI_SUCCESS Success. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. ++ **/ ++ EFI_STATUS ++ EFIAPI ++ SetMemoryRegionAttribute ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 Attributes, ++ IN UINT64 BlockEntryMask ++ ); ++#endif // ARM_MMU_LIB_H_ +diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c +index 1e57e589..78237b7c 100644 +--- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c ++++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c +@@ -753,6 +753,20 @@ ArmMmuBaseLibConstructor ( + ArmReplaceLiveTranslationEntrySize + ); + } +- +- return RETURN_SUCCESS; +-} ++ ++ return RETURN_SUCCESS; ++} ++EFI_STATUS ++EFIAPI ++SetMemoryRegionAttribute ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 Attributes, ++ IN UINT64 BlockEntryMask ++ ) ++{ ++ DEBUG ((DEBUG_INFO, "SetMemoryRegionAttribute base 0x%llx, Length 0x%llx, set 0x%llx, clear 0x%llx\n", ++ BaseAddress, Length, Attributes, BlockEntryMask)); ++ return UpdateRegionMapping (BaseAddress, Length, Attributes, BlockEntryMask,ArmGetTTBR0BaseAddress (), ++ TRUE); ++} +\ No newline at end of file +diff --git a/ArmPlatformPkg/Include/Library/ArmCcaInitPeiLib.h b/ArmPlatformPkg/Include/Library/ArmCcaInitPeiLib.h +new file mode 100644 +index 00000000..9374fe81 +--- /dev/null ++++ b/ArmPlatformPkg/Include/Library/ArmCcaInitPeiLib.h +@@ -0,0 +1,49 @@ ++/** @file ++ Library that implements the Arm CCA helper functions. ++ ++ Copyright (c) 2022 2023, Arm Ltd. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++ ++#ifndef ARM_CCA_INIT_PEI_LIB_ ++#define ARM_CCA_INIT_PEI_LIB_ ++ ++#include ++ ++/** ++ Configure the System Memory region as Protected RAM. ++ ++ When a VMM creates a Realm, a small amount of DRAM (which contains the ++ firmware image) and the initial content is configured as Protected RAM. ++ The remaining System Memory is in the Protected Empty state. The firmware ++ must then initialise the remaining System Memory as Protected RAM before ++ it can be accessed. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaConfigureSystemMemory ( ++ VOID ++ ); ++ ++/** ++ Perform Arm CCA specific initialisations. ++ ++ @retval RETURN_SUCCESS Success or execution context is not a Realm. ++ @retval RETURN_OUT_OF_RESOURCES Out of resources. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaInitialize ( ++ VOID ++ ); ++ ++#endif // ARM_CCA_LIB_ +diff --git a/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c +new file mode 100644 +index 00000000..9b664b18 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c +@@ -0,0 +1,813 @@ ++/** @file ++ The protocol provides support to allocate, free, map and umap a DMA buffer ++ for bus master (e.g PciHostBridge). When the execution context is a Realm, ++ the DMA operations must be performed on buffers that are shared with the Host. ++ Hence the RAMP protocol is used to manage the sharing of the DMA buffers or ++ in some cases to bounce the buffers. ++ ++ Copyright (c) 2017, AMD Inc. All rights reserved.
++ Copyright (c) 2017, Intel Corporation. All rights reserved.
++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include "ArmCcaIoMmu.h" ++ ++/** List of the MAP_INFO structures that have been set up by IoMmuMap() and not ++ yet torn down by IoMmuUnmap(). The list represents the full set of mappings ++ currently in effect. ++*/ ++STATIC LIST_ENTRY mMapInfos = INITIALIZE_LIST_HEAD_VARIABLE (mMapInfos); ++ ++#if !defined (MDEPKG_NDEBUG) ++ ++/** ASCII names for EDKII_IOMMU_OPERATION constants, for debug logging. ++*/ ++STATIC CONST CHAR8 *CONST ++mBusMasterOperationName[EdkiiIoMmuOperationMaximum] = { ++ "Read", ++ "Write", ++ "CommonBuffer", ++ "Read64", ++ "Write64", ++ "CommonBuffer64" ++}; ++#endif ++ ++/** Pointer to the Realm Aperture Management Protocol ++*/ ++extern EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL *mRamp; ++ ++/** ++ Given the host address find a mapping node in the linked list. ++ ++ @param [in] HostAddress Host address. ++ ++ @return Pointer to the MapInfo node if found, otherwise NULL. ++**/ ++STATIC ++MAP_INFO * ++EFIAPI ++FindMappingByHostAddress ( ++ IN VOID *HostAddress ++ ) ++{ ++ LIST_ENTRY *Node; ++ LIST_ENTRY *NextNode; ++ MAP_INFO *MapInfo; ++ ++ for (Node = GetFirstNode (&mMapInfos); Node != &mMapInfos; Node = NextNode) { ++ NextNode = GetNextNode (&mMapInfos, Node); ++ MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG); ++ if (MapInfo->HostAddress == HostAddress) { ++ return MapInfo; ++ } ++ } ++ ++ return NULL; ++} ++ ++/** ++ Map a shared buffer ++ ++ @param [in] Operation IoMMU operation to perform. ++ @param [in] HostAddress Pointer to the Host buffer. ++ @param [in] NumberOfBytes Number of bytes to map. ++ @param [in] BbAddress Bounce buffer address. ++ @param [in] BbPages Number of pages covering the bounce buffer. ++ @param [out] Mapping Pointer to the MapInfo node. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. ++**/ ++STATIC ++EFI_STATUS ++MapSharedBuffer ( ++ IN EDKII_IOMMU_OPERATION Operation, ++ IN VOID *HostAddress, ++ IN UINTN NumberOfBytes, ++ IN EFI_PHYSICAL_ADDRESS BbAddress, ++ IN UINTN BbPages, ++ OUT MAP_INFO **Mapping ++ ) ++{ ++ EFI_STATUS Status; ++ MAP_INFO *MapInfo; ++ ++ if (BbPages != EFI_SIZE_TO_PAGES (NumberOfBytes)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // Allocate a MAP_INFO structure to remember the mapping when Unmap() is ++ // called later. ++ MapInfo = AllocateZeroPool (sizeof (MAP_INFO)); ++ if (MapInfo == NULL) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ InitializeListHead (&MapInfo->Link); ++ ++ // Initialize the MAP_INFO structure, except the NonParAddress field ++ MapInfo->Signature = MAP_INFO_SIG; ++ MapInfo->Operation = Operation; ++ MapInfo->NumberOfBytes = NumberOfBytes; ++ MapInfo->NumberOfPages = BbPages; ++ MapInfo->HostAddress = HostAddress; ++ MapInfo->BbAddress = BbAddress; ++ ++ // Open aperture here ++ Status = mRamp->OpenAperture ( ++ BbAddress, ++ BbPages, ++ &MapInfo->ApertureRef ++ ); ++ ++ if (EFI_ERROR (Status)) { ++ goto FreeMapInfo; ++ } ++ ++ // Track all MAP_INFO structures. ++ InsertHeadList (&mMapInfos, &MapInfo->Link); ++ *Mapping = MapInfo; ++ return Status; ++ ++FreeMapInfo: ++ FreePool (MapInfo); ++ return Status; ++} ++ ++/** ++ Unmap a shared buffer. ++ ++ @param [in] MapInfo Pointer to the MapInfo node. ++ @param [in] MemoryMapLocked The function is executing on the stack of ++ gBS->ExitBootServices(); changes to the UEFI ++ memory map are forbidden. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++STATIC ++EFI_STATUS ++EFIAPI ++UnMapSharedBuffer ( ++ IN MAP_INFO *MapInfo, ++ IN BOOLEAN MemoryMapLocked ++ ) ++{ ++ EFI_STATUS Status; ++ ++ if (MapInfo == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ DEBUG (( ++ DEBUG_VERBOSE, ++ "%a: HostAddress = 0x%p, BbAddress = 0x%p\n", ++ __func__, ++ MapInfo->HostAddress, ++ MapInfo->BbAddress ++ )); ++ Status = mRamp->CloseAperture (MapInfo->ApertureRef); ++ if (EFI_ERROR (Status)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "Failed to close aperture. Status = %r\n", ++ Status ++ )); ++ } ++ ++ RemoveEntryList (&MapInfo->Link); ++ ++ if (!MemoryMapLocked) { ++ FreePool (MapInfo); ++ } ++ ++ return Status; ++} ++ ++/** ++ Provides the controller-specific addresses required to access system memory ++ from a DMA bus master. On guest Realms, the DMA operations must be performed ++ on shared buffer hence we allocate a bounce buffer to map the HostAddress to ++ a DeviceAddress. The Realm Aperture Management protocol is then involved to ++ open the aperture for sharing the buffer pages with the Host OS. ++ ++ @param This The protocol instance pointer. ++ @param Operation Indicates if the bus master is going to read or ++ write to system memory. ++ @param HostAddress The system memory address to map to the PCI ++ controller. ++ @param NumberOfBytes On input the number of bytes to map. On output ++ the number of bytes that were mapped. ++ @param DeviceAddress The resulting map address for the bus master ++ PCI controller to use to access the hosts ++ HostAddress. ++ @param Mapping A resulting value to pass to Unmap(). ++ ++ @retval EFI_SUCCESS The range was mapped for the returned ++ NumberOfBytes. ++ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common ++ buffer. ++ @retval EFI_INVALID_PARAMETER One or more parameters are invalid. ++ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a ++ lack of resources. ++ @retval EFI_DEVICE_ERROR The system hardware could not map the requested ++ address. ++ ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuMap ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN EDKII_IOMMU_OPERATION Operation, ++ IN VOID *HostAddress, ++ IN OUT UINTN *NumberOfBytes, ++ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, ++ OUT VOID **Mapping ++ ) ++{ ++ EFI_STATUS Status; ++ MAP_INFO *MapInfo; ++ EFI_PHYSICAL_ADDRESS BbAddress; ++ UINTN Pages; ++ EFI_ALLOCATE_TYPE AllocateType; ++ DEBUG (( ++ DEBUG_VERBOSE, ++ "%a: Operation=%a Host=0x%p Bytes=0x%lx\n", ++ __func__, ++ ((Operation >= 0 && ++ Operation < ARRAY_SIZE (mBusMasterOperationName)) ? ++ mBusMasterOperationName[Operation] : ++ "Invalid"), ++ HostAddress, ++ (UINT64)((NumberOfBytes == NULL) ? 0 : *NumberOfBytes) ++ )); ++ ++ if ((HostAddress == NULL) || ++ (NumberOfBytes == NULL) || ++ (DeviceAddress == NULL) || ++ (Mapping == NULL) || ++ (Operation >= EdkiiIoMmuOperationMaximum) || ++ (Operation < EdkiiIoMmuOperationBusMasterRead)) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BbAddress = MAX_ADDRESS; ++ Pages = EFI_SIZE_TO_PAGES (*NumberOfBytes); ++ AllocateType = AllocateAnyPages; ++ switch (Operation) { ++ // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer ++ // is necessary as the original buffer may not meet the page start/end and ++ // page size alignment requirements. Also we need to consider the case where ++ // the original buffer crosses the 4GB limit. ++ case EdkiiIoMmuOperationBusMasterRead: ++ case EdkiiIoMmuOperationBusMasterWrite: ++ BbAddress = BASE_4GB - 1; ++ AllocateType = AllocateMaxAddress; ++ // fall through ++ case EdkiiIoMmuOperationBusMasterRead64: ++ case EdkiiIoMmuOperationBusMasterWrite64: ++ // Allocate a bounce buffer. ++ Status = gBS->AllocatePages ( ++ AllocateType, ++ EfiBootServicesData, ++ Pages, ++ &BbAddress ++ ); ++ if (EFI_ERROR (Status)) { ++ goto Failed; ++ } ++ ++ // Open aperture here ++ Status = MapSharedBuffer ( ++ Operation, ++ HostAddress, ++ *NumberOfBytes, ++ BbAddress, ++ Pages, ++ &MapInfo ++ ); ++ if (EFI_ERROR (Status)) { ++ goto FreeBounceBuffer; ++ } ++ ++ break; ++ ++ // For BusMasterCommonBuffer[64] operations, the buffer is already allocated ++ // and mapped in a call to AllocateBuffer(). So, we only need to return the ++ // device address and the mapping info ++ case EdkiiIoMmuOperationBusMasterCommonBuffer: ++ // fall through ++ case EdkiiIoMmuOperationBusMasterCommonBuffer64: ++ MapInfo = FindMappingByHostAddress (HostAddress); ++ if (MapInfo == NULL) { ++ ASSERT (MapInfo == NULL); ++ goto Failed; ++ } ++ ++ BbAddress = MapInfo->BbAddress; ++ break; ++ ++ default: ++ // Operation is invalid ++ Status = EFI_INVALID_PARAMETER; ++ goto Failed; ++ } // switch ++ ++ // If this is a read operation from the Bus Master's point of view, ++ // then copy the contents of the real buffer into the mapped buffer ++ // so the Bus Master can read the contents of the real buffer. ++ // No special action is needed for BusMasterCommonBuffer[64] operations. ++ if ((Operation == EdkiiIoMmuOperationBusMasterRead) || ++ (Operation == EdkiiIoMmuOperationBusMasterRead64)) ++ { ++ CopyMem ( ++ (VOID *)(UINTN)BbAddress, ++ (VOID *)(UINTN)HostAddress, ++ MapInfo->NumberOfBytes ++ ); ++ } ++ ++ // Populate output parameters. ++ *DeviceAddress = BbAddress; ++ *Mapping = MapInfo; ++ ++ DEBUG (( ++ DEBUG_VERBOSE, ++ "%a: Mapping=0x%p HostAddress = 0x%p BBAddress = 0x%Lx Pages=0x%Lx\n", ++ __func__, ++ MapInfo, ++ HostAddress, ++ MapInfo->BbAddress, ++ MapInfo->NumberOfPages ++ )); ++ ++ return EFI_SUCCESS; ++ ++FreeBounceBuffer: ++ gBS->FreePages (BbAddress, Pages); ++ ++Failed: ++ *NumberOfBytes = 0; ++ return Status; ++} ++ ++/** ++ Completes the Map() operation and releases any corresponding resources. ++ ++ This is an internal worker function that only extends the Map() API with ++ the MemoryMapLocked parameter. ++ ++ @param This The protocol instance pointer. ++ @param MapInfo The mapping value returned from Map(). ++ @param MemoryMapLocked The function is executing on the stack of ++ gBS->ExitBootServices(); changes to the UEFI ++ memory map are forbidden. ++ ++ @retval EFI_SUCCESS The range was unmapped. ++ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by ++ Map(). ++ @retval EFI_DEVICE_ERROR The data was not committed to the target system ++ memory. ++**/ ++STATIC ++EFI_STATUS ++EFIAPI ++IoMmuUnmapWorker ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN MAP_INFO *MapInfo, ++ IN BOOLEAN MemoryMapLocked ++ ) ++{ ++ EFI_STATUS Status; ++ PHYSICAL_ADDRESS BbAddress; ++ UINTN Pages; ++ ++ DEBUG (( ++ DEBUG_VERBOSE, ++ "%a: MapInfo=0x%p MemoryMapLocked=%d\n", ++ __func__, ++ MapInfo, ++ MemoryMapLocked ++ )); ++ ++ if (MapInfo == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BbAddress = MapInfo->BbAddress; ++ Pages = MapInfo->NumberOfPages; ++ ++ // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations ++ // we have to copy the results, ultimately to the original place (i.e., ++ // "MapInfo->HostAddress"). ++ // No special operaton is needed for BusMasterCommonBuffer[64] operations. ++ switch (MapInfo->Operation) { ++ case EdkiiIoMmuOperationBusMasterCommonBuffer: ++ case EdkiiIoMmuOperationBusMasterCommonBuffer64: ++ ASSERT (BbAddress == (PHYSICAL_ADDRESS)MapInfo->HostAddress); ++ break; ++ case EdkiiIoMmuOperationBusMasterWrite: ++ case EdkiiIoMmuOperationBusMasterWrite64: ++ CopyMem ( ++ (VOID *)(UINTN)MapInfo->HostAddress, ++ (VOID *)(UINTN)BbAddress, ++ MapInfo->NumberOfBytes ++ ); ++ break; ++ ++ default: ++ // nothing to do for BusMasterRead[64] operations ++ break; ++ } ++ ++ // For all other operations, fill the late bounce buffer with zeros, and ++ // then release it (unless the UEFI memory map is locked). ++ if ((MapInfo->Operation != EdkiiIoMmuOperationBusMasterCommonBuffer) && ++ (MapInfo->Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) ++ { ++ ZeroMem ( ++ (VOID *)(UINTN)BbAddress, ++ EFI_PAGES_TO_SIZE (Pages) ++ ); ++ ++ // UnMapSharedPages ++ Status = UnMapSharedBuffer (MapInfo, MemoryMapLocked); ++ ASSERT_EFI_ERROR (Status); ++ ++ if (!MemoryMapLocked) { ++ gBS->FreePages (BbAddress, Pages); ++ } ++ } ++ ++ return Status; ++} ++ ++/** ++ Completes the Map() operation and releases any corresponding resources. ++ ++ @param This The protocol instance pointer. ++ @param Mapping The mapping value returned from Map(). ++ ++ @retval EFI_SUCCESS The range was unmapped. ++ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by ++ Map(). ++ @retval EFI_DEVICE_ERROR The data was not committed to the target system ++ memory. ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuUnmap ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN VOID *Mapping ++ ) ++{ ++ return IoMmuUnmapWorker ( ++ This, ++ (MAP_INFO *)Mapping, ++ FALSE // MemoryMapLocked ++ ); ++} ++ ++/** ++ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or ++ OperationBusMasterCommonBuffer64 mapping. ++ ++ @param This The protocol instance pointer. ++ @param Type This parameter is not used and must be ignored. ++ @param MemoryType The type of memory to allocate, ++ EfiBootServicesData or EfiRuntimeServicesData. ++ @param Pages The number of pages to allocate. ++ @param HostAddress A pointer to store the base system memory ++ address of the allocated range. ++ @param Attributes The requested bit mask of attributes for the ++ allocated range. ++ ++ @retval EFI_SUCCESS The requested memory pages were allocated. ++ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal ++ attribute bits are MEMORY_WRITE_COMBINE and ++ MEMORY_CACHED. ++ @retval EFI_INVALID_PARAMETER One or more parameters are invalid. ++ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. ++ ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuAllocateBuffer ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN EFI_ALLOCATE_TYPE Type, ++ IN EFI_MEMORY_TYPE MemoryType, ++ IN UINTN Pages, ++ IN OUT VOID **HostAddress, ++ IN UINT64 Attributes ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PHYSICAL_ADDRESS BbAddress; ++ MAP_INFO *MapInfo; ++ ++ // Validate Attributes ++ if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ // Check for invalid inputs ++ if (HostAddress == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // The only valid memory types are EfiBootServicesData ++ if (MemoryType != EfiBootServicesData) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (Pages >= MAX_UINTN) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BbAddress = (UINTN)-1; ++ if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) { ++ // Limit allocations to memory below 4GB ++ BbAddress = SIZE_4GB - 1; ++ } ++ ++ Status = gBS->AllocatePages ( ++ AllocateMaxAddress, ++ MemoryType, ++ Pages, ++ &BbAddress ++ ); ++ if (EFI_ERROR (Status)) { ++ // Set the host address to NULL in case of error ++ *HostAddress = NULL; ++ } else { ++ *HostAddress = (VOID *)(UINTN)BbAddress; ++ Status = MapSharedBuffer ( ++ EdkiiIoMmuOperationBusMasterCommonBuffer, ++ *HostAddress, ++ EFI_PAGES_TO_SIZE (Pages), ++ BbAddress, ++ Pages, ++ &MapInfo ++ ); ++ ASSERT_EFI_ERROR (Status); ++ } ++ ++ return Status; ++} ++ ++/** ++ Frees memory that was allocated with AllocateBuffer(). ++ ++ @param This The protocol instance pointer. ++ @param Pages The number of pages to free. ++ @param HostAddress The base system memory address of the allocated ++ range. ++ ++ @retval EFI_SUCCESS The requested memory pages were freed. ++ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and ++ Pages was not allocated with AllocateBuffer(). ++ ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuFreeBuffer ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN UINTN Pages, ++ IN VOID *HostAddress ++ ) ++{ ++ EFI_STATUS Status; ++ MAP_INFO *MapInfo; ++ ++ // Release the common buffer itself. Unmap() has re-encrypted it in-place, so ++ // no need to zero it. ++ MapInfo = FindMappingByHostAddress (HostAddress); ++ if (MapInfo == NULL) { ++ ASSERT (0); ++ return EFI_NOT_FOUND; ++ } else { ++ // UnMapSharedPages ++ Status = UnMapSharedBuffer (MapInfo, FALSE); ++ ASSERT_EFI_ERROR (Status); ++ } ++ ++ return gBS->FreePages ((UINTN)HostAddress, Pages); ++} ++ ++/** ++ Set IOMMU attribute for a system memory. ++ ++ If the IOMMU protocol exists, the system memory cannot be used ++ for DMA by default. ++ ++ When a device requests a DMA access to system memory, ++ the device driver need use SetAttribute() to update the IOMMU ++ attribute to request DMA access (read and/or write). ++ ++ The DeviceHandle is used to identify which device submits the request. ++ The IOMMU implementation need to translate the device path to an IOMMU device ++ ID, and set the IOMMU hardware register accordingly. ++ 1) DeviceHandle can be a standard PCI device. ++ The memory for BusMasterRead needs EDKII_IOMMU_ACCESS_READ set. ++ The memory for BusMasterWrite needs EDKII_IOMMU_ACCESS_WRITE set. ++ The memory for BusMasterCommonBuffer needs ++ EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE set. ++ After the memory is used, the memory need set 0 to keep it being ++ protected. ++ 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc). ++ The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or ++ EDKII_IOMMU_ACCESS_WRITE. ++ ++ @param[in] This The protocol instance pointer. ++ @param[in] DeviceHandle The device initiating the DMA access ++ request. ++ @param[in] Mapping The mapping value returned from Map(). ++ @param[in] IoMmuAccess The IOMMU access. ++ ++ @retval EFI_UNSUPPORTED Operation not supported by IOMMU. ++ ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuSetAttribute ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN EFI_HANDLE DeviceHandle, ++ IN VOID *Mapping, ++ IN UINT64 IoMmuAccess ++ ) ++{ ++ return EFI_UNSUPPORTED; ++} ++ ++/** Arm CCA IoMMU protocol ++*/ ++EDKII_IOMMU_PROTOCOL mArmCcaIoMmu = { ++ EDKII_IOMMU_PROTOCOL_REVISION, ++ IoMmuSetAttribute, ++ IoMmuMap, ++ IoMmuUnmap, ++ IoMmuAllocateBuffer, ++ IoMmuFreeBuffer, ++}; ++ ++/** ++ Notification function that is queued when gBS->ExitBootServices() signals the ++ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another ++ event, received as Context, and returns. ++ ++ Signaling an event in this context is safe. The UEFI spec allows ++ gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not ++ listed, hence memory is not allocated. The edk2 implementation also does not ++ release memory (and we only have to care about the edk2 implementation ++ because EDKII_IOMMU_PROTOCOL is edk2-specific anyway). ++ ++ @param[in] Event Event whose notification function is being invoked. ++ Event is permitted to request the queueing of this ++ function at TPL_CALLBACK or TPL_NOTIFY task ++ priority level. ++ ++ @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal ++ is permitted to request the queueing of its ++ notification function only at TPL_CALLBACK level. ++**/ ++STATIC ++VOID ++EFIAPI ++ArmCcaIoMmuExitBoot ( ++ IN EFI_EVENT Event, ++ IN VOID *EventToSignal ++ ) ++{ ++ // (1) The NotifyFunctions of all the events in ++ // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before ++ // ArmCcaIoMmuExitBoot() is entered. ++ // ++ // (2) ArmCcaIoMmuExitBoot() is executing minimally at TPL_CALLBACK. ++ // ++ // (3) ArmCcaIoMmuExitBoot() has been queued in unspecified order relative ++ // to the NotifyFunctions of all the other events in ++ // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as ++ // Event's. ++ // ++ // Consequences: ++ // ++ // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions ++ // queued at TPL_CALLBACK may be invoked after ArmCcaIoMmuExitBoot() ++ // returns. ++ // ++ // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions ++ // queued at TPL_NOTIFY may be invoked after ArmCcaIoMmuExitBoot() returns; ++ // plus *all* NotifyFunctions queued at TPL_CALLBACK will be invoked ++ // strictly after all NotifyFunctions queued at TPL_NOTIFY, including ++ // ArmCcaIoMmuExitBoot(), have been invoked. ++ // ++ // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we ++ // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all* ++ // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES. ++ gBS->SignalEvent (EventToSignal); ++} ++ ++/** ++ Notification function that is queued after the notification functions of all ++ events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same memory ++ map restrictions apply. ++ ++ This function unmaps all currently existing IOMMU mappings. ++ ++ @param[in] Event Event whose notification function is being invoked. Event ++ is permitted to request the queueing of this function ++ only at TPL_CALLBACK task priority level. ++ ++ @param[in] Context Ignored. ++**/ ++STATIC ++VOID ++EFIAPI ++ArmCcaIoMmuUnmapAllMappings ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ LIST_ENTRY *Node; ++ LIST_ENTRY *NextNode; ++ MAP_INFO *MapInfo; ++ ++ // All drivers that had set up IOMMU mappings have halted their respective ++ // controllers by now; tear down the mappings. ++ for (Node = GetFirstNode (&mMapInfos); Node != &mMapInfos; Node = NextNode) { ++ NextNode = GetNextNode (&mMapInfos, Node); ++ MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG); ++ IoMmuUnmapWorker ( ++ &mArmCcaIoMmu, // This ++ MapInfo, // Mapping ++ TRUE // MemoryMapLocked ++ ); ++ } ++} ++ ++/** ++ Initialize and install the ArmCca IoMmu Protocol. ++ ++ @return RETURN_SUCCESS if successful, otherwise any other error. ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaInstallIoMmuProtocol ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_EVENT UnmapAllMappingsEvent; ++ EFI_EVENT ExitBootEvent; ++ EFI_HANDLE Handle; ++ ++ // Create the "late" event whose notification function will tear down all ++ // left-over IOMMU mappings. ++ Status = gBS->CreateEvent ( ++ EVT_NOTIFY_SIGNAL, // Type ++ TPL_CALLBACK, // NotifyTpl ++ ArmCcaIoMmuUnmapAllMappings, // NotifyFunction ++ NULL, // NotifyContext ++ &UnmapAllMappingsEvent // Event ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ // Create the event whose notification function will be queued by ++ // gBS->ExitBootServices() and will signal the event created above. ++ Status = gBS->CreateEvent ( ++ EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type ++ TPL_CALLBACK, // NotifyTpl ++ ArmCcaIoMmuExitBoot, // NotifyFunction ++ UnmapAllMappingsEvent, // NotifyContext ++ &ExitBootEvent // Event ++ ); ++ if (EFI_ERROR (Status)) { ++ goto CloseUnmapAllMappingsEvent; ++ } ++ ++ Handle = NULL; ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gEdkiiIoMmuProtocolGuid, ++ &mArmCcaIoMmu, ++ NULL ++ ); ++ if (!EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ // cleanup on error ++ gBS->CloseEvent (ExitBootEvent); ++ ++CloseUnmapAllMappingsEvent: ++ gBS->CloseEvent (UnmapAllMappingsEvent); ++ ++ return Status; ++} +diff --git a/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h +new file mode 100644 +index 00000000..a12ca775 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h +@@ -0,0 +1,66 @@ ++/** @file ++ The protocol provides support to allocate, free, map and umap a DMA buffer ++ for bus master (e.g PciHostBridge). When the execution context is a Realm, ++ the DMA operations must be performed on buffers that are shared with the HOST, ++ hence the RAMP protocol is used to manage the sharing of the DMA buffers or in ++ some cases bounce the buffers. ++ ++ Copyright (c) 2017, Intel Corporation. All rights reserved.
++ Copyright (c) 2017, AMD Inc. All rights reserved.
++ (C) Copyright 2017 Hewlett Packard Enterprise Development LP
++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#ifndef ARM_CCA_IOMMU_H_ ++#define ARM_CCA_IOMMU_H_ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ A macro defning the signature for the MAP_INFO structure. ++*/ ++#define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O') ++ ++/** A structure describing the mapping for the buffers shared with the host. ++*/ ++typedef struct { ++ /// Signature. ++ UINT64 Signature; ++ /// Linked List node entry. ++ LIST_ENTRY Link; ++ /// IoMMU operation. ++ EDKII_IOMMU_OPERATION Operation; ++ /// Number of bytes. ++ UINTN NumberOfBytes; ++ /// Number of pages. ++ UINTN NumberOfPages; ++ /// Address of the Host buffer. ++ VOID *HostAddress; ++ ++ /// Address for the Bounce Buffer. ++ EFI_PHYSICAL_ADDRESS BbAddress; ++ /// Handle to the Aperture. ++ EFI_HANDLE ApertureRef; ++} MAP_INFO; ++ ++/** ++ Install IOMMU protocol to provide the DMA support for PciHostBridge and ++ RAMP. ++ ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaInstallIoMmuProtocol ( ++ VOID ++ ); ++ ++#endif +diff --git a/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c +new file mode 100644 +index 00000000..01e4e6fa +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c +@@ -0,0 +1,60 @@ ++/** @file ++ ++ IoMmuArmBowDxe driver installs EDKII_IOMMU_PROTOCOL to support ++ DMA operations when the execution context is a Realm. ++ ++ Copyright (c) 2017, AMD Inc. All rights reserved.
++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include "ArmCcaIoMmu.h" ++ ++/** Pointer to the Realm Aperture Management Protocol ++*/ ++EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL *mRamp = NULL; ++ ++/** Entrypoint of Arm CCA IoMMU Dxe. ++ ++ @param [in] ImageHandle Image handle of this driver. ++ @param [in] SystemTable Pointer to the EFI System Table. ++ ++ @return RETURN_SUCCESS if successful, otherwise any other error. ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaIoMmuDxeEntryPoint ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_HANDLE Handle; ++ DEBUG ((DEBUG_INFO, "ArmCcaIoMmuDxeEntryPoint 1.\n")); ++ // When the execution context is a Realm, install ArmCcaIoMmu protocol ++ // otherwise install the placeholder protocol so that other dependent ++ // module can run. ++ Status = gBS->LocateProtocol ( ++ &gEfiRealmApertureManagementProtocolGuid, ++ NULL, ++ (VOID **)&mRamp ++ ); ++ if (!EFI_ERROR (Status)) { ++ // If the Realm Aperture Management Protocol is present ++ // then the execution context is a Realm. ++ Status = ArmCcaInstallIoMmuProtocol (); ++ DEBUG ((DEBUG_INFO, "ArmCcaIoMmuDxeEntryPoint 1.1.\n")); ++ } else { ++ DEBUG ((DEBUG_INFO, "Execution context is not a Realm.\n")); ++ Handle = NULL; ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gIoMmuAbsentProtocolGuid, ++ NULL, ++ NULL ++ ); ++ } ++ DEBUG ((DEBUG_INFO, "ArmCcaIoMmuDxeEntryPoint 2.\n")); ++ return Status; ++} +diff --git a/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +new file mode 100644 +index 00000000..59fa1abd +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +@@ -0,0 +1,45 @@ ++## @file ++# Driver provides the IOMMU protcol support for PciHostBridgeIo and others ++# drivers. ++# ++# Copyright (c) 2017, AMD Inc. All rights reserved.
++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = IoMmuDxe ++ FILE_GUID = AA6C1A48-A341-439C-950E-CC394FDFE144 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = ArmCcaIoMmuDxeEntryPoint ++ ++[Sources] ++ ArmCcaIoMmu.c ++ ArmCcaIoMmu.h ++ ArmCcaIoMmuDxe.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ OvmfPkg/OvmfPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ BaseMemoryLib ++ DebugLib ++ MemoryAllocationLib ++ UefiBootServicesTableLib ++ UefiDriverEntryPoint ++ ++[Protocols] ++ gEdkiiIoMmuProtocolGuid ## SOMETIME_PRODUCES ++ gIoMmuAbsentProtocolGuid ## SOMETIME_PRODUCES ++ gEfiRealmApertureManagementProtocolGuid ++ ++[Depex] ++ gEfiRealmApertureManagementProtocolGuid +diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec +index 4645c91a..ac1c3ed0 100644 +--- a/ArmVirtPkg/ArmVirtPkg.dec ++++ b/ArmVirtPkg/ArmVirtPkg.dec +@@ -30,13 +30,15 @@ + + [Guids.common] + gArmVirtTokenSpaceGuid = { 0x0B6F5CA7, 0x4F53, 0x445A, { 0xB7, 0x6E, 0x2E, 0x36, 0x5B, 0x80, 0x63, 0x66 } } +- gEarlyPL011BaseAddressGuid = { 0xB199DEA9, 0xFD5C, 0x4A84, { 0x80, 0x82, 0x2F, 0x41, 0x70, 0x78, 0x03, 0x05 } } +- gEarly16550UartBaseAddressGuid = { 0xea67ca3e, 0x1f54, 0x436b, { 0x97, 0x88, 0xd4, 0xeb, 0x29, 0xc3, 0x42, 0x67 } } +- gArmVirtSystemMemorySizeGuid = { 0x504eccb9, 0x1bf0, 0x4420, { 0x86, 0x5d, 0xdc, 0x66, 0x06, 0xd4, 0x13, 0xbf } } +- +-[PcdsFeatureFlag] +- # +- # Feature Flag PCD that defines whether TPM2 support is enabled ++ gEarlyPL011BaseAddressGuid = { 0xB199DEA9, 0xFD5C, 0x4A84, { 0x80, 0x82, 0x2F, 0x41, 0x70, 0x78, 0x03, 0x05 } } ++ gEarly16550UartBaseAddressGuid = { 0xea67ca3e, 0x1f54, 0x436b, { 0x97, 0x88, 0xd4, 0xeb, 0x29, 0xc3, 0x42, 0x67 } } ++ gArmVirtSystemMemorySizeGuid = { 0x504eccb9, 0x1bf0, 0x4420, { 0x86, 0x5d, 0xdc, 0x66, 0x06, 0xd4, 0x13, 0xbf } } ++ gArmCcaIpaWidthGuid = { 0xbdb66787, 0xfc8a, 0x412e, { 0xa0, 0x9b, 0x84, 0x96, 0x61, 0x81, 0x72, 0xc0 } } ++[Protocols] ++ gEfiRealmApertureManagementProtocolGuid = { 0x585c00be, 0xcf7c, 0x4db8, { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } } ++[PcdsFeatureFlag] ++ # ++ # Feature Flag PCD that defines whether TPM2 support is enabled + # + gArmVirtTokenSpaceGuid.PcdTpm2SupportEnabled|FALSE|BOOLEAN|0x00000004 + +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index 1e022595..b7d34b91 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -78,13 +78,13 @@ + FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf + PciPcdProducerLib|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf + PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf +- PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf +- PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf +- PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf +- +-!if $(TPM2_ENABLE) == TRUE +- Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf +- Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf ++ PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf ++ PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf ++ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf ++ ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf ++!if $(TPM2_ENABLE) == TRUE ++ Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf ++ Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf + TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf + TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLib/PeiDxeTpmPlatformHierarchyLib.inf + !else +@@ -97,12 +97,13 @@ + + [LibraryClasses.ARM] + ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf +- +-[LibraryClasses.common.PEIM] +- ArmVirtMemInfoLib|ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf +- +-!if $(TPM2_ENABLE) == TRUE +- BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf ++ ++[LibraryClasses.common.PEIM] ++ ArmVirtMemInfoLib|ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf ++ ArmCcaInitPeiLib|ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf ++ ++!if $(TPM2_ENABLE) == TRUE ++ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf + ResetSystemLib|MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.inf + Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf + !endif +@@ -251,12 +252,16 @@ + + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|0x0 + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|0x0 +- gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0 +- gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0 +- +- # +- # ARM General Interrupt Controller +- # ++ gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0 ++ gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0 ++ ++ # Define PCD for emulating runtime variable storage when CFI flash is absent ++ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|FALSE ++ ++ ++ # ++ # ARM General Interrupt Controller ++ # + gArmTokenSpaceGuid.PcdGicDistributorBase|0x0 + gArmTokenSpaceGuid.PcdGicRedistributorsBase|0x0 + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x0 +@@ -439,12 +444,16 @@ + # + MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf + +- # +- # Platform Driver +- # +- OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf +- EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf +- OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf ++ # ++ # Platform Driver ++ # ++ ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf { ++ ++ NULL|ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf ++ } ++ OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf ++ EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf ++ OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf + OvmfPkg/VirtioBlkDxe/VirtioBlk.inf + OvmfPkg/VirtioScsiDxe/VirtioScsi.inf + OvmfPkg/VirtioNetDxe/VirtioNet.inf +@@ -576,12 +585,22 @@ + !endif + + # +- # ACPI Support +- # +- OvmfPkg/PlatformHasAcpiDtDxe/PlatformHasAcpiDtDxe.inf +-[Components.AARCH64] +- MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf +- OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { ++ # ACPI Support ++ # ++ OvmfPkg/PlatformHasAcpiDtDxe/PlatformHasAcpiDtDxe.inf ++ ++ # ++ # Realm Aperture Management ++ # ++ ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf ++[Components.AARCH64] ++ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf ++ OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { + + NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf + } +diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf +index 764f652a..0a89f24c 100644 +--- a/ArmVirtPkg/ArmVirtQemu.fdf ++++ b/ArmVirtPkg/ArmVirtQemu.fdf +@@ -108,12 +108,21 @@ READ_LOCK_STATUS = TRUE + INF MdeModulePkg/Core/Pei/PeiMain.inf + INF ArmPlatformPkg/PlatformPei/PlatformPeim.inf + INF ArmVirtPkg/MemoryInitPei/MemoryInitPeim.inf +- INF ArmPkg/Drivers/CpuPei/CpuPei.inf +- INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf +- +-!if $(TPM2_ENABLE) == TRUE +- INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf +- INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf ++ INF ArmPkg/Drivers/CpuPei/CpuPei.inf ++ INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf ++ ++ # ++ # Realm Aperture Management ++ # ++ INF ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ INF ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf ++!if $(TPM2_ENABLE) == TRUE ++ INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf ++ INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf + INF OvmfPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf + INF SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf + !endif +diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +index 2894bc85..bef91421 100644 +--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc ++++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +@@ -39,12 +39,13 @@ READ_LOCK_CAP = TRUE + READ_LOCK_STATUS = TRUE + + INF MdeModulePkg/Core/Dxe/DxeMain.inf +- INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf +- INF OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf +- INF EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf +- INF OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf +- +- # ++ INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf ++ INF OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf ++ INF EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf ++ INF ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf ++ INF OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf ++ ++ # + # PI DXE Drivers producing Architectural Protocols (EFI Services) + # + INF ArmPkg/Drivers/CpuDxe/CpuDxe.inf +diff --git a/ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h b/ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h +new file mode 100644 +index 00000000..9374fe81 +--- /dev/null ++++ b/ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h +@@ -0,0 +1,49 @@ ++/** @file ++ Library that implements the Arm CCA helper functions. ++ ++ Copyright (c) 2022 2023, Arm Ltd. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++ ++#ifndef ARM_CCA_INIT_PEI_LIB_ ++#define ARM_CCA_INIT_PEI_LIB_ ++ ++#include ++ ++/** ++ Configure the System Memory region as Protected RAM. ++ ++ When a VMM creates a Realm, a small amount of DRAM (which contains the ++ firmware image) and the initial content is configured as Protected RAM. ++ The remaining System Memory is in the Protected Empty state. The firmware ++ must then initialise the remaining System Memory as Protected RAM before ++ it can be accessed. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaConfigureSystemMemory ( ++ VOID ++ ); ++ ++/** ++ Perform Arm CCA specific initialisations. ++ ++ @retval RETURN_SUCCESS Success or execution context is not a Realm. ++ @retval RETURN_OUT_OF_RESOURCES Out of resources. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaInitialize ( ++ VOID ++ ); ++ ++#endif // ARM_CCA_LIB_ +diff --git a/ArmVirtPkg/Include/Library/ArmCcaLib.h b/ArmVirtPkg/Include/Library/ArmCcaLib.h +new file mode 100644 +index 00000000..ff9c2e91 +--- /dev/null ++++ b/ArmVirtPkg/Include/Library/ArmCcaLib.h +@@ -0,0 +1,114 @@ ++/** @file ++ Library that implements the Arm CCA helper functions. ++ ++ Copyright (c) 2022 - 2023, Arm Ltd. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++ ++#ifndef ARM_CCA_LIB_ ++#define ARM_CCA_LIB_ ++ ++#include ++#include ++ ++/** ++ Check if running in a Realm. ++ ++ @retval TRUE The execution is within the context of a Realm. ++ @retval FALSE The execution is not within the context of a Realm. ++**/ ++BOOLEAN ++EFIAPI ++IsRealm ( ++ VOID ++ ); ++ ++/** ++ Configure the protection attribute for the page tables ++ describing the memory region. ++ ++ The IPA space of a Realm is divided into two halves: ++ - Protected IPA space and ++ - Unprotected IPA space. ++ ++ Software in a Realm should treat the most significant bit of an ++ IPA as a protection attribute. ++ ++ A Protected IPA is an address in the lower half of a Realms IPA ++ space. The most significant bit of a Protected IPA is 0. ++ ++ An Unprotected IPA is an address in the upper half of a Realms ++ IPA space. The most significant bit of an Unprotected IPA is 1. ++ ++ Note: ++ - Configuring the memory region as Unprotected IPA enables the ++ Realm to share the memory region with the Host. ++ - This function updates the page table entries to reflect the ++ protection attribute. ++ - A separate call to transition the memory range using the Realm ++ Service Interface (RSI) RSI_IPA_STATE_SET command is additionally ++ required and is expected to be done outside this function. ++ ++ @param [in] BaseAddress Base address of the memory region. ++ @param [in] Length Length of the memory region. ++ @param [in] IpaWidth IPA width of the Realm. ++ @param [in] Share If TRUE, set the most significant ++ bit of the IPA to configure the memory ++ region as Unprotected IPA. ++ If FALSE, clear the most significant ++ bit of the IPA to configure the memory ++ region as Protected IPA. ++ ++ @retval RETURN_SUCCESS IPA protection attribute updated. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The request is not initiated in a ++ Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaSetMemoryProtectAttribute ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 IpaWidth, ++ IN BOOLEAN Share ++ ); ++ ++/** ++ Return the IPA width of the Realm. ++ ++ The IPA width of the Realm is used to configure the protection attribute ++ for memory regions, see ArmCcaSetMemoryProtectAttribute(). ++ ++ The IPA width of the Realm is present in the Realm config which is read ++ when the ArmCcaInitPeiLib library hook function ArmCcaInitialize () is ++ called in the PrePi phase. ArmCcaInitialize () stores the IPA width of ++ the Realm in a GUID HOB gArmCcaIpaWidthGuid. ++ ++ This function searches the GUID HOB gArmCcaIpaWidthGuid and returns the ++ IPA width value stored therein. ++ ++ Note: ++ - This function must only be called after ArmCcaInitialize () has setup ++ the GUID HOB gArmCcaIpaWidthGuid. ++ ++ @param [out] IpaWidth IPA width of the Realm. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_NOT_FOUND The GUID HOB gArmCcaIpaWidthGuid is not ++ found and could mean that this function ++ was called before ArmCcaInitialize () ++ has created and initialised the GUID ++ HOB gArmCcaIpaWidthGuid. ++**/ ++RETURN_STATUS ++EFIAPI ++GetIpaWidth ( ++ OUT UINT64 *IpaWidth ++ ); ++ ++#endif // ARM_CCA_LIB_ +diff --git a/ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h b/ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h +index 7812c2e2..74fbe7e1 100644 +--- a/ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h ++++ b/ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h +@@ -29,7 +29,23 @@ + VOID + EFIAPI + ArmVirtGetMemoryMap ( +- OUT ARM_MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap +- ); +- +-#endif ++ OUT ARM_MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap ++ ); ++ ++/** ++ Configure the MMIO regions as shared with the VMM. ++ ++ Set the protection attribute for the MMIO regions as Unprotected IPA. ++ ++ @param[in] IpaWidth IPA width of the Realm. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaConfigureMmio ( ++ IN UINT64 IpaWidth ++ ); ++#endif +diff --git a/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h b/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h +new file mode 100644 +index 00000000..a3f200be +--- /dev/null ++++ b/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h +@@ -0,0 +1,103 @@ ++/** @file ++ Realm Aperture Management Protocol (RAMP) ++ On Arm CCA Systems the Realm protects access and visibility of Guest memory ++ and code execution from software outside the realm. ++ ++ However, software executing in a Realm needs to interact with the external ++ world. This may be done using virtualised disk, network interfaces, etc. ++ The drivers for these virtualised devices need to share buffers with the host ++ OS to exchange information/data. ++ ++ Since the Guest memory is protected by the Realm, the host cannot access these ++ buffers unless the IPA state of the buffers is changed to Protected EMPTY by ++ the software executing in the Realm. ++ ++ By enabling the sharing of the buffers, we are essentially opening an ++ aperture so that the host OS can access the range of pages that are shared. ++ ++ The virtual firmware (Guest firmware) needs a mechanism to manage the sharing ++ of buffers. The Realm Aperture Management Protocol provides an interface that ++ UEFI drivers/modules can use to enable/disable the sharing of buffers with the ++ Host. The protocol also tracks open apertures and ensures they are shut on ++ ExitBootServices. ++ ++ Copyright (c) 2022 - 2023, ARM Ltd. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - RAMP - Realm Aperture Management Protocol ++**/ ++ ++#ifndef REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ ++#define REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ ++ ++/** This macro defines the Realm Aperture Management Protocol GUID. ++ ++ GUID: {585C00BE-CF7C-4DB8-8AA2-490D67F5F6E6} ++*/ ++#define EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_GUID \ ++ { 0x585c00be, 0xcf7c, 0x4db8, \ ++ { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } \ ++ }; ++ ++/** This macro defines the Realm Aperture Management Protocol Revision. ++*/ ++#define EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_REVISION 0x00010000 ++ ++#pragma pack(1) ++ ++/** Enables sharing of the memory buffers with the host. ++ ++ @param [in] Memory Pointer to the page start address. ++ @param [in] Pages Number of pages to share. ++ @param [out] ApertureReference Reference to the opened aperture. ++ ++ @retval EFI_SUCCESS Success. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_OUT_OF_RESOURCES Memory allocation failed. ++ @retval EFI_ACCESS_DENIED Aperture already open over memory region. ++**/ ++typedef ++EFI_STATUS ++(EFIAPI *EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_OPEN_APERTURE)( ++ IN CONST EFI_PHYSICAL_ADDRESS Memory, ++ IN CONST UINTN Pages, ++ OUT EFI_HANDLE *CONST ApertureReference ++ ); ++ ++/** Disables the sharing of the buffers. ++ ++ @param [in] ApertureReference Reference to the aperture for closing. ++ ++ @retval EFI_SUCCESS The operation completed successfully. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_NOT_FOUND The required buffer information is not found. ++**/ ++typedef ++EFI_STATUS ++(EFIAPI *EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_CLOSE_APERTURE)( ++ IN CONST EFI_HANDLE ApertureReference ++ ); ++ ++/** A structure describing the interface provided by the Realm Aperture ++ Management Protocol. ++*/ ++typedef struct RealmApertureManagementProtocol { ++ /// The Realm Aperture Management Protocol revision. ++ UINT64 Revision; ++ ++ /// Shares Realm Pages(s) with the Host. ++ EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_OPEN_APERTURE OpenAperture; ++ ++ /// Makes the Realm Pages(s) private to the Realm. ++ EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_CLOSE_APERTURE CloseAperture; ++} EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL; ++ ++/** The Realm Aperture Management Protocol GUID. ++*/ ++extern EFI_GUID gEfiRealmApertureManagementProtocolGuid; ++ ++#pragma pack() ++ ++#endif // REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ +diff --git a/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c b/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c +new file mode 100644 +index 00000000..dc3f55a8 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c +@@ -0,0 +1,60 @@ ++/** @file ++ Library that implements the Arm CCA initialisation in PEI phase. ++ ++ Copyright (c) 2022 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ Configure the System Memory region as Protected RAM. ++ ++ When a VMM creates a Realm, a small amount of DRAM (which contains the ++ firmware image) and the initial content is configured as Protected RAM. ++ The remaining System Memory is in the Protected Empty state. The firmware ++ must then initialise the remaining System Memory as Protected RAM before ++ it can be accessed. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaConfigureSystemMemory ( ++ VOID ++ ) ++{ ++ return RETURN_SUCCESS; ++} ++ ++/** ++ Perform Arm CCA specific initialisations. ++ ++ @retval RETURN_SUCCESS Success or execution context is not a Realm. ++ @retval RETURN_OUT_OF_RESOURCES Out of resources. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaInitialize ( ++ VOID ++ ) ++{ ++ return ArmCcaConfigureMmio (48); ++} +diff --git a/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf b/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf +new file mode 100644 +index 00000000..b3c17a6a +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf +@@ -0,0 +1,38 @@ ++## @file ++# Library that implements the Arm CCA initialisation in PEI phase. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = ArmCcaInitPeiLib ++ FILE_GUID = 9A8C3768-79ED-487E-8155-BBF4DD638296 ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmCcaInitPeiLib ++ ++[Sources] ++ ArmCcaInitPeiLib.c ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmCcaLib ++ ArmLib ++ ArmMmuLib ++ ArmVirtMemInfoLib ++ BaseLib ++ ++[Pcd] ++ gArmTokenSpaceGuid.PcdSystemMemoryBase ++ gArmTokenSpaceGuid.PcdSystemMemorySize ++ ++[Guids] ++ gArmCcaIpaWidthGuid +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +new file mode 100644 +index 00000000..894c6db0 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +@@ -0,0 +1,176 @@ ++/** @file ++ Library that implements the Arm CCA helper functions. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/** ++ Check if running in a Realm. ++ ++ @retval TRUE The execution is within the context of a Realm. ++ @retval FALSE The execution is not within the context of a Realm. ++**/ ++BOOLEAN ++EFIAPI ++IsRealm ( ++ VOID ++ ) ++{ ++ return TRUE; ++} ++ ++/** ++ Configure the protection attribute for the page tables ++ describing the memory region. ++ ++ The IPA space of a Realm is divided into two halves: ++ - Protected IPA space and ++ - Unprotected IPA space. ++ ++ Software in a Realm should treat the most significant bit of an ++ IPA as a protection attribute. ++ ++ A Protected IPA is an address in the lower half of a Realms IPA ++ space. The most significant bit of a Protected IPA is 0. ++ ++ An Unprotected IPA is an address in the upper half of a Realms ++ IPA space. The most significant bit of an Unprotected IPA is 1. ++ ++ Note: ++ - Configuring the memory region as Unprotected IPA enables the ++ Realm to share the memory region with the Host. ++ - This function updates the page table entries to reflect the ++ protection attribute. ++ - A separate call to transition the memory range using the Realm ++ Service Interface (RSI) RSI_IPA_STATE_SET command is additionally ++ required and is expected to be done outside this function. ++ ++ @param [in] BaseAddress Base address of the memory region. ++ @param [in] Length Length of the memory region. ++ @param [in] IpaWidth IPA width of the Realm. ++ @param [in] Share If TRUE, set the most significant ++ bit of the IPA to configure the memory ++ region as Unprotected IPA. ++ If FALSE, clear the most significant ++ bit of the IPA to configure the memory ++ region as Protected IPA. ++ ++ @retval RETURN_SUCCESS IPA protection attribute updated. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The request is not initiated in a ++ Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaSetMemoryProtectAttribute ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 IpaWidth, ++ IN BOOLEAN Share ++ ) ++{ ++ UINT64 Val; ++ UINT64 Mask; ++ UINT64 ProtectionAttributeMask; ++ ++ if (!IsRealm ()) { ++ return RETURN_UNSUPPORTED; ++ } ++ ++ if (IpaWidth == 0) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ /* Software in a Realm should treat the most significant bit of an ++ IPA as a protection attribute. ++ */ ++ ProtectionAttributeMask = 1ULL << 5; ++ if (Share) { ++ Val = ProtectionAttributeMask; ++ Mask = 0xFFFFFFFFFFFFFFFF; ++ } else { ++ Val = 0; ++ Mask = ~(TT_ADDRESS_MASK_BLOCK_ENTRY | ProtectionAttributeMask); ++ } ++ return SetMemoryRegionAttribute ( ++ BaseAddress, ++ Length, ++ Val, ++ Mask ++ ); ++} ++ ++/** ++ Return the IPA width of the Realm. ++ ++ The IPA width of the Realm is used to configure the protection attribute ++ for memory regions, see ArmCcaSetMemoryProtectAttribute(). ++ ++ The IPA width of the Realm is present in the Realm config which is read ++ when the ArmCcaInitPeiLib library hook function ArmCcaInitialize () is ++ called in the PrePi phase. ArmCcaInitialize () stores the IPA width of ++ the Realm in a GUID HOB gArmCcaIpaWidthGuid. ++ ++ This function searches the GUID HOB gArmCcaIpaWidthGuid and returns the ++ IPA width value stored therein. ++ ++ Note: ++ - This function must only be called after ArmCcaInitialize () has setup ++ the GUID HOB gArmCcaIpaWidthGuid. ++ ++ @param [out] IpaWidth IPA width of the Realm. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_NOT_FOUND The GUID HOB gArmCcaIpaWidthGuid is not ++ found and could mean that this function ++ was called before ArmCcaInitialize () ++ has created and initialised the GUID ++ HOB gArmCcaIpaWidthGuid. ++**/ ++RETURN_STATUS ++EFIAPI ++GetIpaWidth ( ++ OUT UINT64 *IpaWidth ++ ) ++{ ++ VOID *Hob; ++ UINT64 *CcaIpaWidth; ++ ++ if (IpaWidth == NULL) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ Hob = GetFirstGuidHob (&gArmCcaIpaWidthGuid); ++ if ((Hob == NULL) || ++ (GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64))) ++ { ++ return RETURN_NOT_FOUND; ++ } ++ ++ CcaIpaWidth = GET_GUID_HOB_DATA (Hob); ++ if ((UINT64)*CcaIpaWidth == 0) { ++ return RETURN_NOT_FOUND; ++ } ++ ++ *IpaWidth = *CcaIpaWidth; ++ ++ return RETURN_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +new file mode 100644 +index 00000000..c0d703b2 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +@@ -0,0 +1,34 @@ ++## @file ++# Library that implements the Arm CCA helper functions. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = ArmCcaLib ++ FILE_GUID = 11C18743-52F9-405E-B35B-D7BE91A26F9F ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmCcaLib ++ ++[Sources] ++ ArmCcaLib.c ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ArmPlatformPkg/ArmPlatformPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmLib ++ ArmMmuLib ++ BaseLib ++ HobLib ++ ++[Guids] ++ gArmCcaIpaWidthGuid +diff --git a/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.c b/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.c +index 72e5c65a..5ba92275 100644 +--- a/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.c ++++ b/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.c +@@ -6,12 +6,13 @@ + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ +- +-#include +- +-#include +-#include +-#include ++ ++#include ++ ++#include ++#include ++#include ++#include + #include + #include + #include +@@ -103,9 +104,9 @@ MemoryPeim ( + InitMmu (); + + if (FeaturePcdGet (PcdPrePiProduceMemoryTypeInformationHob)) { +- // Optional feature that helps prevent EFI memory map fragmentation. +- BuildMemoryTypeInformationHob (); +- } +- +- return EFI_SUCCESS; +-} ++ // Optional feature that helps prevent EFI memory map fragmentation. ++ BuildMemoryTypeInformationHob (); ++ } ++ ArmCcaInitialize(); ++ return EFI_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.inf b/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.inf +index 48d9c66b..da9504d8 100644 +--- a/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.inf ++++ b/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.inf +@@ -23,12 +23,13 @@ + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec +- ArmVirtPkg/ArmVirtPkg.dec +- +-[LibraryClasses] +- DebugLib +- HobLib +- ArmLib ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ ArmCcaInitPeiLib ++ DebugLib ++ HobLib ++ ArmLib + ArmMmuLib + ArmVirtMemInfoLib + CacheMaintenanceLib +diff --git a/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c b/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c +new file mode 100644 +index 00000000..efc03e2f +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c +@@ -0,0 +1,119 @@ ++/** @file ++ Arm Monitor Library. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ An enum representing the PSCI conduits for issuing monitor calls. ++*/ ++typedef enum PsciConduit { ++ PsciConduitHvc, // < HVC conduit ++ PsciConduitSmc, // < SMC conduit ++ PsciConduitMax ++} PSCI_CONDUIT; ++ ++/** ++ A variable that stores the PSCI conduit to be used. ++*/ ++STATIC PSCI_CONDUIT mArmPsciConduit = PsciConduitMax; ++ ++/** Monitor call. ++ ++ An HyperVisor Call (HVC) or System Monitor Call (SMC) will be issued ++ depending on the conduit. The library constructor for ArmVirtMonitorLib ++ determines the conduit by parsing the Device Tree handed off by the VMM ++ and initialising mArmPsciConduit. ++ ++ @param [in,out] Args Arguments for the HVC/SMC. ++**/ ++VOID ++EFIAPI ++ArmMonitorCall ( ++ IN OUT ARM_MONITOR_ARGS *Args ++ ) ++{ ++ switch (mArmPsciConduit) { ++ case PsciConduitHvc: ++ ArmCallHvc ((ARM_HVC_ARGS *)Args); ++ break; ++ case PsciConduitSmc: ++ ArmCallSmc ((ARM_SMC_ARGS *)Args); ++ break; ++ default: ++ ASSERT (0); ++ CpuDeadLoop (); ++ } ++} ++ ++/** Constructor for ArmVirtMonitorLib. ++ ++ The library constructor for ArmVirtMonitorLib determines the conduit ++ by parsing the Device Tree handed off by the VMM and initialising ++ mArmPsciConduit, which can then be used to select the appropriate ++ conduit for invoking the monitor call. ++ ++ @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS. ++ @retval RETURN_NOT_FOUND An entry for the PSCI conduit was not found in ++ the platform device tree. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmVirtMonitorLibConstructor ( ++ VOID ++ ) ++{ ++ RETURN_STATUS Status; ++ FDT_CLIENT_PROTOCOL *FdtClient; ++ CONST VOID *Prop; ++ ++ Status = gBS->LocateProtocol ( ++ &gFdtClientProtocolGuid, ++ NULL, ++ (VOID **)&FdtClient ++ ); ++ if (RETURN_ERROR (Status)) { ++ ASSERT (0); ++ return Status; ++ } ++ ++ Status = FdtClient->FindCompatibleNodeProperty ( ++ FdtClient, ++ "arm,psci-0.2", ++ "method", ++ &Prop, ++ NULL ++ ); ++ if (RETURN_ERROR (Status)) { ++ return Status; ++ } ++ ++ if (AsciiStrnCmp (Prop, "hvc", 3) == 0) { ++ mArmPsciConduit = PsciConduitHvc; ++ } else if (AsciiStrnCmp (Prop, "smc", 3) == 0) { ++ mArmPsciConduit = PsciConduitSmc; ++ } else { ++ DEBUG (( ++ DEBUG_ERROR, ++ "%a: Unknown PSCI method \"%a\"\n", ++ __func__, ++ Prop ++ )); ++ return RETURN_NOT_FOUND; ++ } ++ ++ return RETURN_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.inf b/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.inf +new file mode 100644 +index 00000000..fbc21933 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.inf +@@ -0,0 +1,36 @@ ++## @file ++# Arm Virt Monitor Library ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++ ++[Defines] ++ INF_VERSION = 1.29 ++ BASE_NAME = ArmVirtMonitorLib ++ FILE_GUID = 3E464134-890D-4C3F-A559-D0FE2803E332 ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmMonitorLib|DXE_DRIVER DXE_RUNTIME_DRIVER ++ CONSTRUCTOR = ArmVirtMonitorLibConstructor ++ ++[Sources] ++ ArmVirtMonitorLib.c ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ EmbeddedPkg/EmbeddedPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmHvcLib ++ ArmSmcLib ++ DebugLib ++ UefiBootServicesTableLib ++ ++[Protocols] ++ gFdtClientProtocolGuid ## CONSUMES ++ ++[Depex] ++ gFdtClientProtocolGuid +diff --git a/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c b/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c +index d0fa7e50..9807e8de 100644 +--- a/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c ++++ b/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c +@@ -14,61 +14,109 @@ + #include + + #define QEMU_NOR_BLOCK_SIZE SIZE_256KB +- +-#define MAX_FLASH_BANKS 4 +- +-EFI_STATUS +-VirtNorFlashPlatformInitialization ( +- VOID +- ) +-{ +- return EFI_SUCCESS; +-} +- +-STATIC VIRT_NOR_FLASH_DESCRIPTION mNorFlashDevices[MAX_FLASH_BANKS]; +- +-EFI_STATUS +-VirtNorFlashPlatformGetDevices ( +- OUT VIRT_NOR_FLASH_DESCRIPTION **NorFlashDescriptions, +- OUT UINT32 *Count +- ) +-{ +- FDT_CLIENT_PROTOCOL *FdtClient; +- INT32 Node; +- EFI_STATUS Status; +- EFI_STATUS FindNodeStatus; ++ ++#define MAX_FLASH_BANKS 4 ++ ++STATIC VIRT_NOR_FLASH_DESCRIPTION mNorFlashDevices[MAX_FLASH_BANKS]; ++STATIC UINTN mNorFlashDeviceCount = 0; ++STATIC INT32 mNorFlashNodes[MAX_FLASH_BANKS]; ++STATIC UINTN mNorFlashNodeCount = 0; ++FDT_CLIENT_PROTOCOL *mFdtClient; ++ ++EFI_STATUS ++VirtNorFlashPlatformInitialization ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UINTN Index; ++ // ++ // UEFI takes ownership of the NOR flash, and exposes its functionality ++ // through the UEFI Runtime Services GetVariable, SetVariable, etc. This ++ // means we need to disable it in the device tree to prevent the OS from ++ // attaching its device driver as well. ++ // Note that this also hides other flash banks, but the only other flash ++ // bank we expect to encounter is the one that carries the UEFI executable ++ // code, which is not intended to be guest updatable, and is usually backed ++ // in a readonly manner by QEMU anyway. ++ // ++ for (Index = 0; Index < mNorFlashNodeCount; Index++) { ++ Status = mFdtClient->SetNodeProperty ( ++ mFdtClient, ++ mNorFlashNodes[Index], ++ "status", ++ "disabled", ++ sizeof ("disabled") ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_WARN, "Failed to set NOR flash status to 'disabled'\n")); ++ } ++ } ++ return EFI_SUCCESS; ++} ++ ++EFI_STATUS ++VirtNorFlashPlatformGetDevices ( ++ OUT VIRT_NOR_FLASH_DESCRIPTION **NorFlashDescriptions, ++ OUT UINT32 *Count ++ ) ++{ ++ ++ if (mNorFlashDeviceCount == 0) { ++ return EFI_NOT_FOUND; ++ } ++ ++ *NorFlashDescriptions = mNorFlashDevices; ++ *Count = mNorFlashDeviceCount; ++ ++ return EFI_SUCCESS; ++} ++ ++ ++ ++EFI_STATUS ++EFIAPI ++NorFlashQemuLibConstructor ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ++ ) ++{ ++ INT32 Node; ++ EFI_STATUS Status; ++ EFI_STATUS FindNodeStatus; + CONST UINT32 *Reg; + UINT32 PropSize; + UINT32 Num; + UINT64 Base; + UINT64 Size; + +- Status = gBS->LocateProtocol ( +- &gFdtClientProtocolGuid, +- NULL, +- (VOID **)&FdtClient +- ); +- ASSERT_EFI_ERROR (Status); +- +- Num = 0; +- for (FindNodeStatus = FdtClient->FindCompatibleNode ( +- FdtClient, +- "cfi-flash", +- &Node +- ); +- !EFI_ERROR (FindNodeStatus) && Num < MAX_FLASH_BANKS; +- FindNodeStatus = FdtClient->FindNextCompatibleNode ( +- FdtClient, +- "cfi-flash", +- Node, +- &Node +- )) +- { +- Status = FdtClient->GetNodeProperty ( +- FdtClient, +- Node, +- "reg", +- (CONST VOID **)&Reg, ++ Status = gBS->LocateProtocol ( ++ &gFdtClientProtocolGuid, ++ NULL, ++ (VOID **)&mFdtClient ++ ); ++ ASSERT_EFI_ERROR (Status); ++ ++ Num = 0; ++ for (FindNodeStatus = mFdtClient->FindCompatibleNode ( ++ mFdtClient, ++ "cfi-flash", ++ &Node ++ ); ++ !EFI_ERROR (FindNodeStatus) && Num < MAX_FLASH_BANKS; ++ FindNodeStatus = mFdtClient->FindNextCompatibleNode ( ++ mFdtClient, ++ "cfi-flash", ++ Node, ++ &Node ++ )) ++ { ++ Status = mFdtClient->GetNodeProperty ( ++ mFdtClient, ++ Node, ++ "reg", ++ (CONST VOID **)&Reg, + &PropSize + ); + if (EFI_ERROR (Status)) { +@@ -101,36 +149,23 @@ VirtNorFlashPlatformGetDevices ( + } + + mNorFlashDevices[Num].DeviceBaseAddress = (UINTN)Base; +- mNorFlashDevices[Num].RegionBaseAddress = (UINTN)Base; +- mNorFlashDevices[Num].Size = (UINTN)Size; +- mNorFlashDevices[Num].BlockSize = QEMU_NOR_BLOCK_SIZE; +- Num++; +- } +- +- // +- // UEFI takes ownership of the NOR flash, and exposes its functionality +- // through the UEFI Runtime Services GetVariable, SetVariable, etc. This +- // means we need to disable it in the device tree to prevent the OS from +- // attaching its device driver as well. +- // Note that this also hides other flash banks, but the only other flash +- // bank we expect to encounter is the one that carries the UEFI executable +- // code, which is not intended to be guest updatable, and is usually backed +- // in a readonly manner by QEMU anyway. +- // +- Status = FdtClient->SetNodeProperty ( +- FdtClient, +- Node, +- "status", +- "disabled", +- sizeof ("disabled") +- ); +- if (EFI_ERROR (Status)) { +- DEBUG ((DEBUG_WARN, "Failed to set NOR flash status to 'disabled'\n")); +- } +- } +- +- *NorFlashDescriptions = mNorFlashDevices; +- *Count = Num; +- +- return EFI_SUCCESS; +-} ++ mNorFlashDevices[Num].RegionBaseAddress = (UINTN)Base; ++ mNorFlashDevices[Num].Size = (UINTN)Size; ++ mNorFlashDevices[Num].BlockSize = QEMU_NOR_BLOCK_SIZE; ++ mNorFlashDeviceCount = ++Num; ++ } ++ mNorFlashNodes[mNorFlashNodeCount++] = Node; ++ } ++ if (Num == 0) { ++ DEBUG ((DEBUG_INFO, ++ "No Flash device found, falling back to Runtime Variable Emulation\n")); ++ ++ Status = PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, ++ "Failed to set PcdEmuVariableNvModeEnable, Status = %r\n", ++ Status)); ++ } ++ } ++ return EFI_SUCCESS; ++} +\ No newline at end of file +diff --git a/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf b/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf +index a6b5865b..e5842430 100644 +--- a/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf ++++ b/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf +@@ -12,18 +12,19 @@ + INF_VERSION = 0x00010005 + BASE_NAME = NorFlashQemuLib + FILE_GUID = 339B7829-4C5F-4EFC-B2DD-5050E530DECE +- MODULE_TYPE = DXE_DRIVER +- VERSION_STRING = 1.0 +- LIBRARY_CLASS = VirtNorFlashPlatformLib +- +-[Sources.common] +- NorFlashQemuLib.c +- +-[Packages] +- MdePkg/MdePkg.dec +- ArmPkg/ArmPkg.dec +- ArmVirtPkg/ArmVirtPkg.dec +- EmbeddedPkg/EmbeddedPkg.dec ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = VirtNorFlashPlatformLib ++ CONSTRUCTOR = NorFlashQemuLibConstructor ++[Sources.common] ++ NorFlashQemuLib.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ ArmPkg/ArmPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ EmbeddedPkg/EmbeddedPkg.dec + OvmfPkg/OvmfPkg.dec + + [LibraryClasses] +@@ -37,6 +38,7 @@ + [Depex] + gFdtClientProtocolGuid + +-[Pcd] +- gArmTokenSpaceGuid.PcdFvBaseAddress +- gArmTokenSpaceGuid.PcdFvSize ++[Pcd] ++ gArmTokenSpaceGuid.PcdFvBaseAddress ++ gArmTokenSpaceGuid.PcdFvSize ++ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable +diff --git a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c +index 62fa62e5..487f88eb 100644 +--- a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c ++++ b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c +@@ -5,12 +5,13 @@ + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ +- +-#include +-#include +-#include +-#include +-#include ++ ++#include ++#include ++#include ++#include ++#include ++#include + #include + #include + +@@ -119,6 +120,26 @@ ArmVirtGetMemoryMap ( + + // End of Table + ZeroMem (&VirtualMemoryTable[3], sizeof (ARM_MEMORY_REGION_DESCRIPTOR)); +- +- *VirtualMemoryMap = VirtualMemoryTable; +-} ++ ++ *VirtualMemoryMap = VirtualMemoryTable; ++} ++ ++/** ++ Configure the MMIO regions as shared with the VMM. ++ ++ Set the protection attribute for the MMIO regions as Unprotected IPA. ++ ++ @param[in] IpaWidth IPA width of the Realm. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaConfigureMmio ( ++ IN UINT64 IpaWidth ++ ) ++{ ++ return RETURN_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf +index 6acad8bb..d6fe9e7a 100644 +--- a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf ++++ b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf +@@ -24,12 +24,13 @@ + ArmVirtPkg/ArmVirtPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec +- MdePkg/MdePkg.dec +- +-[LibraryClasses] +- ArmLib +- BaseMemoryLib +- DebugLib ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmCcaLib ++ ArmLib ++ BaseMemoryLib ++ DebugLib + MemoryAllocationLib + + [Guids] +diff --git a/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf b/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf +index 7edf5018..2d38d242 100755 +--- a/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf ++++ b/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf +@@ -34,12 +34,13 @@ + EmbeddedPkg/EmbeddedPkg.dec + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec +- ArmVirtPkg/ArmVirtPkg.dec +- +-[LibraryClasses] +- BaseLib +- DebugLib +- FdtLib ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ ArmCcaInitPeiLib ++ BaseLib ++ DebugLib ++ FdtLib + ArmLib + IoLib + TimerLib +diff --git a/ArmVirtPkg/PrePi/PrePi.c b/ArmVirtPkg/PrePi/PrePi.c +index ff51a757..e03baa20 100755 +--- a/ArmVirtPkg/PrePi/PrePi.c ++++ b/ArmVirtPkg/PrePi/PrePi.c +@@ -63,13 +63,14 @@ PrePiMain ( + // SEC phase needs to run library constructors by hand. + ProcessLibraryConstructorList (); + +- // Initialize MMU and Memory HOBs (Resource Descriptor HOBs) +- Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)); +- ASSERT_EFI_ERROR (Status); +- +- // Initialize the Serial Port +- SerialPortInitialize (); +- CharCount = AsciiSPrint ( ++ // Initialize MMU and Memory HOBs (Resource Descriptor HOBs) ++ Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)); ++ ASSERT_EFI_ERROR (Status); ++ // Perform the Arm CCA specific initialisations. ++ ArmCcaInitialize (); ++ // Initialize the Serial Port ++ SerialPortInitialize (); ++ CharCount = AsciiSPrint ( + Buffer, + sizeof (Buffer), + "UEFI firmware (version %s built at %a on %a)\n\r", +diff --git a/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c b/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c +new file mode 100644 +index 00000000..cabda236 +--- /dev/null ++++ b/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c +@@ -0,0 +1,38 @@ ++/** @file ++ ++ The QemuPlatformDxe performs platform specific initialization. ++ ++ Copyright (c) 2018 - 2023, Arm Limited. All rights reserved. ++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++#include ++#include ++#include ++ ++EFI_STATUS ++EFIAPI ++QemuPlatformDxeEntryPoint ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ) ++{ ++ EFI_STATUS Status = EFI_SUCCESS; ++ ++ if (PcdGetBool (PcdEmuVariableNvModeEnable)) { ++ ++ // The driver implementing the variable service can now be dispatched. ++ Status = gBS->InstallProtocolInterface ( ++ &gImageHandle, ++ &gEdkiiNvVarStoreFormattedGuid, ++ EFI_NATIVE_INTERFACE, ++ NULL ++ ); ++ ASSERT_EFI_ERROR (Status); ++ } ++ ++ return Status; ++} +diff --git a/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf b/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf +new file mode 100644 +index 00000000..b62f5274 +--- /dev/null ++++ b/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf +@@ -0,0 +1,39 @@ ++## @file ++# ++# Copyright (c) 2018 - 2023, Arm Limited. All rights reserved. ++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = QemuPlatformDxe ++ FILE_GUID = 30E617DC-3EB6-4225-B990-A5C22C87AC27 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = QemuPlatformDxeEntryPoint ++ ++[Sources] ++ QemuPlatformDxe.c ++ ++[Packages] ++ OvmfPkg/OvmfPkg.dec ++ EmbeddedPkg/EmbeddedPkg.dec ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ DebugLib ++ UefiBootServicesTableLib ++ UefiDriverEntryPoint ++ ++[Guids] ++ gEdkiiNvVarStoreFormattedGuid ## SOMETIMES_PRODUCES ## PROTOCOL ++ ++[Pcd] ++ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ++ ++[Depex] ++ TRUE +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +new file mode 100644 +index 00000000..58ea4c66 +--- /dev/null ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +@@ -0,0 +1,593 @@ ++/** @file ++ Realm Aperture Management Protocol Dxe ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved. ++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - IPA - Intermediate Physical Address ++ - RAMP - Realm Aperture Management Protocol ++ - RIPAS - Realm IPA state ++ - RSI - Realm Service Interface ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ A macro defining the signature for the aperture information structure. ++*/ ++#define APERTURE_INFO_SIG SIGNATURE_64 ('A', 'P', 'E', 'R', 'T', 'U', 'R', 'E') ++ ++/** ++ A structure describing the aperture. ++*/ ++typedef struct { ++ /// Signature for identifying this structure. ++ UINT64 Signature; ++ ++ /// The linked list entry. ++ LIST_ENTRY Link; ++ ++ /// The base address for the start of the aperture. ++ EFI_PHYSICAL_ADDRESS BaseAddress; ++ ++ /// The number of pages covered by the aperture. ++ UINTN Pages; ++ ++ /// The bit mask of attributes for the memory region. The ++ /// bit mask of available attributes is defined in GetMemoryMap(). ++ UINT64 MemoryAttributes; ++} APERTURE_INFO; ++ ++/** ++ List of the APERTURE_INFO structures that have been set up by OpenAperture() ++ and not yet torn down by CloseAperture(). The list represents the full set ++ of open apertures currently in effect. ++*/ ++STATIC ++LIST_ENTRY mApertureInfos = INITIALIZE_LIST_HEAD_VARIABLE (mApertureInfos); ++ ++/** ++ A local variable to store the IPA width of the Realm. The IPA width ++ of the Realm is required to configure the protection attribute of ++ memory regions. ++*/ ++STATIC UINT64 mIpaWidth; ++ ++/** Checks if an open aperture is overlapping the memory region. ++ ++ @param [in] Memory Pointer to the page start address. ++ @param [in] Pages Number of pages to share. ++ ++ @retval TRUE If memory region overlaps an open aperture. ++ @retval FALSE Memory region does not overlap any open apertures. ++**/ ++STATIC ++BOOLEAN ++EFIAPI ++IsApertureOverlapping ( ++ IN CONST EFI_PHYSICAL_ADDRESS MemStart, ++ IN CONST UINTN Pages ++ ) ++{ ++ LIST_ENTRY *Node; ++ LIST_ENTRY *NextNode; ++ APERTURE_INFO *ApertureInfo; ++ EFI_PHYSICAL_ADDRESS MemEnd; ++ EFI_PHYSICAL_ADDRESS ApertureStart; ++ EFI_PHYSICAL_ADDRESS ApertureEnd; ++ ++ MemEnd = MemStart + (EFI_PAGE_SIZE * Pages) - 1; ++ ++ // All drivers that had opened the apertures have halted their respective ++ // controllers by now; close all the apertures. ++ for ( ++ Node = GetFirstNode (&mApertureInfos); ++ Node != &mApertureInfos; ++ Node = NextNode ++ ) ++ { ++ NextNode = GetNextNode (&mApertureInfos, Node); ++ ApertureInfo = CR (Node, APERTURE_INFO, Link, APERTURE_INFO_SIG); ++ ApertureStart = ApertureInfo->BaseAddress; ++ ApertureEnd = ApertureStart + (EFI_PAGE_SIZE * ApertureInfo->Pages) - 1; ++ ++ if (((ApertureStart >= MemStart) && (ApertureStart <= MemEnd)) || ++ ((ApertureEnd >= MemStart) && (ApertureEnd <= MemEnd)) || ++ ((MemStart >= ApertureStart) && (MemStart <= ApertureEnd)) || ++ ((MemEnd >= ApertureStart) && (MemEnd <= ApertureEnd))) ++ { ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/** Enables sharing of the memory buffers with the host. ++ ++ @param [in] Memory Pointer to the page start address. ++ @param [in] Pages Number of pages to share. ++ @param [out] ApertureReference Reference to the opened aperture. ++ ++ @retval EFI_SUCCESS Success. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_OUT_OF_RESOURCES Memory allocation failed. ++ @retval EFI_ACCESS_DENIED Aperture already open over memory region. ++**/ ++STATIC ++EFI_STATUS ++EFIAPI ++RampOpenAperture ( ++ IN CONST EFI_PHYSICAL_ADDRESS Memory, ++ IN CONST UINTN Pages, ++ OUT EFI_HANDLE *CONST ApertureReference ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_STATUS Status1; ++ APERTURE_INFO *ApertInfo; ++ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; ++ EFI_PHYSICAL_ADDRESS MemRangeAddr; ++ UINTN Index; ++ ++ if ((Memory == 0) || ++ (Pages == 0) || ++ (ApertureReference == NULL) || ++ ((Memory & (EFI_PAGE_SIZE - 1)) != 0)) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // The pages size must be aligned to the Realm Granule size. ++ // STATIC_ASSERT ((EFI_PAGE_SIZE & (REALM_GRANULE_SIZE - 1)) == 0); ++ ++ // Checks if we already have an open aperture that overlaps the ++ // memory region. If so return the request as invalid. ++ if (IsApertureOverlapping (Memory, Pages)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ MemRangeAddr = Memory; ++ for (Index = 0; Index < Pages; Index++) { ++ Status = gDS->GetMemorySpaceDescriptor (MemRangeAddr, &GcdDescriptor); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: Memory = 0x%lx, MemType = %a\n", ++ __func__, ++ MemRangeAddr, ++ ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) ? ++ "Runtime Services Memory" : "Boot Services Memory" ++ )); ++ ++ // We currently do not have a usecase where we would want to open apertures ++ // for runtime services memory ++ if ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ MemRangeAddr += EFI_PAGE_SIZE; ++ } // for ++ ++ Status = ArmCcaSetMemoryProtectAttribute ( ++ Memory, ++ EFI_PAGES_TO_SIZE (Pages), ++ mIpaWidth, ++ TRUE ++ ); ++ if (RETURN_ERROR (Status)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "ERROR: Failed to update page tables for Protected EMPTY page mapping, " ++ "Address = %p, Pages = 0x%lx, Status = %r\n", ++ Memory, ++ Pages, ++ Status ++ )); ++ return Status; ++ } ++ DEBUG ((DEBUG_INFO, "RampOpenAperture set 0x%p NS 1.\n", Memory)); ++ ++ // Allocate a APERTURE_INFO structure to remember the apertures opened. ++ ApertInfo = AllocateZeroPool (sizeof (APERTURE_INFO)); ++ if (ApertInfo == NULL) { ++ Status = EFI_OUT_OF_RESOURCES; ++ goto error_handler1; ++ } ++ ++ InitializeListHead (&ApertInfo->Link); ++ ApertInfo->Signature = APERTURE_INFO_SIG; ++ ApertInfo->BaseAddress = Memory; ++ ApertInfo->Pages = Pages; ++ ApertInfo->MemoryAttributes = GcdDescriptor.Attributes; ++ ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: ApertRef = 0x%p, Memory = 0x%lx, Pages = 0x%x, " ++ "MemoryAttributes = 0x%x\n", ++ __func__, ++ ApertInfo, ++ ApertInfo->BaseAddress, ++ ApertInfo->Pages, ++ ApertInfo->MemoryAttributes ++ )); ++ ++ InsertHeadList (&mApertureInfos, &ApertInfo->Link); ++ *ApertureReference = (EFI_HANDLE *)&ApertInfo->Link; ++ ++ return Status; ++ ++error_handler1: ++ Status1 = ArmCcaSetMemoryProtectAttribute ( ++ Memory, ++ EFI_PAGES_TO_SIZE (Pages), ++ mIpaWidth, ++ TRUE ++ ); ++ if (RETURN_ERROR (Status1)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "ERROR: Failed to update page tables to Protected page mapping, " ++ "Address = %p, Pages = 0x%lx, Status = %r\n", ++ Memory, ++ Pages, ++ Status1 ++ )); ++ } ++ ++ *ApertureReference = NULL; ++ return Status; ++} ++ ++/** Disables the sharing of the buffers. ++ ++ @param [in] ApertureReference Reference to the aperture for closing. ++ ++ @retval EFI_SUCCESS The operation completed successfully. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_NOT_FOUND The required buffer information is not found. ++**/ ++STATIC ++EFI_STATUS ++EFIAPI ++RampCloseAperture ( ++ IN CONST EFI_HANDLE ApertureReference ++ ) ++{ ++ EFI_STATUS Status; ++ APERTURE_INFO *ApertInfo = NULL; ++ ++ if (ApertureReference == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ ApertInfo = CR (ApertureReference, APERTURE_INFO, Link, APERTURE_INFO_SIG); ++ if (ApertInfo == NULL) { ++ return EFI_NOT_FOUND; ++ } ++ ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: ApertRef = 0x%p, Memory = 0x%lx, Pages = 0x%x, " ++ "MemoryAttributes = 0x%x\n", ++ __func__, ++ ApertInfo, ++ ApertInfo->BaseAddress, ++ ApertInfo->Pages, ++ ApertInfo->MemoryAttributes ++ )); ++ ++ Status = ArmCcaSetMemoryProtectAttribute ( ++ ApertInfo->BaseAddress, ++ EFI_PAGES_TO_SIZE (ApertInfo->Pages), ++ mIpaWidth, ++ FALSE ++ ); ++ if (RETURN_ERROR (Status)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "ERROR: Failed to update page tables for Protected RAM page mapping," ++ "Address = %p, Pages = 0x%lx, Status = %r\n", ++ ApertInfo->BaseAddress, ++ ApertInfo->Pages, ++ Status ++ )); ++ } ++ ++ RemoveEntryList (&ApertInfo->Link); ++ FreePool (ApertInfo); ++ ++ return Status; ++} ++ ++/** Closes all open apertures. ++ ++**/ ++STATIC ++VOID ++EFIAPI ++RampCloseAllApertures ( ++ VOID ++ ) ++{ ++ LIST_ENTRY *Node; ++ LIST_ENTRY *NextNode; ++ APERTURE_INFO *ApertureInfo; ++ ++ // All drivers that had opened the apertures have halted their respective ++ // controllers by now; close all the apertures. ++ for ( ++ Node = GetFirstNode (&mApertureInfos); ++ Node != &mApertureInfos; ++ Node = NextNode ++ ) ++ { ++ NextNode = GetNextNode (&mApertureInfos, Node); ++ ApertureInfo = CR (Node, APERTURE_INFO, Link, APERTURE_INFO_SIG); ++ RampCloseAperture (&ApertureInfo->Link); ++ } ++} ++ ++/** ++ Notification function that is queued after the notification functions of all ++ events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. ++ ++ This function invokes the closing of all open apertures. ++ ++ @param[in] Event Event whose notification function is being invoked. Event ++ is permitted to request the queueing of this function ++ only at TPL_CALLBACK task priority level. ++ ++ @param[in] Context Ignored. ++**/ ++STATIC ++VOID ++EFIAPI ++OnRampExitBootServicesEvent ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ RampCloseAllApertures (); ++} ++ ++/** ++ Notification function that is queued when gBS->ExitBootServices() signals the ++ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another ++ event, received as Context, and returns. ++ ++ Signaling an event in this context is safe. The UEFI spec allows ++ gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not ++ listed, hence memory is not allocated. ++ ++ @param[in] Event Event whose notification function is being invoked. ++ Event is permitted to request the queueing of this ++ function at TPL_CALLBACK or TPL_NOTIFY task ++ priority level. ++ ++ @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal ++ is permitted to request the queueing of its ++ notification function only at TPL_CALLBACK level. ++**/ ++STATIC ++VOID ++EFIAPI ++RampExitBootServices ( ++ IN EFI_EVENT Event, ++ IN VOID *EventToSignal ++ ) ++{ ++ /** ++ (1) The NotifyFunctions of all the events in ++ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before ++ RampExitBootServices() is entered. ++ ++ (2) RampExitBootServices() is executing minimally at TPL_CALLBACK. ++ ++ (3) RampExitBootServices() has been queued in unspecified order relative ++ to the NotifyFunctions of all the other events in ++ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as ++ Event's. ++ ++ Consequences: ++ ++ - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions ++ queued at TPL_CALLBACK may be invoked after RampExitBootServices() ++ returns. ++ ++ - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions ++ queued at TPL_NOTIFY may be invoked after RampExitBootServices() ++ returns; plus *all* NotifyFunctions queued at TPL_CALLBACK will be ++ invoked strictly after all NotifyFunctions queued at TPL_NOTIFY, ++ including RampExitBootServices(), have been invoked. ++ ++ - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we ++ queue EventToSignal's NotifyFunction after the NotifyFunctions of *all* ++ events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES. ++ */ ++ gBS->SignalEvent (EventToSignal); ++} ++ ++/** A structure describing the Realm Aperture Management protocol. ++*/ ++STATIC ++CONST ++EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL Ramp = { ++ EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_REVISION, ++ RampOpenAperture, ++ RampCloseAperture ++}; ++ ++/** ++ This routine is called to close all apertures before system reset. ++ ++ @param[in] ResetType The type of reset to perform. ++ @param[in] ResetStatus The status code for the reset. ++ @param[in] DataSize The size, in bytes, of ResetData. ++ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or ++ EfiResetShutdown the data buffer starts with a Null- ++ terminated string, optionally followed by additional ++ binary data. The string is a description that the ++ caller may use to further indicate the reason for ++ the system reset. ResetData is only valid if ++ ResetStatus is something other than EFI_SUCCESS ++ unless the ResetType is EfiResetPlatformSpecific ++ where a minimum amount of ResetData is always ++ required. ++ For a ResetType of EfiResetPlatformSpecific the data ++ buffer also starts with a Null-terminated string ++ that is followed by an EFI_GUID that describes the ++ specific type of reset to perform. ++**/ ++VOID ++EFIAPI ++OnResetEvent ( ++ IN EFI_RESET_TYPE ResetType, ++ IN EFI_STATUS ResetStatus, ++ IN UINTN DataSize, ++ IN VOID *ResetData OPTIONAL ++ ) ++{ ++ RampCloseAllApertures (); ++} ++ ++/** ++ Hook the system reset to close all apertures. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++**/ ++VOID ++EFIAPI ++OnResetNotificationInstall ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify; ++ ++ Status = gBS->LocateProtocol ( ++ &gEfiResetNotificationProtocolGuid, ++ NULL, ++ (VOID **)&ResetNotify ++ ); ++ if (!EFI_ERROR (Status)) { ++ Status = ResetNotify->RegisterResetNotify (ResetNotify, OnResetEvent); ++ ASSERT_EFI_ERROR (Status); ++ DEBUG ((DEBUG_INFO, "RAMP: Hook system reset to close all apertures.\n")); ++ gBS->CloseEvent (Event); ++ } ++} ++ ++/** Entry point for Realm Aperture Management Protocol Dxe ++ ++ @param [in] ImageHandle Handle for this image. ++ @param [in] SystemTable Pointer to the EFI system table. ++ ++ @retval EFI_SUCCESS When executing in a Realm the RAMP was ++ installed successfully. ++ When execution context is not a Realm, this ++ function returns success indicating nothing ++ needs to be done and allow other modules to ++ run. ++ @retval EFI_OUT_OF_RESOURCES There was not enough memory to install the ++ protocols. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ ++**/ ++EFI_STATUS ++EFIAPI ++RealmApertureManagementProtocolDxeInitialize ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_HANDLE Handle = NULL; ++ EFI_EVENT CloseAllAperturesEvent; ++ EFI_EVENT ExitBootEvent; ++ VOID *Registration; ++ DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 1.\n")); ++ // When the execution context is a Realm, install the Realm Aperture ++ // Management protocol otherwise return success so that other modules ++ // can run. ++ if (!IsRealm ()) { ++ return EFI_SUCCESS; ++ } ++ ++ mIpaWidth = 64; ++ ++ /* ++ Create the "late" event whose notification function will close all ++ apertures. ++ */ ++ Status = gBS->CreateEvent ( ++ EVT_NOTIFY_SIGNAL, // Type ++ TPL_CALLBACK, // NotifyTpl ++ OnRampExitBootServicesEvent, // NotifyFunction ++ NULL, // NotifyContext ++ &CloseAllAperturesEvent // Event ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ /* ++ Create the event whose notification function will be queued by ++ gBS->ExitBootServices() and will signal the event created above. ++ */ ++ Status = gBS->CreateEvent ( ++ EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type ++ TPL_CALLBACK, // NotifyTpl ++ RampExitBootServices, // NotifyFunction ++ CloseAllAperturesEvent, // NotifyContext ++ &ExitBootEvent // Event ++ ); ++ if (EFI_ERROR (Status)) { ++ goto error_handler1; ++ } ++ ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gEfiRealmApertureManagementProtocolGuid, ++ &Ramp, ++ NULL ++ ); ++ if (!EFI_ERROR (Status)) { ++ // RAMP Protocol installed successfully ++ // Hook the system reset to close all apertures. ++ EfiCreateProtocolNotifyEvent ( ++ &gEfiResetNotificationProtocolGuid, ++ TPL_CALLBACK, ++ OnResetNotificationInstall, ++ NULL, ++ &Registration ++ ); ++ DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 2.\n")); ++ return Status; ++ } ++ ++ // cleanup on error ++ gBS->CloseEvent (ExitBootEvent); ++ ++error_handler1: ++ gBS->CloseEvent (CloseAllAperturesEvent); ++ DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 3.\n")); ++ return Status; ++} +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +new file mode 100644 +index 00000000..029e933e +--- /dev/null ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +@@ -0,0 +1,47 @@ ++## @file ++# Module to manage the sharing of buffers in a Realm with the Host. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved. ++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = RealmApertureManagementProtocolDxe ++ FILE_GUID = CEC2F7D5-2564-46D4-A23F-501623F7F56A ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = RealmApertureManagementProtocolDxeInitialize ++ ++# ++# The following information is for reference only and not required by the build tools. ++# ++# VALID_ARCHITECTURES = AARCH64 ++# ++ ++[Sources] ++ RealmApertureManagementProtocolDxe.c ++ ++[Packages] ++ ArmVirtPkg/ArmVirtPkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmCcaLib ++ BaseLib ++ DxeServicesTableLib ++ MemoryAllocationLib ++ PrintLib ++ UefiBootServicesTableLib ++ UefiDriverEntryPoint ++ UefiLib ++ ++[Protocols] ++ gEfiRealmApertureManagementProtocolGuid ## SOMETIME_PRODUCES ++ gEfiResetNotificationProtocolGuid ## CONSUMES ++ ++[Depex] ++ TRUE +diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c +index 115a2107..e5429ea3 100644 +--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c ++++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c +@@ -19,13 +19,12 @@ + #include + + #include +- +-STATIC UINTN mFwCfgSelectorAddress; +-STATIC UINTN mFwCfgDataAddress; +-STATIC UINTN mFwCfgDmaAddress; +- +-/** +- Reads firmware configuration bytes into a buffer ++ ++STATIC UINTN mFwCfgSelectorAddress; ++STATIC UINTN mFwCfgDataAddress; ++ ++/** ++ Reads firmware configuration bytes into a buffer + + @param[in] Size Size in bytes to read + @param[in] Buffer Buffer to store data into (OPTIONAL if Size is 0) +@@ -64,15 +63,12 @@ VOID(EFIAPI SKIP_BYTES_FUNCTION)( + // + // Forward declaration of the two implementations we have. + // +-STATIC READ_BYTES_FUNCTION MmioReadBytes; +-STATIC WRITE_BYTES_FUNCTION MmioWriteBytes; +-STATIC SKIP_BYTES_FUNCTION MmioSkipBytes; +-STATIC READ_BYTES_FUNCTION DmaReadBytes; +-STATIC WRITE_BYTES_FUNCTION DmaWriteBytes; +-STATIC SKIP_BYTES_FUNCTION DmaSkipBytes; +- +-// +-// These correspond to the implementation we detect at runtime. ++STATIC READ_BYTES_FUNCTION MmioReadBytes; ++STATIC WRITE_BYTES_FUNCTION MmioWriteBytes; ++STATIC SKIP_BYTES_FUNCTION MmioSkipBytes; ++ ++// ++// These correspond to the implementation we detect at runtime. + // + STATIC READ_BYTES_FUNCTION *InternalQemuFwCfgReadBytes = MmioReadBytes; + STATIC WRITE_BYTES_FUNCTION *InternalQemuFwCfgWriteBytes = MmioWriteBytes; +@@ -198,18 +194,12 @@ QemuFwCfgInitialize ( + // + if (FwCfgDmaAddress != 0) { + UINT32 Features; +- +- QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion); +- Features = QemuFwCfgRead32 (); +- if ((Features & FW_CFG_F_DMA) != 0) { +- mFwCfgDmaAddress = FwCfgDmaAddress; +- InternalQemuFwCfgReadBytes = DmaReadBytes; +- InternalQemuFwCfgWriteBytes = DmaWriteBytes; +- InternalQemuFwCfgSkipBytes = DmaSkipBytes; +- } +- } +- } else { +- mFwCfgSelectorAddress = 0; ++ ++ QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion); ++ Features = QemuFwCfgRead32 (); ++ } ++ } else { ++ mFwCfgSelectorAddress = 0; + mFwCfgDataAddress = 0; + } + } +@@ -288,97 +278,12 @@ MmioReadBytes ( + + if (Left & 1) { + *Ptr = MmioRead8 (mFwCfgDataAddress); +- } +-} +- +-/** +- Transfer an array of bytes, or skip a number of bytes, using the DMA +- interface. +- +- @param[in] Size Size in bytes to transfer or skip. +- +- @param[in,out] Buffer Buffer to read data into or write data from. Ignored, +- and may be NULL, if Size is zero, or Control is +- FW_CFG_DMA_CTL_SKIP. +- +- @param[in] Control One of the following: +- FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer. +- FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer. +- FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg. +-**/ +-STATIC +-VOID +-DmaTransferBytes ( +- IN UINTN Size, +- IN OUT VOID *Buffer OPTIONAL, +- IN UINT32 Control +- ) +-{ +- volatile FW_CFG_DMA_ACCESS Access; +- UINT32 Status; +- +- ASSERT ( +- Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ || +- Control == FW_CFG_DMA_CTL_SKIP +- ); +- +- if (Size == 0) { +- return; +- } +- +- ASSERT (Size <= MAX_UINT32); +- +- Access.Control = SwapBytes32 (Control); +- Access.Length = SwapBytes32 ((UINT32)Size); +- Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer); +- +- // +- // We shouldn't start the transfer before setting up Access. +- // +- MemoryFence (); +- +- // +- // This will fire off the transfer. +- // +- #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_RISCV64) +- MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access)); +- #else +- MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access)); +- #endif +- +- // +- // We shouldn't look at Access.Control before starting the transfer. +- // +- MemoryFence (); +- +- do { +- Status = SwapBytes32 (Access.Control); +- ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0); +- } while (Status != 0); +- +- // +- // The caller will want to access the transferred data. +- // +- MemoryFence (); +-} +- +-/** +- Fast READ_BYTES_FUNCTION. +-**/ +-STATIC +-VOID +-EFIAPI +-DmaReadBytes ( +- IN UINTN Size, +- IN VOID *Buffer OPTIONAL +- ) +-{ +- DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_READ); +-} +- +-/** +- Reads firmware configuration bytes into a buffer +- ++ } ++} ++ ++/** ++ Reads firmware configuration bytes into a buffer ++ + If called multiple times, then the data read will continue at the offset of + the firmware configuration item where the previous read ended. + +@@ -415,26 +320,12 @@ MmioWriteBytes ( + + for (Idx = 0; Idx < Size; ++Idx) { + MmioWrite8 (mFwCfgDataAddress, ((UINT8 *)Buffer)[Idx]); +- } +-} +- +-/** +- Fast WRITE_BYTES_FUNCTION. +-**/ +-STATIC +-VOID +-EFIAPI +-DmaWriteBytes ( +- IN UINTN Size, +- IN VOID *Buffer OPTIONAL +- ) +-{ +- DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_WRITE); +-} +- +-/** +- Write firmware configuration bytes from a buffer +- ++ } ++} ++ ++/** ++ Write firmware configuration bytes from a buffer ++ + If called multiple times, then the data written will continue at the offset + of the firmware configuration item where the previous write ended. + +@@ -478,25 +369,12 @@ MmioSkipBytes ( + ChunkSize = MIN (Size, sizeof SkipBuffer); + MmioReadBytes (ChunkSize, SkipBuffer); + Size -= ChunkSize; +- } +-} +- +-/** +- Fast SKIP_BYTES_FUNCTION. +-**/ +-STATIC +-VOID +-EFIAPI +-DmaSkipBytes ( +- IN UINTN Size +- ) +-{ +- DmaTransferBytes (Size, NULL, FW_CFG_DMA_CTL_SKIP); +-} +- +-/** +- Skip bytes in the firmware configuration item. +- ++ } ++} ++ ++/** ++ Skip bytes in the firmware configuration item. ++ + Increase the offset of the firmware configuration item without transferring + bytes between the item and a caller-provided buffer. Subsequent read, write + or skip operations will commence at the increased offset. +diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec +index a6016d58..61d5ba42 100644 +--- a/OvmfPkg/OvmfPkg.dec ++++ b/OvmfPkg/OvmfPkg.dec +@@ -182,12 +182,13 @@ + gOvmfTpmMmioAccessiblePpiGuid = {0x35c84ff2, 0x7bfe, 0x453d, {0x84, 0x5f, 0x68, 0x3a, 0x49, 0x2c, 0xf7, 0xb7}} + + gEfiPeiMpInitLibMpDepPpiGuid = {0x138f9cf4, 0xf0e7, 0x4721, { 0x8f, 0x49, 0xf5, 0xff, 0xec, 0xf4, 0x2d, 0x40}} +- gEfiPeiMpInitLibUpDepPpiGuid = {0xb590774, 0xbc67, 0x49f4, { 0xa7, 0xdb, 0xe8, 0x2e, 0x89, 0xe6, 0xb5, 0xd6}} +- +-[Protocols] +- gVirtioDeviceProtocolGuid = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}} +- gXenBusProtocolGuid = {0x3d3ca290, 0xb9a5, 0x11e3, {0xb7, 0x5d, 0xb8, 0xac, 0x6f, 0x7d, 0x65, 0xe6}} +- gXenIoProtocolGuid = {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 0x85, 0x55, 0x62, 0x59, 0x04, 0x49}} ++ gEfiPeiMpInitLibUpDepPpiGuid = {0xb590774, 0xbc67, 0x49f4, { 0xa7, 0xdb, 0xe8, 0x2e, 0x89, 0xe6, 0xb5, 0xd6}} ++ ++[Protocols] ++ gEfiRealmApertureManagementProtocolGuid = { 0x585c00be, 0xcf7c, 0x4db8, { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } } ++ gVirtioDeviceProtocolGuid = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}} ++ gXenBusProtocolGuid = {0x3d3ca290, 0xb9a5, 0x11e3, {0xb7, 0x5d, 0xb8, 0xac, 0x6f, 0x7d, 0x65, 0xe6}} ++ gXenIoProtocolGuid = {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 0x85, 0x55, 0x62, 0x59, 0x04, 0x49}} + gIoMmuAbsentProtocolGuid = {0xf8775d50, 0x8abd, 0x4adf, {0x92, 0xac, 0x85, 0x3e, 0x51, 0xf6, 0xc8, 0xdc}} + gEfiLegacy8259ProtocolGuid = {0x38321dba, 0x4fe0, 0x4e17, {0x8a, 0xec, 0x41, 0x30, 0x55, 0xea, 0xed, 0xc1}} + gEfiFirmwareVolumeProtocolGuid = {0x389F751F, 0x1838, 0x4388, {0x83, 0x90, 0xcd, 0x81, 0x54, 0xbd, 0x27, 0xf8}} +-- +2.27.0 + diff --git a/edk2.spec b/edk2.spec index 0bb1bf3..f37c23d 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 17 +Release: 18 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -132,6 +132,9 @@ patch80: 0080-Platform-Loongson-Remove-minimium-memory-size-limita.patch patch81: 0081-Platform-Loongson-Modify-loongarch-uefi-firmware-siz.patch patch82: 0082-fixup-fdt-parse-error.patch +# Support virtCCA +patch83: 0083-edk2-1219-support-virtCCA.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -401,6 +404,10 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Thu Jan 9 2025 z00570632 - 202308-18 +- Support virtCCA +- 0083-edk2-1219-support-virtCCA.patch + * Tue Dec 17 2024 Xiaotian Wu - 202308-17 - Update LoongArch virtual machine - 0080-Platform-Loongson-Remove-minimium-memory-size-limita.patch -- Gitee From 5b9b8f019abb3b743529f893bfd39c3add026c07 Mon Sep 17 00:00:00 2001 From: gongchangsui Date: Mon, 17 Feb 2025 07:22:59 -0500 Subject: [PATCH 2/2] enable cc measurement and sha256 in cc measurement --- ...urement-and-sha256-in-cc-measurement.patch | 4912 +++++++++++++++++ edk2.spec | 7 + 2 files changed, 4919 insertions(+) create mode 100644 0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch diff --git a/0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch b/0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch new file mode 100644 index 0000000..98cea5f --- /dev/null +++ b/0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch @@ -0,0 +1,4912 @@ +From 6b83755a46db898016d51a3d0d8f44e4a656747c Mon Sep 17 00:00:00 2001 +From: z00570632 +Date: Mon, 17 Feb 2025 19:17:07 +0800 +Subject: [PATCH] enable cc measurement and sha256 in cc measurement + +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 2235 +++++++++++++++++ + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf | 86 + + ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c | 407 +++ + ArmVirtPkg/ArmVirtPkg.dec | 2 + + ArmVirtPkg/ArmVirtQemu.dsc | 127 +- + ArmVirtPkg/ArmVirtQemu.fdf | 25 +- + ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc | 10 + + ArmVirtPkg/Include/Library/ArmCcaRsiLib.h | 373 +++ + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c | 13 + + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf | 1 + + ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h | 59 + + .../Library/ArmCcaRsiLib/ArmCcaRsiLib.c | 730 ++++++ + .../Library/ArmCcaRsiLib/ArmCcaRsiLib.inf | 29 + + ArmVirtPkg/Library/HashLibCca/HashLibCca.c | 209 ++ + ArmVirtPkg/Library/HashLibCca/HashLibCca.inf | 39 + + .../RealmApertureManagementProtocolDxe.c | 7 +- + .../RealmApertureManagementProtocolDxe.inf | 1 + + MdeModulePkg/MdeModulePkg.dec | 2 +- + .../IndustryStandard/UefiTcgPlatform.h | 1 + + MdePkg/Include/Protocol/CcMeasurement.h | 5 +- + .../DxeTpm2MeasureBootLib.c | 96 +- + .../HashInstanceLibSha256.c | 1 - + .../HashInstanceLibSha256.inf | 1 - + 23 files changed, 4334 insertions(+), 125 deletions(-) + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c + create mode 100644 ArmVirtPkg/Include/Library/ArmCcaRsiLib.h + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf + create mode 100644 ArmVirtPkg/Library/HashLibCca/HashLibCca.c + create mode 100644 ArmVirtPkg/Library/HashLibCca/HashLibCca.inf + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +new file mode 100644 +index 00000000..a4881ad5 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -0,0 +1,2235 @@ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define PERF_ID_CC_TCG2_DXE 0x3130 ++ ++#define CC_EVENT_LOG_AREA_COUNT_MAX 1 ++#define CC_MR_INDEX_0_RIM 0 ++#define CC_MR_INDEX_1_REM0 1 ++#define CC_MR_INDEX_2_REM1 2 ++#define CC_MR_INDEX_3_REM2 3 ++#define CC_MR_INDEX_INVALID 4 ++ ++typedef struct { ++ CHAR16 *VariableName; ++ EFI_GUID *VendorGuid; ++} VARIABLE_TYPE; ++ ++typedef struct { ++ EFI_CC_EVENT_LOG_FORMAT EventLogFormat; ++ EFI_PHYSICAL_ADDRESS Lasa; ++ UINT64 Laml; ++ UINTN EventLogSize; ++ UINT8 *LastEvent; ++ BOOLEAN EventLogStarted; ++ BOOLEAN EventLogTruncated; ++ UINTN Next800155EventOffset; ++} CC_EVENT_LOG_AREA_STRUCT; ++ ++typedef struct _CCA_DXE_DATA { ++ EFI_CC_BOOT_SERVICE_CAPABILITY BsCap; ++ CC_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ BOOLEAN GetEventLogCalled[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ CC_EVENT_LOG_AREA_STRUCT FinalEventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ EFI_CC_FINAL_EVENTS_TABLE *FinalEventsTable[CC_EVENT_LOG_AREA_COUNT_MAX]; ++} CCA_DXE_DATA; ++ ++typedef struct { ++ TPMI_ALG_HASH HashAlgo; ++ UINT16 HashSize; ++ UINT32 HashMask; ++} CCA_HASH_INFO; ++ ++CCA_DXE_DATA mCcaDxeData = { ++ { ++ sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY), // Size ++ { 1, 1 }, // StructureVersion ++ { 1, 1 }, // ProtocolVersion ++ EFI_CC_BOOT_HASH_ALG_SHA256, // HashAlgorithmBitmap ++ EFI_CC_EVENT_LOG_FORMAT_TCG_2, // SupportedEventLogs ++ { 2, 0 } // {CC_TYPE, CC_SUBTYPE} ++ }, ++}; ++ ++UINTN mBootAttempts = 0; ++CHAR16 mBootVarName[] = L"BootOrder"; ++ ++VARIABLE_TYPE mVariableType[] = { ++ { EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid }, ++ { EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid }, ++}; ++ ++EFI_CC_EVENTLOG_ACPI_TABLE mCcaEventlogAcpiTemplate = { ++ { ++ EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE, ++ sizeof (mCcaEventlogAcpiTemplate), ++ EFI_CC_EVENTLOG_ACPI_TABLE_REVISION, ++ // ++ // Compiler initializes the remaining bytes to 0 ++ // These fields should be filled in production ++ // ++ }, ++ { EFI_CC_TYPE_CCA, 0 }, // CcType ++ 0, // rsvd ++ 0, // laml ++ 0, // lasa ++}; ++ ++// ++// Supported Hash list in Td guest. ++// Currently SHA256 is supported. ++// ++CCA_HASH_INFO mHashInfo[] = { ++ { TPM_ALG_SHA256, SHA256_DIGEST_SIZE, HASH_ALG_SHA256 } ++}; ++ ++/** ++ Get hash size based on Algo ++ ++ @param[in] HashAlgo Hash Algorithm Id. ++ ++ @return Size of the hash. ++**/ ++UINT16 ++GetHashSizeFromAlgo ( ++ IN TPMI_ALG_HASH HashAlgo ++ ) ++{ ++ UINTN Index; ++ ++ for (Index = 0; Index < sizeof (mHashInfo)/sizeof (mHashInfo[0]); Index++) { ++ if (mHashInfo[Index].HashAlgo == HashAlgo) { ++ return mHashInfo[Index].HashSize; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ Copy TPML_DIGEST_VALUES into a buffer ++ ++ @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary. ++ @param[in] DigestList TPML_DIGEST_VALUES to be copied. ++ @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy. ++ ++ @return The end of buffer to hold TPML_DIGEST_VALUES. ++**/ ++VOID * ++CopyDigestListToBuffer ( ++ IN OUT VOID *Buffer, ++ IN TPML_DIGEST_VALUES *DigestList, ++ IN UINT32 HashAlgorithmMask ++ ) ++{ ++ UINTN Index; ++ UINT16 DigestSize; ++ UINT32 DigestListCount; ++ UINT32 *DigestListCountPtr; ++ ++ DigestListCountPtr = (UINT32 *)Buffer; ++ DigestListCount = 0; ++ Buffer = (UINT8 *)Buffer + sizeof (DigestList->count); ++ for (Index = 0; Index < DigestList->count; Index++) { ++ if ((DigestList->digests[Index].hashAlg & HashAlgorithmMask) == 0) { ++ DEBUG ((DEBUG_ERROR, "WARNING: CCA Event log has HashAlg unsupported (0x%x)\n", DigestList->digests[Index].hashAlg)); ++ continue; ++ } ++ ++ CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof (DigestList->digests[Index].hashAlg)); ++ Buffer = (UINT8 *)Buffer + sizeof (DigestList->digests[Index].hashAlg); ++ DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg); ++ CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize); ++ Buffer = (UINT8 *)Buffer + DigestSize; ++ DigestListCount++; ++ } ++ ++ WriteUnaligned32 (DigestListCountPtr, DigestListCount); ++ ++ return Buffer; ++} ++ ++EFI_HANDLE mImageHandle; ++ ++/** ++ Measure PE image into TPM log based on the authenticode image hashing in ++ PE/COFF Specification 8.0 Appendix A. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will validate its data structure ++ within this image buffer before use. ++ ++ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). ++ ++ @param[in] RemIndex REM index ++ @param[in] ImageAddress Start address of image buffer. ++ @param[in] ImageSize Image size ++ @param[out] DigestList Digest list of this image. ++ ++ @retval EFI_SUCCESS Successfully measure image. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. ++ @retval other error value ++**/ ++EFI_STATUS ++MeasurePeImageAndExtend ( ++ IN UINT32 RemIndex, ++ IN EFI_PHYSICAL_ADDRESS ImageAddress, ++ IN UINTN ImageSize, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ); ++ ++#define COLUME_SIZE (16 * 2) ++ ++/** ++ ++ This function dump raw data. ++ ++ @param Data raw data ++ @param Size raw data size ++ ++**/ ++VOID ++InternalDumpData ( ++ IN UINT8 *Data, ++ IN UINTN Size ++ ) ++{ ++ UINTN Index; ++ ++ for (Index = 0; Index < Size; Index++) { ++ DEBUG ((DEBUG_INFO, Index == COLUME_SIZE/2 ? " | %02x" : " %02x", (UINTN)Data[Index])); ++ } ++} ++ ++/** ++ ++ This function dump raw data with colume format. ++ ++ @param Data raw data ++ @param Size raw data size ++ ++**/ ++VOID ++InternalDumpHex ( ++ IN UINT8 *Data, ++ IN UINTN Size ++ ) ++{ ++ UINTN Index; ++ UINTN Count; ++ UINTN Left; ++ ++ Count = Size / COLUME_SIZE; ++ Left = Size % COLUME_SIZE; ++ for (Index = 0; Index < Count; Index++) { ++ DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); ++ InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); ++ DEBUG ((DEBUG_INFO, "\n")); ++ } ++ ++ if (Left != 0) { ++ DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); ++ InternalDumpData (Data + Index * COLUME_SIZE, Left); ++ DEBUG ((DEBUG_INFO, "\n")); ++ } ++} ++ ++/** ++ ++ This function initialize TD_EVENT_HDR for EV_NO_ACTION ++ Event Type other than EFI Specification ID event. The behavior is defined ++ by TCG PC Client PFP Spec. Section 9.3.4 EV_NO_ACTION Event Types ++ ++ @param[in, out] NoActionEvent Event Header of EV_NO_ACTION Event ++ @param[in] EventSize Event Size of the EV_NO_ACTION Event ++ ++**/ ++VOID ++InitNoActionEvent ( ++ IN OUT CC_EVENT_HDR *NoActionEvent, ++ IN UINT32 EventSize ++ ) ++{ ++ UINT32 DigestListCount; ++ TPMI_ALG_HASH HashAlgId; ++ UINT8 *DigestBuffer; ++ ++ DigestBuffer = (UINT8 *)NoActionEvent->Digests.digests; ++ DigestListCount = 0; ++ ++ NoActionEvent->MrIndex = 0; ++ NoActionEvent->EventType = EV_NO_ACTION; ++ ++ // ++ // Set Hash count & hashAlg accordingly, while Digest.digests[n].digest to all 0 ++ // ++ ZeroMem (&NoActionEvent->Digests, sizeof (NoActionEvent->Digests)); ++ ++ if ((mCcaDxeData.BsCap.HashAlgorithmBitmap & EFI_CC_BOOT_HASH_ALG_SHA256) != 0) { ++ HashAlgId = TPM_ALG_SHA256; ++ CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); ++ DigestListCount++; ++ } ++ ++ // ++ // Set Digests Count ++ // ++ WriteUnaligned32 ((UINT32 *)&NoActionEvent->Digests.count, DigestListCount); ++ ++ // ++ // Set Event Size ++ // ++ WriteUnaligned32 ((UINT32 *)DigestBuffer, EventSize); ++} ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL GetCapability function call provides protocol ++ capability information and state information. ++ ++ @param[in] This Indicates the calling context ++ @param[in, out] ProtocolCapability The caller allocates memory for a EFI_CC_BOOT_SERVICE_CAPABILITY ++ structure and sets the size field to the size of the structure allocated. ++ The callee fills in the fields with the EFI protocol capability information ++ and the current EFI TCG2 state information up to the number of fields which ++ fit within the size of the structure passed in. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ The ProtocolCapability variable will not be populated. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. ++ The ProtocolCapability variable will not be populated. ++ @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response. ++ It will be partially populated (required Size field will be set). ++**/ ++EFI_STATUS ++EFIAPI ++CcaGetCapability ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN OUT EFI_CC_BOOT_SERVICE_CAPABILITY *ProtocolCapability ++ ) ++{ ++ DEBUG ((DEBUG_VERBOSE, "CcaGetCapability\n")); ++ ++ if ((This == NULL) || (ProtocolCapability == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ CopyMem (ProtocolCapability, &mCcaDxeData.BsCap, sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY)); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ This function dump PCR event. ++ TD Event log reuse the TCG PCR Event spec. ++ The first event in the event log is the SHA1 log format. ++ There is only ONE TCG_PCR_EVENT in TD Event log. ++ ++ @param[in] EventHdr TCG PCR event structure. ++**/ ++VOID ++DumpPcrEvent ( ++ IN TCG_PCR_EVENT_HDR *EventHdr ++ ) ++{ ++ UINTN Index; ++ ++ DEBUG ((DEBUG_INFO, " Event:\n")); ++ DEBUG ((DEBUG_INFO, " MrIndex - %d\n", EventHdr->PCRIndex)); ++ DEBUG ((DEBUG_INFO, " EventType - 0x%08x\n", EventHdr->EventType)); ++ DEBUG ((DEBUG_INFO, " Digest - ")); ++ for (Index = 0; Index < sizeof (TCG_DIGEST); Index++) { ++ DEBUG ((DEBUG_INFO, "%02x ", EventHdr->Digest.digest[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "\n")); ++ DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventHdr->EventSize)); ++ InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize); ++} ++ ++/** ++ This function dump TCG_EfiSpecIDEventStruct. ++ ++ @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. ++**/ ++VOID ++DumpTcgEfiSpecIdEventStruct ( ++ IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct ++ ) ++{ ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ UINTN Index; ++ UINT8 *VendorInfoSize; ++ UINT8 *VendorInfo; ++ UINT32 NumberOfAlgorithms; ++ ++ DEBUG ((DEBUG_INFO, " TCG_EfiSpecIDEventStruct:\n")); ++ DEBUG ((DEBUG_INFO, " signature - '")); ++ for (Index = 0; Index < sizeof (TcgEfiSpecIdEventStruct->signature); Index++) { ++ DEBUG ((DEBUG_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "'\n")); ++ DEBUG ((DEBUG_INFO, " platformClass - 0x%08x\n", TcgEfiSpecIdEventStruct->platformClass)); ++ DEBUG ((DEBUG_INFO, " specVersion - %d.%d%d\n", TcgEfiSpecIdEventStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, TcgEfiSpecIdEventStruct->specErrata)); ++ DEBUG ((DEBUG_INFO, " uintnSize - 0x%02x\n", TcgEfiSpecIdEventStruct->uintnSize)); ++ ++ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms)); ++ DEBUG ((DEBUG_INFO, " NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorithms)); ++ ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); ++ for (Index = 0; Index < NumberOfAlgorithms; Index++) { ++ DEBUG ((DEBUG_INFO, " digest(%d)\n", Index)); ++ DEBUG ((DEBUG_INFO, " algorithmId - 0x%04x\n", DigestSize[Index].algorithmId)); ++ DEBUG ((DEBUG_INFO, " digestSize - 0x%04x\n", DigestSize[Index].digestSize)); ++ } ++ ++ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; ++ DEBUG ((DEBUG_INFO, " VendorInfoSize - 0x%02x\n", *VendorInfoSize)); ++ VendorInfo = VendorInfoSize + 1; ++ DEBUG ((DEBUG_INFO, " VendorInfo - ")); ++ for (Index = 0; Index < *VendorInfoSize; Index++) { ++ DEBUG ((DEBUG_INFO, "%02x ", VendorInfo[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "\n")); ++} ++ ++/** ++ This function get size of TCG_EfiSpecIDEventStruct. ++ ++ @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. ++**/ ++UINTN ++GetTcgEfiSpecIdEventStructSize ( ++ IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct ++ ) ++{ ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ UINT8 *VendorInfoSize; ++ UINT32 NumberOfAlgorithms; ++ ++ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms)); ++ ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); ++ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; ++ return sizeof (TCG_EfiSpecIDEventStruct) + sizeof (UINT32) + (NumberOfAlgorithms * sizeof (TCG_EfiSpecIdEventAlgorithmSize)) + sizeof (UINT8) + (*VendorInfoSize); ++} ++ ++/** ++ This function dump CCA Event (including the Digests). ++ ++ @param[in] CcEvent CCA Event structure. ++**/ ++VOID ++DumpCcEvent ( ++ IN CC_EVENT *CcEvent ++ ) ++{ ++ UINT32 DigestIndex; ++ UINT32 DigestCount; ++ TPMI_ALG_HASH HashAlgo; ++ UINT32 DigestSize; ++ UINT8 *DigestBuffer; ++ UINT32 EventSize; ++ UINT8 *EventBuffer; ++ ++ DEBUG ((DEBUG_INFO, "Cc Event:\n")); ++ DEBUG ((DEBUG_INFO, " MrIndex - %d\n", CcEvent->MrIndex)); ++ DEBUG ((DEBUG_INFO, " EventType - 0x%08x\n", CcEvent->EventType)); ++ DEBUG ((DEBUG_INFO, " DigestCount: 0x%08x\n", CcEvent->Digests.count)); ++ ++ DigestCount = CcEvent->Digests.count; ++ HashAlgo = CcEvent->Digests.digests[0].hashAlg; ++ DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest; ++ for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { ++ DEBUG ((DEBUG_INFO, " HashAlgo : 0x%04x\n", HashAlgo)); ++ DEBUG ((DEBUG_INFO, " Digest(%d): \n", DigestIndex)); ++ DigestSize = GetHashSizeFromAlgo (HashAlgo); ++ InternalDumpHex (DigestBuffer, DigestSize); ++ // ++ // Prepare next ++ // ++ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); ++ } ++ ++ DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH); ++ ++ CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize)); ++ DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventSize)); ++ EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize); ++ InternalDumpHex (EventBuffer, EventSize); ++ DEBUG ((DEBUG_INFO, "\n")); ++} ++ ++/** ++ This function returns size of Td Table event. ++ ++ @param[in] CcEvent Td Table event structure. ++ ++ @return size of Td event. ++**/ ++UINTN ++GetCcEventSize ( ++ IN CC_EVENT *CcEvent ++ ) ++{ ++ UINT32 DigestIndex; ++ UINT32 DigestCount; ++ TPMI_ALG_HASH HashAlgo; ++ UINT32 DigestSize; ++ UINT8 *DigestBuffer; ++ UINT32 EventSize; ++ UINT8 *EventBuffer; ++ ++ DigestCount = CcEvent->Digests.count; ++ HashAlgo = CcEvent->Digests.digests[0].hashAlg; ++ DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest; ++ for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { ++ DigestSize = GetHashSizeFromAlgo (HashAlgo); ++ // ++ // Prepare next ++ // ++ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); ++ } ++ ++ DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH); ++ ++ CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize)); ++ EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize); ++ ++ return (UINTN)EventBuffer + EventSize - (UINTN)CcEvent; ++} ++ ++/** ++ This function dump CC event log. ++ TDVF only supports EFI_CC_EVENT_LOG_FORMAT_TCG_2 ++ ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[in] EventLogLocation A pointer to the memory address of the event log. ++ @param[in] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the ++ address of the start of the last entry in the event log in memory. ++ @param[in] FinalEventsTable A pointer to the memory address of the final event table. ++**/ ++VOID ++DumpCcEventLog ( ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ IN EFI_PHYSICAL_ADDRESS EventLogLocation, ++ IN EFI_PHYSICAL_ADDRESS EventLogLastEntry, ++ IN EFI_CC_FINAL_EVENTS_TABLE *FinalEventsTable ++ ) ++{ ++ TCG_PCR_EVENT_HDR *EventHdr; ++ CC_EVENT *CcEvent; ++ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; ++ UINTN NumberOfEvents; ++ ++ DEBUG ((DEBUG_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat)); ++ ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2); ++ ++ // ++ // Dump first event. ++ // The first event is always the TCG_PCR_EVENT_HDR ++ // After this event is a TCG_EfiSpecIDEventStruct ++ // ++ EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; ++ DumpPcrEvent (EventHdr); ++ ++ TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)(EventHdr + 1); ++ DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct); ++ ++ // ++ // Then the CcEvent (Its structure is similar to TCG_PCR_EVENT2) ++ // ++ CcEvent = (CC_EVENT *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct)); ++ while ((UINTN)CcEvent <= EventLogLastEntry) { ++ DumpCcEvent (CcEvent); ++ CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent)); ++ } ++ ++ if (FinalEventsTable == NULL) { ++ DEBUG ((DEBUG_INFO, "FinalEventsTable: NOT FOUND\n")); ++ } else { ++ DEBUG ((DEBUG_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable)); ++ DEBUG ((DEBUG_INFO, " Version: (0x%x)\n", FinalEventsTable->Version)); ++ DEBUG ((DEBUG_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents)); ++ ++ CcEvent = (CC_EVENT *)(UINTN)(FinalEventsTable + 1); ++ for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) { ++ DumpCcEvent (CcEvent); ++ CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent)); ++ } ++ } ++ ++ return; ++} ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL Get Event Log function call allows a caller to ++ retrieve the address of a given event log and its last entry. ++ ++ @param[in] This Indicates the calling context ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[out] EventLogLocation A pointer to the memory address of the event log. ++ @param[out] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the ++ address of the start of the last entry in the event log in memory. ++ @param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would ++ have exceeded the area allocated for events, this value is set to TRUE. ++ Otherwise, the value will be FALSE and the Event Log will be complete. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect ++ (e.g. asking for an event log whose format is not supported). ++**/ ++EFI_STATUS ++EFIAPI ++CcaGetEventLog ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, ++ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry, ++ OUT BOOLEAN *EventLogTruncated ++ ) ++{ ++ UINTN Index = 0; ++ ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog ... (0x%x)\n", EventLogFormat)); ++ ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2); ++ ++ if (EventLogLocation != NULL) { ++ *EventLogLocation = mCcaDxeData.EventLogAreaStruct[Index].Lasa; ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogLocation - %x)\n", *EventLogLocation)); ++ } ++ ++ if (EventLogLastEntry != NULL) { ++ if (!mCcaDxeData.EventLogAreaStruct[Index].EventLogStarted) { ++ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; ++ } else { ++ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mCcaDxeData.EventLogAreaStruct[Index].LastEvent; ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry)); ++ } ++ ++ if (EventLogTruncated != NULL) { ++ *EventLogTruncated = mCcaDxeData.EventLogAreaStruct[Index].EventLogTruncated; ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated)); ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog - %r\n", EFI_SUCCESS)); ++ ++ // Dump Event Log for debug purpose ++ if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) { ++ DumpCcEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mCcaDxeData.FinalEventsTable[Index]); ++ } ++ ++ // ++ // All events generated after the invocation of EFI_TCG2_GET_EVENT_LOG SHALL be stored ++ // in an instance of an EFI_CONFIGURATION_TABLE named by the VendorGuid of EFI_TCG2_FINAL_EVENTS_TABLE_GUID. ++ // ++ mCcaDxeData.GetEventLogCalled[Index] = TRUE; ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Return if this is a Tcg800155PlatformIdEvent. ++ ++ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. ++ @param[in] NewEventHdrSize New event header size. ++ @param[in] NewEventData Pointer to the new event data. ++ @param[in] NewEventSize New event data size. ++ ++ @retval TRUE This is a Tcg800155PlatformIdEvent. ++ @retval FALSE This is NOT a Tcg800155PlatformIdEvent. ++ ++**/ ++BOOLEAN ++Is800155Event ( ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ if ((((TCG_PCR_EVENT2_HDR *)NewEventHdr)->EventType == EV_NO_ACTION) && ++ (NewEventSize >= sizeof (TCG_Sp800_155_PlatformId_Event2)) && ++ ((CompareMem ( ++ NewEventData, ++ TCG_Sp800_155_PlatformId_Event2_SIGNATURE, ++ sizeof (TCG_Sp800_155_PlatformId_Event2_SIGNATURE) - 1 ++ ) == 0) || ++ (CompareMem ( ++ NewEventData, ++ TCG_Sp800_155_PlatformId_Event3_SIGNATURE, ++ sizeof (TCG_Sp800_155_PlatformId_Event3_SIGNATURE) - 1 ++ ) == 0))) ++ { ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/** ++ Add a new entry to the Event Log. ++ ++ @param[in, out] EventLogAreaStruct The event log area data structure ++ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. ++ @param[in] NewEventHdrSize New event header size. ++ @param[in] NewEventData Pointer to the new event data. ++ @param[in] NewEventSize New event data size. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ ++**/ ++EFI_STATUS ++TcgCommLogEvent ( ++ IN OUT CC_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct, ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ UINTN NewLogSize; ++ BOOLEAN Record800155Event; ++ CC_EVENT_HDR *CcEventHdr; ++ ++ CcEventHdr = (CC_EVENT_HDR *)NewEventHdr; ++ DEBUG ((DEBUG_INFO, "Cca: Try to log event. Index = %d, EventType = 0x%x\n", CcEventHdr->MrIndex, CcEventHdr->EventType)); ++ ++ if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ NewLogSize = NewEventHdrSize + NewEventSize; ++ ++ if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ if (NewLogSize + EventLogAreaStruct->EventLogSize > EventLogAreaStruct->Laml) { ++ DEBUG ((DEBUG_INFO, " Laml - 0x%x\n", EventLogAreaStruct->Laml)); ++ DEBUG ((DEBUG_INFO, " NewLogSize - 0x%x\n", NewLogSize)); ++ DEBUG ((DEBUG_INFO, " LogSize - 0x%x\n", EventLogAreaStruct->EventLogSize)); ++ DEBUG ((DEBUG_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ // ++ // Check 800-155 event ++ // Record to 800-155 event offset only. ++ // If the offset is 0, no need to record. ++ // ++ Record800155Event = Is800155Event (NewEventHdr, NewEventHdrSize, NewEventData, NewEventSize); ++ if (Record800155Event) { ++ DEBUG ((DEBUG_INFO, "It is 800155Event.\n")); ++ ++ if (EventLogAreaStruct->Next800155EventOffset != 0) { ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewLogSize, ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, ++ EventLogAreaStruct->EventLogSize - EventLogAreaStruct->Next800155EventOffset ++ ); ++ ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, ++ NewEventHdr, ++ NewEventHdrSize ++ ); ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ EventLogAreaStruct->Next800155EventOffset += NewLogSize; ++ EventLogAreaStruct->LastEvent += NewLogSize; ++ EventLogAreaStruct->EventLogSize += NewLogSize; ++ } ++ ++ return EFI_SUCCESS; ++ } ++ ++ EventLogAreaStruct->LastEvent = (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->EventLogSize; ++ EventLogAreaStruct->EventLogSize += NewLogSize; ++ ++ CopyMem (EventLogAreaStruct->LastEvent, NewEventHdr, NewEventHdrSize); ++ CopyMem ( ++ EventLogAreaStruct->LastEvent + NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ According to UEFI Spec 2.10 Section 38.4.1: ++ The following table shows the TPM PCR index mapping and CC event log measurement ++ register index interpretation for ARM CCA, where RIM means Realm Initial Measurement ++ and REM means Realm Extensive Measurement ++ ++ // TPM PCR Index | CC Measurement Register Index | CCA-measurement register ++ // ------------------------------------------------------------------------ ++ // 0 | 0 | RIM ++ // 1, 7 | 1 | REM[0] ++ // 2~6 | 2 | REM[1] ++ // 8~15 | 3 | REM[2] ++ ++ @param[in] PCRIndex Index of the TPM PCR ++ ++ @retval UINT32 Index of the CC Event Log Measurement Register Index ++ @retval CC_MR_INDEX_INVALID Invalid MR Index ++**/ ++UINT32 ++EFIAPI ++MapPcrToMrIndex ( ++ IN UINT32 PCRIndex ++ ) ++{ ++ UINT32 MrIndex; ++ ++ if (PCRIndex > 15) { ++ ASSERT (FALSE); ++ return CC_MR_INDEX_INVALID; ++ } ++ ++ MrIndex = 0; ++ if (PCRIndex == 0) { ++ MrIndex = CC_MR_INDEX_0_RIM; ++ } else if ((PCRIndex == 1) || (PCRIndex == 7)) { ++ MrIndex = CC_MR_INDEX_1_REM0; ++ } else if ((PCRIndex >= 2) && (PCRIndex <= 6)) { ++ MrIndex = CC_MR_INDEX_2_REM1; ++ } else if ((PCRIndex >= 8) && (PCRIndex <= 15)) { ++ MrIndex = CC_MR_INDEX_3_REM2; ++ } ++ ++ return MrIndex; ++} ++ ++EFI_STATUS ++EFIAPI ++CcaMapPcrToMrIndex ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN UINT32 PCRIndex, ++ OUT UINT32 *MrIndex ++ ) ++{ ++ if (MrIndex == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ *MrIndex = MapPcrToMrIndex (PCRIndex); ++ ++ return *MrIndex == CC_MR_INDEX_INVALID ? EFI_INVALID_PARAMETER : EFI_SUCCESS; ++} ++ ++/** ++ Add a new entry to the Event Log. ++ ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. ++ @param[in] NewEventHdrSize New event header size. ++ @param[in] NewEventData Pointer to the new event data. ++ @param[in] NewEventSize New event data size. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ ++**/ ++EFI_STATUS ++CcaDxeLogEvent ( ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ EFI_STATUS Status; ++ UINTN Index; ++ CC_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct; ++ ++ if (EventLogFormat != EFI_CC_EVENT_LOG_FORMAT_TCG_2) { ++ ASSERT (FALSE); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ Index = 0; ++ ++ // ++ // Record to normal event log ++ // ++ EventLogAreaStruct = &mCcaDxeData.EventLogAreaStruct[Index]; ++ ++ if (EventLogAreaStruct->EventLogTruncated) { ++ return EFI_VOLUME_FULL; ++ } ++ ++ Status = TcgCommLogEvent ( ++ EventLogAreaStruct, ++ NewEventHdr, ++ NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ if (Status == EFI_OUT_OF_RESOURCES) { ++ EventLogAreaStruct->EventLogTruncated = TRUE; ++ return EFI_VOLUME_FULL; ++ } else if (Status == EFI_SUCCESS) { ++ EventLogAreaStruct->EventLogStarted = TRUE; ++ } ++ ++ // ++ // If GetEventLog is called, record to FinalEventsTable, too. ++ // ++ if (mCcaDxeData.GetEventLogCalled[Index]) { ++ if (mCcaDxeData.FinalEventsTable[Index] == NULL) { ++ // ++ // no need for FinalEventsTable ++ // ++ return EFI_SUCCESS; ++ } ++ ++ EventLogAreaStruct = &mCcaDxeData.FinalEventLogAreaStruct[Index]; ++ ++ if (EventLogAreaStruct->EventLogTruncated) { ++ return EFI_VOLUME_FULL; ++ } ++ ++ Status = TcgCommLogEvent ( ++ EventLogAreaStruct, ++ NewEventHdr, ++ NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ if (Status == EFI_OUT_OF_RESOURCES) { ++ EventLogAreaStruct->EventLogTruncated = TRUE; ++ return EFI_VOLUME_FULL; ++ } else if (Status == EFI_SUCCESS) { ++ EventLogAreaStruct->EventLogStarted = TRUE; ++ // ++ // Increase the NumberOfEvents in FinalEventsTable ++ // ++ (mCcaDxeData.FinalEventsTable[Index])->NumberOfEvents++; ++ DEBUG ((DEBUG_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mCcaDxeData.FinalEventsTable[Index])->NumberOfEvents)); ++ DEBUG ((DEBUG_INFO, " Size - 0x%x\n", (UINTN)EventLogAreaStruct->EventLogSize)); ++ } ++ } ++ ++ return Status; ++} ++ ++/** ++ Get TPML_DIGEST_VALUES compact binary buffer size. ++ ++ @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. ++ ++ @return TPML_DIGEST_VALUES compact binary buffer size. ++**/ ++UINT32 ++GetDigestListBinSize ( ++ IN VOID *DigestListBin ++ ) ++{ ++ UINTN Index; ++ UINT16 DigestSize; ++ UINT32 TotalSize; ++ UINT32 Count; ++ TPMI_ALG_HASH HashAlg; ++ ++ Count = ReadUnaligned32 (DigestListBin); ++ TotalSize = sizeof (Count); ++ DigestListBin = (UINT8 *)DigestListBin + sizeof (Count); ++ for (Index = 0; Index < Count; Index++) { ++ HashAlg = ReadUnaligned16 (DigestListBin); ++ TotalSize += sizeof (HashAlg); ++ DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg); ++ ++ DigestSize = GetHashSizeFromAlgo (HashAlg); ++ TotalSize += DigestSize; ++ DigestListBin = (UINT8 *)DigestListBin + DigestSize; ++ } ++ ++ return TotalSize; ++} ++ ++/** ++ Add a new entry to the Event Log. The call chain is like below: ++ CcaDxeLogHashEvent -> CcaDxeLogEvent -> TcgCommonLogEvent ++ ++ Before this function is called, the event information (including the digest) ++ is ready. ++ ++ @param[in] DigestList A list of digest. ++ @param[in,out] NewEventHdr Pointer to a TD_EVENT_HDR data structure. ++ @param[in] NewEventData Pointer to the new event data. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++**/ ++EFI_STATUS ++CcaDxeLogHashEvent ( ++ IN TPML_DIGEST_VALUES *DigestList, ++ IN OUT CC_EVENT_HDR *NewEventHdr, ++ IN UINT8 *NewEventData ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_TPL OldTpl; ++ EFI_STATUS RetStatus; ++ CC_EVENT CcEvent; ++ UINT8 *DigestBuffer; ++ UINT32 *EventSizePtr; ++ EFI_CC_EVENT_LOG_FORMAT LogFormat; ++ ++ RetStatus = EFI_SUCCESS; ++ LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ ZeroMem (&CcEvent, sizeof (CcEvent)); ++ CcEvent.MrIndex = NewEventHdr->MrIndex; ++ CcEvent.EventType = NewEventHdr->EventType; ++ DigestBuffer = (UINT8 *)&CcEvent.Digests; ++ EventSizePtr = CopyDigestListToBuffer (DigestBuffer, DigestList, HASH_ALG_SHA256); ++ CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize)); ++ ++ // ++ // Enter critical region ++ // ++ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); ++ Status = CcaDxeLogEvent ( ++ LogFormat, ++ &CcEvent, ++ sizeof (CcEvent.MrIndex) + sizeof (CcEvent.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (CcEvent.EventSize), ++ NewEventData, ++ NewEventHdr->EventSize ++ ); ++ if (Status != EFI_SUCCESS) { ++ RetStatus = Status; ++ } ++ ++ gBS->RestoreTPL (OldTpl); ++ ++ return RetStatus; ++} ++ ++/** ++ Do a hash operation on a data buffer, extend a specific REM with the hash result, ++ and add an entry to the Event Log. ++ ++ @param[in] Flags Bitmap providing additional information. ++ @param[in] HashData Physical address of the start of the data buffer ++ to be hashed, extended, and logged. ++ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData ++ @param[in, out] NewEventHdr Pointer to a TD_EVENT_HDR data structure. ++ @param[in] NewEventData Pointer to the new event data. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ ++**/ ++EFI_STATUS ++CcaDxeHashLogExtendEvent ( ++ IN UINT64 Flags, ++ IN UINT8 *HashData, ++ IN UINT64 HashDataLen, ++ IN OUT CC_EVENT_HDR *NewEventHdr, ++ IN UINT8 *NewEventData ++ ) ++{ ++ EFI_STATUS Status; ++ TPML_DIGEST_VALUES DigestList; ++ CC_EVENT_HDR NoActionEvent; ++ ++ if (NewEventHdr->EventType == EV_NO_ACTION) { ++ // ++ // Do not do REM extend for EV_NO_ACTION ++ // ++ Status = EFI_SUCCESS; ++ InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize); ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData); ++ } ++ ++ return Status; ++ } ++ ++ // ++ // According to UEFI Spec 2.10 Section 38.4.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // Only the REM registers can be extended in EDK2 by HashAndExtend. ++ // ++ Status = HashAndExtend ( ++ NewEventHdr->MrIndex, ++ HashData, ++ (UINTN)HashDataLen, ++ &DigestList ++ ); ++ if (!EFI_ERROR (Status)) { ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData); ++ } ++ } ++ ++ return Status; ++} ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL HashLogExtendEvent function call provides callers with ++ an opportunity to extend and optionally log events without requiring ++ knowledge of actual TPM commands. ++ The extend operation will occur even if this function cannot create an event ++ log entry (e.g. due to the event log being full). ++ ++ @param[in] This Indicates the calling context ++ @param[in] Flags Bitmap providing additional information. ++ @param[in] DataToHash Physical address of the start of the data buffer to be hashed. ++ @param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash. ++ @param[in] Event Pointer to data buffer containing information about the event. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ @retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. ++ @retval EFI_UNSUPPORTED The PE/COFF image type is not supported. ++**/ ++EFI_STATUS ++EFIAPI ++CcaHashLogExtendEvent ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN UINT64 Flags, ++ IN EFI_PHYSICAL_ADDRESS DataToHash, ++ IN UINT64 DataToHashLen, ++ IN EFI_CC_EVENT *CcEvent ++ ) ++{ ++ EFI_STATUS Status; ++ CC_EVENT_HDR NewEventHdr; ++ TPML_DIGEST_VALUES DigestList; ++ ++ DEBUG ((DEBUG_VERBOSE, "CcaHashLogExtendEvent ...\n")); ++ ++ if ((This == NULL) || (CcEvent == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Do not check hash data size for EV_NO_ACTION event. ++ // ++ if ((CcEvent->Header.EventType != EV_NO_ACTION) && (DataToHash == 0)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (CcEvent->Size < CcEvent->Header.HeaderSize + sizeof (UINT32)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (CcEvent->Header.MrIndex == CC_MR_INDEX_0_RIM) { ++ DEBUG ((DEBUG_ERROR, "%a: RIM cannot be extended.\n", __func__)); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (CcEvent->Header.MrIndex >= CC_MR_INDEX_INVALID) { ++ DEBUG ((DEBUG_ERROR, "%a: MrIndex is invalid. (%d)\n", __func__, CcEvent->Header.MrIndex)); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ NewEventHdr.MrIndex = CcEvent->Header.MrIndex; ++ NewEventHdr.EventType = CcEvent->Header.EventType; ++ NewEventHdr.EventSize = CcEvent->Size - sizeof (UINT32) - CcEvent->Header.HeaderSize; ++ if ((Flags & EFI_CC_FLAG_PE_COFF_IMAGE) != 0) { ++ // ++ // According to UEFI Spec 2.10 Section 38.4.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // Only the REM registers can be extended in EDK2 by HashAndExtend. ++ // ++ Status = MeasurePeImageAndExtend ( ++ NewEventHdr.MrIndex, ++ DataToHash, ++ (UINTN)DataToHashLen, ++ &DigestList ++ ); ++ if (!EFI_ERROR (Status)) { ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&DigestList, &NewEventHdr, CcEvent->Event); ++ } ++ } ++ } else { ++ Status = CcaDxeHashLogExtendEvent ( ++ Flags, ++ (UINT8 *)(UINTN)DataToHash, ++ DataToHashLen, ++ &NewEventHdr, ++ CcEvent->Event ++ ); ++ } ++ ++ DEBUG ((DEBUG_VERBOSE, "CcaHashLogExtendEvent - %r\n", Status)); ++ return Status; ++} ++ ++EFI_CC_MEASUREMENT_PROTOCOL mCcaProtocol = { ++ CcaGetCapability, ++ CcaGetEventLog, ++ CcaHashLogExtendEvent, ++ CcaMapPcrToMrIndex ++}; ++ ++#define CCA_HASH_COUNT 1 ++#define TEMP_BUF_LEN (sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32) \ ++ + (CCA_HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8)) ++ ++/** ++ Initialize the Realm Event Log and log events passed from the PEI phase. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ ++**/ ++EFI_STATUS ++SetupCcEventLog ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PHYSICAL_ADDRESS Lasa; ++ UINTN Index; ++ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; ++ UINT8 TempBuf[TEMP_BUF_LEN]; ++ TCG_PCR_EVENT_HDR SpecIdEvent; ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ TCG_EfiSpecIdEventAlgorithmSize *TempDigestSize; ++ UINT8 *VendorInfoSize; ++ UINT32 NumberOfAlgorithms; ++ EFI_CC_EVENT_LOG_FORMAT LogFormat; ++ EFI_PEI_HOB_POINTERS GuidHob; ++ CC_EVENT_HDR NoActionEvent; ++ ++ Status = EFI_SUCCESS; ++ DEBUG ((DEBUG_INFO, "SetupCcEventLog\n")); ++ ++ Index = 0; ++ LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ // ++ // 1. Create Log Area ++ // ++ mCcaDxeData.EventLogAreaStruct[Index].EventLogFormat = LogFormat; ++ ++ // allocate pages for Realm Event log ++ Status = gBS->AllocatePages ( ++ AllocateAnyPages, ++ EfiACPIMemoryNVS, ++ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), ++ &Lasa ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ mCcaDxeData.EventLogAreaStruct[Index].Lasa = Lasa; ++ mCcaDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); ++ mCcaDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0; ++ ++ // ++ // Report Realm event log address and length, so that they can be reported in ++ // Realm ACPI table. Ignore the return status, because those fields are optional. ++ // ++ PcdSet32S (PcdCcEventlogAcpiTableLaml, (UINT32)mCcaDxeData.EventLogAreaStruct[Index].Laml); ++ PcdSet64S (PcdCcEventlogAcpiTableLasa, mCcaDxeData.EventLogAreaStruct[Index].Lasa); ++ ++ // ++ // To initialize them as 0xFF is recommended ++ // because the OS can know the last entry for that. ++ // ++ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); ++ ++ // ++ // Create first entry for Log Header Entry Data ++ // ++ ++ // ++ // TcgEfiSpecIdEventStruct ++ // ++ TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)TempBuf; ++ CopyMem (TcgEfiSpecIdEventStruct->signature, TCG_EfiSpecIDEventStruct_SIGNATURE_03, sizeof (TcgEfiSpecIdEventStruct->signature)); ++ ++ TcgEfiSpecIdEventStruct->platformClass = PcdGet8 (PcdTpmPlatformClass); ++ ++ TcgEfiSpecIdEventStruct->specVersionMajor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MAJOR_TPM2; ++ TcgEfiSpecIdEventStruct->specVersionMinor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MINOR_TPM2; ++ TcgEfiSpecIdEventStruct->specErrata = TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2; ++ TcgEfiSpecIdEventStruct->uintnSize = sizeof (UINTN)/sizeof (UINT32); ++ NumberOfAlgorithms = 0; ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct ++ + sizeof (*TcgEfiSpecIdEventStruct) ++ + sizeof (NumberOfAlgorithms)); ++ ++ TempDigestSize = DigestSize; ++ TempDigestSize += NumberOfAlgorithms; ++ TempDigestSize->algorithmId = TPM_ALG_SHA256; ++ TempDigestSize->digestSize = SHA256_DIGEST_SIZE; ++ NumberOfAlgorithms++; ++ ++ CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof (NumberOfAlgorithms)); ++ TempDigestSize = DigestSize; ++ TempDigestSize += NumberOfAlgorithms; ++ VendorInfoSize = (UINT8 *)TempDigestSize; ++ *VendorInfoSize = 0; ++ ++ SpecIdEvent.PCRIndex = 1; // PCRIndex 0 maps to MrIndex 1 ++ SpecIdEvent.EventType = EV_NO_ACTION; ++ ZeroMem (&SpecIdEvent.Digest, sizeof (SpecIdEvent.Digest)); ++ SpecIdEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct); ++ ++ // ++ // Realm Event log re-use the spec of TCG2 Event log. ++ // Log TcgEfiSpecIdEventStruct as the first Event. Event format is TCG_PCR_EVENT. ++ // TCG EFI Protocol Spec. Section 5.3 Event Log Header ++ // TCG PC Client PFP spec. Section 9.2 Measurement Event Entries and Log ++ // ++ Status = CcaDxeLogEvent ( ++ LogFormat, ++ &SpecIdEvent, ++ sizeof (SpecIdEvent), ++ (UINT8 *)TcgEfiSpecIdEventStruct, ++ SpecIdEvent.EventSize ++ ); ++ // ++ // record the offset at the end of 800-155 event. ++ // the future 800-155 event can be inserted here. ++ // ++ mCcaDxeData.EventLogAreaStruct[Index].Next800155EventOffset = mCcaDxeData.EventLogAreaStruct[Index].EventLogSize; ++ ++ // ++ // Tcg800155PlatformIdEvent. Event format is TCG_PCR_EVENT2 ++ // ++ GuidHob.Guid = GetFirstGuidHob (&gTcg800155PlatformIdEventHobGuid); ++ while (GuidHob.Guid != NULL) { ++ InitNoActionEvent (&NoActionEvent, GET_GUID_HOB_DATA_SIZE (GuidHob.Guid)); ++ ++ Status = CcaDxeLogEvent ( ++ LogFormat, ++ &NoActionEvent, ++ sizeof (NoActionEvent.MrIndex) + sizeof (NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof (NoActionEvent.EventSize), ++ GET_GUID_HOB_DATA (GuidHob.Guid), ++ GET_GUID_HOB_DATA_SIZE (GuidHob.Guid) ++ ); ++ ++ GuidHob.Guid = GET_NEXT_HOB (GuidHob); ++ GuidHob.Guid = GetNextGuidHob (&gTcg800155PlatformIdEventHobGuid, GuidHob.Guid); ++ } ++ ++ // ++ // 2. Create Final Log Area ++ // ++ Status = gBS->AllocatePages ( ++ AllocateAnyPages, ++ EfiACPIMemoryNVS, ++ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcg2FinalLogAreaLen)), ++ &Lasa ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcg2FinalLogAreaLen), 0xFF); ++ ++ // ++ // Initialize ++ // ++ mCcaDxeData.FinalEventsTable[Index] = (VOID *)(UINTN)Lasa; ++ (mCcaDxeData.FinalEventsTable[Index])->Version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION; ++ (mCcaDxeData.FinalEventsTable[Index])->NumberOfEvents = 0; ++ ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = LogFormat; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof (EFI_CC_FINAL_EVENTS_TABLE); ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_CC_FINAL_EVENTS_TABLE); ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mCcaDxeData.FinalEventLogAreaStruct[Index].Lasa; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; ++ ++ // ++ // Install to configuration table for EFI_CC_EVENT_LOG_FORMAT_TCG_2 ++ // ++ Status = gBS->InstallConfigurationTable (&gEfiCcFinalEventsTableGuid, (VOID *)mCcaDxeData.FinalEventsTable[Index]); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ return Status; ++} ++ ++/** ++ Measure and log an action string, and extend the measurement result into REM. ++ ++ @param[in] MrIndex MrIndex to extend ++ @param[in] String A specific string that indicates an Action event. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++CcaMeasureAction ( ++ IN UINT32 MrIndex, ++ IN CHAR8 *String ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EV_EFI_ACTION; ++ CcEvent.EventSize = (UINT32)AsciiStrLen (String); ++ return CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)String, ++ CcEvent.EventSize, ++ &CcEvent, ++ (UINT8 *)String ++ ); ++} ++ ++/** ++ Measure and log EFI handoff tables, and extend the measurement result into PCR[1]. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureHandoffTables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ Status = EFI_SUCCESS; ++ ++ // TODO: may delete this function ++ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { ++ DEBUG ((DEBUG_ERROR, "MeasureHandoffTables: TCG_PLATFORM_TYPE_SERVER")); ++ } ++ ++ return Status; ++} ++ ++/** ++ Measure and log Separator event, and extend the measurement result into a specific PCR. ++ ++ @param[in] MrIndex REM Index. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureSeparatorEvent ( ++ IN UINT32 MrIndex ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ UINT32 EventData; ++ ++ DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent to Rem - %d\n", MrIndex)); ++ ++ EventData = 0; ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EV_SEPARATOR; ++ CcEvent.EventSize = (UINT32)sizeof (EventData); ++ ++ return CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)&EventData, ++ sizeof (EventData), ++ &CcEvent, ++ (UINT8 *)&EventData ++ ); ++} ++ ++/** ++ Measure and log an EFI variable, and extend the measurement result into a specific REM. ++ ++ @param[in] MrIndex REM Index. ++ @param[in] EventType Event type. ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[in] VarData The content of the variable data. ++ @param[in] VarSize The size of the variable data. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureVariable ( ++ IN UINT32 MrIndex, ++ IN TCG_EVENTTYPE EventType, ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ IN VOID *VarData, ++ IN UINTN VarSize ++ ) ++{ ++ EFI_STATUS Status; ++ CC_EVENT_HDR CcEvent; ++ UINTN VarNameLength; ++ UEFI_VARIABLE_DATA *VarLog; ++ ++ DEBUG ((DEBUG_INFO, "CcaTcg2Dxe: MeasureVariable (REM - %x, EventType - %x, ", (UINTN)MrIndex, (UINTN)EventType)); ++ DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); ++ ++ VarNameLength = StrLen (VarName); ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EventType; ++ ++ CcEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize ++ - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); ++ ++ VarLog = (UEFI_VARIABLE_DATA *)AllocatePool (CcEvent.EventSize); ++ if (VarLog == NULL) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ VarLog->VariableName = *VendorGuid; ++ VarLog->UnicodeNameLength = VarNameLength; ++ VarLog->VariableDataLength = VarSize; ++ CopyMem ( ++ VarLog->UnicodeName, ++ VarName, ++ VarNameLength * sizeof (*VarName) ++ ); ++ if ((VarSize != 0) && (VarData != NULL)) { ++ CopyMem ( ++ (CHAR16 *)VarLog->UnicodeName + VarNameLength, ++ VarData, ++ VarSize ++ ); ++ } ++ ++ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { ++ // ++ // Digest is the event data (UEFI_VARIABLE_DATA) ++ // ++ Status = CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)VarLog, ++ CcEvent.EventSize, ++ &CcEvent, ++ (UINT8 *)VarLog ++ ); ++ } else { ++ ASSERT (VarData != NULL); ++ Status = CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)VarData, ++ VarSize, ++ &CcEvent, ++ (UINT8 *)VarLog ++ ); ++ } ++ ++ FreePool (VarLog); ++ return Status; ++} ++ ++/** ++ Read then Measure and log an EFI variable, and extend the measurement result into a specific RTMR. ++ ++ @param[in] MrIndex REM Index. ++ @param[in] EventType Event type. ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureVariable ( ++ IN UINT32 MrIndex, ++ IN TCG_EVENTTYPE EventType, ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ EFI_STATUS Status; ++ ++ Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize); ++ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { ++ if (EFI_ERROR (Status)) { ++ // ++ // It is valid case, so we need handle it. ++ // ++ *VarData = NULL; ++ *VarSize = 0; ++ } ++ } else { ++ // ++ // if status error, VarData is freed and set NULL by GetVariable2 ++ // ++ if (EFI_ERROR (Status)) { ++ return EFI_NOT_FOUND; ++ } ++ } ++ ++ Status = MeasureVariable ( ++ MrIndex, ++ EventType, ++ VarName, ++ VendorGuid, ++ *VarData, ++ *VarSize ++ ); ++ return Status; ++} ++ ++/** ++ Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[1]. ++according to TCG PC Client PFP spec 0021 Section 2.4.4.2 ++ ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureBootVariable ( ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ return ReadAndMeasureVariable ( ++ MapPcrToMrIndex (1), ++ EV_EFI_VARIABLE_BOOT, ++ VarName, ++ VendorGuid, ++ VarSize, ++ VarData ++ ); ++} ++ ++/** ++ Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7]. ++ ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureSecureVariable ( ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ return ReadAndMeasureVariable ( ++ MapPcrToMrIndex (7), ++ EV_EFI_VARIABLE_DRIVER_CONFIG, ++ VarName, ++ VendorGuid, ++ VarSize, ++ VarData ++ ); ++} ++ ++/** ++ Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. ++ ++ The EFI boot variables are BootOrder and Boot#### variables. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureAllBootVariables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UINT16 *BootOrder; ++ UINTN BootCount; ++ UINTN Index; ++ VOID *BootVarData; ++ UINTN Size; ++ ++ Status = ReadAndMeasureBootVariable ( ++ mBootVarName, ++ &gEfiGlobalVariableGuid, ++ &BootCount, ++ (VOID **)&BootOrder ++ ); ++ if ((Status == EFI_NOT_FOUND) || (BootOrder == NULL)) { ++ return EFI_SUCCESS; ++ } ++ ++ if (EFI_ERROR (Status)) { ++ // ++ // BootOrder can't be NULL if status is not EFI_NOT_FOUND ++ // ++ FreePool (BootOrder); ++ return Status; ++ } ++ ++ BootCount /= sizeof (*BootOrder); ++ for (Index = 0; Index < BootCount; Index++) { ++ UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]); ++ Status = ReadAndMeasureBootVariable ( ++ mBootVarName, ++ &gEfiGlobalVariableGuid, ++ &Size, ++ &BootVarData ++ ); ++ if (!EFI_ERROR (Status)) { ++ FreePool (BootVarData); ++ } ++ } ++ ++ FreePool (BootOrder); ++ return EFI_SUCCESS; ++} ++ ++/** ++ Measure and log all EFI Secure variables, and extend the measurement result into a specific PCR. ++ ++ The EFI boot variables are BootOrder and Boot#### variables. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureAllSecureVariables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ VOID *Data; ++ UINTN DataSize; ++ UINTN Index; ++ ++ Status = EFI_NOT_FOUND; ++ for (Index = 0; Index < sizeof (mVariableType)/sizeof (mVariableType[0]); Index++) { ++ Status = ReadAndMeasureSecureVariable ( ++ mVariableType[Index].VariableName, ++ mVariableType[Index].VendorGuid, ++ &DataSize, ++ &Data ++ ); ++ if (!EFI_ERROR (Status)) { ++ if (Data != NULL) { ++ FreePool (Data); ++ } ++ } ++ } ++ ++ // ++ // Measure DBT if present and not empty ++ // ++ Status = GetVariable2 (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, &Data, &DataSize); ++ if (!EFI_ERROR (Status)) { ++ Status = MeasureVariable ( ++ MapPcrToMrIndex (7), ++ EV_EFI_VARIABLE_DRIVER_CONFIG, ++ EFI_IMAGE_SECURITY_DATABASE2, ++ &gEfiImageSecurityDatabaseGuid, ++ Data, ++ DataSize ++ ); ++ FreePool (Data); ++ } else { ++ DEBUG ((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2)); ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureLaunchOfFirmwareDebugger ( ++ VOID ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ ++ CcEvent.MrIndex = MapPcrToMrIndex (7); ++ CcEvent.EventType = EV_EFI_ACTION; ++ CcEvent.EventSize = sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1; ++ return CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING, ++ sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1, ++ &CcEvent, ++ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING ++ ); ++} ++ ++/** ++ Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR. ++ ++ Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed) ++ - The contents of the SecureBoot variable ++ - The contents of the PK variable ++ - The contents of the KEK variable ++ - The contents of the EFI_IMAGE_SECURITY_DATABASE variable ++ - The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable ++ - Separator ++ - Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path ++ ++ NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE, ++ EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3]. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++**/ ++VOID ++EFIAPI ++MeasureSecureBootPolicy ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ VOID *Protocol; ++ ++ Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol); ++ if (EFI_ERROR (Status)) { ++ return; ++ } ++ ++ if (PcdGetBool (PcdFirmwareDebuggerInitialized)) { ++ Status = MeasureLaunchOfFirmwareDebugger (); ++ DEBUG ((DEBUG_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status)); ++ } ++ ++ Status = MeasureAllSecureVariables (); ++ DEBUG ((DEBUG_INFO, "MeasureAllSecureVariables - %r\n", Status)); ++ ++ // ++ // We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure) ++ // and ImageVerification (Authority) ++ // There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So ++ // the Authority measurement happen before ReadToBoot event. ++ // ++ Status = MeasureSeparatorEvent (MapPcrToMrIndex (7)); ++ DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent - %r\n", Status)); ++ return; ++} ++ ++/** ++ Ready to Boot Event notification handler. ++ ++ Sequence of OS boot events is measured in this event notification handler. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnReadyToBoot ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ PERF_START_EX (mImageHandle, "EventRec", "CcaTcg2Dxe", 0, PERF_ID_CC_TCG2_DXE); ++ if (mBootAttempts == 0) { ++ // ++ // Measure handoff tables. ++ // ++ Status = MeasureHandoffTables (); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "HOBs not Measured. Error!\n")); ++ } ++ ++ // ++ // Measure BootOrder & Boot#### variables. ++ // ++ Status = MeasureAllBootVariables (); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Boot Variables not Measured. Error!\n")); ++ } ++ ++ // ++ // 1. This is the first boot attempt. ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (4), ++ EFI_CALLING_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); ++ } ++ ++ // ++ // 2. Draw a line between pre-boot env and entering post-boot env. ++ // ++ // According to UEFI Spec 2.10 Section 38.4.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // REM[0] (i.e. MrIndex 1) is already done. So SepartorEvent shall be extended to ++ // REM[1] (i.e. MrIndex 2) as well. ++ // ++ Status = MeasureSeparatorEvent (CC_MR_INDEX_2_REM1); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Separator Event not Measured to RTMR[1]. Error!\n")); ++ } ++ ++ // ++ // 3. Measure GPT. It would be done in SAP driver. ++ // ++ ++ // ++ // 4. Measure PE/COFF OS loader. It would be done in SAP driver. ++ // ++ ++ // ++ // 5. Read & Measure variable. BootOrder already measured. ++ // ++ } else { ++ // ++ // 6. Not first attempt, meaning a return from last attempt ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (4), ++ EFI_RETURNING_FROM_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATION)); ++ } ++ // ++ // 7. Next boot attempt, measure "Calling EFI Application from Boot Option" again ++ // TCG PC Client PFP spec Section 2.4.4.5 Step 4 ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (4), ++ EFI_CALLING_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); ++ } ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaTcg2Dxe Measure Data when ReadyToBoot\n")); ++ // ++ // Increase boot attempt counter. ++ // ++ mBootAttempts++; ++ PERF_END_EX (mImageHandle, "EventRec", "CcaTcg2Dxe", 0, PERF_ID_CC_TCG2_DXE + 1); ++} ++ ++/** ++ Exit Boot Services Event notification handler. ++ ++ Measure invocation and success of ExitBootServices. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnExitBootServices ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ // ++ // Measure invocation of ExitBootServices, ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_INVOCATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION)); ++ } ++ ++ // ++ // Measure success of ExitBootServices ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_SUCCEEDED ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED)); ++ } ++} ++ ++/** ++ Exit Boot Services Failed Event notification handler. ++ ++ Measure Failure of ExitBootServices. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnExitBootServicesFailed ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ // ++ // Measure Failure of ExitBootServices, ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_FAILED ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED)); ++ } ++} ++ ++/** ++ Install TDVF ACPI Table when ACPI Table Protocol is available. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++**/ ++VOID ++EFIAPI ++InstallAcpiTable ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ UINTN TableKey; ++ EFI_STATUS Status; ++ EFI_ACPI_TABLE_PROTOCOL *AcpiTable; ++ ++ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "CCA: AcpiTableProtocol is not installed. %r\n", Status)); ++ return; ++ } ++ ++ mCcaEventlogAcpiTemplate.Laml = (UINT64)PcdGet32 (PcdCcEventlogAcpiTableLaml); ++ mCcaEventlogAcpiTemplate.Lasa = PcdGet64 (PcdCcEventlogAcpiTableLasa); ++ CopyMem (mCcaEventlogAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mCcaEventlogAcpiTemplate.Header.OemId)); ++ mCcaEventlogAcpiTemplate.Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); ++ mCcaEventlogAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); ++ mCcaEventlogAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); ++ mCcaEventlogAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); ++ ++ // ++ // Construct ACPI Table ++ Status = AcpiTable->InstallAcpiTable ( ++ AcpiTable, ++ &mCcaEventlogAcpiTemplate, ++ mCcaEventlogAcpiTemplate.Header.Length, ++ &TableKey ++ ); ++ ASSERT_EFI_ERROR (Status); ++ ++ DEBUG ((DEBUG_INFO, "CCA Eventlog ACPI Table is installed.\n")); ++} ++ ++/** ++ The function install CcaTcg2 protocol. ++ ++ @retval EFI_SUCCESS CcaTcg2 protocol is installed. ++ @retval other Some error occurs. ++**/ ++EFI_STATUS ++InstallCcMeasurementProtocol ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_HANDLE Handle; ++ ++ Handle = NULL; ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gEfiCcMeasurementProtocolGuid, ++ &mCcaProtocol, ++ NULL ++ ); ++ DEBUG ((DEBUG_INFO, "CcProtocol: Install %r\n", Status)); ++ return Status; ++} ++ ++EFI_STATUS ++EFIAPI ++DriverEntry ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++) ++{ ++ EFI_STATUS Status; ++ EFI_EVENT Event; ++ VOID *Registration; ++ ++ if (!IsRealm ()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ mImageHandle = ImageHandle; ++ ++ // ++ // Fill information ++ // ++ mCcaDxeData.BsCap.Size = sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY); ++ mCcaDxeData.BsCap.ProtocolVersion.Major = 1; ++ mCcaDxeData.BsCap.ProtocolVersion.Minor = 0; ++ mCcaDxeData.BsCap.StructureVersion.Major = 1; ++ mCcaDxeData.BsCap.StructureVersion.Minor = 0; ++ ++ // ++ // Get supported PCR and current Active PCRs ++ // For Realm gueset HA384 is tested first. ++ // ++ mCcaDxeData.BsCap.HashAlgorithmBitmap = HASH_ALG_SHA256; ++ ++ // Realm guest only supports EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 ++ mCcaDxeData.BsCap.SupportedEventLogs = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ // ++ // Setup the log area and copy event log from hob list to it ++ // ++ Status = SetupCcEventLog (); ++ ASSERT_EFI_ERROR (Status); ++ ++ // ++ // Measure handoff tables, Boot#### variables etc. ++ // ++ Status = EfiCreateEventReadyToBootEx ( ++ TPL_CALLBACK, ++ OnReadyToBoot, ++ NULL, ++ &Event ++ ); ++ ++ Status = gBS->CreateEventEx ( ++ EVT_NOTIFY_SIGNAL, ++ TPL_NOTIFY, ++ OnExitBootServices, ++ NULL, ++ &gEfiEventExitBootServicesGuid, ++ &Event ++ ); ++ ++ // ++ // Measure Exit Boot Service failed ++ // ++ Status = gBS->CreateEventEx ( ++ EVT_NOTIFY_SIGNAL, ++ TPL_NOTIFY, ++ OnExitBootServicesFailed, ++ NULL, ++ &gEventExitBootServicesFailedGuid, ++ &Event ++ ); ++ ++ // ++ // Create event callback, because we need access variable on SecureBootPolicyVariable ++ // We should use VariableWriteArch instead of VariableArch, because Variable driver ++ // may update SecureBoot value based on last setting. ++ // ++ EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration); ++ ++ // ++ // Install CcMeasurementProtocol ++ // ++ Status = InstallCcMeasurementProtocol (); ++ DEBUG ((DEBUG_INFO, "InstallCcMeasurementProtocol - %r\n", Status)); ++ ++ if (Status == EFI_SUCCESS) { ++ // ++ // Create event callback to install CC EventLog ACPI Table ++ EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration); ++ } else { ++ // ++ // Cc measurement feature is crucial to a Realm and it shall stop running immediately ++ // when it is failed to be installed. ++ DEBUG ((DEBUG_ERROR, "%a: CcMeasurement protocol failed to be installed - %r\n", __func__, Status)); ++ CpuDeadLoop (); ++ } ++ ++ return Status; ++} +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf +new file mode 100644 +index 00000000..750c7762 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf +@@ -0,0 +1,86 @@ ++## @file ++# ++# Produces EFI_CC_MEASUREMENT_PROTOCOL and measure boot environment ++# ++# Copyright (C) 2023, Linaro Ltd ++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = CcaTcg2Dxe ++ FILE_GUID = 1788737c-83c4-47b9-899c-b741ab263964 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = DriverEntry ++ ++[Sources] ++ CcaTcg2Dxe.c ++ MeasureBootPeCoff.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ SecurityPkg/SecurityPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ MemoryAllocationLib ++ BaseLib ++ UefiBootServicesTableLib ++ HobLib ++ UefiDriverEntryPoint ++ UefiRuntimeServicesTableLib ++ BaseMemoryLib ++ DebugLib ++ PrintLib ++ UefiLib ++ HashLib ++ PerformanceLib ++ PeCoffLib ++ ArmCcaLib ++ ++[Guids] ++ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" ++ ## SOMETIMES_CONSUMES ## Variable:L"PK" ++ ## SOMETIMES_CONSUMES ## Variable:L"KEK" ++ ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" ++ gEfiGlobalVariableGuid ++ ++ ## SOMETIMES_CONSUMES ## Variable:L"db" ++ ## SOMETIMES_CONSUMES ## Variable:L"dbx" ++ gEfiImageSecurityDatabaseGuid ++ ++ # gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gEfiEventExitBootServicesGuid ## CONSUMES ## Event ++ gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event ++ ++ gCcEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gTcg800155PlatformIdEventHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gEfiCcFinalEventsTableGuid ## PRODUCES ++ ++[Protocols] ++ gEfiCcMeasurementProtocolGuid ## PRODUCES ++ gEfiVariableWriteArchProtocolGuid ## NOTIFY ++ gEfiAcpiTableProtocolGuid ## NOTIFY ++ ++[Pcd] ++ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES ++ # gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES ++ # gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES ++ # gEfiSecurityPkgTokenSpaceGuid.PcdTcg2NumberOfPCRBanks ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLaml ## PRODUCES ++ gEfiSecurityPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLasa ## PRODUCES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ++ ++[Depex] ++ gEfiVariableArchProtocolGuid AND gEfiAcpiTableProtocolGuid +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c b/ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c +new file mode 100644 +index 00000000..e01d46d5 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c +@@ -0,0 +1,407 @@ ++/** @file ++ This module implements measuring PeCoff image for Tcg2 Protocol. ++ ++ Caution: This file requires additional review when modified. ++ This driver will have external input - PE/COFF image. ++ This external input must be validated carefully to avoid security issue like ++ buffer overflow, integer overflow. ++ ++Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
++SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++UINTN mTcg2DxeImageSize = 0; ++ ++/** ++ Reads contents of a PE/COFF image in memory buffer. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ @param FileHandle Pointer to the file handle to read the PE/COFF image. ++ @param FileOffset Offset into the PE/COFF image to begin the read operation. ++ @param ReadSize On input, the size in bytes of the requested read operation. ++ On output, the number of bytes actually read. ++ @param Buffer Output buffer that contains the data read from the PE/COFF image. ++ ++ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size ++**/ ++EFI_STATUS ++EFIAPI ++Tcg2DxeImageRead ( ++ IN VOID *FileHandle, ++ IN UINTN FileOffset, ++ IN OUT UINTN *ReadSize, ++ OUT VOID *Buffer ++ ) ++{ ++ UINTN EndPosition; ++ ++ if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (MAX_ADDRESS - FileOffset < *ReadSize) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ EndPosition = FileOffset + *ReadSize; ++ if (EndPosition > mTcg2DxeImageSize) { ++ *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset); ++ } ++ ++ if (FileOffset >= mTcg2DxeImageSize) { ++ *ReadSize = 0; ++ } ++ ++ CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Measure PE image into TPM log based on the authenticode image hashing in ++ PE/COFF Specification 8.0 Appendix A. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will validate its data structure ++ within this image buffer before use. ++ ++ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). ++ ++ @param[in] RemIndex Rem index ++ @param[in] ImageAddress Start address of image buffer. ++ @param[in] ImageSize Image size ++ @param[out] DigestList Digest list of this image. ++ ++ @retval EFI_SUCCESS Successfully measure image. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. ++ @retval other error value ++**/ ++EFI_STATUS ++MeasurePeImageAndExtend ( ++ IN UINT32 RemIndex, ++ IN EFI_PHYSICAL_ADDRESS ImageAddress, ++ IN UINTN ImageSize, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_IMAGE_DOS_HEADER *DosHdr; ++ UINT32 PeCoffHeaderOffset; ++ EFI_IMAGE_SECTION_HEADER *Section; ++ UINT8 *HashBase; ++ UINTN HashSize; ++ UINTN SumOfBytesHashed; ++ EFI_IMAGE_SECTION_HEADER *SectionHeader; ++ UINTN Index; ++ UINTN Pos; ++ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; ++ UINT32 NumberOfRvaAndSizes; ++ UINT32 CertSize; ++ HASH_HANDLE HashHandle; ++ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; ++ ++ HashHandle = 0xFFFFFFFF; // Know bad value ++ ++ Status = EFI_UNSUPPORTED; ++ SectionHeader = NULL; ++ ++ // ++ // Check PE/COFF image ++ // ++ ZeroMem (&ImageContext, sizeof (ImageContext)); ++ ImageContext.Handle = (VOID *)(UINTN)ImageAddress; ++ mTcg2DxeImageSize = ImageSize; ++ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)Tcg2DxeImageRead; ++ ++ // ++ // Get information about the image being loaded ++ // ++ Status = PeCoffLoaderGetImageInfo (&ImageContext); ++ if (EFI_ERROR (Status)) { ++ // ++ // The information can't be got from the invalid PeImage ++ // ++ DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n")); ++ goto Finish; ++ } ++ ++ DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress; ++ PeCoffHeaderOffset = 0; ++ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { ++ PeCoffHeaderOffset = DosHdr->e_lfanew; ++ } ++ ++ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset); ++ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { ++ Status = EFI_UNSUPPORTED; ++ goto Finish; ++ } ++ ++ // ++ // PE/COFF Image Measurement ++ // ++ // NOTE: The following codes/steps are based upon the authenticode image hashing in ++ // PE/COFF Specification 8.0 Appendix A. ++ // ++ // ++ ++ // 1. Load the image header into memory. ++ ++ // 2. Initialize a SHA hash context. ++ ++ Status = HashStart (&HashHandle); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ // ++ // Measuring PE/COFF Image Header; ++ // But CheckSum field and SECURITY data directory (certificate) are excluded ++ // ++ ++ // ++ // 3. Calculate the distance from the base of the image header to the image checksum address. ++ // 4. Hash the image header from its base to beginning of the image checksum. ++ // ++ HashBase = (UINT8 *)(UINTN)ImageAddress; ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; ++ HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; ++ HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase; ++ } ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ // ++ // 5. Skip over the image checksum (it occupies a single ULONG). ++ // ++ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { ++ // ++ // 6. Since there is no Cert Directory in optional header, hash everything ++ // from the end of the checksum to the end of image header. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset. ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } else { ++ // ++ // Use PE32+ offset. ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ } else { ++ // ++ // 7. Hash everything from the end of the checksum to the start of the Cert Directory. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ ++ // ++ // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) ++ // 9. Hash everything from the end of the Cert Directory to the end of image header. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; ++ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; ++ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ } ++ ++ // ++ // 10. Set the SUM_OF_BYTES_HASHED to the size of the header ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; ++ } ++ ++ // ++ // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER ++ // structures in the image. The 'NumberOfSections' field of the image ++ // header indicates how big the table should be. Do not include any ++ // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. ++ // ++ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); ++ if (SectionHeader == NULL) { ++ Status = EFI_OUT_OF_RESOURCES; ++ goto Finish; ++ } ++ ++ // ++ // 12. Using the 'PointerToRawData' in the referenced section headers as ++ // a key, arrange the elements in the table in ascending order. In other ++ // words, sort the section headers according to the disk-file offset of ++ // the section. ++ // ++ Section = (EFI_IMAGE_SECTION_HEADER *)( ++ (UINT8 *)(UINTN)ImageAddress + ++ PeCoffHeaderOffset + ++ sizeof (UINT32) + ++ sizeof (EFI_IMAGE_FILE_HEADER) + ++ Hdr.Pe32->FileHeader.SizeOfOptionalHeader ++ ); ++ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { ++ Pos = Index; ++ while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { ++ CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); ++ Pos--; ++ } ++ ++ CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); ++ Section += 1; ++ } ++ ++ // ++ // 13. Walk through the sorted table, bring the corresponding section ++ // into memory, and hash the entire section (using the 'SizeOfRawData' ++ // field in the section header to determine the amount of data to hash). ++ // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . ++ // 15. Repeat steps 13 and 14 for all the sections in the sorted table. ++ // ++ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { ++ Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index]; ++ if (Section->SizeOfRawData == 0) { ++ continue; ++ } ++ ++ HashBase = (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData; ++ HashSize = (UINTN)Section->SizeOfRawData; ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ SumOfBytesHashed += HashSize; ++ } ++ ++ // ++ // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra ++ // data in the file that needs to be added to the hash. This data begins ++ // at file offset SUM_OF_BYTES_HASHED and its length is: ++ // FileSize - (CertDirectory->Size) ++ // ++ if (ImageSize > SumOfBytesHashed) { ++ HashBase = (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed; ++ ++ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { ++ CertSize = 0; ++ } else { ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset. ++ // ++ CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; ++ } else { ++ // ++ // Use PE32+ offset. ++ // ++ CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; ++ } ++ } ++ ++ if (ImageSize > CertSize + SumOfBytesHashed) { ++ HashSize = (UINTN)(ImageSize - CertSize - SumOfBytesHashed); ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } else if (ImageSize < CertSize + SumOfBytesHashed) { ++ Status = EFI_UNSUPPORTED; ++ goto Finish; ++ } ++ } ++ ++ // ++ // 17. Finalize the SHA hash. ++ // ++ Status = HashCompleteAndExtend (HashHandle, RemIndex, NULL, 0, DigestList); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++Finish: ++ if (SectionHeader != NULL) { ++ FreePool (SectionHeader); ++ } ++ ++ return Status; ++} +diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec +index ac1c3ed0..8aed7750 100644 +--- a/ArmVirtPkg/ArmVirtPkg.dec ++++ b/ArmVirtPkg/ArmVirtPkg.dec +@@ -26,6 +26,8 @@ + Include # Root include for the package + + [LibraryClasses] ++ ArmCcaLib|Include/Library/ArmCcaLib.h ++ ArmCcaRsiLib|Include/Library/ArmCcaRsiLib.h + ArmVirtMemInfoLib|Include/Library/ArmVirtMemInfoLib.h + + [Guids.common] +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index b7d34b91..7e91fea2 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -32,6 +32,7 @@ + DEFINE TPM2_ENABLE = FALSE + DEFINE TPM2_CONFIG_ENABLE = FALSE + DEFINE CAVIUM_ERRATUM_27456 = FALSE ++ DEFINE CC_MEASUREMENT_ENABLE = FALSE + + # + # Network definition +@@ -78,13 +79,13 @@ + FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf + PciPcdProducerLib|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf + PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf +- PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf +- PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf +- PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf +- ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +-!if $(TPM2_ENABLE) == TRUE +- Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf +- Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf ++ PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf ++ PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf ++ PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf ++ ++!if $(TPM2_ENABLE) == TRUE ++ Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf ++ Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf + TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf + TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLib/PeiDxeTpmPlatformHierarchyLib.inf + !else +@@ -94,16 +95,19 @@ + + [LibraryClasses.AARCH64] + ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf ++ ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf ++ ArmCcaRsiLib|ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf ++ HashLib|ArmVirtPkg/Library/HashLibCca/HashLibCca.inf + + [LibraryClasses.ARM] + ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf +- +-[LibraryClasses.common.PEIM] +- ArmVirtMemInfoLib|ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf +- ArmCcaInitPeiLib|ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf +- +-!if $(TPM2_ENABLE) == TRUE +- BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf ++ ++[LibraryClasses.common.PEIM] ++ ArmVirtMemInfoLib|ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf ++ ArmCcaInitPeiLib|ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf ++ ++!if $(TPM2_ENABLE) == TRUE ++ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf + ResetSystemLib|MdeModulePkg/Library/PeiResetSystemLib/PeiResetSystemLib.inf + Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf + !endif +@@ -252,16 +256,16 @@ + + gArmTokenSpaceGuid.PcdArmArchTimerSecIntrNum|0x0 + gArmTokenSpaceGuid.PcdArmArchTimerIntrNum|0x0 +- gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0 +- gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0 +- +- # Define PCD for emulating runtime variable storage when CFI flash is absent +- gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|FALSE +- +- +- # +- # ARM General Interrupt Controller +- # ++ gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0 ++ gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0 ++ ++ # Define PCD for emulating runtime variable storage when CFI flash is absent ++ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|FALSE ++ ++ ++ # ++ # ARM General Interrupt Controller ++ # + gArmTokenSpaceGuid.PcdGicDistributorBase|0x0 + gArmTokenSpaceGuid.PcdGicRedistributorsBase|0x0 + gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase|0x0 +@@ -396,18 +400,23 @@ + # don't use unaligned CopyMem () on the UEFI varstore NOR flash region + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + } +-!if $(SECURE_BOOT_ENABLE) == TRUE + MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf { + ++!if $(SECURE_BOOT_ENABLE) == TRUE + NULL|SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf +-!if $(TPM2_ENABLE) == TRUE ++!endif ++!if $(TPM2_ENABLE) == TRUE || $(CC_MEASUREMENT_ENABLE) == TRUE ++ # ++ # DxeTpm2MeasureBootLib provides security service of TPM2 measure boot and ++ # Confidential Computing (CC) measure boot. It should be controlled by ++ # TPM2_ENABLE and CC_MEASUREMENT_ENABLE ++ # + NULL|SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf + !endif + } ++!if $(SECURE_BOOT_ENABLE) == TRUE + SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf +-!else +- MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf + !endif + MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf + MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf +@@ -444,16 +453,16 @@ + # + MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf + +- # +- # Platform Driver +- # +- ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf { +- +- NULL|ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf +- } +- OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf +- EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf +- OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf ++ # ++ # Platform Driver ++ # ++ ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf { ++ ++ NULL|ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf ++ } ++ OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf ++ EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf ++ OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf + OvmfPkg/VirtioBlkDxe/VirtioBlk.inf + OvmfPkg/VirtioScsiDxe/VirtioScsi.inf + OvmfPkg/VirtioNetDxe/VirtioNet.inf +@@ -585,22 +594,32 @@ + !endif + + # +- # ACPI Support +- # +- OvmfPkg/PlatformHasAcpiDtDxe/PlatformHasAcpiDtDxe.inf +- +- # +- # Realm Aperture Management +- # +- ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +- +- # +- # IoMMU support for Arm CCA +- # +- ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +-[Components.AARCH64] +- MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf +- OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { ++ # ACPI Support ++ # ++ OvmfPkg/PlatformHasAcpiDtDxe/PlatformHasAcpiDtDxe.inf ++[Components.AARCH64] ++ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf ++ OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { + + NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf + } ++ # ++ # Realm Aperture Management ++ # ++ ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf ++ ++ # ++ # Cc Measurement Protocol for Cca guest ++ # ++!if $(CC_MEASUREMENT_ENABLE) == TRUE ++ ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf { ++ ++ HashLib|ArmVirtPkg/Library/HashLibCca/HashLibCca.inf ++ NULL|SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf ++ } ++!endif +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf +index 0a89f24c..f4ef6ee2 100644 +--- a/ArmVirtPkg/ArmVirtQemu.fdf ++++ b/ArmVirtPkg/ArmVirtQemu.fdf +@@ -108,21 +108,16 @@ READ_LOCK_STATUS = TRUE + INF MdeModulePkg/Core/Pei/PeiMain.inf + INF ArmPlatformPkg/PlatformPei/PlatformPeim.inf + INF ArmVirtPkg/MemoryInitPei/MemoryInitPeim.inf +- INF ArmPkg/Drivers/CpuPei/CpuPei.inf +- INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf +- +- # +- # Realm Aperture Management +- # +- INF ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +- +- # +- # IoMMU support for Arm CCA +- # +- INF ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +-!if $(TPM2_ENABLE) == TRUE +- INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf +- INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf ++ INF ArmPkg/Drivers/CpuPei/CpuPei.inf ++ INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf ++ ++!if $(CC_MEASUREMENT_ENABLE) == TRUE ++ INF ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf ++!endif ++ ++!if $(TPM2_ENABLE) == TRUE ++ INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf ++ INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf + INF OvmfPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf + INF SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf + !endif +diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +index bef91421..e89dec81 100644 +--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc ++++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +@@ -148,6 +148,16 @@ READ_LOCK_STATUS = TRUE + INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf + INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf + INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf ++ ++ # ++ # Realm Aperture Management ++ # ++ INF ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ INF ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf + !endif + + # +diff --git a/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h b/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h +new file mode 100644 +index 00000000..b5ad68f3 +--- /dev/null ++++ b/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h +@@ -0,0 +1,373 @@ ++/** @file ++ Library that implements the Arm CCA Realm Service Interface calls. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ - RIM - Realm Initial Measurement ++ - REM - Realm Extensible Measurement ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++**/ ++ ++#ifndef ARM_CCA_RSI_LIB_ ++#define ARM_CCA_RSI_LIB_ ++ ++#include ++ ++/** ++ A macro defining the size of a Realm Granule. ++ See Section A2.2, RMM Specification, version A-bet0 ++ DNBXXX A Granule is a unit of physical memory whose size is 4KB. ++*/ ++#define REALM_GRANULE_SIZE SIZE_4KB ++ ++/** ++ A macro defining the mask for the RSI RIPAS type. ++ See Section B4.4.5 RsiRipas type, RMM Specification, version A-bet0. ++*/ ++#define RIPAS_TYPE_MASK 0xFF ++ ++/* Maximum challenge data size in bits. ++*/ ++#define MAX_CHALLENGE_DATA_SIZE_BITS 512 ++ ++/* Minimum recommended challenge data size in bits. ++*/ ++#define MIN_CHALLENGE_DATA_SIZE_BITS 256 ++ ++/* Maximum measurement data size in bytes. ++ See Section C1.11 RmmRealmMeasurement type, RMM Specification, version A-bet0 ++ The width of the RmmRealmMeasurement type is 512 bits. ++*/ ++#define MAX_MEASUREMENT_DATA_SIZE_BYTES 64 ++ ++/* Minimum and Maximum indices for REMs ++ See Section A2.1.3 Realm attributes, RMM Specification, version A-bet0 ++ IFMPYL - Attributes of a Realm include an array of measurement values. The ++ first entry in this array is a RIM. The remaining entries in this array are ++ REMs. ++*/ ++#define MIN_REM_INDEX 1 ++#define MAX_REM_INDEX 4 ++ ++/* The values of the RsiHashAlgorithm enumeration. ++ SHA-256 (Secure Hash Standard (SHS)) ++*/ ++#define RSI_HASH_SHA_256 0 ++ ++/* The values of the RsiHashAlgorithm enumeration. ++ SHA-512 (Secure Hash Standard (SHS)) ++*/ ++#define RSI_HASH_SHA_512 1 ++ ++/* The RsiRipasChangeFlags fieldset contains flags provided by ++ the Realm when requesting a RIPAS change. ++ See section B4.4.8 RsiRipasChangeFlags type in the ++ RMM Specification, version 1.0-eac2. ++ The following macros prefixed RIPAS_CHANGE_FLAGS_xxx ++ define the values of the RsiRipasChangeFlags fieldset. ++*/ ++ ++/* A RIPAS change from DESTROYED should not be permitted. ++ See section B4.4.7 RsiRipasChangeDestroyed type in the ++ RMM Specification, version 1.0-eac2 ++*/ ++#define RIPAS_CHANGE_FLAGS_RSI_NO_CHANGE_DESTROYED 0 ++ ++/* A RIPAS change from DESTROYED should be permitted. ++ See section B4.4.7 RsiRipasChangeDestroyed type in the ++ RMM Specification, version 1.0-eac2 ++*/ ++#define RIPAS_CHANGE_FLAGS_RSI_CHANGE_DESTROYED 1 ++ ++/* The RsiResponse type is a value returned by the ++ RSI_IPA_STATE_SET command and represents whether ++ the Host accepted or rejected a Realm request. ++ See section B4.4.6 RsiResponse type in the ++ RMM Specification, version 1.0-eac3. ++ The width of the RsiResponse enumeration is 1 bit ++ and the following macros prefixed RIPAS_CHANGE_RESPONSE_xxx ++ define the values of the RsiResponse type. ++*/ ++ ++/* The RIPAS change request to RAM was accepted ++ by the host. ++*/ ++#define RIPAS_CHANGE_RESPONSE_ACCEPT 0 ++ ++/* The RIPAS change request to RAM was rejected ++ by the host. ++*/ ++#define RIPAS_CHANGE_RESPONSE_REJECT 1 ++ ++/* A mask for the RSI Response bit */ ++#define RSI_RESPONSE_MASK BIT0 ++ ++/** An enum describing the RSI RIPAS. ++ See Section A5.2.2 Realm IPA state, RMM Specification, version 1.0-eac2 ++*/ ++typedef enum Ripas { ++ RipasEmpty, ///< Unused IPA location. ++ RipasRam, ///< Private code or data owned by the Realm. ++ RipasDestroyed, ///< An address which is inaccessible to the Realm. ++ RipasMax ///< A valid RIPAS type value is less than RipasMax. ++} RIPAS; ++ ++/** A structure describing the Realm Configuration. ++ See Section B4.4.5 RsiRealmConfig type, RMM Specification, version 1.0-eac2 ++ The width of the RsiRealmConfig structure is 4096 (0x1000) bytes. ++*/ ++typedef struct RealmConfig { ++ // Width of IPA in bits. ++ UINT64 IpaWidth; ++ // Width of the RsiHashAlgorithm enumeration is 8 bits. ++ UINT8 HashAlgorithm; ++ // Unused bits of the RsiRealmConfig structure should be zero. ++ UINT8 Reserved[SIZE_4KB - (sizeof (UINT64) + sizeof (UINT8))]; ++} REALM_CONFIG; ++ ++/** A structure describing the Host Call arguments ++ See Section 4.4.2 RsiHostCall type, RMM Specification, version 1.0-bet2 ++*/ ++typedef struct HostCallArgs { ++ UINT16 Imm; ++ UINT8 Reserved1[6]; ++ ++ UINT64 Gprs0; ++ UINT64 Gprs1; ++ UINT64 Gprs2; ++ UINT64 Gprs3; ++ UINT64 Gprs4; ++ UINT64 Gprs5; ++ UINT64 Gprs6; ++ UINT64 Gprs7; ++ UINT64 Gprs8; ++ UINT64 Gprs9; ++ UINT64 Gprs10; ++ UINT64 Gprs11; ++ UINT64 Gprs12; ++ UINT64 Gprs13; ++ UINT64 Gprs14; ++ UINT64 Gprs15; ++ UINT64 Gprs16; ++ UINT64 Gprs17; ++ UINT64 Gprs18; ++ UINT64 Gprs19; ++ UINT64 Gprs20; ++ UINT64 Gprs21; ++ UINT64 Gprs22; ++ UINT64 Gprs23; ++ UINT64 Gprs24; ++ UINT64 Gprs25; ++ UINT64 Gprs26; ++ UINT64 Gprs27; ++ UINT64 Gprs28; ++ UINT64 Gprs29; ++ UINT64 Gprs30; ++} HOST_CALL_ARGS; ++ ++/** ++ Retrieve an attestation token from the RMM. ++ ++ @param [in] ChallengeData Pointer to the challenge data to be ++ included in the attestation token. ++ @param [in] ChallengeDataSizeBits Size of the challenge data in bits. ++ @param [out] TokenBuffer Pointer to a buffer to store the ++ retrieved attestation token. ++ @param [out] TokenBufferSize Length of token data returned. ++ ++ Note: The TokenBuffer allocated must be freed by the caller ++ using RsiFreeAttestationToken(). ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetAttestationToken ( ++ IN CONST UINT8 *CONST ChallengeData, ++ IN UINT64 ChallengeDataSizeBits, ++ OUT UINT8 **CONST TokenBuffer, ++ OUT UINT64 *CONST TokenBufferSize ++ ); ++ ++/** ++ Free the attestation token buffer. ++ ++ @param [in] TokenBuffer Pointer to the retrieved ++ attestation token. ++ @param [in] TokenBufferSize Size of the token buffer. ++**/ ++VOID ++RsiFreeAttestationToken ( ++ IN UINT8 *CONST TokenBuffer, ++ IN UINT64 CONST TokenBufferSize ++ ); ++ ++/** ++ Returns the IPA state for the page pointed by the address. ++ ++ @param [in] Address Address to retrive IPA state. ++ @param [out] State The RIPAS state for the address specified. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetIpaState ( ++ IN UINT64 *Address, ++ OUT RIPAS *State ++ ); ++ ++/** ++ Sets the IPA state for the pages pointed by the memory range. ++ ++ @param [in] Address Address to the start of the memory range. ++ @param [in] Size Length of the memory range. ++ @param [in] State The RIPAS state to be configured. ++ @param [in] Flags The RIPAS change flags. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ACCESS_DENIED RIPAS change request was rejected. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiSetIpaState ( ++ IN UINT64 *Address, ++ IN UINT64 Size, ++ IN RIPAS State, ++ IN UINT64 Flags ++ ); ++ ++/** ++ Extends a measurement to a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [in] Measurement Pointer to the measurement buffer. ++ @param [in] MeasurementSize Size of the measurement data. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiExtendMeasurement ( ++ IN UINTN MeasurementIndex, ++ IN CONST UINT8 *CONST Measurement, ++ IN UINTN MeasurementSize ++ ); ++ ++/** ++ Read the measurement value from a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [out] MeasurementBuffer Pointer to store the measurement data. ++ @param [in] MeasurementBufferSize Size of the measurement buffer. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiReadMeasurement ( ++ IN UINTN MeasurementIndex, ++ OUT UINT8 *CONST MeasurementBuffer, ++ IN UINTN MeasurementBufferSize ++ ); ++ ++/** ++ Read the Realm Configuration. ++ ++ @param [out] Config Pointer to the address of the buffer to retrieve ++ the Realm configuration. ++ ++ Note: The buffer to retrieve the Realm configuration must be aligned to the ++ Realm granule size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetRealmConfig ( ++ IN REALM_CONFIG *Config ++ ); ++ ++/** ++ Make a Host Call. ++ ++ A Host call can be used by a Realm to make a hypercall. ++ On Realm execution of HVC, an Unknown exception is taken to the Realm. ++ ++ @param [in] Args Pointer to the IPA of the Host call data ++ structure. ++ ++ Note: The IPA of the Host call arguments data structure must be aligned ++ to the Realm granule size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiHostCall ( ++ IN HOST_CALL_ARGS *Args ++ ); ++ ++/** ++ Get the version of the RSI implementation. ++ ++ @param [out] UefiImpl The version of the RSI specification ++ implemented by the UEFI firmware. ++ @param [out] RmmImpl The version of the RSI specification ++ implemented by the RMM. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_UNSUPPORTED The execution context is not a Realm. ++ @retval RETURN_INCOMPATIBLE_VERSION The Firmware and RMM specification ++ revisions are not compatible. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetVersion ( ++ OUT UINT32 *CONST UefiImpl, ++ OUT UINT32 *CONST RmmImpl ++ ); ++ ++/** ++ Get the features supported by the RSI implementation. ++ ++ RMM implementations across different CCA platforms may support ++ disparate features and may offer disparate configuration options ++ for Realms. The features supported by an RSI implementation are ++ discovered by reading feature pseudo-register values using the ++ RSI_FEATURES command. ++ ++ @param [in] FeatureRegIndex The Feature Register Index. ++ @param [out] FeatureRegValue The Feature Register Value. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetFeatures ( ++ IN UINT64 FeatureRegIndex, ++ OUT UINT64 *FeatureRegValue ++ ); ++ ++#endif // ARM_CCA_RSI_LIB_ +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +index 894c6db0..4b974d86 100644 +--- a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +@@ -13,6 +13,7 @@ + + #include + #include ++#include + #include + #include + +@@ -33,7 +34,19 @@ IsRealm ( + VOID + ) + { ++ RETURN_STATUS Status; ++ UINT32 UefiImpl; ++ UINT32 RmmImpl; ++ ++ Status = RsiGetVersion ( ++ &UefiImpl, ++ &RmmImpl ++ ); ++ if (!RETURN_ERROR (Status)) { + return TRUE; ++ } ++ ++ return FALSE; + } + + /** +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +index c0d703b2..2c96d2a5 100644 +--- a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +@@ -25,6 +25,7 @@ + MdePkg/MdePkg.dec + + [LibraryClasses] ++ ArmCcaRsiLib + ArmLib + ArmMmuLib + BaseLib +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h +new file mode 100644 +index 00000000..ce3cb0c3 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h +@@ -0,0 +1,59 @@ ++/** @file ++ Definitions for Arm CCA Realm Service Interface. ++ ++ Copyright (c) 2022 - 2023, ARM Ltd. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++**/ ++ ++#ifndef ARM_CCA_RSI_H_ ++#define ARM_CCA_RSI_H_ ++ ++// FIDs for Realm Service Interface calls. ++#define FID_RSI_ATTESTATION_TOKEN_CONTINUE 0xC4000195 ++#define FID_RSI_ATTESTATION_TOKEN_INIT 0xC4000194 ++#define FID_RSI_FEATURES 0xC4000191 ++#define FID_RSI_HOST_CALL 0xC4000199 ++#define FID_RSI_IPA_STATE_GET 0xC4000198 ++#define FID_RSI_IPA_STATE_SET 0xC4000197 ++#define FID_RSI_MEASUREMENT_EXTEND 0xC4000193 ++#define FID_RSI_MEASUREMENT_READ 0xC4000192 ++#define FID_RSI_REALM_CONFIG 0xC4000196 ++#define FID_RSI_VERSION 0xC4000190 ++ ++/** RSI Command Return codes ++ See Section B4.4.1, RMM Specification, version A-bet0. ++ The width of the RsiCommandReturnCode enumeration is 64 bits. ++*/ ++#define RSI_SUCCESS 0ULL ++#define RSI_ERROR_INPUT 1ULL ++#define RSI_ERROR_STATE 2ULL ++#define RSI_INCOMPLETE 3ULL ++ ++/** RSI interface Version ++ See Section B4.4.3, RMM Specification, version A-bet0. ++ The width of the RsiInterfaceVersion fieldset is 64 bits. ++*/ ++#define RSI_VER_MINOR_MASK 0x0000FFFFULL ++#define RSI_VER_MAJOR_MASK 0x7FFF0000ULL ++#define RSI_VER_MAJOR_SHIFT 16 ++#define RSI_VERSION_MASK (RSI_VER_MAJOR_MASK | RSI_VER_MINOR_MASK) ++ ++#define RMM_VERSION(Major, Minor) ((Minor & RSI_VER_MINOR_MASK) | \ ++ ((Major << RSI_VER_MAJOR_SHIFT) & RSI_VER_MAJOR_MASK)) ++ ++#define GET_MAJOR_REVISION(Rev) \ ++ ((Rev & RSI_VER_MAJOR_MASK) >> RSI_VER_MAJOR_SHIFT) ++ ++#define GET_MINOR_REVISION(Rev) \ ++ ((Rev & RSI_VER_MINOR_MASK)) ++ ++#endif // ARM_CCA_RSI_H_ +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c +new file mode 100644 +index 00000000..76fc761e +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c +@@ -0,0 +1,730 @@ ++/** @file ++ Library that implements the Arm CCA Realm Service Interface calls. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ - REM - Realm Extensible Measurement ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++ ++**/ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ArmCcaRsi.h" ++ ++/** The version of RSI specification implemented by this module. ++*/ ++STATIC CONST UINT32 mRsiImplVersion = RMM_VERSION (1, 0); ++ ++/** ++ Convert the RSI status code to EFI Status code. ++ ++ @param [in] RsiCommandReturnCode RSI status code. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++ **/ ++STATIC ++RETURN_STATUS ++RsiCmdStatusToEfiStatus ( ++ IN UINT64 RsiCommandReturnCode ++ ) ++{ ++ switch (RsiCommandReturnCode) { ++ /* TODO: when running in the host, RSI is not available. Find out how to probe ++ * this reliably. ++ */ ++ case 0xFFFFFFFFFFFFFFFF: ++ return RETURN_ABORTED; ++ case RSI_SUCCESS: ++ return RETURN_SUCCESS; ++ case RSI_ERROR_INPUT: ++ return RETURN_INVALID_PARAMETER; ++ case RSI_ERROR_STATE: ++ return RETURN_ABORTED; ++ case RSI_INCOMPLETE: ++ return RETURN_NOT_READY; ++ default: ++ // Unknown error code. ++ ASSERT (0); ++ break; ++ } // switch ++ ++ return RETURN_ABORTED; ++} ++ ++/** ++ Check if the address is aligned to the size of the Realm granule. ++ ++ @param [in] Address Address to check granule alignment. ++ ++ @retval TRUE Address is aligned to the Realm granule size. ++ @retval FALSE Address is not aligned to the Realm granule size. ++**/ ++STATIC ++BOOLEAN ++EFIAPI ++AddrIsGranuleAligned ( ++ IN UINT64 *Address ++ ) ++{ ++ if (((UINT64)Address & (REALM_GRANULE_SIZE - 1)) != 0) { ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++/** ++ Continue the operation to retrieve an attestation token. ++ ++ @param [out] TokenBuffer Pointer to a buffer to store the ++ retrieved attestation token. ++ @param [in] Offset Offset within Token buffer granule ++ to start of buffer in bytes. ++ @param [in,out] TokenSize On input size of the token buffer, ++ and on output size of the token ++ returned if operation is successful, ++ otherwise 0. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++ **/ ++STATIC ++RETURN_STATUS ++EFIAPI ++RsiAttestationTokenContinue ( ++ OUT UINT8 *CONST TokenBuffer, ++ IN UINT64 CONST Offset, ++ IN OUT UINT64 *CONST TokenSize ++ ) ++{ ++ RETURN_STATUS Status; ++ ARM_SMC_ARGS SmcCmd; ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_ATTESTATION_TOKEN_CONTINUE; ++ // Set the IPA of the Granule to which the token will be written. ++ SmcCmd.Arg1 = (UINTN)TokenBuffer; ++ // Set the Offset within Granule to start of buffer in bytes ++ SmcCmd.Arg2 = (UINTN)Offset; ++ // Set the size of the buffer in bytes ++ SmcCmd.Arg3 = (UINTN)*TokenSize; ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (!RETURN_ERROR (Status)) { ++ // Update the token size ++ *TokenSize = SmcCmd.Arg1; ++ } else { ++ // Clear the TokenBuffer on error. ++ ZeroMem (TokenBuffer, *TokenSize); ++ *TokenSize = 0; ++ } ++ ++ return Status; ++} ++ ++/** ++ Initialize the operation to retrieve an attestation token. ++ ++ @param [in] ChallengeData Pointer to the challenge data to be ++ included in the attestation token. ++ @param [in] ChallengeDataSizeBits Size of the challenge data in bits. ++ @param [out] MaxTokenSize Pointer to an integer to retrieve ++ the maximum attestation token size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ **/ ++STATIC ++RETURN_STATUS ++EFIAPI ++RsiAttestationTokenInit ( ++ IN CONST UINT8 *CONST ChallengeData, ++ IN UINT64 ChallengeDataSizeBits, ++ OUT UINT64 *CONST MaxTokenSize ++ ) ++{ ++ RETURN_STATUS Status; ++ ARM_SMC_ARGS SmcCmd; ++ UINT8 *Buffer8; ++ CONST UINT8 *Data8; ++ UINT64 Count; ++ UINT8 TailBits; ++ ++ /* See A7.2.2 Attestation token generation, RMM Specification, version A-bet0 ++ IWTKDD - If the size of the challenge provided by the relying party is less ++ than 64 bytes, it should be zero-padded prior to calling ++ RSI_ATTESTATION_TOKEN_INIT. ++ ++ Therefore, zero out the SmcCmd memory before coping the ChallengeData ++ bits. ++ */ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_ATTESTATION_TOKEN_INIT; ++ // Copy challenge data. ++ Buffer8 = (UINT8 *)&SmcCmd.Arg1; ++ Data8 = ChallengeData; ++ ++ // First copy whole bytes ++ Count = ChallengeDataSizeBits >> 3; ++ CopyMem (Buffer8, Data8, Count); ++ ++ // Now copy any remaining tail bits. ++ TailBits = ChallengeDataSizeBits & (8 - 1); ++ if (TailBits > 0) { ++ // Advance buffer pointers. ++ Buffer8 += Count; ++ Data8 += Count; ++ ++ // Copy tail byte. ++ *Buffer8 = *Data8; ++ ++ // Clear unused tail bits. ++ *Buffer8 &= ~(0xFF << TailBits); ++ } ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (RETURN_ERROR (Status)) { ++ // Set the max token size to zero ++ *MaxTokenSize = 0; ++ } else { ++ *MaxTokenSize = SmcCmd.Arg1; ++ } ++ ++ return Status; ++} ++ ++/** ++ Free the attestation token buffer. ++ ++ @param [in] TokenBuffer Pointer to the retrieved ++ attestation token. ++ @param [in] TokenBufferSize Size of the token buffer. ++**/ ++VOID ++RsiFreeAttestationToken ( ++ IN UINT8 *CONST TokenBuffer, ++ IN UINT64 CONST TokenBufferSize ++ ) ++{ ++ if (TokenBuffer != NULL) { ++ if (TokenBufferSize > 0) { ++ // Scrub the token buffer ++ ZeroMem (TokenBuffer, TokenBufferSize); ++ } ++ ++ FreePool (TokenBuffer); ++ } ++} ++ ++/** ++ Retrieve an attestation token from the RMM. ++ ++ @param [in] ChallengeData Pointer to the challenge data to be ++ included in the attestation token. ++ @param [in] ChallengeDataSizeBits Size of the challenge data in bits. ++ @param [out] TokenBuffer Pointer to a buffer to store the ++ retrieved attestation token. ++ @param [out] TokenBufferSize Length of token data returned. ++ ++ Note: The TokenBuffer allocated must be freed by the caller ++ using RsiFreeAttestationToken(). ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetAttestationToken ( ++ IN CONST UINT8 *CONST ChallengeData, ++ IN UINT64 ChallengeDataSizeBits, ++ OUT UINT8 **CONST TokenBuffer, ++ OUT UINT64 *CONST TokenBufferSize ++ ) ++{ ++ RETURN_STATUS Status; ++ UINT8 *Granule; ++ UINT64 GranuleSize; ++ UINT64 Offset; ++ UINT8 *Token; ++ UINT64 TokenSize; ++ UINT64 MaxTokenSize; ++ ++ if ((TokenBuffer == NULL) || ++ (TokenBufferSize == NULL) || ++ (ChallengeData == NULL)) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ if (ChallengeDataSizeBits > MAX_CHALLENGE_DATA_SIZE_BITS) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ /* See A7.2.2 Attestation token generation, RMM Specification, version A-bet0 ++ IWTKDD - Arm recommends that the challenge should contain at least 32 bytes ++ of unique data. ++ */ ++ if (ChallengeDataSizeBits < MIN_CHALLENGE_DATA_SIZE_BITS) { ++ DEBUG ((DEBUG_WARN, "Minimum Challenge data size should be 32 bytes\n")); ++ } ++ ++ Status = RsiAttestationTokenInit ( ++ ChallengeData, ++ ChallengeDataSizeBits, ++ &MaxTokenSize ++ ); ++ if (RETURN_ERROR (Status)) { ++ ASSERT (0); ++ return Status; ++ } ++ ++ // Allocate a granule to retrieve the attestation token chunk. ++ Granule = (UINT8 *)AllocateAlignedPages ( ++ EFI_SIZE_TO_PAGES (REALM_GRANULE_SIZE), ++ REALM_GRANULE_SIZE ++ ); ++ if (Granule == NULL) { ++ ASSERT (0); ++ return RETURN_OUT_OF_RESOURCES; ++ } ++ ++ // Alloate a buffer to store the retrieved attestation token. ++ Token = AllocateZeroPool (MaxTokenSize); ++ if (Token == NULL) { ++ ASSERT (0); ++ Status = RETURN_OUT_OF_RESOURCES; ++ goto exit_handler; ++ } ++ ++ TokenSize = 0; ++ do { ++ // Retrieve one Granule of data per loop iteration ++ ZeroMem (Granule, REALM_GRANULE_SIZE); ++ Offset = 0; ++ do { ++ // Retrieve sub-Granule chunk of data per loop iteration ++ GranuleSize = REALM_GRANULE_SIZE - Offset; ++ Status = RsiAttestationTokenContinue ( ++ Granule, ++ Offset, ++ &GranuleSize ++ ); ++ Offset += GranuleSize; ++ } while ((Status == RETURN_NOT_READY) && (Offset < REALM_GRANULE_SIZE)); ++ ++ if (RETURN_ERROR (Status) && (Status != RETURN_NOT_READY)) { ++ ASSERT (0); ++ goto exit_handler1; ++ } ++ ++ // "Offset" bytes of data are now ready for consumption from "Granule" ++ // Copy the new token data from the Granule. ++ CopyMem (&Token[TokenSize], Granule, Offset); ++ TokenSize += Offset; ++ } while ((Status == RETURN_NOT_READY) && (TokenSize < MaxTokenSize)); ++ ++ *TokenBuffer = Token; ++ *TokenBufferSize = TokenSize; ++ goto exit_handler; ++ ++exit_handler1: ++ if (Token != NULL) { ++ // Scrub the old Token ++ ZeroMem (Token, TokenSize); ++ FreePool (Token); ++ } ++ ++ *TokenBuffer = NULL; ++ *TokenBufferSize = 0; ++ ++exit_handler: ++ // Scrub the Granule buffer ++ ZeroMem (Granule, REALM_GRANULE_SIZE); ++ FreePages (Granule, EFI_SIZE_TO_PAGES (REALM_GRANULE_SIZE)); ++ ++ return Status; ++} ++ ++/** ++ Returns the IPA state for the page pointed by the address. ++ ++ @param [in] Address Address to retrive IPA state. ++ @param [out] State The RIPAS state for the address specified. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetIpaState ( ++ IN UINT64 *Address, ++ OUT RIPAS *State ++ ) ++{ ++ RETURN_STATUS Status; ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((State == NULL) || (!AddrIsGranuleAligned (Address))) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_IPA_STATE_GET; ++ SmcCmd.Arg1 = (UINTN)Address; ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (!RETURN_ERROR (Status)) { ++ *State = (RIPAS)(SmcCmd.Arg1 & RIPAS_TYPE_MASK); ++ } ++ ++ return Status; ++} ++ ++/** ++ Sets the IPA state for the pages pointed by the memory range. ++ ++ @param [in] Address Address to the start of the memory range. ++ @param [in] Size Length of the memory range. ++ @param [in] State The RIPAS state to be configured. ++ @param [in] Flags The RIPAS change flags. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ACCESS_DENIED RIPAS change request was rejected. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiSetIpaState ( ++ IN UINT64 *Address, ++ IN UINT64 Size, ++ IN RIPAS State, ++ IN UINT64 Flags ++ ) ++{ ++ RETURN_STATUS Status; ++ UINT64 *BaseAddress; ++ UINT64 *EndAddress; ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((Size == 0) || ++ ((Size & (REALM_GRANULE_SIZE - 1)) != 0) || ++ (!AddrIsGranuleAligned (Address))) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ BaseAddress = Address; ++ // Divide Size by 8 for the pointer arithmetic ++ // to work, as we are adding to UINT64*. ++ EndAddress = Address + (Size >> 3); ++ ++ while (Size > 0) { ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_IPA_STATE_SET; ++ SmcCmd.Arg1 = (UINTN)BaseAddress; ++ SmcCmd.Arg2 = (UINTN)EndAddress; ++ SmcCmd.Arg3 = (UINTN)State; ++ SmcCmd.Arg4 = Flags; ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (RETURN_ERROR (Status)) { ++ break; ++ } ++ ++ BaseAddress = (UINT64 *)SmcCmd.Arg1; ++ Size = EndAddress - BaseAddress; ++ ++ if ((SmcCmd.Arg2 & RSI_RESPONSE_MASK) == RIPAS_CHANGE_RESPONSE_REJECT) { ++ Status = RETURN_ACCESS_DENIED; ++ break; ++ } ++ } // while ++ ++ return Status; ++} ++ ++/** ++ Extends a measurement to a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [in] Measurement Pointer to the measurement buffer. ++ @param [in] MeasurementSize Size of the measurement data. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiExtendMeasurement ( ++ IN UINTN MeasurementIndex, ++ IN CONST UINT8 *CONST Measurement, ++ IN UINTN MeasurementSize ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((MeasurementIndex < MIN_REM_INDEX) || ++ (MeasurementIndex > MAX_REM_INDEX) || ++ (Measurement == NULL) || ++ (MeasurementSize == 0) || ++ (MeasurementSize > MAX_MEASUREMENT_DATA_SIZE_BYTES)) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ ++ SmcCmd.Arg0 = FID_RSI_MEASUREMENT_EXTEND; ++ SmcCmd.Arg1 = MeasurementIndex; ++ SmcCmd.Arg2 = MeasurementSize; ++ ++ SmcCmd.Arg3 = (UINTN) Measurement; ++ ++ ArmCallSmc (&SmcCmd); ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} ++ ++/** ++ Read the measurement value from a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [out] MeasurementBuffer Pointer to store the measurement data. ++ @param [in] MeasurementBufferSize Size of the measurement buffer. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiReadMeasurement ( ++ IN UINTN MeasurementIndex, ++ OUT UINT8 *CONST MeasurementBuffer, ++ IN UINTN MeasurementBufferSize ++ ) ++{ ++ RETURN_STATUS Status; ++ ARM_SMC_ARGS SmcCmd; ++ UINT64 *Data64; ++ ++ if ((MeasurementIndex < MIN_REM_INDEX) || ++ (MeasurementIndex > MAX_REM_INDEX) || ++ (MeasurementBuffer == NULL)) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ if (MeasurementBufferSize < MAX_MEASUREMENT_DATA_SIZE_BYTES) { ++ return RETURN_BUFFER_TOO_SMALL; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_MEASUREMENT_READ; ++ SmcCmd.Arg1 = MeasurementIndex; ++ ++ ArmCallSmc (&SmcCmd); ++ Status = RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++ if (!RETURN_ERROR (Status)) { ++ Data64 = &SmcCmd.Arg1; ++ CopyMem (MeasurementBuffer, Data64, MAX_MEASUREMENT_DATA_SIZE_BYTES); ++ } ++ ++ return Status; ++} ++ ++/** ++ Read the Realm Configuration. ++ ++ @param [out] Config Pointer to the address of the buffer to retrieve ++ the Realm configuration. ++ ++ Note: The buffer to retrieve the Realm configuration must be aligned to the ++ Realm granule size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetRealmConfig ( ++ OUT REALM_CONFIG *Config ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((Config == NULL) || (!AddrIsGranuleAligned ((UINT64 *)Config))) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_REALM_CONFIG; ++ SmcCmd.Arg1 = (UINTN)Config; ++ ++ ArmCallSmc (&SmcCmd); ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} ++ ++/** ++ Make a Host Call. ++ ++ A Host call can be used by a Realm to make a hypercall. ++ On Realm execution of HVC, an Unknown exception is taken to the Realm. ++ ++ @param [in] Args Pointer to the IPA of the Host call data ++ structure. ++ ++ Note: The IPA of the Host call arguments data structure must be aligned ++ to the Realm granule size. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiHostCall ( ++ IN HOST_CALL_ARGS *Args ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ // The RMM specification, version 1.0-eac1, relaxes the alignment ++ // requirement for RSI_HOST_CALL from 4KB to 256B. Also see RMM ++ // specification, sections B4.3.3 RSI_HOST_CALL command and ++ // section B4.3.3.2 Failure conditions. ++ if ((Args == NULL) || (((UINT64)Args & (0x100 - 1)) != 0)) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ // See RMM specification, version 1.0-bet1, Section B4.4.2 RsiHostCall type ++ // The width of the RsiHostCall structure is 256 (0x100) bytes. ++ STATIC_ASSERT (sizeof (HOST_CALL_ARGS) == 0x100); ++ ++ // Clear the reserved fields ++ ZeroMem (&Args->Reserved1, sizeof (Args->Reserved1)); ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_HOST_CALL; ++ SmcCmd.Arg1 = (UINTN)Args; ++ ++ ArmCallSmc (&SmcCmd); ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} ++ ++/** ++ Get the version of the RSI implementation. ++ ++ @param [out] UefiImpl The version of the RSI specification ++ implemented by the UEFI firmware. ++ @param [out] RmmImpl The version of the RSI specification ++ implemented by the RMM. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_UNSUPPORTED The execution context is not a Realm. ++ @retval RETURN_INCOMPATIBLE_VERSION The Firmware and RMM specification ++ revisions are not compatible. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetVersion ( ++ OUT UINT32 *CONST UefiImpl, ++ OUT UINT32 *CONST RmmImpl ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((UefiImpl == NULL) || (RmmImpl == NULL)) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_VERSION; ++ ArmCallSmc (&SmcCmd); ++ if (SmcCmd.Arg0 == MAX_UINT64) { ++ // This FID is not implemented, which means ++ // we are not running in a Realm, therefore ++ // return the error code as unsupported. ++ return RETURN_UNSUPPORTED; ++ } ++ ++ *RmmImpl = (SmcCmd.Arg0 & RSI_VERSION_MASK); ++ *UefiImpl = mRsiImplVersion; ++ if (*RmmImpl != *UefiImpl) { ++ // The RSI version implemented by UEFI ++ // firmware and RMM dose not match, return ++ // the status code as RETURN_INCOMPATIBLE_VERSION. ++ return RETURN_INCOMPATIBLE_VERSION; ++ } ++ ++ return RETURN_SUCCESS; ++} ++ ++/** ++ Get the features supported by the RSI implementation. ++ ++ RMM implementations across different CCA platforms may support ++ disparate features and may offer disparate configuration options ++ for Realms. The features supported by an RSI implementation are ++ discovered by reading feature pseudo-register values using the ++ RSI_FEATURES command. ++ ++ @param [in] FeatureRegIndex The Feature Register Index. ++ @param [out] FeatureRegValue The Feature Register Value. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetFeatures ( ++ IN UINT64 FeatureRegIndex, ++ OUT UINT64 *FeatureRegValue ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if (FeatureRegValue == NULL) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_FEATURES; ++ SmcCmd.Arg1 = FeatureRegIndex; ++ ++ ArmCallSmc (&SmcCmd); ++ *FeatureRegValue = SmcCmd.Arg1; ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf +new file mode 100644 +index 00000000..1e2b72f3 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf +@@ -0,0 +1,29 @@ ++## @file ++# Library that implements the Arm CCA Realm Service Interface calls. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = ArmCcaRsiLib ++ FILE_GUID = 5EF34A0A-28B5-4E57-A999-CC1528FC629A ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmCcaRsiLib ++ ++[Sources] ++ ArmCcaRsiLib.c ++ ArmCcaRsi.h ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmLib ++ ArmSmcLib +diff --git a/ArmVirtPkg/Library/HashLibCca/HashLibCca.c b/ArmVirtPkg/Library/HashLibCca/HashLibCca.c +new file mode 100644 +index 00000000..3d0a133d +--- /dev/null ++++ b/ArmVirtPkg/Library/HashLibCca/HashLibCca.c +@@ -0,0 +1,209 @@ ++/** @file ++ This library is HashLib for Cca. ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++EFI_GUID mSha256Guid = HASH_ALGORITHM_SHA256_GUID; ++ ++// ++// Currently CCA supports SHA256. ++// ++HASH_INTERFACE mHashInterface = { ++ { 0 }, NULL, NULL, NULL ++}; ++ ++UINTN mHashInterfaceCount = 0; ++ ++/** ++ Start hash sequence. ++ ++ @param HashHandle Hash handle. ++ ++ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. ++**/ ++EFI_STATUS ++EFIAPI ++HashStart ( ++ OUT HASH_HANDLE *HashHandle ++ ) ++{ ++ HASH_HANDLE HashCtx; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ HashCtx = 0; ++ mHashInterface.HashInit (&HashCtx); ++ ++ *HashHandle = HashCtx; ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Update hash sequence data. ++ ++ @param HashHandle Hash handle. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ ++ @retval EFI_SUCCESS Hash sequence updated. ++**/ ++EFI_STATUS ++EFIAPI ++HashUpdate ( ++ IN HASH_HANDLE HashHandle, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen ++ ) ++{ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ mHashInterface.HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Hash sequence complete and extend to PCR. ++ ++ @param HashHandle Hash handle. ++ @param PcrIndex PCR to be extended. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ @param DigestList Digest list. ++ ++ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. ++**/ ++EFI_STATUS ++EFIAPI ++HashCompleteAndExtend ( ++ IN HASH_HANDLE HashHandle, ++ IN TPMI_DH_PCR PcrIndex, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ TPML_DIGEST_VALUES Digest; ++ EFI_STATUS Status; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ ZeroMem (DigestList, sizeof (*DigestList)); ++ ++ mHashInterface.HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ mHashInterface.HashFinal (HashHandle, &Digest); ++ ++ CopyMem ( ++ &DigestList->digests[0], ++ &Digest.digests[0], ++ sizeof (Digest.digests[0]) ++ ); ++ DigestList->count++; ++ ++ ASSERT (DigestList->count == 1 && DigestList->digests[0].hashAlg == TPM_ALG_SHA256); ++ ++ Status = RsiExtendMeasurement ( ++ (UINTN)PcrIndex, ++ (UINT8 *)DigestList->digests[0].digest.sha256, ++ SHA256_DIGEST_SIZE ++ ); ++ ++ ASSERT (!EFI_ERROR (Status)); ++ return Status; ++} ++ ++/** ++ Hash data and extend to RTMR. ++ ++ @param PcrIndex PCR to be extended. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ @param DigestList Digest list. ++ ++ @retval EFI_SUCCESS Hash data and DigestList is returned. ++**/ ++EFI_STATUS ++EFIAPI ++HashAndExtend ( ++ IN TPMI_DH_PCR PcrIndex, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ HASH_HANDLE HashHandle; ++ EFI_STATUS Status; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ ASSERT (IsRealm ()); ++ ++ HashStart (&HashHandle); ++ HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ Status = HashCompleteAndExtend (HashHandle, PcrIndex, NULL, 0, DigestList); ++ ++ return Status; ++} ++ ++/** ++ This service register Hash. ++ ++ @param HashInterface Hash interface ++ ++ @retval EFI_SUCCESS This hash interface is registered successfully. ++ @retval EFI_UNSUPPORTED System does not support register this interface. ++ @retval EFI_ALREADY_STARTED System already register this interface. ++**/ ++EFI_STATUS ++EFIAPI ++RegisterHashInterfaceLib ( ++ IN HASH_INTERFACE *HashInterface ++ ) ++{ ++ // ++ // HashLibCca is designed for Cca guest. So if it is not Cca guest, ++ // return EFI_UNSUPPORTED. ++ // ++ if (!IsRealm ()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ // ++ // Only SHA256 is allowed. ++ // ++ if (!CompareGuid (&mSha256Guid, &HashInterface->HashGuid)) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ if (mHashInterfaceCount != 0) { ++ ASSERT (FALSE); ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ CopyMem (&mHashInterface, HashInterface, sizeof (*HashInterface)); ++ mHashInterfaceCount++; ++ ++ return EFI_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf b/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf +new file mode 100644 +index 00000000..7d23792d +--- /dev/null ++++ b/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf +@@ -0,0 +1,39 @@ ++## @file ++# Provides hash service by registered hash handler in Tdx. ++# ++# This library is HashLib for Cca. Currently only SHA384 is supported. ++# ++# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = HashLibCca ++ FILE_GUID = 60a6d467-4f75-4089-8c8e-52a74af1e068 ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = HashLib|DXE_DRIVER ++ ++# ++# The following information is for reference only and not required by the build tools. ++# ++# VALID_ARCHITECTURES = AARCH64 ++# ++ ++[Sources] ++ HashLibCca.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ SecurityPkg/SecurityPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ BaseMemoryLib ++ DebugLib ++ PcdLib ++ ArmCcaLib ++ ArmCcaRsiLib +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +index 58ea4c66..82ae9571 100644 +--- a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +@@ -201,7 +201,6 @@ RampOpenAperture ( + )); + return Status; + } +- DEBUG ((DEBUG_INFO, "RampOpenAperture set 0x%p NS 1.\n", Memory)); + + // Allocate a APERTURE_INFO structure to remember the apertures opened. + ApertInfo = AllocateZeroPool (sizeof (APERTURE_INFO)); +@@ -523,7 +522,7 @@ RealmApertureManagementProtocolDxeInitialize ( + EFI_EVENT CloseAllAperturesEvent; + EFI_EVENT ExitBootEvent; + VOID *Registration; +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 1.\n")); ++ + // When the execution context is a Realm, install the Realm Aperture + // Management protocol otherwise return success so that other modules + // can run. +@@ -579,7 +578,7 @@ RealmApertureManagementProtocolDxeInitialize ( + NULL, + &Registration + ); +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 2.\n")); ++ + return Status; + } + +@@ -588,6 +587,6 @@ RealmApertureManagementProtocolDxeInitialize ( + + error_handler1: + gBS->CloseEvent (CloseAllAperturesEvent); +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 3.\n")); ++ + return Status; + } +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +index 029e933e..8f8e7585 100644 +--- a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +@@ -31,6 +31,7 @@ + + [LibraryClasses] + ArmCcaLib ++ ArmCcaRsiLib + BaseLib + DxeServicesTableLib + MemoryAllocationLib +diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec +index 0ff058b0..9c66c292 100644 +--- a/MdeModulePkg/MdeModulePkg.dec ++++ b/MdeModulePkg/MdeModulePkg.dec +@@ -1984,7 +1984,7 @@ + + ## Default OEM ID for ACPI table creation, its length must be 0x6 bytes to follow ACPI specification. + # @Prompt Default OEM ID for ACPI table creation. +- gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"INTEL "|VOID*|0x30001034 ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"Huawei "|VOID*|0x30001034 + + ## Default OEM Table ID for ACPI table creation, it is "EDK2 ". + # According to ACPI specification, this field is particularly useful when +diff --git a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h +index e07840c9..ee99897b 100644 +--- a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h ++++ b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h +@@ -438,6 +438,7 @@ typedef struct tdTCG_PCClientTaggedEvent { + + #define TCG_Sp800_155_PlatformId_Event_SIGNATURE "SP800-155 Event" + #define TCG_Sp800_155_PlatformId_Event2_SIGNATURE "SP800-155 Event2" ++#define TCG_Sp800_155_PlatformId_Event3_SIGNATURE "SP800-155 Event3" + + typedef struct tdTCG_Sp800_155_PlatformId_Event2 { + UINT8 Signature[16]; +diff --git a/MdePkg/Include/Protocol/CcMeasurement.h b/MdePkg/Include/Protocol/CcMeasurement.h +index 4bf21fc4..23681a3a 100644 +--- a/MdePkg/Include/Protocol/CcMeasurement.h ++++ b/MdePkg/Include/Protocol/CcMeasurement.h +@@ -36,6 +36,7 @@ typedef struct { + #define EFI_CC_TYPE_NONE 0 + #define EFI_CC_TYPE_SEV 1 + #define EFI_CC_TYPE_TDX 2 ++#define EFI_CC_TYPE_CCA 3 + + typedef struct { + UINT8 Type; +@@ -57,7 +58,9 @@ typedef UINT32 EFI_CC_MR_INDEX; + #define TDX_MR_INDEX_RTMR3 4 + + #define EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 +-#define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define EFI_CC_BOOT_HASH_ALG_SHA256 0x00000002 ++#define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define EFI_CC_BOOT_HASH_ALG_SHA512 0x00000008 + + // + // This bit is shall be set when an event shall be extended but not logged. +diff --git a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +index cc58b8bf..73719f3b 100644 +--- a/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c ++++ b/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c +@@ -20,8 +20,8 @@ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +-Copyright (c) Microsoft Corporation.
+-SPDX-License-Identifier: BSD-2-Clause-Patent ++Copyright (c) Microsoft Corporation.
++SPDX-License-Identifier: BSD-2-Clause-Patent + **/ + + #include +@@ -46,8 +46,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + +-#include "DxeTpm2MeasureBootLibSanitization.h" +- ++#include "DxeTpm2MeasureBootLibSanitization.h" ++ + typedef struct { + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; +@@ -148,11 +148,11 @@ Tcg2MeasureGptTable ( + EFI_TCG2_EVENT *Tcg2Event; + EFI_CC_EVENT *CcEvent; + EFI_GPT_DATA *GptData; +- UINT32 TcgEventSize; ++ UINT32 TcgEventSize; + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_CC_MEASUREMENT_PROTOCOL *CcProtocol; + EFI_CC_MR_INDEX MrIndex; +- UINT32 AllocSize; ++ UINT32 AllocSize; + + if (mTcg2MeasureGptCount > 0) { + return EFI_SUCCESS; +@@ -200,22 +200,22 @@ Tcg2MeasureGptTable ( + BlockIo->Media->BlockSize, + (UINT8 *)PrimaryHeader + ); +- if (EFI_ERROR (Status) || EFI_ERROR (Tpm2SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { +- DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); ++ if (EFI_ERROR (Status) || EFI_ERROR (Tpm2SanitizeEfiPartitionTableHeader (PrimaryHeader, BlockIo))) { ++ DEBUG ((DEBUG_ERROR, "Failed to read Partition Table Header or invalid Partition Table Header!\n")); + FreePool (PrimaryHeader); + return EFI_DEVICE_ERROR; + } + + // +- // Read the partition entry. ++ // Read the partition entry. + // +- Status = Tpm2SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); +- if (EFI_ERROR (Status)) { ++ Status = Tpm2SanitizePrimaryHeaderAllocationSize (PrimaryHeader, &AllocSize); ++ if (EFI_ERROR (Status)) { + FreePool (PrimaryHeader); + return EFI_BAD_BUFFER_SIZE; + } + +- EntryPtr = (UINT8 *)AllocatePool (AllocSize); ++ EntryPtr = (UINT8 *)AllocatePool (AllocSize); + if (EntryPtr == NULL) { + FreePool (PrimaryHeader); + return EFI_OUT_OF_RESOURCES; +@@ -225,7 +225,7 @@ Tcg2MeasureGptTable ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32 (PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), +- AllocSize, ++ AllocSize, + EntryPtr + ); + if (EFI_ERROR (Status)) { +@@ -250,21 +250,21 @@ Tcg2MeasureGptTable ( + // + // Prepare Data for Measurement (CcProtocol and Tcg2Protocol) + // +- Status = Tpm2SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); +- if (EFI_ERROR (Status)) { +- FreePool (PrimaryHeader); +- FreePool (EntryPtr); +- return EFI_DEVICE_ERROR; +- } +- +- EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); ++ Status = Tpm2SanitizePrimaryHeaderGptEventSize (PrimaryHeader, NumberOfPartition, &TcgEventSize); ++ if (EFI_ERROR (Status)) { ++ FreePool (PrimaryHeader); ++ FreePool (EntryPtr); ++ return EFI_DEVICE_ERROR; ++ } ++ ++ EventPtr = (UINT8 *)AllocateZeroPool (TcgEventSize); + if (EventPtr == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Exit; + } + + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; +- Tcg2Event->Size = TcgEventSize; ++ Tcg2Event->Size = TcgEventSize; + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + Tcg2Event->Header.PCRIndex = 5; +@@ -317,7 +317,7 @@ Tcg2MeasureGptTable ( + CcProtocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, +- (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), + CcEvent + ); + if (!EFI_ERROR (Status)) { +@@ -333,7 +333,7 @@ Tcg2MeasureGptTable ( + Tcg2Protocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)(VOID *)GptData, +- (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), ++ (UINT64)TcgEventSize - OFFSET_OF (EFI_TCG2_EVENT, Event), + Tcg2Event + ); + if (!EFI_ERROR (Status)) { +@@ -404,7 +404,7 @@ Tcg2MeasurePeImage ( + Status = EFI_UNSUPPORTED; + ImageLoad = NULL; + EventPtr = NULL; +- Tcg2Event = NULL; ++ Tcg2Event = NULL; + + Tcg2Protocol = MeasureBootProtocols->Tcg2Protocol; + CcProtocol = MeasureBootProtocols->CcProtocol; +@@ -420,22 +420,22 @@ Tcg2MeasurePeImage ( + } + + FilePathSize = (UINT32)GetDevicePathSize (FilePath); +- Status = Tpm2SanitizePeImageEventSize (FilePathSize, &EventSize); +- if (EFI_ERROR (Status)) { +- return EFI_UNSUPPORTED; +- } ++ Status = Tpm2SanitizePeImageEventSize (FilePathSize, &EventSize); ++ if (EFI_ERROR (Status)) { ++ return EFI_UNSUPPORTED; ++ } + + // + // Determine destination PCR by BootPolicy + // +- // from a malicious GPT disk partition +- EventPtr = AllocateZeroPool (EventSize); ++ // from a malicious GPT disk partition ++ EventPtr = AllocateZeroPool (EventSize); + if (EventPtr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Tcg2Event = (EFI_TCG2_EVENT *)EventPtr; +- Tcg2Event->Size = EventSize; ++ Tcg2Event->Size = EventSize; + Tcg2Event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + ImageLoad = (EFI_IMAGE_LOAD_EVENT *)Tcg2Event->Event; +@@ -454,13 +454,13 @@ Tcg2MeasurePeImage ( + Tcg2Event->Header.PCRIndex = 2; + break; + default: +- DEBUG ( +- ( +- DEBUG_ERROR, +- "Tcg2MeasurePeImage: Unknown subsystem type %d", +- ImageType +- ) +- ); ++ DEBUG ( ++ ( ++ DEBUG_ERROR, ++ "Tcg2MeasurePeImage: Unknown subsystem type %d", ++ ImageType ++ ) ++ ); + goto Finish; + } + +@@ -528,7 +528,7 @@ Finish: + + @param MeasureBootProtocols Pointer to the located measure boot protocol instances. + +- @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). ++ @retval EFI_SUCCESS Successfully locate the measure boot protocol instances (at least one instance). + @retval EFI_UNSUPPORTED Measure boot is not supported. + **/ + EFI_STATUS +@@ -659,14 +659,14 @@ DxeTpm2MeasureBootHandler ( + return EFI_SUCCESS; + } + +- DEBUG ( +- ( +- DEBUG_INFO, +- "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", +- MeasureBootProtocols.Tcg2Protocol, +- MeasureBootProtocols.CcProtocol +- ) +- ); ++ DEBUG ( ++ ( ++ DEBUG_INFO, ++ "Tcg2Protocol = %p, CcMeasurementProtocol = %p\n", ++ MeasureBootProtocols.Tcg2Protocol, ++ MeasureBootProtocols.CcProtocol ++ ) ++ ); + + // + // Copy File Device Path +diff --git a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c +index 43877400..f06c7028 100644 +--- a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c ++++ b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c +@@ -10,7 +10,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + #include +-#include + #include + #include + #include +diff --git a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf +index a7d1f162..72fd1b44 100644 +--- a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf ++++ b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf +@@ -36,6 +36,5 @@ + BaseLib + BaseMemoryLib + DebugLib +- Tpm2CommandLib + MemoryAllocationLib + BaseCryptLib +-- +2.33.0 + diff --git a/edk2.spec b/edk2.spec index f37c23d..fe5f64e 100644 --- a/edk2.spec +++ b/edk2.spec @@ -135,6 +135,9 @@ patch82: 0082-fixup-fdt-parse-error.patch # Support virtCCA patch83: 0083-edk2-1219-support-virtCCA.patch +# enable cc measurement and sha256 in cc measurement +patch84: 0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -404,6 +407,10 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Tue Feb 18 2025 z00570632 - 202308-19 +- enable cc measurement and sha256 in cc measurement +- 0084-enable-cc-measurement-and-sha256-in-cc-measurement.patch + * Thu Jan 9 2025 z00570632 - 202308-18 - Support virtCCA - 0083-edk2-1219-support-virtCCA.patch -- Gitee