123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- /** @file
- * PE/COFF emulator protocol implementation to start Linux kernel
- * images from non-native firmware
- *
- * Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
- *
- * SPDX-License-Identifier: BSD-2-Clause-Patent
- *
- */
- #include <PiDxe.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/DebugLib.h>
- #include <Library/PeCoffLib.h>
- #include <Library/UefiBootServicesTableLib.h>
- #include <Protocol/PeCoffImageEmulator.h>
- #pragma pack (1)
- typedef struct {
- UINT8 Type;
- UINT8 Size;
- UINT16 MachineType;
- UINT32 EntryPoint;
- } PE_COMPAT_TYPE1;
- #pragma pack ()
- STATIC
- BOOLEAN
- EFIAPI
- IsImageSupported (
- IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
- IN UINT16 ImageType,
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
- )
- {
- return ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
- }
- STATIC
- EFI_IMAGE_ENTRY_POINT
- EFIAPI
- GetCompatEntryPoint (
- IN EFI_PHYSICAL_ADDRESS ImageBase
- )
- {
- EFI_IMAGE_DOS_HEADER *DosHdr;
- UINTN PeCoffHeaderOffset;
- EFI_IMAGE_NT_HEADERS32 *Pe32;
- EFI_IMAGE_SECTION_HEADER *Section;
- UINTN NumberOfSections;
- PE_COMPAT_TYPE1 *PeCompat;
- UINTN PeCompatEnd;
- DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase;
- if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
- return NULL;
- }
- PeCoffHeaderOffset = DosHdr->e_lfanew;
- Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageBase + PeCoffHeaderOffset);
- Section = (EFI_IMAGE_SECTION_HEADER *)((UINTN)&Pe32->OptionalHeader +
- Pe32->FileHeader.SizeOfOptionalHeader);
- NumberOfSections = (UINTN)Pe32->FileHeader.NumberOfSections;
- while (NumberOfSections--) {
- if (!CompareMem (Section->Name, ".compat", sizeof (Section->Name))) {
- //
- // Dereference the section contents to find the mixed mode entry point
- //
- PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)ImageBase + Section->VirtualAddress);
- PeCompatEnd = (UINTN)(VOID *)PeCompat + Section->Misc.VirtualSize;
- while (PeCompat->Type != 0 && (UINTN)(VOID *)PeCompat < PeCompatEnd) {
- if ((PeCompat->Type == 1) &&
- (PeCompat->Size >= sizeof (PE_COMPAT_TYPE1)) &&
- EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCompat->MachineType))
- {
- return (EFI_IMAGE_ENTRY_POINT)((UINTN)ImageBase + PeCompat->EntryPoint);
- }
- PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)PeCompat + PeCompat->Size);
- ASSERT ((UINTN)(VOID *)PeCompat < PeCompatEnd);
- }
- }
- Section++;
- }
- return NULL;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- RegisterImage (
- IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS ImageBase,
- IN UINT64 ImageSize,
- IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
- )
- {
- EFI_IMAGE_ENTRY_POINT CompatEntryPoint;
- CompatEntryPoint = GetCompatEntryPoint (ImageBase);
- if (CompatEntryPoint == NULL) {
- return EFI_UNSUPPORTED;
- }
- *EntryPoint = CompatEntryPoint;
- return EFI_SUCCESS;
- }
- STATIC
- EFI_STATUS
- EFIAPI
- UnregisterImage (
- IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS ImageBase
- )
- {
- return EFI_SUCCESS;
- }
- STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mCompatLoaderPeCoffEmuProtocol = {
- IsImageSupported,
- RegisterImage,
- UnregisterImage,
- EDKII_PECOFF_IMAGE_EMULATOR_VERSION,
- EFI_IMAGE_MACHINE_X64
- };
- EFI_STATUS
- EFIAPI
- CompatImageLoaderDxeEntryPoint (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- return gBS->InstallProtocolInterface (
- &ImageHandle,
- &gEdkiiPeCoffImageEmulatorProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &mCompatLoaderPeCoffEmuProtocol
- );
- }
|