VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/PrmPkg/Library/DxePrmPeCoffLib/DxePrmPeCoffLib.c

Last change on this file was 101291, checked in by vboxsync, 20 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

  • Property svn:eol-style set to native
File size: 16.7 KB
Line 
1/** @file
2
3 This file contains implementation for additional PE/COFF functionality needed to use
4 Platform Runtime Mechanism (PRM) modules.
5
6 Copyright (c) Microsoft Corporation
7 Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10**/
11
12#include <IndustryStandard/PeImage.h>
13#include <Library/BaseLib.h>
14#include <Library/DebugLib.h>
15#include <Library/PeCoffLib.h>
16
17#include <PrmExportDescriptor.h>
18#include <PrmModuleImageContext.h>
19
20#define _DBGMSGID_ "[PRMPECOFFLIB]"
21
22/**
23 Gets a pointer to the export directory in a given PE/COFF image.
24
25 @param[in] ImageExportDirectory A pointer to an export directory table in a PE/COFF image.
26 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
27 PE/COFF image context for the Image containing the PRM Module Export
28 Descriptor table.
29 @param[out] ExportDescriptor A pointer to a pointer to the PRM Module Export Descriptor table found
30 in the ImageExportDirectory given.
31
32 @retval EFI_SUCCESS The PRM Module Export Descriptor table was found successfully.
33 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
34 @retval EFI_NOT_FOUND The PRM Module Export Descriptor table was not found in the given
35 ImageExportDirectory.
36
37**/
38EFI_STATUS
39GetPrmModuleExportDescriptorTable (
40 IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,
41 IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,
42 OUT PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT **ExportDescriptor
43 )
44{
45 UINTN Index;
46 EFI_PHYSICAL_ADDRESS CurrentImageAddress;
47 UINT16 PrmModuleExportDescriptorOrdinal;
48 CONST CHAR8 *CurrentExportName;
49 UINT16 *OrdinalTable;
50 UINT32 *ExportNamePointerTable;
51 UINT32 *ExportAddressTable;
52 PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *TempExportDescriptor;
53
54 DEBUG ((DEBUG_INFO, "%a %a - Entry.\n", _DBGMSGID_, __func__));
55
56 if ((ImageExportDirectory == NULL) ||
57 (PeCoffLoaderImageContext == NULL) ||
58 (PeCoffLoaderImageContext->ImageAddress == 0) ||
59 (ExportDescriptor == NULL))
60 {
61 return EFI_INVALID_PARAMETER;
62 }
63
64 *ExportDescriptor = NULL;
65
66 DEBUG ((
67 DEBUG_INFO,
68 " %a %a: %d exported names found in this image.\n",
69 _DBGMSGID_,
70 __func__,
71 ImageExportDirectory->NumberOfNames
72 ));
73
74 //
75 // The export name pointer table and export ordinal table form two parallel arrays associated by index.
76 //
77 CurrentImageAddress = PeCoffLoaderImageContext->ImageAddress;
78 ExportAddressTable = (UINT32 *)((UINTN)CurrentImageAddress + ImageExportDirectory->AddressOfFunctions);
79 ExportNamePointerTable = (UINT32 *)((UINTN)CurrentImageAddress + ImageExportDirectory->AddressOfNames);
80 OrdinalTable = (UINT16 *)((UINTN)CurrentImageAddress + ImageExportDirectory->AddressOfNameOrdinals);
81
82 for (Index = 0; Index < ImageExportDirectory->NumberOfNames; Index++) {
83 CurrentExportName = (CONST CHAR8 *)((UINTN)CurrentImageAddress + ExportNamePointerTable[Index]);
84 DEBUG ((
85 DEBUG_INFO,
86 " %a %a: Export Name[0x%x] - %a.\n",
87 _DBGMSGID_,
88 __func__,
89 Index,
90 CurrentExportName
91 ));
92 if (
93 AsciiStrnCmp (
94 PRM_STRING (PRM_MODULE_EXPORT_DESCRIPTOR_NAME),
95 CurrentExportName,
96 AsciiStrLen (PRM_STRING (PRM_MODULE_EXPORT_DESCRIPTOR_NAME))
97 ) == 0)
98 {
99 PrmModuleExportDescriptorOrdinal = OrdinalTable[Index];
100 DEBUG ((
101 DEBUG_INFO,
102 " %a %a: PRM Module Export Descriptor found. Ordinal = %d.\n",
103 _DBGMSGID_,
104 __func__,
105 PrmModuleExportDescriptorOrdinal
106 ));
107 if (PrmModuleExportDescriptorOrdinal >= ImageExportDirectory->NumberOfFunctions) {
108 DEBUG ((DEBUG_ERROR, "%a %a: The PRM Module Export Descriptor ordinal value is invalid.\n", _DBGMSGID_, __func__));
109 return EFI_NOT_FOUND;
110 }
111
112 TempExportDescriptor = (PRM_MODULE_EXPORT_DESCRIPTOR_STRUCT *)((UINTN)CurrentImageAddress + ExportAddressTable[PrmModuleExportDescriptorOrdinal]);
113 if (TempExportDescriptor->Header.Signature == PRM_MODULE_EXPORT_DESCRIPTOR_SIGNATURE) {
114 *ExportDescriptor = TempExportDescriptor;
115 DEBUG ((DEBUG_INFO, " %a %a: PRM Module Export Descriptor found at 0x%x.\n", _DBGMSGID_, __func__, (UINTN)ExportDescriptor));
116 } else {
117 DEBUG ((
118 DEBUG_INFO,
119 " %a %a: PRM Module Export Descriptor found at 0x%x but signature check failed.\n",
120 _DBGMSGID_,
121 __func__,
122 (UINTN)TempExportDescriptor
123 ));
124 }
125
126 DEBUG ((DEBUG_INFO, " %a %a: Exiting export iteration since export descriptor found.\n", _DBGMSGID_, __func__));
127 return EFI_SUCCESS;
128 }
129 }
130
131 return EFI_NOT_FOUND;
132}
133
134/**
135 Gets a pointer to the export directory in a given PE/COFF image.
136
137 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory
138 and already relocated to the memory base address. RVAs in the image given
139 should be valid.
140 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
141 PE/COFF image context for the Image given.
142 @param[out] ImageExportDirectory A pointer to a pointer to the export directory found in the Image given.
143
144 @retval EFI_SUCCESS The export directory was found successfully.
145 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
146 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported as a PRM Module.
147 @retval EFI_NOT_FOUND The image export directory could not be found for this image.
148
149**/
150EFI_STATUS
151GetExportDirectoryInPeCoffImage (
152 IN VOID *Image,
153 IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,
154 OUT EFI_IMAGE_EXPORT_DIRECTORY **ImageExportDirectory
155 )
156{
157 UINT16 Magic;
158 UINT32 NumberOfRvaAndSizes;
159 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;
160 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
161 EFI_IMAGE_EXPORT_DIRECTORY *ExportDirectory;
162
163 if ((Image == NULL) || (PeCoffLoaderImageContext == NULL) || (ImageExportDirectory == NULL)) {
164 return EFI_INVALID_PARAMETER;
165 }
166
167 DirectoryEntry = NULL;
168 ExportDirectory = NULL;
169
170 //
171 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+
172 // image instead of using the Magic field. Some systems might generate a PE32+
173 // image with PE32 magic.
174 //
175 switch (PeCoffLoaderImageContext->Machine) {
176 case EFI_IMAGE_MACHINE_IA32:
177 //
178 // Assume PE32 image with IA32 Machine field.
179 //
180 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
181 break;
182 case EFI_IMAGE_MACHINE_X64:
183 case EFI_IMAGE_MACHINE_AARCH64:
184 //
185 // Assume PE32+ image with X64 Machine field
186 //
187 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
188 break;
189 default:
190 //
191 // For unknown Machine field, use Magic in optional header
192 //
193 DEBUG ((
194 DEBUG_WARN,
195 "%a %a: The machine type for this image is not valid for a PRM module.\n",
196 _DBGMSGID_,
197 __func__
198 ));
199 return EFI_UNSUPPORTED;
200 }
201
202 OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(
203 (UINTN)Image +
204 PeCoffLoaderImageContext->PeCoffHeaderOffset
205 );
206
207 //
208 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.
209 //
210 if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
211 DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __func__));
212 return EFI_UNSUPPORTED;
213 }
214
215 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
216 //
217 // Use the PE32 offset to get the Export Directory Entry
218 //
219 NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32->OptionalHeader.NumberOfRvaAndSizes;
220 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(OptionalHeaderPtrUnion.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);
221 } else if (OptionalHeaderPtrUnion.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
222 //
223 // Use the PE32+ offset get the Export Directory Entry
224 //
225 NumberOfRvaAndSizes = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
226 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXPORT]);
227 } else {
228 return EFI_UNSUPPORTED;
229 }
230
231 if ((NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_EXPORT) || (DirectoryEntry->VirtualAddress == 0)) {
232 //
233 // The export directory is not present
234 //
235 return EFI_NOT_FOUND;
236 } else if (((UINT32)(~0) - DirectoryEntry->VirtualAddress) < DirectoryEntry->Size) {
237 //
238 // The directory address overflows
239 //
240 DEBUG ((DEBUG_ERROR, "%a %a: The export directory entry in this image results in overflow.\n", _DBGMSGID_, __func__));
241 return EFI_UNSUPPORTED;
242 } else {
243 DEBUG ((DEBUG_INFO, "%a %a: Export Directory Entry found in the image at 0x%x.\n", _DBGMSGID_, __func__, (UINTN)OptionalHeaderPtrUnion.Pe32));
244 DEBUG ((DEBUG_INFO, " %a %a: Directory Entry Virtual Address = 0x%x.\n", _DBGMSGID_, __func__, DirectoryEntry->VirtualAddress));
245
246 ExportDirectory = (EFI_IMAGE_EXPORT_DIRECTORY *)((UINTN)Image + DirectoryEntry->VirtualAddress);
247 DEBUG ((
248 DEBUG_INFO,
249 " %a %a: Export Directory Table found successfully at 0x%x. Name address = 0x%x. Name = %a.\n",
250 _DBGMSGID_,
251 __func__,
252 (UINTN)ExportDirectory,
253 ((UINTN)Image + ExportDirectory->Name),
254 (CHAR8 *)((UINTN)Image + ExportDirectory->Name)
255 ));
256 }
257
258 *ImageExportDirectory = ExportDirectory;
259
260 return EFI_SUCCESS;
261}
262
263/**
264 Returns the image major and image minor version in a given PE/COFF image.
265
266 @param[in] Image A pointer to a PE32/COFF image base address that is loaded into memory
267 and already relocated to the memory base address. RVAs in the image given
268 should be valid.
269 @param[in] PeCoffLoaderImageContext A pointer to a PE_COFF_LOADER_IMAGE_CONTEXT structure that contains the
270 PE/COFF image context for the Image given.
271 @param[out] ImageMajorVersion A pointer to a UINT16 buffer to hold the image major version.
272 @param[out] ImageMinorVersion A pointer to a UINT16 buffer to hold the image minor version.
273
274 @retval EFI_SUCCESS The image version was read successfully.
275 @retval EFI_INVALID_PARAMETER A required parameter is NULL.
276 @retval EFI_UNSUPPORTED The PE/COFF image given is not supported.
277
278**/
279EFI_STATUS
280GetImageVersionInPeCoffImage (
281 IN VOID *Image,
282 IN PE_COFF_LOADER_IMAGE_CONTEXT *PeCoffLoaderImageContext,
283 OUT UINT16 *ImageMajorVersion,
284 OUT UINT16 *ImageMinorVersion
285 )
286{
287 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION OptionalHeaderPtrUnion;
288 UINT16 Magic;
289
290 DEBUG ((DEBUG_INFO, " %a %a - Entry.\n", _DBGMSGID_, __func__));
291
292 if ((Image == NULL) || (PeCoffLoaderImageContext == NULL) || (ImageMajorVersion == NULL) || (ImageMinorVersion == NULL)) {
293 return EFI_INVALID_PARAMETER;
294 }
295
296 //
297 // NOTE: For backward compatibility, use the Machine field to identify a PE32/PE32+
298 // image instead of using the Magic field. Some systems might generate a PE32+
299 // image with PE32 magic.
300 //
301 switch (PeCoffLoaderImageContext->Machine) {
302 case EFI_IMAGE_MACHINE_IA32:
303 //
304 // Assume PE32 image
305 //
306 Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
307 break;
308 case EFI_IMAGE_MACHINE_X64:
309 case EFI_IMAGE_MACHINE_AARCH64:
310 //
311 // Assume PE32+ image
312 //
313 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
314 break;
315 default:
316 //
317 // For unknown Machine field, use Magic in optional header
318 //
319 DEBUG ((
320 DEBUG_WARN,
321 "%a %a: The machine type for this image is not valid for a PRM module.\n",
322 _DBGMSGID_,
323 __func__
324 ));
325 return EFI_UNSUPPORTED;
326 }
327
328 OptionalHeaderPtrUnion.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(
329 (UINTN)Image +
330 PeCoffLoaderImageContext->PeCoffHeaderOffset
331 );
332 //
333 // Check the PE/COFF Header Signature. Determine if the image is valid and/or a TE image.
334 //
335 if (OptionalHeaderPtrUnion.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
336 DEBUG ((DEBUG_ERROR, "%a %a: The PE signature is not valid for the current image.\n", _DBGMSGID_, __func__));
337 return EFI_UNSUPPORTED;
338 }
339
340 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
341 //
342 // Use the PE32 offset to get the Export Directory Entry
343 //
344 *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MajorImageVersion;
345 *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32->OptionalHeader.MinorImageVersion;
346 } else {
347 //
348 // Use the PE32+ offset to get the Export Directory Entry
349 //
350 *ImageMajorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MajorImageVersion;
351 *ImageMinorVersion = OptionalHeaderPtrUnion.Pe32Plus->OptionalHeader.MinorImageVersion;
352 }
353
354 DEBUG ((DEBUG_INFO, " %a %a - Image Major Version: 0x%02x.\n", _DBGMSGID_, __func__, *ImageMajorVersion));
355 DEBUG ((DEBUG_INFO, " %a %a - Image Minor Version: 0x%02x.\n", _DBGMSGID_, __func__, *ImageMinorVersion));
356
357 return EFI_SUCCESS;
358}
359
360/**
361 Gets the address of an entry in an image export table by ASCII name.
362
363 @param[in] ExportName A pointer to an ASCII name string of the entry name.
364 @param[in] ImageBaseAddress The base address of the PE/COFF image.
365 @param[in] ImageExportDirectory A pointer to the export directory in the image.
366 @param[out] ExportPhysicalAddress A pointer that will be updated with the address of the address of the
367 export entry if found.
368
369 @retval EFI_SUCCESS The export entry was found successfully.
370 @retval EFI_INVALID_PARAMETER A required pointer argument is NULL.
371 @retval EFI_NOT_FOUND An entry with the given ExportName was not found.
372
373**/
374EFI_STATUS
375GetExportEntryAddress (
376 IN CONST CHAR8 *ExportName,
377 IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,
378 IN EFI_IMAGE_EXPORT_DIRECTORY *ImageExportDirectory,
379 OUT EFI_PHYSICAL_ADDRESS *ExportPhysicalAddress
380 )
381{
382 UINTN ExportNameIndex;
383 UINT16 CurrentExportOrdinal;
384 UINT32 *ExportAddressTable;
385 UINT32 *ExportNamePointerTable;
386 UINT16 *OrdinalTable;
387 CONST CHAR8 *ExportNameTablePointerName;
388
389 if ((ExportName == NULL) || (ImageBaseAddress == 0) || (ImageExportDirectory == NULL) || (ExportPhysicalAddress == NULL)) {
390 return EFI_INVALID_PARAMETER;
391 }
392
393 *ExportPhysicalAddress = 0;
394
395 ExportAddressTable = (UINT32 *)((UINTN)ImageBaseAddress + ImageExportDirectory->AddressOfFunctions);
396 ExportNamePointerTable = (UINT32 *)((UINTN)ImageBaseAddress + ImageExportDirectory->AddressOfNames);
397 OrdinalTable = (UINT16 *)((UINTN)ImageBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
398
399 for (ExportNameIndex = 0; ExportNameIndex < ImageExportDirectory->NumberOfNames; ExportNameIndex++) {
400 ExportNameTablePointerName = (CONST CHAR8 *)((UINTN)ImageBaseAddress + ExportNamePointerTable[ExportNameIndex]);
401
402 if (AsciiStrnCmp (ExportName, ExportNameTablePointerName, PRM_HANDLER_NAME_MAXIMUM_LENGTH) == 0) {
403 CurrentExportOrdinal = OrdinalTable[ExportNameIndex];
404
405 ASSERT (CurrentExportOrdinal < ImageExportDirectory->NumberOfFunctions);
406 if (CurrentExportOrdinal >= ImageExportDirectory->NumberOfFunctions) {
407 DEBUG ((DEBUG_ERROR, " %a %a: The export ordinal value is invalid.\n", _DBGMSGID_, __func__));
408 break;
409 }
410
411 *ExportPhysicalAddress = (EFI_PHYSICAL_ADDRESS)((UINTN)ImageBaseAddress + ExportAddressTable[CurrentExportOrdinal]);
412 return EFI_SUCCESS;
413 }
414 }
415
416 return EFI_NOT_FOUND;
417}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette