]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/CompatImageLoaderDxe/CompatImageLoaderDxe.c
OvmfPkg IA32: add support for loading X64 images
[mirror_edk2.git] / OvmfPkg / CompatImageLoaderDxe / CompatImageLoaderDxe.c
1 /** @file
2 * PE/COFF emulator protocol implementation to start Linux kernel
3 * images from non-native firmware
4 *
5 * Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>
6 *
7 * SPDX-License-Identifier: BSD-2-Clause-Patent
8 *
9 */
10
11 #include <PiDxe.h>
12
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/PeCoffLib.h>
16 #include <Library/UefiBootServicesTableLib.h>
17
18 #include <Protocol/PeCoffImageEmulator.h>
19
20 #pragma pack (1)
21 typedef struct {
22 UINT8 Type;
23 UINT8 Size;
24 UINT16 MachineType;
25 UINT32 EntryPoint;
26 } PE_COMPAT_TYPE1;
27 #pragma pack ()
28
29 STATIC
30 BOOLEAN
31 EFIAPI
32 IsImageSupported (
33 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
34 IN UINT16 ImageType,
35 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
36 )
37 {
38 return ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
39 }
40
41 STATIC
42 EFI_IMAGE_ENTRY_POINT
43 EFIAPI
44 GetCompatEntryPoint (
45 IN EFI_PHYSICAL_ADDRESS ImageBase
46 )
47 {
48 EFI_IMAGE_DOS_HEADER *DosHdr;
49 UINTN PeCoffHeaderOffset;
50 EFI_IMAGE_NT_HEADERS32 *Pe32;
51 EFI_IMAGE_SECTION_HEADER *Section;
52 UINTN NumberOfSections;
53 PE_COMPAT_TYPE1 *PeCompat;
54 UINTN PeCompatEnd;
55
56 DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageBase;
57 if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
58 return NULL;
59 }
60
61 PeCoffHeaderOffset = DosHdr->e_lfanew;
62 Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageBase + PeCoffHeaderOffset);
63
64 Section = (EFI_IMAGE_SECTION_HEADER *)((UINTN)&Pe32->OptionalHeader +
65 Pe32->FileHeader.SizeOfOptionalHeader);
66 NumberOfSections = (UINTN)Pe32->FileHeader.NumberOfSections;
67
68 while (NumberOfSections--) {
69 if (!CompareMem (Section->Name, ".compat", sizeof (Section->Name))) {
70 //
71 // Dereference the section contents to find the mixed mode entry point
72 //
73 PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)ImageBase + Section->VirtualAddress);
74 PeCompatEnd = (UINTN)(VOID *)PeCompat + Section->Misc.VirtualSize;
75
76 while (PeCompat->Type != 0 && (UINTN)(VOID *)PeCompat < PeCompatEnd) {
77 if (PeCompat->Type == 1 &&
78 PeCompat->Size >= sizeof (PE_COMPAT_TYPE1) &&
79 EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCompat->MachineType)) {
80
81 return (EFI_IMAGE_ENTRY_POINT)((UINTN)ImageBase + PeCompat->EntryPoint);
82 }
83 PeCompat = (PE_COMPAT_TYPE1 *)((UINTN)PeCompat + PeCompat->Size);
84 ASSERT ((UINTN)(VOID *)PeCompat < PeCompatEnd);
85 }
86 }
87 Section++;
88 }
89 return NULL;
90 }
91
92 STATIC
93 EFI_STATUS
94 EFIAPI
95 RegisterImage (
96 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
97 IN EFI_PHYSICAL_ADDRESS ImageBase,
98 IN UINT64 ImageSize,
99 IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
100 )
101 {
102 EFI_IMAGE_ENTRY_POINT CompatEntryPoint;
103
104 CompatEntryPoint = GetCompatEntryPoint (ImageBase);
105 if (CompatEntryPoint == NULL) {
106 return EFI_UNSUPPORTED;
107 }
108
109 *EntryPoint = CompatEntryPoint;
110 return EFI_SUCCESS;
111 }
112
113 STATIC
114 EFI_STATUS
115 EFIAPI
116 UnregisterImage (
117 IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
118 IN EFI_PHYSICAL_ADDRESS ImageBase
119 )
120 {
121 return EFI_SUCCESS;
122 }
123
124 STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mCompatLoaderPeCoffEmuProtocol = {
125 IsImageSupported,
126 RegisterImage,
127 UnregisterImage,
128 EDKII_PECOFF_IMAGE_EMULATOR_VERSION,
129 EFI_IMAGE_MACHINE_X64
130 };
131
132 EFI_STATUS
133 EFIAPI
134 CompatImageLoaderDxeEntryPoint (
135 IN EFI_HANDLE ImageHandle,
136 IN EFI_SYSTEM_TABLE *SystemTable
137 )
138 {
139 return gBS->InstallProtocolInterface (&ImageHandle,
140 &gEdkiiPeCoffImageEmulatorProtocolGuid,
141 EFI_NATIVE_INTERFACE,
142 &mCompatLoaderPeCoffEmuProtocol);
143 }