mirror of
https://github.com/acidanthera/audk.git
synced 2025-09-03 07:58:11 +02:00
StandaloneMm has its own version of the ArmMmuLib library class, but includes the ArmMmuLib header. This happens to work because the prototypes that are referenced are the same, but this will no longer be the case after a future patch. So correct the #includes. Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com>
251 lines
7.5 KiB
C
251 lines
7.5 KiB
C
/**@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/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/PeCoffLib.h>
|
|
#include <Library/PeCoffExtraActionLib.h>
|
|
#include <Library/StandaloneMmMmuLib.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",
|
|
__func__,
|
|
Status
|
|
));
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if (TmpContext.IsTeImage &&
|
|
(TmpContext.ImageAddress == ImageContext->ImageAddress))
|
|
{
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: ignoring XIP TE image at 0x%lx\n",
|
|
__func__,
|
|
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",
|
|
__func__,
|
|
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",
|
|
__func__,
|
|
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",
|
|
__func__,
|
|
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",
|
|
__func__,
|
|
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",
|
|
__func__,
|
|
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",
|
|
__func__,
|
|
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
|
|
);
|
|
}
|