diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library')
27 files changed, 5967 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.c new file mode 100644 index 00000000..cf3beb1f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.c @@ -0,0 +1,379 @@ +/** @file + +Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/FvLib.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> + +#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ + (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) + +/** + Returns the highest bit set of the State field + + @param ErasePolarity Erase Polarity as defined by EFI_FVB_ERASE_POLARITY + in the Attributes field. + @param FfsHeader Pointer to FFS File Header. + + @return the highest bit in the State field +**/ +EFI_FFS_FILE_STATE +GetFileState ( + IN UINT8 ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + EFI_FFS_FILE_STATE FileState; + EFI_FFS_FILE_STATE HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity != 0) { + FileState = (EFI_FFS_FILE_STATE)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && (HighestBit & FileState) == 0) { + HighestBit >>= 1; + } + + return HighestBit; +} + +/** + Calculates the checksum of the header of a file. + + @param FileHeader Pointer to FFS File Header. + + @return Checksum of the header. +**/ +UINT8 +CalculateHeaderChecksum ( + IN EFI_FFS_FILE_HEADER *FileHeader + ) +{ + UINT8 *ptr; + UINTN Index; + UINT8 Sum; + + Sum = 0; + ptr = (UINT8 *) FileHeader; + + for (Index = 0; Index < sizeof (EFI_FFS_FILE_HEADER) - 3; Index += 4) { + Sum = (UINT8) (Sum + ptr[Index]); + Sum = (UINT8) (Sum + ptr[Index + 1]); + Sum = (UINT8) (Sum + ptr[Index + 2]); + Sum = (UINT8) (Sum + ptr[Index + 3]); + } + + for (; Index < sizeof (EFI_FFS_FILE_HEADER); Index++) { + Sum = (UINT8) (Sum + ptr[Index]); + } + // + // State field (since this indicates the different state of file). + // + Sum = (UINT8) (Sum - FileHeader->State); + // + // Checksum field of the file is not part of the header checksum. + // + Sum = (UINT8) (Sum - FileHeader->IntegrityCheck.Checksum.File); + + return Sum; +} + +/** + Given the input file pointer, search for the next matching file in the + FFS volume as defined by SearchType. The search starts from FileHeader inside + the Firmware Volume defined by FwVolHeader. + + @param SearchType Filter to find only files of this type. + Type EFI_FV_FILETYPE_ALL causes no filtering to be done. + @param FwVolHeader Pointer to the FV header of the volume to search. + This parameter must point to a valid FFS volume. + @param FileHeader Pointer to the current file from which to begin searching. + This pointer will be updated upon return to reflect the file found. + + @retval EFI_NOT_FOUND No files matching the search criteria were found + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FfsFindNextFile ( + IN EFI_FV_FILETYPE SearchType, + IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader, + IN OUT EFI_FFS_FILE_HEADER **FileHeader + ) +{ + EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; + + EFI_FFS_FILE_HEADER *FfsFileHeader; + UINT32 FileLength; + UINT32 FileOccupiedSize; + UINT32 FileOffset; + UINT64 FvLength; + UINT8 ErasePolarity; + UINT8 FileState; + + FvLength = FwVolHeader->FvLength; + if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { + ErasePolarity = 1; + } else { + ErasePolarity = 0; + } + // + // If FileHeader is not specified (NULL) start with the first file in the + // firmware volume. Otherwise, start from the FileHeader. + // + if (*FileHeader == NULL) { + + if (FwVolHeader->ExtHeaderOffset != 0) { + + FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FwVolHeader + + FwVolHeader->ExtHeaderOffset); + + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FvExtHeader + + FvExtHeader->ExtHeaderSize); + + } else { + + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + + FwVolHeader->HeaderLength); + + } + + FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINTN)FwVolHeader + + ALIGN_VALUE((UINTN)FfsFileHeader - + (UINTN)FwVolHeader, 8)); + } else { + // + // Length is 24 bits wide so mask upper 8 bits + // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + FileLength = FFS_FILE_SIZE(*FileHeader); + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) *FileHeader + FileOccupiedSize); + } + + FileOffset = (UINT32) ((UINT8 *) FfsFileHeader - (UINT8 *) FwVolHeader); + + while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) { + // + // Get FileState which is the highest bit of the State + // + FileState = GetFileState (ErasePolarity, FfsFileHeader); + + switch (FileState) { + + case EFI_FILE_HEADER_INVALID: + FileOffset += sizeof (EFI_FFS_FILE_HEADER); + FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER)); + break; + + case EFI_FILE_DATA_VALID: + case EFI_FILE_MARKED_FOR_UPDATE: + if (CalculateHeaderChecksum (FfsFileHeader) == 0) { + FileLength = FFS_FILE_SIZE(FfsFileHeader); + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + + if ((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) { + + *FileHeader = FfsFileHeader; + + return EFI_SUCCESS; + } + + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize); + } else { + return EFI_NOT_FOUND; + } + break; + + case EFI_FILE_DELETED: + FileLength = FFS_FILE_SIZE(FfsFileHeader); + FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); + FileOffset += FileOccupiedSize; + FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize); + break; + + default: + return EFI_NOT_FOUND; + + } + } + + return EFI_NOT_FOUND; +} + +/** + Locates a section within a series of sections + with the specified section type. + + @param[in] Sections The sections to search + @param[in] SizeOfSections Total size of all sections + @param[in] SectionType The section type to locate + @param[out] FoundSection The FFS section if found + + @retval EFI_SUCCESS The file and section was found + @retval EFI_NOT_FOUND The file and section was not found + @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted +**/ +EFI_STATUS +EFIAPI +FindFfsSectionInSections ( + IN VOID *Sections, + IN UINTN SizeOfSections, + IN EFI_SECTION_TYPE SectionType, + OUT EFI_COMMON_SECTION_HEADER **FoundSection + ) +{ + EFI_PHYSICAL_ADDRESS CurrentAddress; + UINT32 Size; + EFI_PHYSICAL_ADDRESS EndOfSections; + EFI_COMMON_SECTION_HEADER *Section; + EFI_PHYSICAL_ADDRESS EndOfSection; + + // + // Loop through the FFS file sections + // + EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections; + EndOfSections = EndOfSection + SizeOfSections; + for (;;) { + if (EndOfSection == EndOfSections) { + break; + } + CurrentAddress = EndOfSection; + + Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress; + + Size = SECTION_SIZE (Section); + if (Size < sizeof (*Section)) { + return EFI_VOLUME_CORRUPTED; + } + + EndOfSection = CurrentAddress + Size; + if (EndOfSection > EndOfSections) { + return EFI_VOLUME_CORRUPTED; + } + Size = GET_OCCUPIED_SIZE (Size, 4); + + // + // Look for the requested section type + // + if (Section->Type == SectionType) { + *FoundSection = Section; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Given the input file pointer, search for the next matching section in the + FFS volume. + + @param SearchType Filter to find only sections of this type. + @param FfsFileHeader Pointer to the current file to search. + @param SectionHeader Pointer to the Section matching SectionType in FfsFileHeader. + NULL if section not found + + @retval EFI_NOT_FOUND No files matching the search criteria were found + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FfsFindSection ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT EFI_COMMON_SECTION_HEADER **SectionHeader + ) +{ + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + EFI_STATUS Status; + + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section = (EFI_COMMON_SECTION_HEADER *) (FfsFileHeader + 1); + FileSize = FFS_FILE_SIZE(FfsFileHeader); + FileSize -= sizeof (EFI_FFS_FILE_HEADER); + + Status = FindFfsSectionInSections ( + Section, + FileSize, + SectionType, + SectionHeader + ); + return Status; +} + +/** + Given the input file pointer, search for the next matching section in the + FFS volume. + + @param SearchType Filter to find only sections of this type. + @param FfsFileHeader Pointer to the current file to search. + @param SectionData Pointer to the Section matching SectionType in FfsFileHeader. + NULL if section not found + @param SectionDataSize The size of SectionData + + @retval EFI_NOT_FOUND No files matching the search criteria were found + @retval EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +FfsFindSectionData ( + IN EFI_SECTION_TYPE SectionType, + IN EFI_FFS_FILE_HEADER *FfsFileHeader, + IN OUT VOID **SectionData, + IN OUT UINTN *SectionDataSize + ) +{ + UINT32 FileSize; + EFI_COMMON_SECTION_HEADER *Section; + UINT32 SectionLength; + UINT32 ParsedLength; + + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section = (EFI_COMMON_SECTION_HEADER *) (FfsFileHeader + 1); + FileSize = FFS_FILE_SIZE(FfsFileHeader); + FileSize -= sizeof (EFI_FFS_FILE_HEADER); + + *SectionData = NULL; + ParsedLength = 0; + while (ParsedLength < FileSize) { + if (Section->Type == SectionType) { + *SectionData = (VOID *) (Section + 1); + *SectionDataSize = SECTION_SIZE(Section); + return EFI_SUCCESS; + } + // + // Size is 24 bits wide so mask upper 8 bits. + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength = SECTION_SIZE(Section); + SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); + + ParsedLength += SectionLength; + Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength); + } + + return EFI_NOT_FOUND; +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.inf new file mode 100644 index 00000000..22f71abd --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/FvLib/FvLib.inf @@ -0,0 +1,52 @@ +## @file +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = FvLib + FILE_GUID = C20085E9-E3AB-4938-A727-C10935FEEE2B + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FvLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 +# + +################################################################################ +# +# Sources Section - list of files that are required for the build to succeed. +# +################################################################################ + +[Sources] + FvLib.c + +################################################################################ +# +# Package Dependency Section - list of Package files that are required for +# this module. +# +################################################################################ + +[Packages] + MdePkg/MdePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/CreateHobList.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/CreateHobList.c new file mode 100644 index 00000000..dd2db78a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/CreateHobList.c @@ -0,0 +1,205 @@ +/** @file + Creates HOB during Standalone MM Foundation entry point + on ARM platforms. + +Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include <PiMm.h> + +#include <PiPei.h> +#include <Guid/MmramMemoryReserve.h> +#include <Guid/MpInformation.h> + +#include <Library/AArch64/StandaloneMmCoreEntryPoint.h> +#include <Library/ArmMmuLib.h> +#include <Library/ArmSvcLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/SerialPortLib.h> + +#include <IndustryStandard/ArmStdSmc.h> + +extern EFI_HOB_HANDOFF_INFO_TABLE* +HobConstructor ( + IN VOID *EfiMemoryBegin, + IN UINTN EfiMemoryLength, + IN VOID *EfiFreeMemoryBottom, + IN VOID *EfiFreeMemoryTop + ); + +// GUID to identify HOB with whereabouts of communication buffer with Normal +// World +extern EFI_GUID gEfiStandaloneMmNonSecureBufferGuid; + +// GUID to identify HOB where the entry point of the CPU driver will be +// populated to allow this entry point driver to invoke it upon receipt of an +// event +extern EFI_GUID gEfiArmTfCpuDriverEpDescriptorGuid; + +/** + Use the boot information passed by privileged firmware to populate a HOB list + suitable for consumption by the MM Core and drivers. + + @param [in, out] CpuDriverEntryPoint Address of MM CPU driver entrypoint + @param [in] PayloadBootInfo Boot information passed by privileged + firmware + +**/ +VOID * +CreateHobListFromBootInfo ( + IN OUT PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT *CpuDriverEntryPoint, + IN EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo +) +{ + EFI_HOB_HANDOFF_INFO_TABLE *HobStart; + EFI_RESOURCE_ATTRIBUTE_TYPE Attributes; + UINT32 Index; + UINT32 BufferSize; + UINT32 Flags; + EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHob; + EFI_MMRAM_DESCRIPTOR *MmramRanges; + EFI_MMRAM_DESCRIPTOR *NsCommBufMmramRange; + MP_INFORMATION_HOB_DATA *MpInformationHobData; + EFI_PROCESSOR_INFORMATION *ProcInfoBuffer; + EFI_SECURE_PARTITION_CPU_INFO *CpuInfo; + ARM_TF_CPU_DRIVER_EP_DESCRIPTOR *CpuDriverEntryPointDesc; + + // Create a hoblist with a PHIT and EOH + HobStart = HobConstructor ( + (VOID *) PayloadBootInfo->SpMemBase, + (UINTN) PayloadBootInfo->SpMemLimit - PayloadBootInfo->SpMemBase, + (VOID *) PayloadBootInfo->SpHeapBase, + (VOID *) (PayloadBootInfo->SpHeapBase + PayloadBootInfo->SpHeapSize) + ); + + // Check that the Hoblist starts at the bottom of the Heap + ASSERT (HobStart == (VOID *) PayloadBootInfo->SpHeapBase); + + // Build a Boot Firmware Volume HOB + BuildFvHob (PayloadBootInfo->SpImageBase, PayloadBootInfo->SpImageSize); + + // Build a resource descriptor Hob that describes the available physical + // memory range + Attributes = ( + EFI_RESOURCE_ATTRIBUTE_PRESENT | + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | + EFI_RESOURCE_ATTRIBUTE_TESTED | + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | + EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE + ); + + BuildResourceDescriptorHob ( + EFI_RESOURCE_SYSTEM_MEMORY, + Attributes, + (UINTN) PayloadBootInfo->SpMemBase, + PayloadBootInfo->SpMemLimit - PayloadBootInfo->SpMemBase + ); + + // Find the size of the GUIDed HOB with MP information + BufferSize = sizeof (MP_INFORMATION_HOB_DATA); + BufferSize += sizeof (EFI_PROCESSOR_INFORMATION) * PayloadBootInfo->NumCpus; + + // Create a Guided MP information HOB to enable the ARM TF CPU driver to + // perform per-cpu allocations. + MpInformationHobData = BuildGuidHob (&gMpInformationHobGuid, BufferSize); + + // Populate the MP information HOB with the topology information passed by + // privileged firmware + MpInformationHobData->NumberOfProcessors = PayloadBootInfo->NumCpus; + MpInformationHobData->NumberOfEnabledProcessors = PayloadBootInfo->NumCpus; + ProcInfoBuffer = MpInformationHobData->ProcessorInfoBuffer; + CpuInfo = PayloadBootInfo->CpuInfo; + + for (Index = 0; Index < PayloadBootInfo->NumCpus; Index++) { + ProcInfoBuffer[Index].ProcessorId = CpuInfo[Index].Mpidr; + ProcInfoBuffer[Index].Location.Package = GET_CLUSTER_ID(CpuInfo[Index].Mpidr); + ProcInfoBuffer[Index].Location.Core = GET_CORE_ID(CpuInfo[Index].Mpidr); + ProcInfoBuffer[Index].Location.Thread = GET_CORE_ID(CpuInfo[Index].Mpidr); + + Flags = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT; + if (CpuInfo[Index].Flags & CPU_INFO_FLAG_PRIMARY_CPU) { + Flags |= PROCESSOR_AS_BSP_BIT; + } + ProcInfoBuffer[Index].StatusFlag = Flags; + } + + // Create a Guided HOB to tell the ARM TF CPU driver the location and length + // of the communication buffer shared with the Normal world. + NsCommBufMmramRange = (EFI_MMRAM_DESCRIPTOR *) BuildGuidHob ( + &gEfiStandaloneMmNonSecureBufferGuid, + sizeof (EFI_MMRAM_DESCRIPTOR) + ); + NsCommBufMmramRange->PhysicalStart = PayloadBootInfo->SpNsCommBufBase; + NsCommBufMmramRange->CpuStart = PayloadBootInfo->SpNsCommBufBase; + NsCommBufMmramRange->PhysicalSize = PayloadBootInfo->SpNsCommBufSize; + NsCommBufMmramRange->RegionState = EFI_CACHEABLE | EFI_ALLOCATED; + + // Create a Guided HOB to enable the ARM TF CPU driver to share its entry + // point and populate it with the address of the shared buffer + CpuDriverEntryPointDesc = (ARM_TF_CPU_DRIVER_EP_DESCRIPTOR *) BuildGuidHob ( + &gEfiArmTfCpuDriverEpDescriptorGuid, + sizeof (ARM_TF_CPU_DRIVER_EP_DESCRIPTOR) + ); + + *CpuDriverEntryPoint = NULL; + CpuDriverEntryPointDesc->ArmTfCpuDriverEpPtr = CpuDriverEntryPoint; + + // Find the size of the GUIDed HOB with SRAM ranges + BufferSize = sizeof (EFI_MMRAM_HOB_DESCRIPTOR_BLOCK); + BufferSize += PayloadBootInfo->NumSpMemRegions * sizeof (EFI_MMRAM_DESCRIPTOR); + + // Create a GUIDed HOB with SRAM ranges + MmramRangesHob = BuildGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, BufferSize); + + // Fill up the number of MMRAM memory regions + MmramRangesHob->NumberOfMmReservedRegions = PayloadBootInfo->NumSpMemRegions; + // Fill up the MMRAM ranges + MmramRanges = &MmramRangesHob->Descriptor[0]; + + // Base and size of memory occupied by the Standalone MM image + MmramRanges[0].PhysicalStart = PayloadBootInfo->SpImageBase; + MmramRanges[0].CpuStart = PayloadBootInfo->SpImageBase; + MmramRanges[0].PhysicalSize = PayloadBootInfo->SpImageSize; + MmramRanges[0].RegionState = EFI_CACHEABLE | EFI_ALLOCATED; + + // Base and size of buffer shared with privileged Secure world software + MmramRanges[1].PhysicalStart = PayloadBootInfo->SpSharedBufBase; + MmramRanges[1].CpuStart = PayloadBootInfo->SpSharedBufBase; + MmramRanges[1].PhysicalSize = PayloadBootInfo->SpPcpuSharedBufSize * PayloadBootInfo->NumCpus; + MmramRanges[1].RegionState = EFI_CACHEABLE | EFI_ALLOCATED; + + // Base and size of buffer used for synchronous communication with Normal + // world software + MmramRanges[2].PhysicalStart = PayloadBootInfo->SpNsCommBufBase; + MmramRanges[2].CpuStart = PayloadBootInfo->SpNsCommBufBase; + MmramRanges[2].PhysicalSize = PayloadBootInfo->SpNsCommBufSize; + MmramRanges[2].RegionState = EFI_CACHEABLE | EFI_ALLOCATED; + + // Base and size of memory allocated for stacks for all cpus + MmramRanges[3].PhysicalStart = PayloadBootInfo->SpStackBase; + MmramRanges[3].CpuStart = PayloadBootInfo->SpStackBase; + MmramRanges[3].PhysicalSize = PayloadBootInfo->SpPcpuStackSize * PayloadBootInfo->NumCpus; + MmramRanges[3].RegionState = EFI_CACHEABLE | EFI_ALLOCATED; + + // Base and size of heap memory shared by all cpus + MmramRanges[4].PhysicalStart = (EFI_PHYSICAL_ADDRESS) HobStart; + MmramRanges[4].CpuStart = (EFI_PHYSICAL_ADDRESS) HobStart; + MmramRanges[4].PhysicalSize = HobStart->EfiFreeMemoryBottom - (EFI_PHYSICAL_ADDRESS) HobStart; + MmramRanges[4].RegionState = EFI_CACHEABLE | EFI_ALLOCATED; + + // Base and size of heap memory shared by all cpus + MmramRanges[5].PhysicalStart = HobStart->EfiFreeMemoryBottom; + MmramRanges[5].CpuStart = HobStart->EfiFreeMemoryBottom; + MmramRanges[5].PhysicalSize = HobStart->EfiFreeMemoryTop - HobStart->EfiFreeMemoryBottom; + MmramRanges[5].RegionState = EFI_CACHEABLE; + + return HobStart; +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c new file mode 100644 index 00000000..f0db0eb5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c @@ -0,0 +1,322 @@ +/** @file + Locate, get and update PE/COFF permissions during Standalone MM + Foundation Entry point on ARM platforms. + +Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include <PiMm.h> + +#include <PiPei.h> +#include <Guid/MmramMemoryReserve.h> +#include <Guid/MpInformation.h> + +#include <Library/AArch64/StandaloneMmCoreEntryPoint.h> +#include <Library/ArmMmuLib.h> +#include <Library/ArmSvcLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/SerialPortLib.h> + +#include <IndustryStandard/ArmStdSmc.h> + +/** + Privileged firmware assigns RO & Executable attributes to all memory occupied + by the Boot Firmware Volume. This function sets the correct permissions of + sections in the Standalone MM Core module to be able to access RO and RW data + and make further progress in the boot process. + + @param [in] ImageContext Pointer to PE/COFF image context + @param [in] ImageBase Base of image in memory + @param [in] SectionHeaderOffset Offset of PE/COFF image section header + @param [in] NumberOfSections Number of Sections + @param [in] TextUpdater Function to change code permissions + @param [in] ReadOnlyUpdater Function to change RO permissions + @param [in] ReadWriteUpdater Function to change RW permissions + +**/ +EFI_STATUS +EFIAPI +UpdateMmFoundationPeCoffPermissions ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_PHYSICAL_ADDRESS ImageBase, + IN UINT32 SectionHeaderOffset, + IN CONST UINT16 NumberOfSections, + IN REGION_PERMISSION_UPDATE_FUNC TextUpdater, + IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater, + IN REGION_PERMISSION_UPDATE_FUNC ReadWriteUpdater + ) +{ + EFI_IMAGE_SECTION_HEADER SectionHeader; + RETURN_STATUS Status; + EFI_PHYSICAL_ADDRESS Base; + UINTN Size; + UINTN ReadSize; + UINTN Index; + + ASSERT (ImageContext != NULL); + + // + // Iterate over the sections + // + for (Index = 0; Index < NumberOfSections; Index++) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + ReadSize = Size; + Status = ImageContext->ImageRead ( + ImageContext->Handle, + SectionHeaderOffset, + &Size, + &SectionHeader + ); + + if (RETURN_ERROR (Status) || (Size != ReadSize)) { + DEBUG ((DEBUG_ERROR, + "%a: ImageContext->ImageRead () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, + "%a: Section %d of image at 0x%lx has 0x%x permissions\n", + __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics)); + DEBUG ((DEBUG_INFO, + "%a: Section %d of image at 0x%lx has %a name\n", + __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Name)); + DEBUG ((DEBUG_INFO, + "%a: Section %d of image at 0x%lx has 0x%x address\n", + __FUNCTION__, Index, ImageContext->ImageAddress, + ImageContext->ImageAddress + SectionHeader.VirtualAddress)); + DEBUG ((DEBUG_INFO, + "%a: Section %d of image at 0x%lx has 0x%x data\n", + __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.PointerToRawData)); + + // + // If the section is marked as XN then remove the X attribute. Furthermore, + // if it is a writeable section then mark it appropriately as well. + // + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) { + Base = ImageBase + SectionHeader.VirtualAddress; + + TextUpdater (Base, SectionHeader.Misc.VirtualSize); + + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) != 0) { + ReadWriteUpdater (Base, SectionHeader.Misc.VirtualSize); + DEBUG ((DEBUG_INFO, + "%a: Mapping section %d of image at 0x%lx with RW-XN permissions\n", + __FUNCTION__, Index, ImageContext->ImageAddress)); + } else { + DEBUG ((DEBUG_INFO, + "%a: Mapping section %d of image at 0x%lx with RO-XN permissions\n", + __FUNCTION__, Index, ImageContext->ImageAddress)); + } + } else { + DEBUG ((DEBUG_INFO, + "%a: Ignoring section %d of image at 0x%lx with 0x%x permissions\n", + __FUNCTION__, Index, ImageContext->ImageAddress, SectionHeader.Characteristics)); + } + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + + return RETURN_SUCCESS; +} + +/** + Privileged firmware assigns RO & Executable attributes to all memory occupied + by the Boot Firmware Volume. This function locates the Standalone MM Core + module PE/COFF image in the BFV and returns this information. + + @param [in] BfvAddress Base Address of Boot Firmware Volume + @param [in, out] TeData Pointer to address for allocating memory + for PE/COFF image data + @param [in, out] TeDataSize Pointer to size of PE/COFF image data + +**/ +EFI_STATUS +EFIAPI +LocateStandaloneMmCorePeCoffData ( + IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress, + IN OUT VOID **TeData, + IN OUT UINTN *TeDataSize + ) +{ + EFI_FFS_FILE_HEADER *FileHeader; + EFI_STATUS Status; + + FileHeader = NULL; + Status = FfsFindNextFile ( + EFI_FV_FILETYPE_SECURITY_CORE, + BfvAddress, + &FileHeader + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM FFS file - 0x%x\n", + Status)); + return Status; + } + + Status = FfsFindSectionData (EFI_SECTION_PE32, FileHeader, TeData, TeDataSize); + if (EFI_ERROR (Status)) { + Status = FfsFindSectionData (EFI_SECTION_TE, FileHeader, TeData, TeDataSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Section data - %r\n", + Status)); + return Status; + } + } + + DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *TeData)); + return Status; +} + +/** + Returns the PC COFF section information. + + @param [in, out] ImageContext Pointer to PE/COFF image context + @param [out] ImageBase Base of image in memory + @param [out] SectionHeaderOffset Offset of PE/COFF image section header + @param [out] NumberOfSections Number of Sections + +**/ +STATIC +EFI_STATUS +GetPeCoffSectionInformation ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_PHYSICAL_ADDRESS *ImageBase, + OUT UINT32 *SectionHeaderOffset, + OUT UINT16 *NumberOfSections + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; + UINTN Size; + UINTN ReadSize; + + ASSERT (ImageContext != NULL); + ASSERT (SectionHeaderOffset != NULL); + ASSERT (NumberOfSections != NULL); + + Status = PeCoffLoaderGetImageInfo (ImageContext); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: PeCoffLoaderGetImageInfo () failed (Status == %r)\n", + __FUNCTION__, Status)); + return Status; + } + + if (ImageContext->SectionAlignment < EFI_PAGE_SIZE) { + // + // The sections need to be at least 4 KB aligned, since that is the + // granularity at which we can tighten permissions. + // + if (!ImageContext->IsTeImage) { + DEBUG ((DEBUG_WARN, + "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n", + __FUNCTION__, ImageContext->ImageAddress, ImageContext->SectionAlignment)); + return RETURN_UNSUPPORTED; + } + ImageContext->SectionAlignment = EFI_PAGE_SIZE; + } + + // + // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much + // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic + // determines if this is a PE32 or PE32+ image. The magic is in the same + // location in both images. + // + Hdr.Union = &HdrData; + Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); + ReadSize = Size; + Status = ImageContext->ImageRead ( + ImageContext->Handle, + ImageContext->PeCoffHeaderOffset, + &Size, + Hdr.Pe32 + ); + + if (RETURN_ERROR (Status) || (Size != ReadSize)) { + DEBUG ((DEBUG_ERROR, + "%a: TmpContext->ImageRead () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + + *ImageBase = ImageContext->ImageAddress; + if (!ImageContext->IsTeImage) { + ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE); + + *SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER); + *NumberOfSections = Hdr.Pe32->FileHeader.NumberOfSections; + + switch (Hdr.Pe32->OptionalHeader.Magic) { + case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC: + *SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader; + break; + case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC: + *SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader; + break; + default: + ASSERT (FALSE); + } + } else { + *SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER)); + *NumberOfSections = Hdr.Te->NumberOfSections; + *ImageBase -= (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); + } + return RETURN_SUCCESS; +} + +/** + Privileged firmware assigns RO & Executable attributes to all memory occupied + by the Boot Firmware Volume. This function locates the section information of + the Standalone MM Core module to be able to change permissions of the + individual sections later in the boot process. + + @param [in] TeData Pointer to PE/COFF image data + @param [in, out] ImageContext Pointer to PE/COFF image context + @param [out] ImageBase Pointer to ImageBase variable + @param [in, out] SectionHeaderOffset Offset of PE/COFF image section header + @param [in, out] NumberOfSections Number of Sections + +**/ +EFI_STATUS +EFIAPI +GetStandaloneMmCorePeCoffSections ( + IN VOID *TeData, + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_PHYSICAL_ADDRESS *ImageBase, + IN OUT UINT32 *SectionHeaderOffset, + IN OUT UINT16 *NumberOfSections + ) +{ + EFI_STATUS Status; + + // Initialize the Image Context + ZeroMem (ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); + ImageContext->Handle = TeData; + ImageContext->ImageRead = PeCoffLoaderImageReadFromMemory; + + DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", TeData)); + + Status = GetPeCoffSectionInformation (ImageContext, ImageBase, + SectionHeaderOffset, NumberOfSections); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - %r\n", Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n", + *SectionHeaderOffset, *NumberOfSections)); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c new file mode 100644 index 00000000..5f4e0f74 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c @@ -0,0 +1,413 @@ +/** @file + Entry point to the Standalone MM Foundation when initialized during the SEC + phase on ARM platforms + +Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include <PiMm.h> + +#include <Library/AArch64/StandaloneMmCoreEntryPoint.h> + +#include <PiPei.h> +#include <Guid/MmramMemoryReserve.h> +#include <Guid/MpInformation.h> + +#include <Library/ArmMmuLib.h> +#include <Library/ArmSvcLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/SerialPortLib.h> +#include <Library/PcdLib.h> + +#include <IndustryStandard/ArmStdSmc.h> +#include <IndustryStandard/ArmMmSvc.h> +#include <IndustryStandard/ArmFfaSvc.h> + +#define SPM_MAJOR_VER_MASK 0xFFFF0000 +#define SPM_MINOR_VER_MASK 0x0000FFFF +#define SPM_MAJOR_VER_SHIFT 16 +#define FFA_NOT_SUPPORTED -1 + +STATIC CONST UINT32 mSpmMajorVer = SPM_MAJOR_VERSION; +STATIC CONST UINT32 mSpmMinorVer = SPM_MINOR_VERSION; + +STATIC CONST UINT32 mSpmMajorVerFfa = SPM_MAJOR_VERSION_FFA; +STATIC CONST UINT32 mSpmMinorVerFfa = SPM_MINOR_VERSION_FFA; + +#define BOOT_PAYLOAD_VERSION 1 + +PI_MM_ARM_TF_CPU_DRIVER_ENTRYPOINT CpuDriverEntryPoint = NULL; + +/** + Retrieve a pointer to and print the boot information passed by privileged + secure firmware. + + @param [in] SharedBufAddress The pointer memory shared with privileged + firmware. + +**/ +EFI_SECURE_PARTITION_BOOT_INFO * +GetAndPrintBootinformation ( + IN VOID *SharedBufAddress +) +{ + EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo; + EFI_SECURE_PARTITION_CPU_INFO *PayloadCpuInfo; + UINTN Index; + + PayloadBootInfo = (EFI_SECURE_PARTITION_BOOT_INFO *) SharedBufAddress; + + if (PayloadBootInfo == NULL) { + DEBUG ((DEBUG_ERROR, "PayloadBootInfo NULL\n")); + return NULL; + } + + if (PayloadBootInfo->Header.Version != BOOT_PAYLOAD_VERSION) { + DEBUG ((DEBUG_ERROR, "Boot Information Version Mismatch. Current=0x%x, Expected=0x%x.\n", + PayloadBootInfo->Header.Version, BOOT_PAYLOAD_VERSION)); + return NULL; + } + + DEBUG ((DEBUG_INFO, "NumSpMemRegions - 0x%x\n", PayloadBootInfo->NumSpMemRegions)); + DEBUG ((DEBUG_INFO, "SpMemBase - 0x%lx\n", PayloadBootInfo->SpMemBase)); + DEBUG ((DEBUG_INFO, "SpMemLimit - 0x%lx\n", PayloadBootInfo->SpMemLimit)); + DEBUG ((DEBUG_INFO, "SpImageBase - 0x%lx\n", PayloadBootInfo->SpImageBase)); + DEBUG ((DEBUG_INFO, "SpStackBase - 0x%lx\n", PayloadBootInfo->SpStackBase)); + DEBUG ((DEBUG_INFO, "SpHeapBase - 0x%lx\n", PayloadBootInfo->SpHeapBase)); + DEBUG ((DEBUG_INFO, "SpNsCommBufBase - 0x%lx\n", PayloadBootInfo->SpNsCommBufBase)); + DEBUG ((DEBUG_INFO, "SpSharedBufBase - 0x%lx\n", PayloadBootInfo->SpSharedBufBase)); + + DEBUG ((DEBUG_INFO, "SpImageSize - 0x%x\n", PayloadBootInfo->SpImageSize)); + DEBUG ((DEBUG_INFO, "SpPcpuStackSize - 0x%x\n", PayloadBootInfo->SpPcpuStackSize)); + DEBUG ((DEBUG_INFO, "SpHeapSize - 0x%x\n", PayloadBootInfo->SpHeapSize)); + DEBUG ((DEBUG_INFO, "SpNsCommBufSize - 0x%x\n", PayloadBootInfo->SpNsCommBufSize)); + DEBUG ((DEBUG_INFO, "SpPcpuSharedBufSize - 0x%x\n", PayloadBootInfo->SpPcpuSharedBufSize)); + + DEBUG ((DEBUG_INFO, "NumCpus - 0x%x\n", PayloadBootInfo->NumCpus)); + DEBUG ((DEBUG_INFO, "CpuInfo - 0x%p\n", PayloadBootInfo->CpuInfo)); + + PayloadCpuInfo = (EFI_SECURE_PARTITION_CPU_INFO *) PayloadBootInfo->CpuInfo; + + if (PayloadCpuInfo == NULL) { + DEBUG ((DEBUG_ERROR, "PayloadCpuInfo NULL\n")); + return NULL; + } + + for (Index = 0; Index < PayloadBootInfo->NumCpus; Index++) { + DEBUG ((DEBUG_INFO, "Mpidr - 0x%lx\n", PayloadCpuInfo[Index].Mpidr)); + DEBUG ((DEBUG_INFO, "LinearId - 0x%x\n", PayloadCpuInfo[Index].LinearId)); + DEBUG ((DEBUG_INFO, "Flags - 0x%x\n", PayloadCpuInfo[Index].Flags)); + } + + return PayloadBootInfo; +} + +/** + A loop to delegated events. + + @param [in] EventCompleteSvcArgs Pointer to the event completion arguments. + +**/ +VOID +EFIAPI +DelegatedEventLoop ( + IN ARM_SVC_ARGS *EventCompleteSvcArgs + ) +{ + BOOLEAN FfaEnabled; + EFI_STATUS Status; + UINTN SvcStatus; + + while (TRUE) { + ArmCallSvc (EventCompleteSvcArgs); + + DEBUG ((DEBUG_INFO, "Received delegated event\n")); + DEBUG ((DEBUG_INFO, "X0 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg0)); + DEBUG ((DEBUG_INFO, "X1 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg1)); + DEBUG ((DEBUG_INFO, "X2 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg2)); + DEBUG ((DEBUG_INFO, "X3 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg3)); + DEBUG ((DEBUG_INFO, "X4 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg4)); + DEBUG ((DEBUG_INFO, "X5 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg5)); + DEBUG ((DEBUG_INFO, "X6 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg6)); + DEBUG ((DEBUG_INFO, "X7 : 0x%x\n", (UINT32) EventCompleteSvcArgs->Arg7)); + + FfaEnabled = FeaturePcdGet (PcdFfaEnable); + if (FfaEnabled) { + Status = CpuDriverEntryPoint ( + EventCompleteSvcArgs->Arg0, + EventCompleteSvcArgs->Arg6, + EventCompleteSvcArgs->Arg3 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed delegated event 0x%x, Status 0x%x\n", + EventCompleteSvcArgs->Arg3, Status)); + } + } else { + Status = CpuDriverEntryPoint ( + EventCompleteSvcArgs->Arg0, + EventCompleteSvcArgs->Arg3, + EventCompleteSvcArgs->Arg1 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed delegated event 0x%x, Status 0x%x\n", + EventCompleteSvcArgs->Arg0, Status)); + } + } + + switch (Status) { + case EFI_SUCCESS: + SvcStatus = ARM_SVC_SPM_RET_SUCCESS; + break; + case EFI_INVALID_PARAMETER: + SvcStatus = ARM_SVC_SPM_RET_INVALID_PARAMS; + break; + case EFI_ACCESS_DENIED: + SvcStatus = ARM_SVC_SPM_RET_DENIED; + break; + case EFI_OUT_OF_RESOURCES: + SvcStatus = ARM_SVC_SPM_RET_NO_MEMORY; + break; + case EFI_UNSUPPORTED: + SvcStatus = ARM_SVC_SPM_RET_NOT_SUPPORTED; + break; + default: + SvcStatus = ARM_SVC_SPM_RET_NOT_SUPPORTED; + break; + } + + if (FfaEnabled) { + EventCompleteSvcArgs->Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64; + EventCompleteSvcArgs->Arg1 = 0; + EventCompleteSvcArgs->Arg2 = 0; + EventCompleteSvcArgs->Arg3 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64; + EventCompleteSvcArgs->Arg4 = SvcStatus; + } else { + EventCompleteSvcArgs->Arg0 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64; + EventCompleteSvcArgs->Arg1 = SvcStatus; + } + } +} + +/** + Query the SPM version, check compatibility and return success if compatible. + + @retval EFI_SUCCESS SPM versions compatible. + @retval EFI_UNSUPPORTED SPM versions not compatible. +**/ +STATIC +EFI_STATUS +GetSpmVersion (VOID) +{ + EFI_STATUS Status; + UINT16 CalleeSpmMajorVer; + UINT16 CallerSpmMajorVer; + UINT16 CalleeSpmMinorVer; + UINT16 CallerSpmMinorVer; + UINT32 SpmVersion; + ARM_SVC_ARGS SpmVersionArgs; + + if (FeaturePcdGet (PcdFfaEnable)) { + SpmVersionArgs.Arg0 = ARM_SVC_ID_FFA_VERSION_AARCH32; + SpmVersionArgs.Arg1 = mSpmMajorVerFfa << SPM_MAJOR_VER_SHIFT; + SpmVersionArgs.Arg1 |= mSpmMinorVerFfa; + CallerSpmMajorVer = mSpmMajorVerFfa; + CallerSpmMinorVer = mSpmMinorVerFfa; + } else { + SpmVersionArgs.Arg0 = ARM_SVC_ID_SPM_VERSION_AARCH32; + CallerSpmMajorVer = mSpmMajorVer; + CallerSpmMinorVer = mSpmMinorVer; + } + + ArmCallSvc (&SpmVersionArgs); + + SpmVersion = SpmVersionArgs.Arg0; + if (SpmVersion == FFA_NOT_SUPPORTED) { + return EFI_UNSUPPORTED; + } + + CalleeSpmMajorVer = ((SpmVersion & SPM_MAJOR_VER_MASK) >> SPM_MAJOR_VER_SHIFT); + CalleeSpmMinorVer = ((SpmVersion & SPM_MINOR_VER_MASK) >> 0); + + // Different major revision values indicate possibly incompatible functions. + // For two revisions, A and B, for which the major revision values are + // identical, if the minor revision value of revision B is greater than + // the minor revision value of revision A, then every function in + // revision A must work in a compatible way with revision B. + // However, it is possible for revision B to have a higher + // function count than revision A. + if ((CalleeSpmMajorVer == CallerSpmMajorVer) && + (CalleeSpmMinorVer >= CallerSpmMinorVer)) + { + DEBUG ((DEBUG_INFO, "SPM Version: Major=0x%x, Minor=0x%x\n", + CalleeSpmMajorVer, CalleeSpmMinorVer)); + Status = EFI_SUCCESS; + } + else + { + DEBUG ((DEBUG_INFO, "Incompatible SPM Versions.\n Callee Version: Major=0x%x, Minor=0x%x.\n Caller: Major=0x%x, Minor>=0x%x.\n", + CalleeSpmMajorVer, CalleeSpmMinorVer, CallerSpmMajorVer, CallerSpmMinorVer)); + Status = EFI_UNSUPPORTED; + } + + return Status; +} + +/** + Initialize parameters to be sent via SVC call. + + @param[out] InitMmFoundationSvcArgs Args structure + @param[out] Ret Return Code + +**/ +STATIC +VOID +InitArmSvcArgs ( + OUT ARM_SVC_ARGS *InitMmFoundationSvcArgs, + OUT INT32 *Ret + ) +{ + if (FeaturePcdGet (PcdFfaEnable)) { + InitMmFoundationSvcArgs->Arg0 = ARM_SVC_ID_FFA_MSG_SEND_DIRECT_RESP_AARCH64; + InitMmFoundationSvcArgs->Arg1 = 0; + InitMmFoundationSvcArgs->Arg2 = 0; + InitMmFoundationSvcArgs->Arg3 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64; + InitMmFoundationSvcArgs->Arg4 = *Ret; + } else { + InitMmFoundationSvcArgs->Arg0 = ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64; + InitMmFoundationSvcArgs->Arg1 = *Ret; + } +} + +/** + The entry point of Standalone MM Foundation. + + @param [in] SharedBufAddress Pointer to the Buffer between SPM and SP. + @param [in] SharedBufSize Size of the shared buffer. + @param [in] cookie1 Cookie 1 + @param [in] cookie2 Cookie 2 + +**/ +VOID +EFIAPI +_ModuleEntryPoint ( + IN VOID *SharedBufAddress, + IN UINT64 SharedBufSize, + IN UINT64 cookie1, + IN UINT64 cookie2 + ) +{ + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_SECURE_PARTITION_BOOT_INFO *PayloadBootInfo; + ARM_SVC_ARGS InitMmFoundationSvcArgs; + EFI_STATUS Status; + INT32 Ret; + UINT32 SectionHeaderOffset; + UINT16 NumberOfSections; + VOID *HobStart; + VOID *TeData; + UINTN TeDataSize; + EFI_PHYSICAL_ADDRESS ImageBase; + + // Get Secure Partition Manager Version Information + Status = GetSpmVersion (); + if (EFI_ERROR (Status)) { + goto finish; + } + + PayloadBootInfo = GetAndPrintBootinformation (SharedBufAddress); + if (PayloadBootInfo == NULL) { + Status = EFI_UNSUPPORTED; + goto finish; + } + + // Locate PE/COFF File information for the Standalone MM core module + Status = LocateStandaloneMmCorePeCoffData ( + (EFI_FIRMWARE_VOLUME_HEADER *) PayloadBootInfo->SpImageBase, + &TeData, + &TeDataSize + ); + + if (EFI_ERROR (Status)) { + goto finish; + } + + // Obtain the PE/COFF Section information for the Standalone MM core module + Status = GetStandaloneMmCorePeCoffSections ( + TeData, + &ImageContext, + &ImageBase, + &SectionHeaderOffset, + &NumberOfSections + ); + + if (EFI_ERROR (Status)) { + goto finish; + } + + // + // ImageBase may deviate from ImageContext.ImageAddress if we are dealing + // with a TE image, in which case the latter points to the actual offset + // of the image, whereas ImageBase refers to the address where the image + // would start if the stripped PE headers were still in place. In either + // case, we need to fix up ImageBase so it refers to the actual current + // load address. + // + ImageBase += (UINTN)TeData - ImageContext.ImageAddress; + + // Update the memory access permissions of individual sections in the + // Standalone MM core module + Status = UpdateMmFoundationPeCoffPermissions ( + &ImageContext, + ImageBase, + SectionHeaderOffset, + NumberOfSections, + ArmSetMemoryRegionNoExec, + ArmSetMemoryRegionReadOnly, + ArmClearMemoryRegionReadOnly + ); + + if (EFI_ERROR (Status)) { + goto finish; + } + + if (ImageContext.ImageAddress != (UINTN)TeData) { + ImageContext.ImageAddress = (UINTN)TeData; + ArmSetMemoryRegionNoExec (ImageBase, SIZE_4KB); + ArmClearMemoryRegionReadOnly (ImageBase, SIZE_4KB); + + Status = PeCoffLoaderRelocateImage (&ImageContext); + ASSERT_EFI_ERROR (Status); + } + + // + // Create Hoblist based upon boot information passed by privileged software + // + HobStart = CreateHobListFromBootInfo (&CpuDriverEntryPoint, PayloadBootInfo); + + // + // Call the MM Core entry point + // + ProcessModuleEntryPointList (HobStart); + + DEBUG ((DEBUG_INFO, "Shared Cpu Driver EP 0x%lx\n", (UINT64) CpuDriverEntryPoint)); + +finish: + if (Status == RETURN_UNSUPPORTED) { + Ret = -1; + } else if (Status == RETURN_INVALID_PARAMETER) { + Ret = -2; + } else if (Status == EFI_NOT_FOUND) { + Ret = -7; + } else { + Ret = 0; + } + ZeroMem (&InitMmFoundationSvcArgs, sizeof(InitMmFoundationSvcArgs)); + InitArmSvcArgs (&InitMmFoundationSvcArgs, &Ret); + DelegatedEventLoop (&InitMmFoundationSvcArgs); +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf new file mode 100644 index 00000000..c71929b7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/StandaloneMmCoreEntryPoint.inf @@ -0,0 +1,58 @@ +## @file +# Module entry point library for DXE core. +# +# Copyright (c) 2017 - 2021, Arm Ltd. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = StandaloneMmCoreEntryPoint + FILE_GUID = C97AC593-109A-4C63-905C-675FDE2689E8 + MODULE_TYPE = MM_CORE_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + LIBRARY_CLASS = StandaloneMmCoreEntryPoint|MM_CORE_STANDALONE + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only) +# + +[Sources.AARCH64] + AArch64/StandaloneMmCoreEntryPoint.c + AArch64/SetPermissions.c + AArch64/CreateHobList.c + +[Sources.X64] + X64/StandaloneMmCoreEntryPoint.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[Packages.AARCH64] + ArmPkg/ArmPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + +[LibraryClasses.AARCH64] + StandaloneMmMmuLib + ArmSvcLib + +[Guids] + gMpInformationHobGuid + gEfiMmPeiMmramMemoryReserveGuid + gEfiStandaloneMmNonSecureBufferGuid + gEfiArmTfCpuDriverEpDescriptorGuid + +[FeaturePcd.AARCH64] + gArmTokenSpaceGuid.PcdFfaEnable + +[BuildOptions] + GCC:*_*_*_CC_FLAGS = -fpie diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/X64/StandaloneMmCoreEntryPoint.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/X64/StandaloneMmCoreEntryPoint.c new file mode 100644 index 00000000..10b3dbac --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/X64/StandaloneMmCoreEntryPoint.c @@ -0,0 +1,71 @@ +/** @file + Entry point to the Standalone Mm Core. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include <PiMm.h> + +#include <Library/StandaloneMmCoreEntryPoint.h> +#include <Library/DebugLib.h> +#include <Library/BaseLib.h> + +// +// Cache copy of HobList pointer. +// +VOID *gHobList = NULL; + +/** + The entry point of PE/COFF Image for the STANDALONE MM Core. + + This function is the entry point for the STANDALONE MM Core. This function is required to call + ProcessModuleEntryPointList() and ProcessModuleEntryPointList() is never expected to return. + The STANDALONE MM Core is responsible for calling ProcessLibraryConstructorList() as soon as the EFI + System Table and the image handle for the STANDALONE MM Core itself have been established. + If ProcessModuleEntryPointList() returns, then ASSERT() and halt the system. + + @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase. + +**/ +VOID +EFIAPI +_ModuleEntryPoint ( + IN VOID *HobStart + ) +{ + // + // Cache a pointer to the HobList + // + gHobList = HobStart; + + // + // Call the Standalone MM Core entry point + // + ProcessModuleEntryPointList (HobStart); + + // + // TODO: Set page table here?? AARCH64 has this step for some reason + // +} + + +/** + Required by the EBC compiler and identical in functionality to _ModuleEntryPoint(). + + This function is required to call _ModuleEntryPoint() passing in HobStart. + + @param HobStart Pointer to the beginning of the HOB List passed in from the PEI Phase. + +**/ +VOID +EFIAPI +EfiMain ( + IN VOID *HobStart + ) +{ + _ModuleEntryPoint (HobStart); +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLib.c new file mode 100644 index 00000000..5bb77515 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLib.c @@ -0,0 +1,330 @@ +/** @file + HOB Library implementation for Standalone MM Core. + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include <Library/HobLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> + +#include <Guid/MemoryAllocationHob.h> + +// +// Cache copy of HobList pointer. +// +VOID *gHobList = NULL; + +VOID * +CreateHob ( + IN UINT16 HobType, + IN UINT16 HobLength + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob; + EFI_HOB_GENERIC_HEADER *HobEnd; + EFI_PHYSICAL_ADDRESS FreeMemory; + VOID *Hob; + + HandOffHob = GetHobList (); + + HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom; + + if (FreeMemory < HobLength) { + return NULL; + } + + Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength; + ((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0; + + HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength); + HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof (EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + HobEnd++; + HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + return Hob; +} + +/** + Builds a HOB for a loaded PE32 module. + + This function builds a HOB for a loaded PE32 module. + If ModuleName is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param ModuleName The GUID File Name of the module. + @param MemoryAllocationModule The 64 bit physical address of the module. + @param ModuleLength The length of the module in bytes. + @param EntryPoint The 64 bit physical address of the module entry point. + +**/ +VOID +EFIAPI +BuildModuleHob ( + IN CONST EFI_GUID *ModuleName, + IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule, + IN UINT64 ModuleLength, + IN EFI_PHYSICAL_ADDRESS EntryPoint + ) +{ + EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob; + + ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) && + ((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); + + CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid); + Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule; + Hob->MemoryAllocationHeader.MemoryLength = ModuleLength; + Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved)); + + CopyGuid (&Hob->ModuleName, ModuleName); + Hob->EntryPoint = EntryPoint; +} + +/** + Builds a HOB that describes a chunk of system memory. + + This function builds a HOB that describes a chunk of system memory. + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + +**/ +VOID +EFIAPI +BuildResourceDescriptorHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes + ) +{ + EFI_HOB_RESOURCE_DESCRIPTOR *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)); + ASSERT (Hob != NULL); + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; + Hob->PhysicalStart = PhysicalStart; + Hob->ResourceLength = NumberOfBytes; +} + +/** + Builds a GUID HOB with a certain data length. + + This function builds a customized HOB tagged with a GUID for identification + and returns the start address of GUID HOB data so that caller can fill the customized data. + The HOB Header and Name field is already stripped. + If Guid is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidHob ( + IN CONST EFI_GUID *Guid, + IN UINTN DataLength + ) +{ + EFI_HOB_GUID_TYPE *Hob; + + // + // Make sure that data length is not too long. + // + ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE))); + + Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength)); + CopyGuid (&Hob->Name, Guid); + return Hob + 1; +} + + +/** + Copies a data buffer to a newly-built HOB. + + This function builds a customized HOB tagged with a GUID for identification, + copies the input data to the HOB data field and returns the start address of the GUID HOB data. + The HOB Header and Name field is already stripped. + If Guid is NULL, then ASSERT(). + If Data is NULL and DataLength > 0, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param Data The data to be copied into the data field of the GUID HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidDataHob ( + IN CONST EFI_GUID *Guid, + IN VOID *Data, + IN UINTN DataLength + ) +{ + VOID *HobData; + + ASSERT (Data != NULL || DataLength == 0); + + HobData = BuildGuidHob (Guid, DataLength); + + return CopyMem (HobData, Data, DataLength); +} + +/** + Builds a Firmware Volume HOB. + + This function builds a Firmware Volume HOB. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + +**/ +VOID +EFIAPI +BuildFvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_FIRMWARE_VOLUME *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +} + + +/** + Builds a EFI_HOB_TYPE_FV2 HOB. + + This function builds a EFI_HOB_TYPE_FV2 HOB. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param FvName The name of the Firmware Volume. + @param FileName The name of the file. + +**/ +VOID +EFIAPI +BuildFv2Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN CONST EFI_GUID *FvName, + IN CONST EFI_GUID *FileName + ) +{ + EFI_HOB_FIRMWARE_VOLUME2 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; + CopyGuid (&Hob->FvName, FvName); + CopyGuid (&Hob->FileName, FileName); +} + + +/** + Builds a HOB for the CPU. + + This function builds a HOB for the CPU. + If there is no additional space for HOB creation, then ASSERT(). + + @param SizeOfMemorySpace The maximum physical memory addressability of the processor. + @param SizeOfIoSpace The maximum physical I/O addressability of the processor. + +**/ +VOID +EFIAPI +BuildCpuHob ( + IN UINT8 SizeOfMemorySpace, + IN UINT8 SizeOfIoSpace + ) +{ + EFI_HOB_CPU *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU)); + + Hob->SizeOfMemorySpace = SizeOfMemorySpace; + Hob->SizeOfIoSpace = SizeOfIoSpace; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->Reserved, sizeof (Hob->Reserved)); +} + +/** + Builds a HOB for the memory allocation. + + This function builds a HOB for the memory allocation. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the memory. + @param Length The length of the memory allocation in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildMemoryAllocationHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + EFI_HOB_MEMORY_ALLOCATION *Hob; + + ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) && + ((Length & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION)); + + ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID)); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob->AllocDescriptor.MemoryLength = Length; + Hob->AllocDescriptor.MemoryType = MemoryType; + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved)); +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLibInternal.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLibInternal.c new file mode 100644 index 00000000..a9f94c1c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/AArch64/StandaloneMmCoreHobLibInternal.c @@ -0,0 +1,58 @@ +/** @file + HOB Library implementation for Standalone MM Core. + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include <Library/HobLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> + +#include <Guid/MemoryAllocationHob.h> + +// +// Cache copy of HobList pointer. +// +extern VOID *gHobList; + +EFI_HOB_HANDOFF_INFO_TABLE* +HobConstructor ( + IN VOID *EfiMemoryBegin, + IN UINTN EfiMemoryLength, + IN VOID *EfiFreeMemoryBottom, + IN VOID *EfiFreeMemoryTop + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *Hob; + EFI_HOB_GENERIC_HEADER *HobEnd; + + Hob = EfiFreeMemoryBottom; + HobEnd = (EFI_HOB_GENERIC_HEADER *)(Hob+1); + + Hob->Header.HobType = EFI_HOB_TYPE_HANDOFF; + Hob->Header.HobLength = sizeof (EFI_HOB_HANDOFF_INFO_TABLE); + Hob->Header.Reserved = 0; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof (EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + + Hob->Version = EFI_HOB_HANDOFF_TABLE_VERSION; + Hob->BootMode = BOOT_WITH_FULL_CONFIGURATION; + + Hob->EfiMemoryTop = (UINTN)EfiMemoryBegin + EfiMemoryLength; + Hob->EfiMemoryBottom = (UINTN)EfiMemoryBegin; + Hob->EfiFreeMemoryTop = (UINTN)EfiFreeMemoryTop; + Hob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS)(UINTN)(HobEnd+1); + Hob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS)(UINTN)HobEnd; + + gHobList = Hob; + + return Hob; +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Common.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Common.c new file mode 100644 index 00000000..967fe738 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/Common.c @@ -0,0 +1,291 @@ +/** @file + HOB Library implementation for Standalone MM Core. + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include <Library/HobLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/StandaloneMmCoreEntryPoint.h> + +#include <Guid/MemoryAllocationHob.h> + +/** + Returns the pointer to the HOB list. + + This function returns the pointer to first HOB in the list. + If the pointer to the HOB list is NULL, then ASSERT(). + + @return The pointer to the HOB list. + +**/ +VOID * +EFIAPI +GetHobList ( + VOID + ) +{ + ASSERT (gHobList != NULL); + return gHobList; +} + +/** + Returns the next instance of a HOB type from the starting HOB. + + This function searches the first instance of a HOB type from the starting HOB pointer. + If there does not exist such HOB type from the starting HOB pointer, it will return NULL. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + + If HobStart is NULL, then ASSERT(). + + @param Type The HOB type to return. + @param HobStart The starting HOB pointer to search from. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextHob ( + IN UINT16 Type, + IN CONST VOID *HobStart + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + ASSERT (HobStart != NULL); + + Hob.Raw = (UINT8 *) HobStart; + // + // Parse the HOB list until end of list or matching type is found. + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == Type) { + return Hob.Raw; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + return NULL; +} + +/** + Returns the first instance of a HOB type among the whole HOB list. + + This function searches the first instance of a HOB type among the whole HOB list. + If there does not exist such HOB type in the HOB list, it will return NULL. + + If the pointer to the HOB list is NULL, then ASSERT(). + + @param Type The HOB type to return. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetFirstHob ( + IN UINT16 Type + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextHob (Type, HobList); +} + +/** + Returns the next instance of the matched GUID HOB from the starting HOB. + + This function searches the first instance of a HOB from the starting HOB pointer. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION, and its GUID Name equals to the input Guid. + If such a HOB from the starting HOB pointer does not exist, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size information, respectively. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + + If Guid is NULL, then ASSERT(). + If HobStart is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + @param HobStart A pointer to a Guid. + + @return The next instance of the matched GUID HOB from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextGuidHob ( + IN CONST EFI_GUID *Guid, + IN CONST VOID *HobStart + ) +{ + EFI_PEI_HOB_POINTERS GuidHob; + + GuidHob.Raw = (UINT8 *) HobStart; + while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) { + if (CompareGuid (Guid, &GuidHob.Guid->Name)) { + break; + } + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + } + return GuidHob.Raw; +} + +/** + Returns the first instance of the matched GUID HOB among the whole HOB list. + + This function searches the first instance of a HOB among the whole HOB list. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If such a HOB from the starting HOB pointer does not exist, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size information, respectively. + + If the pointer to the HOB list is NULL, then ASSERT(). + If Guid is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + + @return The first instance of the matched GUID HOB among the whole HOB list. + +**/ +VOID * +EFIAPI +GetFirstGuidHob ( + IN CONST EFI_GUID *Guid + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextGuidHob (Guid, HobList); +} + +/** + Get the system boot mode from the HOB list. + + This function returns the system boot mode information from the + PHIT HOB in HOB list. + + If the pointer to the HOB list is NULL, then ASSERT(). + + @param VOID + + @return The Boot Mode. + +**/ +EFI_BOOT_MODE +EFIAPI +GetBootModeHob ( + VOID + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob; + + HandOffHob = (EFI_HOB_HANDOFF_INFO_TABLE *) GetHobList (); + + return HandOffHob->BootMode; +} + + +/** + Builds a HOB that describes a chunk of system memory with Owner GUID. + + This function builds a HOB that describes a chunk of system memory. + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + @param OwnerGUID GUID for the owner of this resource. + +**/ +VOID +EFIAPI +BuildResourceDescriptorWithOwnerHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes, + IN EFI_GUID *OwnerGUID + ) +{ + ASSERT (FALSE); +} + +/** + Builds a Capsule Volume HOB. + + This function builds a Capsule Volume HOB. + If the platform does not support Capsule Volume HOBs, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Capsule Volume. + @param Length The size of the Capsule Volume in bytes. + +**/ +VOID +EFIAPI +BuildCvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + ASSERT (FALSE); +} + + +/** + Builds a HOB for the BSP store. + + This function builds a HOB for BSP store. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the BSP. + @param Length The length of the BSP store in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildBspStoreHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + ASSERT (FALSE); +} + +/** + Builds a HOB for the Stack. + + This function builds a HOB for the stack. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +EFIAPI +BuildStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + ASSERT (FALSE); +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf new file mode 100644 index 00000000..4f77414d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/StandaloneMmCoreHobLib.inf @@ -0,0 +1,47 @@ +## @file +# Instance of HOB Library for Standalone MM Core. +# +# HOB Library implementation for the Standalone MM Core. Does not have a constructor. +# Uses gHobList defined in the Standalone MM Core Entry Point Library. +# +# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = HobLib + FILE_GUID = CF56EF2C-68D8-4BD5-9A8B-8A7BFCFF751C + MODULE_TYPE = MM_CORE_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + LIBRARY_CLASS = HobLib|MM_CORE_STANDALONE + +# +# VALID_ARCHITECTURES = X64 AARCH64 +# +[Sources.common] + Common.c + +[Sources.X64] + X64/StandaloneMmCoreHobLib.c + +[Sources.AARCH64] + AArch64/StandaloneMmCoreHobLib.c + AArch64/StandaloneMmCoreHobLibInternal.c + +[Packages] + MdePkg/MdePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + + +[LibraryClasses] + BaseMemoryLib + DebugLib + +[Guids] + gEfiHobListGuid ## CONSUMES ## SystemTable diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/X64/StandaloneMmCoreHobLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/X64/StandaloneMmCoreHobLib.c new file mode 100644 index 00000000..bb440da4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreHobLib/X64/StandaloneMmCoreHobLib.c @@ -0,0 +1,298 @@ +/** @file + HOB Library implementation for Standalone MM Core. + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include <Library/HobLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> + +#include <Guid/MemoryAllocationHob.h> + +/** + Builds a HOB for a loaded PE32 module. + + This function builds a HOB for a loaded PE32 module. + It can only be invoked during PEI phase; + for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + + If ModuleName is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param ModuleName The GUID File Name of the module. + @param MemoryAllocationModule The 64 bit physical address of the module. + @param ModuleLength The length of the module in bytes. + @param EntryPoint The 64 bit physical address of the module entry point. + +**/ +VOID +EFIAPI +BuildModuleHob ( + IN CONST EFI_GUID *ModuleName, + IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule, + IN UINT64 ModuleLength, + IN EFI_PHYSICAL_ADDRESS EntryPoint + ) +{ + // + // PEI HOB is read only for MM phase + // + ASSERT (FALSE); +} + +/** + Builds a HOB that describes a chunk of system memory. + + This function builds a HOB that describes a chunk of system memory. + It can only be invoked during PEI phase; + for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + +**/ +VOID +EFIAPI +BuildResourceDescriptorHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes + ) +{ + // + // PEI HOB is read only for MM phase + // + ASSERT (FALSE); +} + +/** + Builds a customized HOB tagged with a GUID for identification and returns + the start address of GUID HOB data. + + This function builds a customized HOB tagged with a GUID for identification + and returns the start address of GUID HOB data so that caller can fill the customized data. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase. + For MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + + If Guid is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength > (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + HobLength is UINT16 and multiples of 8 bytes, so the max HobLength is 0xFFF8. + + @param Guid The GUID to tag the customized HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @retval NULL The GUID HOB could not be allocated. + @retval others The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidHob ( + IN CONST EFI_GUID *Guid, + IN UINTN DataLength + ) +{ + // + // PEI HOB is read only for MM phase + // + ASSERT (FALSE); + return NULL; +} + +/** + Builds a customized HOB tagged with a GUID for identification, copies the input data to the HOB + data field, and returns the start address of the GUID HOB data. + + This function builds a customized HOB tagged with a GUID for identification and copies the input + data to the HOB data field and returns the start address of the GUID HOB data. It can only be + invoked during PEI phase; for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + The HOB Header and Name field is already stripped. + It can only be invoked during PEI phase. + For MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + + If Guid is NULL, then ASSERT(). + If Data is NULL and DataLength > 0, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength > (0xFFF8 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + HobLength is UINT16 and multiples of 8 bytes, so the max HobLength is 0xFFF8. + + @param Guid The GUID to tag the customized HOB. + @param Data The data to be copied into the data field of the GUID HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @retval NULL The GUID HOB could not be allocated. + @retval others The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidDataHob ( + IN CONST EFI_GUID *Guid, + IN VOID *Data, + IN UINTN DataLength + ) +{ + // + // PEI HOB is read only for MM phase + // + ASSERT (FALSE); + return NULL; +} + +/** + Builds a Firmware Volume HOB. + + This function builds a Firmware Volume HOB. + It can only be invoked during PEI phase; + for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + + If there is no additional space for HOB creation, then ASSERT(). + If the FvImage buffer is not at its required alignment, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + +**/ +VOID +EFIAPI +BuildFvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + // + // PEI HOB is read only for MM phase + // + ASSERT (FALSE); +} + +/** + Builds a EFI_HOB_TYPE_FV2 HOB. + + This function builds a EFI_HOB_TYPE_FV2 HOB. + It can only be invoked during PEI phase; + for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + + If there is no additional space for HOB creation, then ASSERT(). + If the FvImage buffer is not at its required alignment, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param FvName The name of the Firmware Volume. + @param FileName The name of the file. + +**/ +VOID +EFIAPI +BuildFv2Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN CONST EFI_GUID *FvName, + IN CONST EFI_GUID *FileName + ) +{ + ASSERT (FALSE); +} + +/** + Builds a EFI_HOB_TYPE_FV3 HOB. + + This function builds a EFI_HOB_TYPE_FV3 HOB. + It can only be invoked during PEI phase; + for MM phase, it will ASSERT() since PEI HOB is read-only for MM phase. + + If there is no additional space for HOB creation, then ASSERT(). + If the FvImage buffer is not at its required alignment, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param AuthenticationStatus The authentication status. + @param ExtractedFv TRUE if the FV was extracted as a file within + another firmware volume. FALSE otherwise. + @param FvName The name of the Firmware Volume. + Valid only if IsExtractedFv is TRUE. + @param FileName The name of the file. + Valid only if IsExtractedFv is TRUE. + +**/ +VOID +EFIAPI +BuildFv3Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT32 AuthenticationStatus, + IN BOOLEAN ExtractedFv, + IN CONST EFI_GUID *FvName, OPTIONAL + IN CONST EFI_GUID *FileName OPTIONAL + ) +{ + ASSERT (FALSE); +} + +/** + Builds a HOB for the CPU. + + This function builds a HOB for the CPU. + It can only be invoked during PEI phase; + for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + + If there is no additional space for HOB creation, then ASSERT(). + + @param SizeOfMemorySpace The maximum physical memory addressability of the processor. + @param SizeOfIoSpace The maximum physical I/O addressability of the processor. + +**/ +VOID +EFIAPI +BuildCpuHob ( + IN UINT8 SizeOfMemorySpace, + IN UINT8 SizeOfIoSpace + ) +{ + // + // PEI HOB is read only for MM phase + // + ASSERT (FALSE); +} + +/** + Builds a HOB for the memory allocation. + + This function builds a HOB for the memory allocation. + It can only be invoked during PEI phase; + for MM phase, it will ASSERT() because PEI HOB is read-only for MM phase. + + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the memory. + @param Length The length of the memory allocation in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildMemoryAllocationHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + // + // PEI HOB is read only for MM phase + // + ASSERT (FALSE); +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.c new file mode 100644 index 00000000..bdf33f62 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.c @@ -0,0 +1,902 @@ +/** @file + Support routines for memory allocation routines based on Standalone MM Core internal functions. + + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2016 - 2021, ARM Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include <Guid/MmramMemoryReserve.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include "StandaloneMmCoreMemoryAllocationServices.h" + +EFI_MM_SYSTEM_TABLE *gMmst = NULL; + +/** + Allocates one or more 4KB pages of a certain memory type. + + Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated + buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned. + If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param MemoryType The type of memory to allocate. + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocatePages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + + if (Pages == 0) { + return NULL; + } + + Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + return (VOID *) (UINTN) Memory; +} + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePages ( + IN UINTN Pages + ) +{ + return InternalAllocatePages (EfiRuntimeServicesData, Pages); +} + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData. + + Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimePages ( + IN UINTN Pages + ) +{ + return InternalAllocatePages (EfiRuntimeServicesData, Pages); +} + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType. + + Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedPages ( + IN UINTN Pages + ) +{ + return NULL; +} + +/** + Frees one or more 4KB pages that were previously allocated with one of the page allocation + functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the page allocation services of the Memory + Allocation Library. If it is not possible to free allocated pages, then this function will + perform no actions. + + If Buffer was not allocated with a page allocation function in the Memory Allocation Library, + then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer Pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreePages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + EFI_STATUS Status; + + ASSERT (Pages != 0); + Status = gMmst->MmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages); + ASSERT_EFI_ERROR (Status); +} + +/** + Allocates one or more 4KB pages of a certain memory type at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment + specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned. + If there is not enough memory at the specified alignment remaining to satisfy the request, then + NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param MemoryType The type of memory to allocate. + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocateAlignedPages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + UINTN AlignedMemory; + UINTN AlignmentMask; + UINTN UnalignedPages; + UINTN RealPages; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Pages == 0) { + return NULL; + } + if (Alignment > EFI_PAGE_SIZE) { + // + // Calculate the total number of pages since alignment is larger than page size. + // + AlignmentMask = Alignment - 1; + RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. + // + ASSERT (RealPages > Pages); + + Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask; + UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory); + if (UnalignedPages > 0) { + // + // Free first unaligned page(s). + // + Status = gMmst->MmFreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + Memory = (EFI_PHYSICAL_ADDRESS) (AlignedMemory + EFI_PAGES_TO_SIZE (Pages)); + UnalignedPages = RealPages - Pages - UnalignedPages; + if (UnalignedPages > 0) { + // + // Free last unaligned page(s). + // + Status = gMmst->MmFreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + } else { + // + // Do not over-allocate pages in this case. + // + Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = (UINTN) Memory; + } + return (VOID *) AlignedMemory; +} + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment); +} + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedRuntimePages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment); +} + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedReservedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return NULL; +} + +/** + Frees one or more 4KB pages that were previously allocated with one of the aligned page + allocation functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the aligned page allocation services of the Memory + Allocation Library. If it is not possible to free allocated pages, then this function will + perform no actions. + + If Buffer was not allocated with an aligned page allocation function in the Memory Allocation + Library, then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer Pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreeAlignedPages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + EFI_STATUS Status; + + ASSERT (Pages != 0); + Status = gMmst->MmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) Buffer, Pages); + ASSERT_EFI_ERROR (Status); +} + +/** + Allocates a buffer of a certain pool type. + + Allocates the number bytes specified by AllocationSize of a certain pool type and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param MemoryType The type of memory to allocate. + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocatePool ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN AllocationSize + ) +{ + EFI_STATUS Status; + VOID *Memory; + + Memory = NULL; + + Status = gMmst->MmAllocatePool (MemoryType, AllocationSize, &Memory); + if (EFI_ERROR (Status)) { + Memory = NULL; + } + return Memory; +} + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePool ( + IN UINTN AllocationSize + ) +{ + return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize); +} + +/** + Allocates a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimePool ( + IN UINTN AllocationSize + ) +{ + return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize); +} + +/** + Allocates a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedPool ( + IN UINTN AllocationSize + ) +{ + return NULL; +} + +/** + Allocates and zeros a buffer of a certain pool type. + + Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer + with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid + buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request, + then NULL is returned. + + @param PoolType The type of memory to allocate. + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocateZeroPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize + ) +{ + VOID *Memory; + + Memory = InternalAllocatePool (PoolType, AllocationSize); + if (Memory != NULL) { + Memory = ZeroMem (Memory, AllocationSize); + } + return Memory; +} + +/** + Allocates and zeros a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateZeroPool ( + IN UINTN AllocationSize + ) +{ + return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize); +} + +/** + Allocates and zeros a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimeZeroPool ( + IN UINTN AllocationSize + ) +{ + return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize); +} + +/** + Allocates and zeros a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedZeroPool ( + IN UINTN AllocationSize + ) +{ + return NULL; +} + +/** + Copies a buffer to an allocated buffer of a certain pool type. + + Allocates the number bytes specified by AllocationSize of a certain pool type, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param PoolType The type of pool to allocate. + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocateCopyPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + VOID *Memory; + + ASSERT (Buffer != NULL); + ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1)); + + Memory = InternalAllocatePool (PoolType, AllocationSize); + if (Memory != NULL) { + Memory = CopyMem (Memory, Buffer, AllocationSize); + } + return Memory; +} + +/** + Copies a buffer to an allocated buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer); +} + +/** + Copies a buffer to an allocated buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer); +} + +/** + Copies a buffer to an allocated buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return NULL; +} + +/** + Reallocates a buffer of a specified memory type. + + Allocates and zeros the number bytes specified by NewSize from memory of the type + specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param PoolType The type of pool to allocate. + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalReallocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + VOID *NewBuffer; + + NewBuffer = InternalAllocateZeroPool (PoolType, NewSize); + if (NewBuffer != NULL && OldBuffer != NULL) { + CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize)); + FreePool (OldBuffer); + } + return NewBuffer; +} + +/** + Reallocates a buffer of type EfiBootServicesData. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocatePool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer); +} + +/** + Reallocates a buffer of type EfiRuntimeServicesData. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocateRuntimePool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer); +} + +/** + Reallocates a buffer of type EfiReservedMemoryType. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocateReservedPool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return NULL; +} + +/** + Frees a buffer that was previously allocated with one of the pool allocation functions in the + Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the + pool allocation services of the Memory Allocation Library. If it is not possible to free pool + resources, then this function will perform no actions. + + If Buffer was not allocated with a pool allocation function in the Memory Allocation Library, + then ASSERT(). + + @param Buffer Pointer to the buffer to free. + +**/ +VOID +EFIAPI +FreePool ( + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + + Status = gMmst->MmFreePool (Buffer); + ASSERT_EFI_ERROR (Status); +} + +/** + The constructor function calls MmInitializeMemoryServices to initialize + memory in MMRAM and caches EFI_MM_SYSTEM_TABLE pointer. + + @param [in] ImageHandle The firmware allocated handle for the EFI image. + @param [in] MmSystemTable A pointer to the Management mode System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +MemoryAllocationLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_MM_SYSTEM_TABLE *MmSystemTable + ) +{ + MM_CORE_PRIVATE_DATA *MmCorePrivate; + EFI_HOB_GUID_TYPE *GuidHob; + MM_CORE_DATA_HOB_DATA *DataInHob; + VOID *HobStart; + EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHobData; + EFI_MMRAM_DESCRIPTOR *MmramRanges; + UINTN MmramRangeCount; + EFI_HOB_GUID_TYPE *MmramRangesHob; + + HobStart = GetHobList (); + DEBUG ((DEBUG_INFO, "StandaloneMmCoreMemoryAllocationLibConstructor - 0x%x\n", HobStart)); + + // + // Extract MM Core Private context from the Hob. If absent search for + // a Hob containing the MMRAM ranges + // + GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart); + if (GuidHob == NULL) { + MmramRangesHob = GetNextGuidHob (&gEfiMmPeiMmramMemoryReserveGuid, HobStart); + if (MmramRangesHob == NULL) { + return EFI_UNSUPPORTED; + } + + MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob); + if (MmramRangesHobData == NULL) { + return EFI_UNSUPPORTED; + } + + MmramRanges = MmramRangesHobData->Descriptor; + if (MmramRanges == NULL) { + return EFI_UNSUPPORTED; + } + + MmramRangeCount = (UINTN) MmramRangesHobData->NumberOfMmReservedRegions; + if (MmramRanges == NULL) { + return EFI_UNSUPPORTED; + } + + } else { + DataInHob = GET_GUID_HOB_DATA (GuidHob); + MmCorePrivate = (MM_CORE_PRIVATE_DATA *)(UINTN)DataInHob->Address; + MmramRanges = (EFI_MMRAM_DESCRIPTOR *)(UINTN)MmCorePrivate->MmramRanges; + MmramRangeCount = (UINTN) MmCorePrivate->MmramRangeCount; + } + + { + UINTN Index; + + DEBUG ((DEBUG_INFO, "MmramRangeCount - 0x%x\n", MmramRangeCount)); + for (Index = 0; Index < MmramRangeCount; Index++) { + DEBUG ((DEBUG_INFO, "MmramRanges[%d]: 0x%016lx - 0x%016lx\n", + Index, MmramRanges[Index].CpuStart, MmramRanges[Index].PhysicalSize)); + } + } + + // + // Initialize memory service using free MMRAM + // + DEBUG ((DEBUG_INFO, "MmInitializeMemoryServices\n")); + MmInitializeMemoryServices ((UINTN)MmramRangeCount, (VOID *)(UINTN)MmramRanges); + + // Initialize MM Services Table + gMmst = MmSystemTable; + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf new file mode 100644 index 00000000..b0bbe28f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationLib.inf @@ -0,0 +1,44 @@ +## @file +# Memory Allocation Library instance dedicated to MM Core. +# The implementation borrows the MM Core Memory Allocation services as the primitive +# for memory allocation instead of using MM System Table services in an indirect way. +# It is assumed that this library instance must be linked with MM Core in this package. +# +# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = MemoryAllocationLib + FILE_GUID = DCDCBE1D-E760-4E1D-85B4-96E3F0439C41 + MODULE_TYPE = MM_CORE_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + LIBRARY_CLASS = MemoryAllocationLib|MM_CORE_STANDALONE + CONSTRUCTOR = MemoryAllocationLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + StandaloneMmCoreMemoryAllocationLib.c + StandaloneMmCoreMemoryAllocationServices.h + +[Packages] + MdePkg/MdePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + HobLib + +[Guids] + gEfiMmPeiMmramMemoryReserveGuid diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationServices.h b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationServices.h new file mode 100644 index 00000000..1bfecbc9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreMemoryAllocationLib/StandaloneMmCoreMemoryAllocationServices.h @@ -0,0 +1,32 @@ +/** @file + Contains function prototypes for Memory Services in the MM Core. + + This header file borrows the StandaloneMmCore Memory Allocation services as the primitive + for memory allocation. + + Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PI_MM_CORE_MEMORY_ALLOCATION_SERVICES_H_ +#define _PI_MM_CORE_MEMORY_ALLOCATION_SERVICES_H_ + +#include <Guid/MmCoreData.h> + +/** + Called to initialize the memory service. + + @param MmramRangeCount Number of MMRAM Regions + @param MmramRanges Pointer to MMRAM Descriptors + +**/ +VOID +MmInitializeMemoryServices ( + IN UINTN MmramRangeCount, + IN EFI_MMRAM_DESCRIPTOR *MmramRanges + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.c new file mode 100644 index 00000000..d444855f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.c @@ -0,0 +1,643 @@ +/** @file + HOB Library implementation for Standalone MM Core. + +Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> +Copyright (c) 2017 - 2018, ARM Limited. All rights reserved.<BR> +Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include <Library/HobLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MmServicesTableLib.h> + +// +// Cache copy of HobList pointer. +// +STATIC VOID *gHobList = NULL; + +/** + The constructor function caches the pointer to HOB list. + + The constructor function gets the start address of HOB list from system configuration table. + It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. + + @param ImageHandle The firmware allocated handle for the image. + @param MmSystemTable A pointer to the MM System Table. + + @retval EFI_SUCCESS The constructor successfully gets HobList. + @retval Other value The constructor can't get HobList. + +**/ +EFI_STATUS +EFIAPI +HobLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_MM_SYSTEM_TABLE *MmSystemTable + ) +{ + UINTN Index; + + for (Index = 0; Index < gMmst->NumberOfTableEntries; Index++) { + if (CompareGuid (&gEfiHobListGuid, &gMmst->MmConfigurationTable[Index].VendorGuid)) { + gHobList = gMmst->MmConfigurationTable[Index].VendorTable; + break; + } + } + return EFI_SUCCESS; +} + +/** + Returns the pointer to the HOB list. + + This function returns the pointer to first HOB in the list. + If the pointer to the HOB list is NULL, then ASSERT(). + + @return The pointer to the HOB list. + +**/ +VOID * +EFIAPI +GetHobList ( + VOID + ) +{ + UINTN Index; + + if (gHobList == NULL) { + for (Index = 0; Index < gMmst->NumberOfTableEntries; Index++) { + if (CompareGuid (&gEfiHobListGuid, &gMmst->MmConfigurationTable[Index].VendorGuid)) { + gHobList = gMmst->MmConfigurationTable[Index].VendorTable; + break; + } + } + } + ASSERT (gHobList != NULL); + return gHobList; +} + +/** + Returns the next instance of a HOB type from the starting HOB. + + This function searches the first instance of a HOB type from the starting HOB pointer. + If there does not exist such HOB type from the starting HOB pointer, it will return NULL. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + + If HobStart is NULL, then ASSERT(). + + @param Type The HOB type to return. + @param HobStart The starting HOB pointer to search from. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextHob ( + IN UINT16 Type, + IN CONST VOID *HobStart + ) +{ + EFI_PEI_HOB_POINTERS Hob; + + ASSERT (HobStart != NULL); + + Hob.Raw = (UINT8 *) HobStart; + // + // Parse the HOB list until end of list or matching type is found. + // + while (!END_OF_HOB_LIST (Hob)) { + if (Hob.Header->HobType == Type) { + return Hob.Raw; + } + Hob.Raw = GET_NEXT_HOB (Hob); + } + return NULL; +} + +/** + Returns the first instance of a HOB type among the whole HOB list. + + This function searches the first instance of a HOB type among the whole HOB list. + If there does not exist such HOB type in the HOB list, it will return NULL. + + If the pointer to the HOB list is NULL, then ASSERT(). + + @param Type The HOB type to return. + + @return The next instance of a HOB type from the starting HOB. + +**/ +VOID * +EFIAPI +GetFirstHob ( + IN UINT16 Type + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextHob (Type, HobList); +} + +/** + Returns the next instance of the matched GUID HOB from the starting HOB. + + This function searches the first instance of a HOB from the starting HOB pointer. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION, and its GUID Name equals to the input Guid. + If such a HOB from the starting HOB pointer does not exist, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size information, respectively. + In contrast with macro GET_NEXT_HOB(), this function does not skip the starting HOB pointer + unconditionally: it returns HobStart back if HobStart itself meets the requirement; + caller is required to use GET_NEXT_HOB() if it wishes to skip current HobStart. + + If Guid is NULL, then ASSERT(). + If HobStart is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + @param HobStart A pointer to a Guid. + + @return The next instance of the matched GUID HOB from the starting HOB. + +**/ +VOID * +EFIAPI +GetNextGuidHob ( + IN CONST EFI_GUID *Guid, + IN CONST VOID *HobStart + ) +{ + EFI_PEI_HOB_POINTERS GuidHob; + + GuidHob.Raw = (UINT8 *) HobStart; + while ((GuidHob.Raw = GetNextHob (EFI_HOB_TYPE_GUID_EXTENSION, GuidHob.Raw)) != NULL) { + if (CompareGuid (Guid, &GuidHob.Guid->Name)) { + break; + } + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + } + return GuidHob.Raw; +} + +/** + Returns the first instance of the matched GUID HOB among the whole HOB list. + + This function searches the first instance of a HOB among the whole HOB list. + Such HOB should satisfy two conditions: + its HOB type is EFI_HOB_TYPE_GUID_EXTENSION and its GUID Name equals to the input Guid. + If such a HOB from the starting HOB pointer does not exist, it will return NULL. + Caller is required to apply GET_GUID_HOB_DATA () and GET_GUID_HOB_DATA_SIZE () + to extract the data section and its size information, respectively. + + If the pointer to the HOB list is NULL, then ASSERT(). + If Guid is NULL, then ASSERT(). + + @param Guid The GUID to match with in the HOB list. + + @return The first instance of the matched GUID HOB among the whole HOB list. + +**/ +VOID * +EFIAPI +GetFirstGuidHob ( + IN CONST EFI_GUID *Guid + ) +{ + VOID *HobList; + + HobList = GetHobList (); + return GetNextGuidHob (Guid, HobList); +} + +/** + Get the system boot mode from the HOB list. + + This function returns the system boot mode information from the + PHIT HOB in HOB list. + + If the pointer to the HOB list is NULL, then ASSERT(). + + @param VOID + + @return The Boot Mode. + +**/ +EFI_BOOT_MODE +EFIAPI +GetBootModeHob ( + VOID + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob; + + HandOffHob = (EFI_HOB_HANDOFF_INFO_TABLE *) GetHobList (); + + return HandOffHob->BootMode; +} + +VOID * +CreateHob ( + IN UINT16 HobType, + IN UINT16 HobLength + ) +{ + EFI_HOB_HANDOFF_INFO_TABLE *HandOffHob; + EFI_HOB_GENERIC_HEADER *HobEnd; + EFI_PHYSICAL_ADDRESS FreeMemory; + VOID *Hob; + + HandOffHob = GetHobList (); + + HobLength = (UINT16)((HobLength + 0x7) & (~0x7)); + + FreeMemory = HandOffHob->EfiFreeMemoryTop - HandOffHob->EfiFreeMemoryBottom; + + if (FreeMemory < HobLength) { + return NULL; + } + + Hob = (VOID*) (UINTN) HandOffHob->EfiEndOfHobList; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobType = HobType; + ((EFI_HOB_GENERIC_HEADER*) Hob)->HobLength = HobLength; + ((EFI_HOB_GENERIC_HEADER*) Hob)->Reserved = 0; + + HobEnd = (EFI_HOB_GENERIC_HEADER*) ((UINTN)Hob + HobLength); + HandOffHob->EfiEndOfHobList = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + HobEnd->HobType = EFI_HOB_TYPE_END_OF_HOB_LIST; + HobEnd->HobLength = sizeof(EFI_HOB_GENERIC_HEADER); + HobEnd->Reserved = 0; + HobEnd++; + HandOffHob->EfiFreeMemoryBottom = (EFI_PHYSICAL_ADDRESS) (UINTN) HobEnd; + + return Hob; +} + +/** + Builds a HOB for a loaded PE32 module. + + This function builds a HOB for a loaded PE32 module. + If ModuleName is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param ModuleName The GUID File Name of the module. + @param MemoryAllocationModule The 64 bit physical address of the module. + @param ModuleLength The length of the module in bytes. + @param EntryPoint The 64 bit physical address of the module entry point. + +**/ +VOID +EFIAPI +BuildModuleHob ( + IN CONST EFI_GUID *ModuleName, + IN EFI_PHYSICAL_ADDRESS MemoryAllocationModule, + IN UINT64 ModuleLength, + IN EFI_PHYSICAL_ADDRESS EntryPoint + ) +{ + EFI_HOB_MEMORY_ALLOCATION_MODULE *Hob; + + ASSERT (((MemoryAllocationModule & (EFI_PAGE_SIZE - 1)) == 0) && + ((ModuleLength & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION_MODULE)); + + CopyGuid (&(Hob->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid); + Hob->MemoryAllocationHeader.MemoryBaseAddress = MemoryAllocationModule; + Hob->MemoryAllocationHeader.MemoryLength = ModuleLength; + Hob->MemoryAllocationHeader.MemoryType = EfiBootServicesCode; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->MemoryAllocationHeader.Reserved, sizeof (Hob->MemoryAllocationHeader.Reserved)); + + CopyGuid (&Hob->ModuleName, ModuleName); + Hob->EntryPoint = EntryPoint; +} + +/** + Builds a HOB that describes a chunk of system memory. + + This function builds a HOB that describes a chunk of system memory. + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + +**/ +VOID +EFIAPI +BuildResourceDescriptorHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes + ) +{ + EFI_HOB_RESOURCE_DESCRIPTOR *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, sizeof (EFI_HOB_RESOURCE_DESCRIPTOR)); + ASSERT(Hob != NULL); + + Hob->ResourceType = ResourceType; + Hob->ResourceAttribute = ResourceAttribute; + Hob->PhysicalStart = PhysicalStart; + Hob->ResourceLength = NumberOfBytes; +} + +/** + Builds a GUID HOB with a certain data length. + + This function builds a customized HOB tagged with a GUID for identification + and returns the start address of GUID HOB data so that caller can fill the customized data. + The HOB Header and Name field is already stripped. + If Guid is NULL, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidHob ( + IN CONST EFI_GUID *Guid, + IN UINTN DataLength + ) +{ + EFI_HOB_GUID_TYPE *Hob; + + // + // Make sure that data length is not too long. + // + ASSERT (DataLength <= (0xffff - sizeof (EFI_HOB_GUID_TYPE))); + + Hob = CreateHob (EFI_HOB_TYPE_GUID_EXTENSION, (UINT16) (sizeof (EFI_HOB_GUID_TYPE) + DataLength)); + CopyGuid (&Hob->Name, Guid); + return Hob + 1; +} + + +/** + Copies a data buffer to a newly-built HOB. + + This function builds a customized HOB tagged with a GUID for identification, + copies the input data to the HOB data field and returns the start address of the GUID HOB data. + The HOB Header and Name field is already stripped. + If Guid is NULL, then ASSERT(). + If Data is NULL and DataLength > 0, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + If DataLength >= (0x10000 - sizeof (EFI_HOB_GUID_TYPE)), then ASSERT(). + + @param Guid The GUID to tag the customized HOB. + @param Data The data to be copied into the data field of the GUID HOB. + @param DataLength The size of the data payload for the GUID HOB. + + @return The start address of GUID HOB data. + +**/ +VOID * +EFIAPI +BuildGuidDataHob ( + IN CONST EFI_GUID *Guid, + IN VOID *Data, + IN UINTN DataLength + ) +{ + VOID *HobData; + + ASSERT (Data != NULL || DataLength == 0); + + HobData = BuildGuidHob (Guid, DataLength); + + return CopyMem (HobData, Data, DataLength); +} + +/** + Builds a Firmware Volume HOB. + + This function builds a Firmware Volume HOB. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + +**/ +VOID +EFIAPI +BuildFvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + EFI_HOB_FIRMWARE_VOLUME *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV, sizeof (EFI_HOB_FIRMWARE_VOLUME)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; +} + + +/** + Builds a EFI_HOB_TYPE_FV2 HOB. + + This function builds a EFI_HOB_TYPE_FV2 HOB. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Firmware Volume. + @param Length The size of the Firmware Volume in bytes. + @param FvName The name of the Firmware Volume. + @param FileName The name of the file. + +**/ +VOID +EFIAPI +BuildFv2Hob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN CONST EFI_GUID *FvName, + IN CONST EFI_GUID *FileName + ) +{ + EFI_HOB_FIRMWARE_VOLUME2 *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_FV2, sizeof (EFI_HOB_FIRMWARE_VOLUME2)); + + Hob->BaseAddress = BaseAddress; + Hob->Length = Length; + CopyGuid (&Hob->FvName, FvName); + CopyGuid (&Hob->FileName, FileName); +} + + +/** + Builds a HOB for the CPU. + + This function builds a HOB for the CPU. + If there is no additional space for HOB creation, then ASSERT(). + + @param SizeOfMemorySpace The maximum physical memory addressability of the processor. + @param SizeOfIoSpace The maximum physical I/O addressability of the processor. + +**/ +VOID +EFIAPI +BuildCpuHob ( + IN UINT8 SizeOfMemorySpace, + IN UINT8 SizeOfIoSpace + ) +{ + EFI_HOB_CPU *Hob; + + Hob = CreateHob (EFI_HOB_TYPE_CPU, sizeof (EFI_HOB_CPU)); + + Hob->SizeOfMemorySpace = SizeOfMemorySpace; + Hob->SizeOfIoSpace = SizeOfIoSpace; + + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->Reserved, sizeof (Hob->Reserved)); +} + +/** + Builds a HOB for the memory allocation. + + This function builds a HOB for the memory allocation. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the memory. + @param Length The length of the memory allocation in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildMemoryAllocationHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + EFI_HOB_MEMORY_ALLOCATION *Hob; + + ASSERT (((BaseAddress & (EFI_PAGE_SIZE - 1)) == 0) && + ((Length & (EFI_PAGE_SIZE - 1)) == 0)); + + Hob = CreateHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, sizeof (EFI_HOB_MEMORY_ALLOCATION)); + + ZeroMem (&(Hob->AllocDescriptor.Name), sizeof (EFI_GUID)); + Hob->AllocDescriptor.MemoryBaseAddress = BaseAddress; + Hob->AllocDescriptor.MemoryLength = Length; + Hob->AllocDescriptor.MemoryType = MemoryType; + // + // Zero the reserved space to match HOB spec + // + ZeroMem (Hob->AllocDescriptor.Reserved, sizeof (Hob->AllocDescriptor.Reserved)); +} + +/** + Builds a HOB that describes a chunk of system memory with Owner GUID. + + This function builds a HOB that describes a chunk of system memory. + If there is no additional space for HOB creation, then ASSERT(). + + @param ResourceType The type of resource described by this HOB. + @param ResourceAttribute The resource attributes of the memory described by this HOB. + @param PhysicalStart The 64 bit physical address of memory described by this HOB. + @param NumberOfBytes The length of the memory described by this HOB in bytes. + @param OwnerGUID GUID for the owner of this resource. + +**/ +VOID +EFIAPI +BuildResourceDescriptorWithOwnerHob ( + IN EFI_RESOURCE_TYPE ResourceType, + IN EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute, + IN EFI_PHYSICAL_ADDRESS PhysicalStart, + IN UINT64 NumberOfBytes, + IN EFI_GUID *OwnerGUID + ) +{ + ASSERT (FALSE); +} + +/** + Builds a Capsule Volume HOB. + + This function builds a Capsule Volume HOB. + If the platform does not support Capsule Volume HOBs, then ASSERT(). + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The base address of the Capsule Volume. + @param Length The size of the Capsule Volume in bytes. + +**/ +VOID +EFIAPI +BuildCvHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + ASSERT (FALSE); +} + + +/** + Builds a HOB for the BSP store. + + This function builds a HOB for BSP store. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the BSP. + @param Length The length of the BSP store in bytes. + @param MemoryType Type of memory allocated by this HOB. + +**/ +VOID +EFIAPI +BuildBspStoreHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN EFI_MEMORY_TYPE MemoryType + ) +{ + ASSERT (FALSE); +} + +/** + Builds a HOB for the Stack. + + This function builds a HOB for the stack. + If there is no additional space for HOB creation, then ASSERT(). + + @param BaseAddress The 64 bit physical address of the Stack. + @param Length The length of the stack in bytes. + +**/ +VOID +EFIAPI +BuildStackHob ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ) +{ + ASSERT (FALSE); +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf new file mode 100644 index 00000000..764d5573 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmHobLib/StandaloneMmHobLib.inf @@ -0,0 +1,40 @@ +## @file +# Instance of HOB Library for Standalone MM modules. +# +# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = HobLib + FILE_GUID = 8262551B-AB2D-4E76-99FC-5EBB83F4988E + MODULE_TYPE = MM_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + LIBRARY_CLASS = HobLib|MM_STANDALONE + CONSTRUCTOR = HobLibConstructor + +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + StandaloneMmHobLib.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MmServicesTableLib + +[Guids] + gEfiHobListGuid ## CONSUMES ## SystemTable + gEfiHobMemoryAllocModuleGuid ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/AArch64/StandaloneMmMemLibInternal.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/AArch64/StandaloneMmMemLibInternal.c new file mode 100644 index 00000000..8f92a997 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/AArch64/StandaloneMmMemLibInternal.c @@ -0,0 +1,70 @@ +/** @file + Internal ARCH Specific file of MM memory check library. + + MM memory check library implementation. This library consumes MM_ACCESS_PROTOCOL + to get MMRAM information. In order to use this library instance, the platform should produce + all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core + and MM driver) and/or specific dedicated hardware. + + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +// +// Maximum support address used to check input buffer +// +extern EFI_PHYSICAL_ADDRESS mMmMemLibInternalMaximumSupportAddress; + +/** + Calculate and save the maximum support address. + +**/ +VOID +MmMemLibInternalCalculateMaximumSupportAddress ( + VOID + ) +{ + UINT8 PhysicalAddressBits; + + PhysicalAddressBits = 36; + + // + // Save the maximum support address in one global variable + // + mMmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1); + DEBUG ((DEBUG_INFO, "mMmMemLibInternalMaximumSupportAddress = 0x%lx\n", mMmMemLibInternalMaximumSupportAddress)); +} + +/** + Initialize cached Mmram Ranges from HOB. + + @retval EFI_UNSUPPORTED The routine is unable to extract MMRAM information. + @retval EFI_SUCCESS MmRanges are populated successfully. + +**/ +EFI_STATUS +MmMemLibInternalPopulateMmramRanges ( + VOID + ) +{ + // Not implemented for AARCH64. + return EFI_SUCCESS; +} + +/** + Deinitialize cached Mmram Ranges. + +**/ +VOID +MmMemLibInternalFreeMmramRanges ( + VOID + ) +{ + // Not implemented for AARCH64. +} + diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.c new file mode 100644 index 00000000..38117ea6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.c @@ -0,0 +1,315 @@ +/** @file + Instance of MM memory check library. + + MM memory check library library implementation. This library consumes MM_ACCESS_PROTOCOL + to get MMRAM information. In order to use this library instance, the platform should produce + all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core + and MM driver) and/or specific dedicated hardware. + + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2016 - 2021, Arm Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include <PiMm.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> + +EFI_MMRAM_DESCRIPTOR *mMmMemLibInternalMmramRanges; +UINTN mMmMemLibInternalMmramCount; + +// +// Maximum support address used to check input buffer +// +EFI_PHYSICAL_ADDRESS mMmMemLibInternalMaximumSupportAddress = 0; + +/** + Calculate and save the maximum support address. + +**/ +VOID +MmMemLibInternalCalculateMaximumSupportAddress ( + VOID + ); + +/** + Initialize cached Mmram Ranges from HOB. + + @retval EFI_UNSUPPORTED The routine is unable to extract MMRAM information. + @retval EFI_SUCCESS MmRanges are populated successfully. + +**/ +EFI_STATUS +MmMemLibInternalPopulateMmramRanges ( + VOID + ); + +/** + Deinitialize cached Mmram Ranges. + +**/ +VOID +MmMemLibInternalFreeMmramRanges ( + VOID + ); + +/** + This function check if the buffer is valid per processor architecture and not overlap with MMRAM. + + @param Buffer The buffer start address to be checked. + @param Length The buffer length to be checked. + + @retval TRUE This buffer is valid per processor architecture and not overlap with MMRAM. + @retval FALSE This buffer is not valid per processor architecture or overlap with MMRAM. +**/ +BOOLEAN +EFIAPI +MmIsBufferOutsideMmValid ( + IN EFI_PHYSICAL_ADDRESS Buffer, + IN UINT64 Length + ) +{ + UINTN Index; + + // + // Check override. + // NOTE: (B:0->L:4G) is invalid for IA32, but (B:1->L:4G-1)/(B:4G-1->L:1) is valid. + // + if ((Length > mMmMemLibInternalMaximumSupportAddress) || + (Buffer > mMmMemLibInternalMaximumSupportAddress) || + ((Length != 0) && (Buffer > (mMmMemLibInternalMaximumSupportAddress - (Length - 1)))) ) { + // + // Overflow happen + // + DEBUG (( + DEBUG_ERROR, + "MmIsBufferOutsideMmValid: Overflow: Buffer (0x%lx) - Length (0x%lx), MaximumSupportAddress (0x%lx)\n", + Buffer, + Length, + mMmMemLibInternalMaximumSupportAddress + )); + return FALSE; + } + + for (Index = 0; Index < mMmMemLibInternalMmramCount; Index ++) { + if (((Buffer >= mMmMemLibInternalMmramRanges[Index].CpuStart) && + (Buffer < mMmMemLibInternalMmramRanges[Index].CpuStart + mMmMemLibInternalMmramRanges[Index].PhysicalSize)) || + ((mMmMemLibInternalMmramRanges[Index].CpuStart >= Buffer) && + (mMmMemLibInternalMmramRanges[Index].CpuStart < Buffer + Length))) { + DEBUG (( + DEBUG_ERROR, + "MmIsBufferOutsideMmValid: Overlap: Buffer (0x%lx) - Length (0x%lx), ", + Buffer, + Length + )); + DEBUG (( + DEBUG_ERROR, + "CpuStart (0x%lx) - PhysicalSize (0x%lx)\n", + mMmMemLibInternalMmramRanges[Index].CpuStart, + mMmMemLibInternalMmramRanges[Index].PhysicalSize + )); + return FALSE; + } + } + + return TRUE; +} + +/** + Copies a source buffer (non-MMRAM) to a destination buffer (MMRAM). + + This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM). + It checks if source buffer is valid per processor architecture and not overlap with MMRAM. + If the check passes, it copies memory and returns EFI_SUCCESS. + If the check fails, it return EFI_SECURITY_VIOLATION. + The implementation must be reentrant. + + @param DestinationBuffer The pointer to the destination buffer of the memory copy. + @param SourceBuffer The pointer to the source buffer of the memory copy. + @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer. + + @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with MMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +MmCopyMemToMmram ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ) +{ + if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) { + DEBUG ((DEBUG_ERROR, "MmCopyMemToMmram: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length)); + return EFI_SECURITY_VIOLATION; + } + CopyMem (DestinationBuffer, SourceBuffer, Length); + return EFI_SUCCESS; +} + +/** + Copies a source buffer (MMRAM) to a destination buffer (NON-MMRAM). + + This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM). + It checks if destination buffer is valid per processor architecture and not overlap with MMRAM. + If the check passes, it copies memory and returns EFI_SUCCESS. + If the check fails, it returns EFI_SECURITY_VIOLATION. + The implementation must be reentrant. + + @param DestinationBuffer The pointer to the destination buffer of the memory copy. + @param SourceBuffer The pointer to the source buffer of the memory copy. + @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer. + + @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with MMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +MmCopyMemFromMmram ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ) +{ + if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) { + DEBUG ((DEBUG_ERROR, "MmCopyMemFromMmram: Security Violation: Destination (0x%x), Length (0x%x)\n", + DestinationBuffer, Length)); + return EFI_SECURITY_VIOLATION; + } + CopyMem (DestinationBuffer, SourceBuffer, Length); + return EFI_SUCCESS; +} + +/** + Copies a source buffer (NON-MMRAM) to a destination buffer (NON-MMRAM). + + This function copies a source buffer (non-MMRAM) to a destination buffer (MMRAM). + It checks if source buffer and destination buffer are valid per processor architecture and not overlap with MMRAM. + If the check passes, it copies memory and returns EFI_SUCCESS. + If the check fails, it returns EFI_SECURITY_VIOLATION. + The implementation must be reentrant, and it must handle the case where source buffer overlaps destination buffer. + + @param DestinationBuffer The pointer to the destination buffer of the memory copy. + @param SourceBuffer The pointer to the source buffer of the memory copy. + @param Length The number of bytes to copy from SourceBuffer to DestinationBuffer. + + @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with MMRAM. + @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with MMRAM. + @retval EFI_SUCCESS Memory is copied. + +**/ +EFI_STATUS +EFIAPI +MmCopyMem ( + OUT VOID *DestinationBuffer, + IN CONST VOID *SourceBuffer, + IN UINTN Length + ) +{ + if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) { + DEBUG ((DEBUG_ERROR, "MmCopyMem: Security Violation: Destination (0x%x), Length (0x%x)\n", + DestinationBuffer, Length)); + return EFI_SECURITY_VIOLATION; + } + if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) { + DEBUG ((DEBUG_ERROR, "MmCopyMem: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length)); + return EFI_SECURITY_VIOLATION; + } + CopyMem (DestinationBuffer, SourceBuffer, Length); + return EFI_SUCCESS; +} + +/** + Fills a target buffer (NON-MMRAM) with a byte value. + + This function fills a target buffer (non-MMRAM) with a byte value. + It checks if target buffer is valid per processor architecture and not overlap with MMRAM. + If the check passes, it fills memory and returns EFI_SUCCESS. + If the check fails, it returns EFI_SECURITY_VIOLATION. + + @param Buffer The memory to set. + @param Length The number of bytes to set. + @param Value The value with which to fill Length bytes of Buffer. + + @retval EFI_SECURITY_VIOLATION The Buffer is invalid per processor architecture or overlap with MMRAM. + @retval EFI_SUCCESS Memory is set. + +**/ +EFI_STATUS +EFIAPI +MmSetMem ( + OUT VOID *Buffer, + IN UINTN Length, + IN UINT8 Value + ) +{ + if (!MmIsBufferOutsideMmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Length)) { + DEBUG ((DEBUG_ERROR, "MmSetMem: Security Violation: Source (0x%x), Length (0x%x)\n", Buffer, Length)); + return EFI_SECURITY_VIOLATION; + } + SetMem (Buffer, Length, Value); + return EFI_SUCCESS; +} + +/** + The constructor function initializes the Mm Mem library + + @param [in] ImageHandle The firmware allocated handle for the EFI image. + @param [in] MmSystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +MemLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_MM_SYSTEM_TABLE *MmSystemTable + ) +{ + EFI_STATUS Status; + + // + // Calculate and save maximum support address + // + MmMemLibInternalCalculateMaximumSupportAddress (); + + // + // Initialize cached Mmram Ranges from HOB. + // + Status = MmMemLibInternalPopulateMmramRanges (); + + return Status; +} + +/** + Destructor for Mm Mem library. + + @param ImageHandle The image handle of the process. + @param MmSystemTable The EFI System Table pointer. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +MemLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_MM_SYSTEM_TABLE *MmSystemTable + ) +{ + + // + // Deinitialize cached Mmram Ranges. + // + MmMemLibInternalFreeMmramRanges (); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf new file mode 100644 index 00000000..bc2f3eea --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/StandaloneMmMemLib.inf @@ -0,0 +1,55 @@ +## @file +# Instance of MM memory check library. +# +# MM memory check library library implementation. This library consumes MM_ACCESS_PROTOCOL +# to get MMRAM information. In order to use this library instance, the platform should produce +# all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core +# and MM driver) and/or specific dedicated hardware. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> +# Copyright (c) Microsoft Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = MemLib + FILE_GUID = EA355F14-6409-4716-829F-37B3BC7C7F26 + MODULE_TYPE = MM_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + LIBRARY_CLASS = MemLib|MM_STANDALONE MM_CORE_STANDALONE + CONSTRUCTOR = MemLibConstructor + DESTRUCTOR = MemLibDestructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 AARCH64 +# + +[Sources.Common] + StandaloneMmMemLib.c + +[Sources.IA32, Sources.X64] + X86StandaloneMmMemLibInternal.c + +[Sources.AARCH64] + AArch64/StandaloneMmMemLibInternal.c + +[Packages] + MdePkg/MdePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + HobLib + MemoryAllocationLib + +[Guids] + gMmCoreDataHobGuid ## SOMETIMES_CONSUMES ## HOB + gEfiMmPeiMmramMemoryReserveGuid ## SOMETIMES_CONSUMES ## HOB diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/X86StandaloneMmMemLibInternal.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/X86StandaloneMmMemLibInternal.c new file mode 100644 index 00000000..530105a6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemLib/X86StandaloneMmMemLibInternal.c @@ -0,0 +1,155 @@ +/** @file + Internal ARCH Specific file of MM memory check library. + + MM memory check library implementation. This library consumes MM_ACCESS_PROTOCOL + to get MMRAM information. In order to use this library instance, the platform should produce + all MMRAM range via MM_ACCESS_PROTOCOL, including the range for firmware (like MM Core + and MM driver) and/or specific dedicated hardware. + + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> + Copyright (c) Microsoft Corporation. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <PiMm.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> + +#include <Guid/MmCoreData.h> +#include <Guid/MmramMemoryReserve.h> + +// +// Maximum support address used to check input buffer +// +extern EFI_PHYSICAL_ADDRESS mMmMemLibInternalMaximumSupportAddress; +extern EFI_MMRAM_DESCRIPTOR *mMmMemLibInternalMmramRanges; +extern UINTN mMmMemLibInternalMmramCount; + +/** + Calculate and save the maximum support address. + +**/ +VOID +MmMemLibInternalCalculateMaximumSupportAddress ( + VOID + ) +{ + VOID *Hob; + UINT32 RegEax; + UINT8 PhysicalAddressBits; + + // + // Get physical address bits supported. + // + Hob = GetFirstHob (EFI_HOB_TYPE_CPU); + if (Hob != NULL) { + PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; + } else { + AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); + if (RegEax >= 0x80000008) { + AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); + PhysicalAddressBits = (UINT8) RegEax; + } else { + PhysicalAddressBits = 36; + } + } + // + // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. + // + ASSERT (PhysicalAddressBits <= 52); + if (PhysicalAddressBits > 48) { + PhysicalAddressBits = 48; + } + + // + // Save the maximum support address in one global variable + // + mMmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1); + DEBUG ((DEBUG_INFO, "mMmMemLibInternalMaximumSupportAddress = 0x%lx\n", mMmMemLibInternalMaximumSupportAddress)); +} + +/** + Initialize cached Mmram Ranges from HOB. + + @retval EFI_UNSUPPORTED The routine is unable to extract MMRAM information. + @retval EFI_SUCCESS MmRanges are populated successfully. + +**/ +EFI_STATUS +MmMemLibInternalPopulateMmramRanges ( + VOID + ) +{ + VOID *HobStart; + EFI_HOB_GUID_TYPE *GuidHob; + MM_CORE_DATA_HOB_DATA *DataInHob; + MM_CORE_PRIVATE_DATA *MmCorePrivateData; + EFI_HOB_GUID_TYPE *MmramRangesHob; + EFI_MMRAM_HOB_DESCRIPTOR_BLOCK *MmramRangesHobData; + EFI_MMRAM_DESCRIPTOR *MmramDescriptors; + + HobStart = GetHobList (); + DEBUG ((DEBUG_INFO, "%a - 0x%x\n", __FUNCTION__, HobStart)); + + // + // Extract MM Core Private context from the Hob. If absent search for + // a Hob containing the MMRAM ranges + // + GuidHob = GetNextGuidHob (&gMmCoreDataHobGuid, HobStart); + if (GuidHob == NULL) { + MmramRangesHob = GetFirstGuidHob (&gEfiMmPeiMmramMemoryReserveGuid); + if (MmramRangesHob == NULL) { + return EFI_UNSUPPORTED; + } + + MmramRangesHobData = GET_GUID_HOB_DATA (MmramRangesHob); + if (MmramRangesHobData == NULL || MmramRangesHobData->Descriptor == NULL) { + return EFI_UNSUPPORTED; + } + + mMmMemLibInternalMmramCount = MmramRangesHobData->NumberOfMmReservedRegions; + MmramDescriptors = MmramRangesHobData->Descriptor; + } else { + DataInHob = GET_GUID_HOB_DATA (GuidHob); + if (DataInHob == NULL) { + return EFI_UNSUPPORTED; + } + + MmCorePrivateData = (MM_CORE_PRIVATE_DATA *) (UINTN) DataInHob->Address; + if (MmCorePrivateData == NULL || MmCorePrivateData->MmramRanges == 0) { + return EFI_UNSUPPORTED; + } + + mMmMemLibInternalMmramCount = (UINTN) MmCorePrivateData->MmramRangeCount; + MmramDescriptors = (EFI_MMRAM_DESCRIPTOR *) (UINTN) MmCorePrivateData->MmramRanges; + } + + mMmMemLibInternalMmramRanges = AllocatePool (mMmMemLibInternalMmramCount * sizeof (EFI_MMRAM_DESCRIPTOR)); + if (mMmMemLibInternalMmramRanges) { + CopyMem (mMmMemLibInternalMmramRanges, + MmramDescriptors, + mMmMemLibInternalMmramCount * sizeof (EFI_MMRAM_DESCRIPTOR)); + } + + return EFI_SUCCESS; +} + +/** + Deinitialize cached Mmram Ranges. + +**/ +VOID +MmMemLibInternalFreeMmramRanges ( + VOID + ) +{ + if (mMmMemLibInternalMmramRanges != NULL) { + FreePool (mMmMemLibInternalMmramRanges); + } +} + diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.c new file mode 100644 index 00000000..2ee32dc4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.c @@ -0,0 +1,815 @@ +/** @file + Support routines for memory allocation routines based on Standalone MM Core internal functions. + + Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> + Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/MmServicesTableLib.h> + +/** + Allocates one or more 4KB pages of a certain memory type. + + Allocates the number of 4KB pages of a certain memory type and returns a pointer to the allocated + buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL is returned. + If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param MemoryType The type of memory to allocate. + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocatePages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + + if (Pages == 0) { + return NULL; + } + + Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + return (VOID *)(UINTN)Memory; +} + +/** + Allocates one or more 4KB pages of type EfiBootServicesData. + + Allocates the number of 4KB pages of type EfiBootServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePages ( + IN UINTN Pages + ) +{ + return InternalAllocatePages (EfiRuntimeServicesData, Pages); +} + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData. + + Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimePages ( + IN UINTN Pages + ) +{ + return InternalAllocatePages (EfiRuntimeServicesData, Pages); +} + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType. + + Allocates the number of 4KB pages of type EfiReservedMemoryType and returns a pointer to the + allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL + is returned. If there is not enough memory remaining to satisfy the request, then NULL is + returned. + + @param Pages The number of 4 KB pages to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedPages ( + IN UINTN Pages + ) +{ + return NULL; +} + +/** + Frees one or more 4KB pages that were previously allocated with one of the page allocation + functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the page allocation services of the Memory + Allocation Library. If it is not possible to free allocated pages, then this function will + perform no actions. + + If Buffer was not allocated with a page allocation function in the Memory Allocation Library, + then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer Pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreePages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + EFI_STATUS Status; + + ASSERT (Pages != 0); + Status = gMmst->MmFreePages ((EFI_PHYSICAL_ADDRESS) (UINTN)Buffer, Pages); + ASSERT_EFI_ERROR (Status); +} + +/** + Allocates one or more 4KB pages of a certain memory type at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of a certain memory type with an alignment + specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is returned. + If there is not enough memory at the specified alignment remaining to satisfy the request, then + NULL is returned. + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param MemoryType The type of memory to allocate. + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocateAlignedPages ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN Pages, + IN UINTN Alignment + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Memory; + UINTN AlignedMemory; + UINTN AlignmentMask; + UINTN UnalignedPages; + UINTN RealPages; + + // + // Alignment must be a power of two or zero. + // + ASSERT ((Alignment & (Alignment - 1)) == 0); + + if (Pages == 0) { + return NULL; + } + if (Alignment > EFI_PAGE_SIZE) { + // + // Calculate the total number of pages since alignment is larger than page size. + // + AlignmentMask = Alignment - 1; + RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment); + // + // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow. + // + ASSERT (RealPages > Pages); + + Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, RealPages, &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask; + UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory); + if (UnalignedPages > 0) { + // + // Free first unaligned page(s). + // + Status = gMmst->MmFreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + Memory = (EFI_PHYSICAL_ADDRESS)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages)); + UnalignedPages = RealPages - Pages - UnalignedPages; + if (UnalignedPages > 0) { + // + // Free last unaligned page(s). + // + Status = gMmst->MmFreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + } else { + // + // Do not over-allocate pages in this case. + // + Status = gMmst->MmAllocatePages (AllocateAnyPages, MemoryType, Pages, &Memory); + if (EFI_ERROR (Status)) { + return NULL; + } + AlignedMemory = (UINTN) Memory; + } + return (VOID *) AlignedMemory; +} + +/** + Allocates one or more 4KB pages of type EfiBootServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiBootServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment); +} + +/** + Allocates one or more 4KB pages of type EfiRuntimeServicesData at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiRuntimeServicesData with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedRuntimePages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return InternalAllocateAlignedPages (EfiRuntimeServicesData, Pages, Alignment); +} + +/** + Allocates one or more 4KB pages of type EfiReservedMemoryType at a specified alignment. + + Allocates the number of 4KB pages specified by Pages of type EfiReservedMemoryType with an + alignment specified by Alignment. The allocated buffer is returned. If Pages is 0, then NULL is + returned. If there is not enough memory at the specified alignment remaining to satisfy the + request, then NULL is returned. + + If Alignment is not a power of two and Alignment is not zero, then ASSERT(). + If Pages plus EFI_SIZE_TO_PAGES (Alignment) overflows, then ASSERT(). + + @param Pages The number of 4 KB pages to allocate. + @param Alignment The requested alignment of the allocation. Must be a power of two. + If Alignment is zero, then byte alignment is used. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateAlignedReservedPages ( + IN UINTN Pages, + IN UINTN Alignment + ) +{ + return NULL; +} + +/** + Frees one or more 4KB pages that were previously allocated with one of the aligned page + allocation functions in the Memory Allocation Library. + + Frees the number of 4KB pages specified by Pages from the buffer specified by Buffer. Buffer + must have been allocated on a previous call to the aligned page allocation services of the Memory + Allocation Library. If it is not possible to free allocated pages, then this function will + perform no actions. + + If Buffer was not allocated with an aligned page allocation function in the Memory Allocation + Library, then ASSERT(). + If Pages is zero, then ASSERT(). + + @param Buffer Pointer to the buffer of pages to free. + @param Pages The number of 4 KB pages to free. + +**/ +VOID +EFIAPI +FreeAlignedPages ( + IN VOID *Buffer, + IN UINTN Pages + ) +{ + EFI_STATUS Status; + + ASSERT (Pages != 0); + Status = gMmst->MmFreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Pages); + ASSERT_EFI_ERROR (Status); +} + +/** + Allocates a buffer of a certain pool type. + + Allocates the number bytes specified by AllocationSize of a certain pool type and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param MemoryType The type of memory to allocate. + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocatePool ( + IN EFI_MEMORY_TYPE MemoryType, + IN UINTN AllocationSize + ) +{ + EFI_STATUS Status; + VOID *Memory; + + Memory = NULL; + + Status = gMmst->MmAllocatePool (MemoryType, AllocationSize, &Memory); + if (EFI_ERROR (Status)) { + Memory = NULL; + } + return Memory; +} + +/** + Allocates a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData and returns a + pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocatePool ( + IN UINTN AllocationSize + ) +{ + return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize); +} + +/** + Allocates a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimePool ( + IN UINTN AllocationSize + ) +{ + return InternalAllocatePool (EfiRuntimeServicesData, AllocationSize); +} + +/** + Allocates a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType and returns + a pointer to the allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is + returned. If there is not enough memory remaining to satisfy the request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedPool ( + IN UINTN AllocationSize + ) +{ + return NULL; +} + +/** + Allocates and zeros a buffer of a certain pool type. + + Allocates the number bytes specified by AllocationSize of a certain pool type, clears the buffer + with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a valid + buffer of 0 size is returned. If there is not enough memory remaining to satisfy the request, + then NULL is returned. + + @param PoolType The type of memory to allocate. + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocateZeroPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize + ) +{ + VOID *Memory; + + Memory = InternalAllocatePool (PoolType, AllocationSize); + if (Memory != NULL) { + Memory = ZeroMem (Memory, AllocationSize); + } + return Memory; +} + +/** + Allocates and zeros a buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateZeroPool ( + IN UINTN AllocationSize + ) +{ + return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize); +} + +/** + Allocates and zeros a buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimeZeroPool ( + IN UINTN AllocationSize + ) +{ + return InternalAllocateZeroPool (EfiRuntimeServicesData, AllocationSize); +} + +/** + Allocates and zeros a buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, clears the + buffer with zeros, and returns a pointer to the allocated buffer. If AllocationSize is 0, then a + valid buffer of 0 size is returned. If there is not enough memory remaining to satisfy the + request, then NULL is returned. + + @param AllocationSize The number of bytes to allocate and zero. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedZeroPool ( + IN UINTN AllocationSize + ) +{ + return NULL; +} + +/** + Copies a buffer to an allocated buffer of a certain pool type. + + Allocates the number bytes specified by AllocationSize of a certain pool type, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param PoolType The type of pool to allocate. + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalAllocateCopyPool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + VOID *Memory; + + ASSERT (Buffer != NULL); + ASSERT (AllocationSize <= (MAX_ADDRESS - (UINTN) Buffer + 1)); + + Memory = InternalAllocatePool (PoolType, AllocationSize); + if (Memory != NULL) { + Memory = CopyMem (Memory, Buffer, AllocationSize); + } + return Memory; +} + +/** + Copies a buffer to an allocated buffer of type EfiBootServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiBootServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer); +} + +/** + Copies a buffer to an allocated buffer of type EfiRuntimeServicesData. + + Allocates the number bytes specified by AllocationSize of type EfiRuntimeServicesData, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateRuntimeCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer); +} + +/** + Copies a buffer to an allocated buffer of type EfiReservedMemoryType. + + Allocates the number bytes specified by AllocationSize of type EfiReservedMemoryType, copies + AllocationSize bytes from Buffer to the newly allocated buffer, and returns a pointer to the + allocated buffer. If AllocationSize is 0, then a valid buffer of 0 size is returned. If there + is not enough memory remaining to satisfy the request, then NULL is returned. + + If Buffer is NULL, then ASSERT(). + If AllocationSize is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT(). + + @param AllocationSize The number of bytes to allocate and zero. + @param Buffer The buffer to copy to the allocated buffer. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +AllocateReservedCopyPool ( + IN UINTN AllocationSize, + IN CONST VOID *Buffer + ) +{ + return NULL; +} + +/** + Reallocates a buffer of a specified memory type. + + Allocates and zeros the number bytes specified by NewSize from memory of the type + specified by PoolType. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param PoolType The type of pool to allocate. + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +InternalReallocatePool ( + IN EFI_MEMORY_TYPE PoolType, + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + VOID *NewBuffer; + + NewBuffer = InternalAllocateZeroPool (PoolType, NewSize); + if (NewBuffer != NULL && OldBuffer != NULL) { + CopyMem (NewBuffer, OldBuffer, MIN (OldSize, NewSize)); + FreePool (OldBuffer); + } + return NewBuffer; +} + +/** + Reallocates a buffer of type EfiBootServicesData. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiBootServicesData. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocatePool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer); +} + +/** + Reallocates a buffer of type EfiRuntimeServicesData. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiRuntimeServicesData. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocateRuntimePool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return InternalReallocatePool (EfiRuntimeServicesData, OldSize, NewSize, OldBuffer); +} + +/** + Reallocates a buffer of type EfiReservedMemoryType. + + Allocates and zeros the number bytes specified by NewSize from memory of type + EfiReservedMemoryType. If OldBuffer is not NULL, then the smaller of OldSize and + NewSize bytes are copied from OldBuffer to the newly allocated buffer, and + OldBuffer is freed. A pointer to the newly allocated buffer is returned. + If NewSize is 0, then a valid buffer of 0 size is returned. If there is not + enough memory remaining to satisfy the request, then NULL is returned. + + If the allocation of the new buffer is successful and the smaller of NewSize and OldSize + is greater than (MAX_ADDRESS - OldBuffer + 1), then ASSERT(). + + @param OldSize The size, in bytes, of OldBuffer. + @param NewSize The size, in bytes, of the buffer to reallocate. + @param OldBuffer The buffer to copy to the allocated buffer. This is an optional + parameter that may be NULL. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +EFIAPI +ReallocateReservedPool ( + IN UINTN OldSize, + IN UINTN NewSize, + IN VOID *OldBuffer OPTIONAL + ) +{ + return NULL; +} + +/** + Frees a buffer that was previously allocated with one of the pool allocation functions in the + Memory Allocation Library. + + Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the + pool allocation services of the Memory Allocation Library. If it is not possible to free pool + resources, then this function will perform no actions. + + If Buffer was not allocated with a pool allocation function in the Memory Allocation Library, + then ASSERT(). + + @param Buffer Pointer to the buffer to free. + +**/ +VOID +EFIAPI +FreePool ( + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + + Status = gMmst->MmFreePool (Buffer); + ASSERT_EFI_ERROR (Status); +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf new file mode 100644 index 00000000..51fce073 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmMemoryAllocationLib/StandaloneMmMemoryAllocationLib.inf @@ -0,0 +1,37 @@ +## @file +# Memory Allocation Library instance standalone MM modules. +# +# Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.<BR> +# Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = MemoryAllocationLib + FILE_GUID = 54646378-A9DC-473F-9BE1-BD027C4C76DE + MODULE_TYPE = MM_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + LIBRARY_CLASS = MemoryAllocationLib|MM_STANDALONE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + StandaloneMmMemoryAllocationLib.c + +[Packages] + MdePkg/MdePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MmServicesTableLib diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c new file mode 100644 index 00000000..2db7551d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/AArch64/StandaloneMmPeCoffExtraActionLib.c @@ -0,0 +1,211 @@ +/**@file + +Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR> +Portions copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR> +Portions copyright (c) 2011 - 2018, ARM Ltd. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Library/ArmMmuLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/PeCoffLib.h> +#include <Library/PeCoffExtraActionLib.h> + +typedef RETURN_STATUS (*REGION_PERMISSION_UPDATE_FUNC) ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length + ); + +STATIC +RETURN_STATUS +UpdatePeCoffPermissions ( + IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN REGION_PERMISSION_UPDATE_FUNC NoExecUpdater, + IN REGION_PERMISSION_UPDATE_FUNC ReadOnlyUpdater + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData; + UINTN Size; + UINTN ReadSize; + UINT32 SectionHeaderOffset; + UINTN NumberOfSections; + UINTN Index; + EFI_IMAGE_SECTION_HEADER SectionHeader; + PE_COFF_LOADER_IMAGE_CONTEXT TmpContext; + EFI_PHYSICAL_ADDRESS Base; + + // + // We need to copy ImageContext since PeCoffLoaderGetImageInfo () + // will mangle the ImageAddress field + // + CopyMem (&TmpContext, ImageContext, sizeof (TmpContext)); + + if (TmpContext.PeCoffHeaderOffset == 0) { + Status = PeCoffLoaderGetImageInfo (&TmpContext); + if (RETURN_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "%a: PeCoffLoaderGetImageInfo () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + } + + if (TmpContext.IsTeImage && + TmpContext.ImageAddress == ImageContext->ImageAddress) { + DEBUG ((DEBUG_INFO, "%a: ignoring XIP TE image at 0x%lx\n", __FUNCTION__, + ImageContext->ImageAddress)); + return RETURN_SUCCESS; + } + + if (TmpContext.SectionAlignment < EFI_PAGE_SIZE) { + // + // The sections need to be at least 4 KB aligned, since that is the + // granularity at which we can tighten permissions. So just clear the + // noexec permissions on the entire region. + // + if (!TmpContext.IsTeImage) { + DEBUG ((DEBUG_WARN, + "%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n", + __FUNCTION__, ImageContext->ImageAddress, TmpContext.SectionAlignment)); + } + Base = ImageContext->ImageAddress & ~(EFI_PAGE_SIZE - 1); + Size = ImageContext->ImageAddress - Base + ImageContext->ImageSize; + return NoExecUpdater (Base, ALIGN_VALUE (Size, EFI_PAGE_SIZE)); + } + + // + // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much + // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic + // determines if this is a PE32 or PE32+ image. The magic is in the same + // location in both images. + // + Hdr.Union = &HdrData; + Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION); + ReadSize = Size; + Status = TmpContext.ImageRead (TmpContext.Handle, + TmpContext.PeCoffHeaderOffset, &Size, Hdr.Pe32); + if (RETURN_ERROR (Status) || (Size != ReadSize)) { + DEBUG ((DEBUG_ERROR, + "%a: TmpContext.ImageRead () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + + ASSERT (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE); + + SectionHeaderOffset = TmpContext.PeCoffHeaderOffset + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER); + NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections); + + switch (Hdr.Pe32->OptionalHeader.Magic) { + case EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC: + SectionHeaderOffset += Hdr.Pe32->FileHeader.SizeOfOptionalHeader; + break; + case EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC: + SectionHeaderOffset += Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader; + break; + default: + ASSERT (FALSE); + } + + // + // Iterate over the sections + // + for (Index = 0; Index < NumberOfSections; Index++) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + ReadSize = Size; + Status = TmpContext.ImageRead (TmpContext.Handle, SectionHeaderOffset, + &Size, &SectionHeader); + if (RETURN_ERROR (Status) || (Size != ReadSize)) { + DEBUG ((DEBUG_ERROR, + "%a: TmpContext.ImageRead () failed (Status = %r)\n", + __FUNCTION__, Status)); + return Status; + } + + Base = TmpContext.ImageAddress + SectionHeader.VirtualAddress; + + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_EXECUTE) == 0) { + + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_MEM_WRITE) == 0) { + + DEBUG ((DEBUG_INFO, + "%a: Mapping section %d of image at 0x%lx with RO-XN permissions and size 0x%x\n", + __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize)); + ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize); + } else { + DEBUG ((DEBUG_WARN, + "%a: Mapping section %d of image at 0x%lx with RW-XN permissions and size 0x%x\n", + __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize)); + } + } else { + DEBUG ((DEBUG_INFO, + "%a: Mapping section %d of image at 0x%lx with RO-X permissions and size 0x%x\n", + __FUNCTION__, Index, Base, SectionHeader.Misc.VirtualSize)); + ReadOnlyUpdater (Base, SectionHeader.Misc.VirtualSize); + NoExecUpdater (Base, SectionHeader.Misc.VirtualSize); + } + + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + return RETURN_SUCCESS; +} + +/** + Performs additional actions after a PE/COFF image has been loaded and relocated. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that has already been loaded and relocated. + +**/ +VOID +EFIAPI +PeCoffLoaderRelocateImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UpdatePeCoffPermissions ( + ImageContext, + ArmClearMemoryRegionNoExec, + ArmSetMemoryRegionReadOnly + ); +} + + + +/** + Performs additional actions just before a PE/COFF image is unloaded. Any resources + that were allocated by PeCoffLoaderRelocateImageExtraAction() must be freed. + + If ImageContext is NULL, then ASSERT(). + + @param ImageContext Pointer to the image context structure that describes the + PE/COFF image that is being unloaded. + +**/ +VOID +EFIAPI +PeCoffLoaderUnloadImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UpdatePeCoffPermissions ( + ImageContext, + ArmSetMemoryRegionNoExec, + ArmClearMemoryRegionReadOnly + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf new file mode 100644 index 00000000..0b4a4509 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmPeCoffExtraActionLib/StandaloneMmPeCoffExtraActionLib.inf @@ -0,0 +1,36 @@ +#/** @file +# PeCoff extra action library for DXE phase that run Unix emulator. +# +# Lib to provide memory journal status code reporting Routines +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +# Portions copyright (c) 2010, Apple Inc. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +#**/ + +[Defines] + INF_VERSION = 0x0001000A + BASE_NAME = StandaloneMmPeCoffExtraActionLib + FILE_GUID = 8B40543B-9588-48F8-840C-5A60E6DB1B03 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PeCoffExtraActionLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = ARM +# + +[Sources.common] + AArch64/StandaloneMmPeCoffExtraActionLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[LibraryClasses] + StandaloneMmMmuLib + PcdLib diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.c b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.c new file mode 100644 index 00000000..b09cfd24 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.c @@ -0,0 +1,47 @@ +/** @file + Runtime DXE part corresponding to StandaloneMM variable module. + +This module installs variable arch protocol and variable write arch protocol +to StandaloneMM runtime variable service. + +Copyright (c) 2019 - 2021, Arm Ltd. All rights reserved. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> + +/** + The constructor function installs variable arch protocol and variable + write arch protocol to StandaloneMM runtime variable service + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the Management mode System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +VariableMmDependencyLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiSmmVariableProtocolGuid, + NULL, + &gSmmVariableWriteGuid, + NULL, + NULL + ); + ASSERT_EFI_ERROR (Status); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf new file mode 100644 index 00000000..7e23987f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/VariableMmDependency/VariableMmDependency.inf @@ -0,0 +1,41 @@ +## @file +# Runtime DXE part corresponding to StandaloneMM variable module. +# +# This module installs variable arch protocol and variable write arch protocol +# to StandaloneMM runtime variable service. +# +# Copyright (c) 2019 - 2021, Arm Ltd. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = VariableMmDependency + FILE_GUID = 64BC4129-778E-4867-BA07-13999A4DEC3F + MODULE_TYPE = DXE_DRIVER + LIBRARY_CLASS = NULL + CONSTRUCTOR = VariableMmDependencyLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = AARCH64 +# +# + +[Sources] + VariableMmDependency.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[Protocols] + gEfiSmmVariableProtocolGuid ## PRODUCES + +[Guids] + gSmmVariableWriteGuid ## PRODUCES ## GUID # Install protocol + +[Depex] + TRUE |