StandaloneMmPkg: Add an AArch64 specific entry point library.

The Standalone MM environment runs in S-EL0 in AArch64 on ARM Standard
Platforms and is initialised during the SEC phase. ARM Trusted firmware
in EL3 is responsible for initialising the architectural context for
S-EL0 and loading the Standalone MM image. The memory allocated to this
image is marked as RO+X. Heap memory is marked as RW+XN.

Certain actions have to be completed prior to executing the generic code
in the Standalone MM Core module. These are:

1. Memory permission attributes for each section of the Standalone MM
   Core module need to be changed prior to accessing any RW data.

2. A Hob list has to be created with information that allows the MM
   environment to initialise and dispatch drivers.

Furthermore, this module is responsible for handing over runtime MM
events to the Standalone MM CPU driver and returning control to ARM
Trusted Firmware upon event completion. Hence it needs to know the CPU
driver entry point.

This patch implements an entry point module that ARM Trusted Firmware
jumps to in S-EL0. It then performs the above actions before calling the
Standalone MM Foundation entry point and handling subsequent MM events.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Sughosh Ganu <sughosh.ganu@arm.com>
Signed-off-by: Achin Gupta <achin.gupta@arm.com>
Signed-off-by: Supreeth Venkatesh <supreeth.venkatesh@arm.com>
Reviewed-by: Achin Gupta <achin.gupta@arm.com>
This commit is contained in:
Supreeth Venkatesh
2018-07-13 23:05:28 +08:00
committed by Jiewen Yao
parent 6b46d77243
commit 184558d072
5 changed files with 1074 additions and 0 deletions

View File

@@ -0,0 +1,289 @@
/** @file
Locate, get and update PE/COFF permissions during Standalone MM
Foundation Entry point on ARM platforms.
Copyright (c) 2017 - 2018, ARM Ltd. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php.
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#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>
EFI_STATUS
EFIAPI
UpdateMmFoundationPeCoffPermissions (
IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
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 %s 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 = ImageContext->ImageAddress + 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;
}
EFI_STATUS
EFIAPI
LocateStandaloneMmCorePeCoffData (
IN EFI_FIRMWARE_VOLUME_HEADER *BfvAddress,
IN OUT VOID **TeData,
IN OUT UINTN *TeDataSize
)
{
EFI_FFS_FILE_HEADER *FileHeader = NULL;
EFI_STATUS Status;
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)) {
DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Section data - 0x%x\n",
Status));
return Status;
}
DEBUG ((DEBUG_INFO, "Found Standalone MM PE data - 0x%x\n", *TeData));
return Status;
}
STATIC
EFI_STATUS
GetPeCoffSectionInformation (
IN CONST PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *TmpContext,
IN OUT UINT32 *SectionHeaderOffset,
IN 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 (TmpContext != NULL);
ASSERT (SectionHeaderOffset != NULL);
ASSERT (NumberOfSections != NULL);
//
// 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_UNSUPPORTED;
}
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.
//
if (!TmpContext->IsTeImage) {
DEBUG ((DEBUG_WARN,
"%a: non-TE Image at 0x%lx has SectionAlignment < 4 KB (%lu)\n",
__FUNCTION__, ImageContext->ImageAddress, TmpContext->SectionAlignment));
}
return RETURN_UNSUPPORTED;
}
//
// 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 = 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);
}
return RETURN_SUCCESS;
}
EFI_STATUS
EFIAPI
GetStandaloneMmCorePeCoffSections (
IN VOID *TeData,
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
IN OUT UINT32 *SectionHeaderOffset,
IN OUT UINT16 *NumberOfSections
)
{
EFI_STATUS Status;
PE_COFF_LOADER_IMAGE_CONTEXT TmpContext;
// 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 = PeCoffLoaderGetImageInfo (ImageContext);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Image information - 0x%x\n", Status));
return Status;
}
Status = GetPeCoffSectionInformation (ImageContext, &TmpContext, SectionHeaderOffset, NumberOfSections);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Unable to locate Standalone MM Core PE-COFF Section information - 0x%x\n", Status));
return Status;
}
DEBUG ((DEBUG_INFO, "Standalone MM Core PE-COFF SectionHeaderOffset - 0x%x, NumberOfSections - %d\n",
*SectionHeaderOffset, *NumberOfSections));
return Status;
}