diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint')
5 files changed, 1069 insertions, 0 deletions
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); +} |