]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdePkg / Library / BasePeCoffLib / BasePeCoff.c
1 /** @file
2 Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
3 only supports relocating IA32, x64, IPF, ARM, RISC-V, LoongArch and EBC images.
4
5 Caution: This file requires additional review when modified.
6 This library will have external input - PE/COFF image.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
9
10 The basic guideline is that caller need provide ImageContext->ImageRead () with the
11 necessary data range check, to make sure when this library reads PE/COFF image, the
12 PE image buffer is always in valid range.
13 This library will also do some additional check for PE header fields.
14
15 PeCoffLoaderGetPeHeader() routine will do basic check for PE/COFF header.
16 PeCoffLoaderGetImageInfo() routine will do basic check for whole PE/COFF image.
17
18 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
19 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
20 Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
21 Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
22 SPDX-License-Identifier: BSD-2-Clause-Patent
23
24 **/
25
26 #include "BasePeCoffLibInternals.h"
27
28 /**
29 Adjust some fields in section header for TE image.
30
31 @param SectionHeader Pointer to the section header.
32 @param TeStrippedOffset Size adjust for the TE image.
33
34 **/
35 VOID
36 PeCoffLoaderAdjustOffsetForTeImage (
37 EFI_IMAGE_SECTION_HEADER *SectionHeader,
38 UINT32 TeStrippedOffset
39 )
40 {
41 SectionHeader->VirtualAddress -= TeStrippedOffset;
42 SectionHeader->PointerToRawData -= TeStrippedOffset;
43 }
44
45 /**
46 Retrieves the PE or TE Header from a PE/COFF or TE image.
47
48 Caution: This function may receive untrusted input.
49 PE/COFF image is external input, so this routine will
50 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
51 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
52
53 @param ImageContext The context of the image being loaded.
54 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
55
56 @retval RETURN_SUCCESS The PE or TE Header is read.
57 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
58
59 **/
60 RETURN_STATUS
61 PeCoffLoaderGetPeHeader (
62 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
63 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
64 )
65 {
66 RETURN_STATUS Status;
67 EFI_IMAGE_DOS_HEADER DosHdr;
68 UINTN Size;
69 UINTN ReadSize;
70 UINT32 SectionHeaderOffset;
71 UINT32 Index;
72 UINT32 HeaderWithoutDataDir;
73 CHAR8 BufferData;
74 UINTN NumberOfSections;
75 EFI_IMAGE_SECTION_HEADER SectionHeader;
76
77 //
78 // Read the DOS image header to check for its existence
79 //
80 Size = sizeof (EFI_IMAGE_DOS_HEADER);
81 ReadSize = Size;
82 Status = ImageContext->ImageRead (
83 ImageContext->Handle,
84 0,
85 &Size,
86 &DosHdr
87 );
88 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
89 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
90 if (Size != ReadSize) {
91 Status = RETURN_UNSUPPORTED;
92 }
93
94 return Status;
95 }
96
97 ImageContext->PeCoffHeaderOffset = 0;
98 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
99 //
100 // DOS image header is present, so read the PE header after the DOS image
101 // header
102 //
103 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
104 }
105
106 //
107 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
108 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
109 // determines if this is a PE32 or PE32+ image. The magic is in the same
110 // location in both images.
111 //
112 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
113 ReadSize = Size;
114 Status = ImageContext->ImageRead (
115 ImageContext->Handle,
116 ImageContext->PeCoffHeaderOffset,
117 &Size,
118 Hdr.Pe32
119 );
120 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
121 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
122 if (Size != ReadSize) {
123 Status = RETURN_UNSUPPORTED;
124 }
125
126 return Status;
127 }
128
129 //
130 // Use Signature to figure out if we understand the image format
131 //
132 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
133 ImageContext->IsTeImage = TRUE;
134 ImageContext->Machine = Hdr.Te->Machine;
135 ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);
136 //
137 // For TeImage, SectionAlignment is undefined to be set to Zero
138 // ImageSize can be calculated.
139 //
140 ImageContext->ImageSize = 0;
141 ImageContext->SectionAlignment = 0;
142 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
143
144 //
145 // Check the StrippedSize.
146 //
147 if (sizeof (EFI_TE_IMAGE_HEADER) >= (UINT32)Hdr.Te->StrippedSize) {
148 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
149 return RETURN_UNSUPPORTED;
150 }
151
152 //
153 // Check the SizeOfHeaders field.
154 //
155 if (Hdr.Te->BaseOfCode <= Hdr.Te->StrippedSize) {
156 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
157 return RETURN_UNSUPPORTED;
158 }
159
160 //
161 // Read last byte of Hdr.Te->SizeOfHeaders from the file.
162 //
163 Size = 1;
164 ReadSize = Size;
165 Status = ImageContext->ImageRead (
166 ImageContext->Handle,
167 ImageContext->SizeOfHeaders - 1,
168 &Size,
169 &BufferData
170 );
171 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
172 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
173 if (Size != ReadSize) {
174 Status = RETURN_UNSUPPORTED;
175 }
176
177 return Status;
178 }
179
180 //
181 // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.
182 // This case is not a valid TE image.
183 //
184 if (((Hdr.Te->DataDirectory[0].Size != 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) ||
185 ((Hdr.Te->DataDirectory[1].Size != 0) && (Hdr.Te->DataDirectory[1].VirtualAddress == 0)))
186 {
187 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
188 return RETURN_UNSUPPORTED;
189 }
190 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
191 ImageContext->IsTeImage = FALSE;
192 ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;
193
194 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
195 //
196 // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
197 //
198 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
199 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
200 return RETURN_UNSUPPORTED;
201 }
202
203 //
204 // 2. Check the FileHeader.SizeOfOptionalHeader field.
205 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
206 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
207 //
208 HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER32) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
209 if (((UINT32)Hdr.Pe32->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
210 Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY))
211 {
212 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
213 return RETURN_UNSUPPORTED;
214 }
215
216 SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
217 //
218 // 3. Check the FileHeader.NumberOfSections field.
219 //
220 if (Hdr.Pe32->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {
221 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
222 return RETURN_UNSUPPORTED;
223 }
224
225 if ((Hdr.Pe32->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32->FileHeader.NumberOfSections) {
226 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
227 return RETURN_UNSUPPORTED;
228 }
229
230 //
231 // 4. Check the OptionalHeader.SizeOfHeaders field.
232 //
233 if (Hdr.Pe32->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {
234 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
235 return RETURN_UNSUPPORTED;
236 }
237
238 if (Hdr.Pe32->OptionalHeader.SizeOfHeaders >= Hdr.Pe32->OptionalHeader.SizeOfImage) {
239 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
240 return RETURN_UNSUPPORTED;
241 }
242
243 if ((Hdr.Pe32->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32->FileHeader.NumberOfSections) {
244 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
245 return RETURN_UNSUPPORTED;
246 }
247
248 //
249 // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
250 //
251 Size = 1;
252 ReadSize = Size;
253 Status = ImageContext->ImageRead (
254 ImageContext->Handle,
255 Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,
256 &Size,
257 &BufferData
258 );
259 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
260 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
261 if (Size != ReadSize) {
262 Status = RETURN_UNSUPPORTED;
263 }
264
265 return Status;
266 }
267
268 //
269 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
270 // Read the last byte to make sure the data is in the image region.
271 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
272 //
273 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
274 if (Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
275 //
276 // Check the member data to avoid overflow.
277 //
278 if ((UINT32)(~0) - Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
279 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size)
280 {
281 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
282 return RETURN_UNSUPPORTED;
283 }
284
285 //
286 // Read last byte of section header from file
287 //
288 Size = 1;
289 ReadSize = Size;
290 Status = ImageContext->ImageRead (
291 ImageContext->Handle,
292 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
293 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
294 &Size,
295 &BufferData
296 );
297 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
298 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
299 if (Size != ReadSize) {
300 Status = RETURN_UNSUPPORTED;
301 }
302
303 return Status;
304 }
305 }
306 }
307
308 //
309 // Use PE32 offset
310 //
311 ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;
312 ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;
313 ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
314 ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
315 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
316 //
317 // 1. Check FileHeader.NumberOfRvaAndSizes filed.
318 //
319 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
320 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
321 return RETURN_UNSUPPORTED;
322 }
323
324 //
325 // 2. Check the FileHeader.SizeOfOptionalHeader field.
326 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
327 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
328 //
329 HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER64) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
330 if (((UINT32)Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
331 Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY))
332 {
333 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
334 return RETURN_UNSUPPORTED;
335 }
336
337 SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
338 //
339 // 3. Check the FileHeader.NumberOfSections field.
340 //
341 if (Hdr.Pe32Plus->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {
342 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
343 return RETURN_UNSUPPORTED;
344 }
345
346 if ((Hdr.Pe32Plus->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32Plus->FileHeader.NumberOfSections) {
347 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
348 return RETURN_UNSUPPORTED;
349 }
350
351 //
352 // 4. Check the OptionalHeader.SizeOfHeaders field.
353 //
354 if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {
355 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
356 return RETURN_UNSUPPORTED;
357 }
358
359 if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders >= Hdr.Pe32Plus->OptionalHeader.SizeOfImage) {
360 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
361 return RETURN_UNSUPPORTED;
362 }
363
364 if ((Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32Plus->FileHeader.NumberOfSections) {
365 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
366 return RETURN_UNSUPPORTED;
367 }
368
369 //
370 // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
371 //
372 Size = 1;
373 ReadSize = Size;
374 Status = ImageContext->ImageRead (
375 ImageContext->Handle,
376 Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,
377 &Size,
378 &BufferData
379 );
380 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
381 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
382 if (Size != ReadSize) {
383 Status = RETURN_UNSUPPORTED;
384 }
385
386 return Status;
387 }
388
389 //
390 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
391 // Read the last byte to make sure the data is in the image region.
392 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
393 //
394 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
395 if (Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
396 //
397 // Check the member data to avoid overflow.
398 //
399 if ((UINT32)(~0) - Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
400 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size)
401 {
402 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
403 return RETURN_UNSUPPORTED;
404 }
405
406 //
407 // Read last byte of section header from file
408 //
409 Size = 1;
410 ReadSize = Size;
411 Status = ImageContext->ImageRead (
412 ImageContext->Handle,
413 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
414 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
415 &Size,
416 &BufferData
417 );
418 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
419 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
420 if (Size != ReadSize) {
421 Status = RETURN_UNSUPPORTED;
422 }
423
424 return Status;
425 }
426 }
427 }
428
429 //
430 // Use PE32+ offset
431 //
432 ImageContext->ImageType = Hdr.Pe32Plus->OptionalHeader.Subsystem;
433 ImageContext->ImageSize = (UINT64)Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
434 ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
435 ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
436 } else {
437 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
438 return RETURN_UNSUPPORTED;
439 }
440 } else {
441 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
442 return RETURN_UNSUPPORTED;
443 }
444
445 if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {
446 //
447 // If the PE/COFF loader does not support the image type return
448 // unsupported. This library can support lots of types of images
449 // this does not mean the user of this library can call the entry
450 // point of the image.
451 //
452 return RETURN_UNSUPPORTED;
453 }
454
455 //
456 // Check each section field.
457 //
458 if (ImageContext->IsTeImage) {
459 SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);
460 NumberOfSections = (UINTN)(Hdr.Te->NumberOfSections);
461 } else {
462 SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
463 NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections);
464 }
465
466 for (Index = 0; Index < NumberOfSections; Index++) {
467 //
468 // Read section header from file
469 //
470 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
471 ReadSize = Size;
472 Status = ImageContext->ImageRead (
473 ImageContext->Handle,
474 SectionHeaderOffset,
475 &Size,
476 &SectionHeader
477 );
478 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
479 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
480 if (Size != ReadSize) {
481 Status = RETURN_UNSUPPORTED;
482 }
483
484 return Status;
485 }
486
487 //
488 // Adjust some field in Section Header for TE image.
489 //
490 if (ImageContext->IsTeImage) {
491 PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader, (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
492 }
493
494 if (SectionHeader.SizeOfRawData > 0) {
495 //
496 // Section data should bigger than the Pe header.
497 //
498 if ((SectionHeader.VirtualAddress < ImageContext->SizeOfHeaders) ||
499 (SectionHeader.PointerToRawData < ImageContext->SizeOfHeaders))
500 {
501 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
502 return RETURN_UNSUPPORTED;
503 }
504
505 //
506 // Check the member data to avoid overflow.
507 //
508 if ((UINT32)(~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {
509 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
510 return RETURN_UNSUPPORTED;
511 }
512
513 //
514 // Base on the ImageRead function to check the section data field.
515 // Read the last byte to make sure the data is in the image region.
516 //
517 Size = 1;
518 ReadSize = Size;
519 Status = ImageContext->ImageRead (
520 ImageContext->Handle,
521 SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,
522 &Size,
523 &BufferData
524 );
525 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
526 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
527 if (Size != ReadSize) {
528 Status = RETURN_UNSUPPORTED;
529 }
530
531 return Status;
532 }
533 }
534
535 //
536 // Check next section.
537 //
538 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
539 }
540
541 return RETURN_SUCCESS;
542 }
543
544 /**
545 Retrieves information about a PE/COFF image.
546
547 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
548 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
549 DebugDirectoryEntryRva fields of the ImageContext structure.
550 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
551 If the PE/COFF image accessed through the ImageRead service in the ImageContext
552 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
553 If any errors occur while computing the fields of ImageContext,
554 then the error status is returned in the ImageError field of ImageContext.
555 If the image is a TE image, then SectionAlignment is set to 0.
556 The ImageRead and Handle fields of ImageContext structure must be valid prior
557 to invoking this service.
558
559 Caution: This function may receive untrusted input.
560 PE/COFF image is external input, so this routine will
561 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
562 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
563
564 @param ImageContext The pointer to the image context structure that describes the PE/COFF
565 image that needs to be examined by this function.
566
567 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
568 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
569 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
570
571 **/
572 RETURN_STATUS
573 EFIAPI
574 PeCoffLoaderGetImageInfo (
575 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
576 )
577 {
578 RETURN_STATUS Status;
579 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
580 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
581 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
582 UINTN Size;
583 UINTN ReadSize;
584 UINTN Index;
585 UINTN DebugDirectoryEntryRva;
586 UINTN DebugDirectoryEntryFileOffset;
587 UINTN SectionHeaderOffset;
588 EFI_IMAGE_SECTION_HEADER SectionHeader;
589 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
590 UINT32 NumberOfRvaAndSizes;
591 UINT32 TeStrippedOffset;
592
593 if (ImageContext == NULL) {
594 return RETURN_INVALID_PARAMETER;
595 }
596
597 //
598 // Assume success
599 //
600 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
601
602 Hdr.Union = &HdrData;
603 Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);
604 if (RETURN_ERROR (Status)) {
605 return Status;
606 }
607
608 //
609 // Retrieve the base address of the image
610 //
611 if (!(ImageContext->IsTeImage)) {
612 TeStrippedOffset = 0;
613 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
614 //
615 // Use PE32 offset
616 //
617 ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;
618 } else {
619 //
620 // Use PE32+ offset
621 //
622 ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;
623 }
624 } else {
625 TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
626 ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + TeStrippedOffset);
627 }
628
629 //
630 // Initialize the alternate destination address to 0 indicating that it
631 // should not be used.
632 //
633 ImageContext->DestinationAddress = 0;
634
635 //
636 // Initialize the debug codeview pointer.
637 //
638 ImageContext->DebugDirectoryEntryRva = 0;
639 ImageContext->CodeView = NULL;
640 ImageContext->PdbPointer = NULL;
641
642 //
643 // Three cases with regards to relocations:
644 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
645 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
646 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
647 // has no base relocs to apply
648 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
649 //
650 // Look at the file header to determine if relocations have been stripped, and
651 // save this information in the image context for later use.
652 //
653 if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
654 ImageContext->RelocationsStripped = TRUE;
655 } else if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
656 ImageContext->RelocationsStripped = TRUE;
657 } else {
658 ImageContext->RelocationsStripped = FALSE;
659 }
660
661 if (!(ImageContext->IsTeImage)) {
662 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
663 //
664 // Use PE32 offset
665 //
666 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
667 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
668 } else {
669 //
670 // Use PE32+ offset
671 //
672 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
673 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
674 }
675
676 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
677 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
678
679 //
680 // Determine the file offset of the debug directory... This means we walk
681 // the sections to find which section contains the RVA of the debug
682 // directory
683 //
684 DebugDirectoryEntryFileOffset = 0;
685
686 SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
687 sizeof (UINT32) +
688 sizeof (EFI_IMAGE_FILE_HEADER) +
689 Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
690
691 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
692 //
693 // Read section header from file
694 //
695 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
696 ReadSize = Size;
697 Status = ImageContext->ImageRead (
698 ImageContext->Handle,
699 SectionHeaderOffset,
700 &Size,
701 &SectionHeader
702 );
703 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
704 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
705 if (Size != ReadSize) {
706 Status = RETURN_UNSUPPORTED;
707 }
708
709 return Status;
710 }
711
712 if ((DebugDirectoryEntryRva >= SectionHeader.VirtualAddress) &&
713 (DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize))
714 {
715 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
716 break;
717 }
718
719 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
720 }
721
722 if (DebugDirectoryEntryFileOffset != 0) {
723 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
724 //
725 // Read next debug directory entry
726 //
727 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
728 ReadSize = Size;
729 Status = ImageContext->ImageRead (
730 ImageContext->Handle,
731 DebugDirectoryEntryFileOffset + Index,
732 &Size,
733 &DebugEntry
734 );
735 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
736 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
737 if (Size != ReadSize) {
738 Status = RETURN_UNSUPPORTED;
739 }
740
741 return Status;
742 }
743
744 //
745 // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
746 // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
747 // ImageContext->ImageSize when DebugEntry.RVA == 0.
748 //
749 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
750 ImageContext->DebugDirectoryEntryRva = (UINT32)(DebugDirectoryEntryRva + Index);
751 if ((DebugEntry.RVA == 0) && (DebugEntry.FileOffset != 0)) {
752 ImageContext->ImageSize += DebugEntry.SizeOfData;
753 }
754
755 return RETURN_SUCCESS;
756 }
757 }
758 }
759 }
760 } else {
761 DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];
762 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
763 SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
764
765 DebugDirectoryEntryFileOffset = 0;
766
767 for (Index = 0; Index < Hdr.Te->NumberOfSections;) {
768 //
769 // Read section header from file
770 //
771 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
772 ReadSize = Size;
773 Status = ImageContext->ImageRead (
774 ImageContext->Handle,
775 SectionHeaderOffset,
776 &Size,
777 &SectionHeader
778 );
779 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
780 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
781 if (Size != ReadSize) {
782 Status = RETURN_UNSUPPORTED;
783 }
784
785 return Status;
786 }
787
788 if ((DebugDirectoryEntryRva >= SectionHeader.VirtualAddress) &&
789 (DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize))
790 {
791 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
792 SectionHeader.VirtualAddress +
793 SectionHeader.PointerToRawData -
794 TeStrippedOffset;
795
796 //
797 // File offset of the debug directory was found, if this is not the last
798 // section, then skip to the last section for calculating the image size.
799 //
800 if (Index < (UINTN)Hdr.Te->NumberOfSections - 1) {
801 SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
802 Index = Hdr.Te->NumberOfSections - 1;
803 continue;
804 }
805 }
806
807 //
808 // In Te image header there is not a field to describe the ImageSize.
809 // Actually, the ImageSize equals the RVA plus the VirtualSize of
810 // the last section mapped into memory (Must be rounded up to
811 // a multiple of Section Alignment). Per the PE/COFF specification, the
812 // section headers in the Section Table must appear in order of the RVA
813 // values for the corresponding sections. So the ImageSize can be determined
814 // by the RVA and the VirtualSize of the last section header in the
815 // Section Table.
816 //
817 if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {
818 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) - TeStrippedOffset;
819 }
820
821 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
822 }
823
824 if (DebugDirectoryEntryFileOffset != 0) {
825 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
826 //
827 // Read next debug directory entry
828 //
829 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
830 ReadSize = Size;
831 Status = ImageContext->ImageRead (
832 ImageContext->Handle,
833 DebugDirectoryEntryFileOffset + Index,
834 &Size,
835 &DebugEntry
836 );
837 if (RETURN_ERROR (Status) || (Size != ReadSize)) {
838 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
839 if (Size != ReadSize) {
840 Status = RETURN_UNSUPPORTED;
841 }
842
843 return Status;
844 }
845
846 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
847 ImageContext->DebugDirectoryEntryRva = (UINT32)(DebugDirectoryEntryRva + Index);
848 return RETURN_SUCCESS;
849 }
850 }
851 }
852 }
853
854 return RETURN_SUCCESS;
855 }
856
857 /**
858 Converts an image address to the loaded address.
859
860 @param ImageContext The context of the image being loaded.
861 @param Address The address to be converted to the loaded address.
862 @param TeStrippedOffset Stripped offset for TE image.
863
864 @return The converted address or NULL if the address can not be converted.
865
866 **/
867 VOID *
868 PeCoffLoaderImageAddress (
869 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
870 IN UINTN Address,
871 IN UINTN TeStrippedOffset
872 )
873 {
874 //
875 // Make sure that Address and ImageSize is correct for the loaded image.
876 //
877 if (Address >= ImageContext->ImageSize + TeStrippedOffset) {
878 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
879 return NULL;
880 }
881
882 return (CHAR8 *)((UINTN)ImageContext->ImageAddress + Address - TeStrippedOffset);
883 }
884
885 /**
886 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
887
888 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
889 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
890 of ImageContext as the relocation base address. The caller must allocate the relocation
891 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
892
893 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
894 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
895 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
896 the ImageContext structure must be valid prior to invoking this service.
897
898 If ImageContext is NULL, then ASSERT().
899
900 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
901 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
902 prior to transferring control to a PE/COFF image that is loaded using this library.
903
904 @param ImageContext The pointer to the image context structure that describes the PE/COFF
905 image that is being relocated.
906
907 @retval RETURN_SUCCESS The PE/COFF image was relocated.
908 Extended status information is in the ImageError field of ImageContext.
909 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
910 Extended status information is in the ImageError field of ImageContext.
911 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
912 Extended status information is in the ImageError field of ImageContext.
913
914 **/
915 RETURN_STATUS
916 EFIAPI
917 PeCoffLoaderRelocateImage (
918 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
919 )
920 {
921 RETURN_STATUS Status;
922 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
923 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
924 UINT64 Adjust;
925 EFI_IMAGE_BASE_RELOCATION *RelocBaseOrg;
926 EFI_IMAGE_BASE_RELOCATION *RelocBase;
927 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
928 UINT16 *Reloc;
929 UINT16 *RelocEnd;
930 CHAR8 *Fixup;
931 CHAR8 *FixupBase;
932 UINT16 *Fixup16;
933 UINT32 *Fixup32;
934 UINT64 *Fixup64;
935 CHAR8 *FixupData;
936 PHYSICAL_ADDRESS BaseAddress;
937 UINT32 NumberOfRvaAndSizes;
938 UINT32 TeStrippedOffset;
939
940 ASSERT (ImageContext != NULL);
941
942 //
943 // Assume success
944 //
945 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
946
947 //
948 // If there are no relocation entries, then we are done
949 //
950 if (ImageContext->RelocationsStripped) {
951 // Applies additional environment specific actions to relocate fixups
952 // to a PE/COFF image if needed
953 PeCoffLoaderRelocateImageExtraAction (ImageContext);
954 return RETURN_SUCCESS;
955 }
956
957 //
958 // If the destination address is not 0, use that rather than the
959 // image address as the relocation target.
960 //
961 if (ImageContext->DestinationAddress != 0) {
962 BaseAddress = ImageContext->DestinationAddress;
963 } else {
964 BaseAddress = ImageContext->ImageAddress;
965 }
966
967 if (!(ImageContext->IsTeImage)) {
968 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
969 TeStrippedOffset = 0;
970
971 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
972 //
973 // Use PE32 offset
974 //
975 Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
976 if (Adjust != 0) {
977 Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
978 }
979
980 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
981 RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
982 } else {
983 //
984 // Use PE32+ offset
985 //
986 Adjust = (UINT64)BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
987 if (Adjust != 0) {
988 Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
989 }
990
991 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
992 RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
993 }
994
995 //
996 // Find the relocation block
997 // Per the PE/COFF spec, you can't assume that a given data directory
998 // is present in the image. You have to check the NumberOfRvaAndSizes in
999 // the optional header to verify a desired directory entry is there.
1000 //
1001 if ((NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)) {
1002 RelocDir = NULL;
1003 }
1004 } else {
1005 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
1006 TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
1007 Adjust = (UINT64)(BaseAddress - (Hdr.Te->ImageBase + TeStrippedOffset));
1008 if (Adjust != 0) {
1009 Hdr.Te->ImageBase = (UINT64)(BaseAddress - TeStrippedOffset);
1010 }
1011
1012 //
1013 // Find the relocation block
1014 //
1015 RelocDir = &Hdr.Te->DataDirectory[0];
1016 }
1017
1018 if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
1019 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress, TeStrippedOffset);
1020 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (
1021 ImageContext,
1022 RelocDir->VirtualAddress + RelocDir->Size - 1,
1023 TeStrippedOffset
1024 );
1025 if ((RelocBase == NULL) || (RelocBaseEnd == NULL) || ((UINTN)RelocBaseEnd < (UINTN)RelocBase)) {
1026 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1027 return RETURN_LOAD_ERROR;
1028 }
1029 } else {
1030 //
1031 // Set base and end to bypass processing below.
1032 //
1033 RelocBase = RelocBaseEnd = NULL;
1034 }
1035
1036 RelocBaseOrg = RelocBase;
1037
1038 //
1039 // If Adjust is not zero, then apply fix ups to the image
1040 //
1041 if (Adjust != 0) {
1042 //
1043 // Run the relocation information and apply the fixups
1044 //
1045 FixupData = ImageContext->FixupData;
1046 while ((UINTN)RelocBase < (UINTN)RelocBaseEnd) {
1047 Reloc = (UINT16 *)((CHAR8 *)RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1048 //
1049 // Add check for RelocBase->SizeOfBlock field.
1050 //
1051 if (RelocBase->SizeOfBlock == 0) {
1052 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1053 return RETURN_LOAD_ERROR;
1054 }
1055
1056 if ((UINTN)RelocBase > MAX_ADDRESS - RelocBase->SizeOfBlock) {
1057 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1058 return RETURN_LOAD_ERROR;
1059 }
1060
1061 RelocEnd = (UINT16 *)((CHAR8 *)RelocBase + RelocBase->SizeOfBlock);
1062 if ((UINTN)RelocEnd > (UINTN)RelocBaseOrg + RelocDir->Size) {
1063 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1064 return RETURN_LOAD_ERROR;
1065 }
1066
1067 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress, TeStrippedOffset);
1068 if (FixupBase == NULL) {
1069 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1070 return RETURN_LOAD_ERROR;
1071 }
1072
1073 //
1074 // Run this relocation record
1075 //
1076 while ((UINTN)Reloc < (UINTN)RelocEnd) {
1077 Fixup = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset);
1078 if (Fixup == NULL) {
1079 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1080 return RETURN_LOAD_ERROR;
1081 }
1082
1083 switch ((*Reloc) >> 12) {
1084 case EFI_IMAGE_REL_BASED_ABSOLUTE:
1085 break;
1086
1087 case EFI_IMAGE_REL_BASED_HIGH:
1088 Fixup16 = (UINT16 *)Fixup;
1089 *Fixup16 = (UINT16)(*Fixup16 + ((UINT16)((UINT32)Adjust >> 16)));
1090 if (FixupData != NULL) {
1091 *(UINT16 *)FixupData = *Fixup16;
1092 FixupData = FixupData + sizeof (UINT16);
1093 }
1094
1095 break;
1096
1097 case EFI_IMAGE_REL_BASED_LOW:
1098 Fixup16 = (UINT16 *)Fixup;
1099 *Fixup16 = (UINT16)(*Fixup16 + (UINT16)Adjust);
1100 if (FixupData != NULL) {
1101 *(UINT16 *)FixupData = *Fixup16;
1102 FixupData = FixupData + sizeof (UINT16);
1103 }
1104
1105 break;
1106
1107 case EFI_IMAGE_REL_BASED_HIGHLOW:
1108 Fixup32 = (UINT32 *)Fixup;
1109 *Fixup32 = *Fixup32 + (UINT32)Adjust;
1110 if (FixupData != NULL) {
1111 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
1112 *(UINT32 *)FixupData = *Fixup32;
1113 FixupData = FixupData + sizeof (UINT32);
1114 }
1115
1116 break;
1117
1118 case EFI_IMAGE_REL_BASED_DIR64:
1119 Fixup64 = (UINT64 *)Fixup;
1120 *Fixup64 = *Fixup64 + (UINT64)Adjust;
1121 if (FixupData != NULL) {
1122 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
1123 *(UINT64 *)(FixupData) = *Fixup64;
1124 FixupData = FixupData + sizeof (UINT64);
1125 }
1126
1127 break;
1128
1129 default:
1130 //
1131 // The common code does not handle some of the stranger IPF relocations
1132 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1133 // on IPF and is a No-Op on other architectures.
1134 //
1135 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1136 if (RETURN_ERROR (Status)) {
1137 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1138 return Status;
1139 }
1140 }
1141
1142 //
1143 // Next relocation record
1144 //
1145 Reloc += 1;
1146 }
1147
1148 //
1149 // Next reloc block
1150 //
1151 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)RelocEnd;
1152 }
1153
1154 ASSERT ((UINTN)FixupData <= (UINTN)ImageContext->FixupData + ImageContext->FixupDataSize);
1155
1156 //
1157 // Adjust the EntryPoint to match the linked-to address
1158 //
1159 if (ImageContext->DestinationAddress != 0) {
1160 ImageContext->EntryPoint -= (UINT64)ImageContext->ImageAddress;
1161 ImageContext->EntryPoint += (UINT64)ImageContext->DestinationAddress;
1162 }
1163 }
1164
1165 // Applies additional environment specific actions to relocate fixups
1166 // to a PE/COFF image if needed
1167 PeCoffLoaderRelocateImageExtraAction (ImageContext);
1168
1169 return RETURN_SUCCESS;
1170 }
1171
1172 /**
1173 Loads a PE/COFF image into memory.
1174
1175 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1176 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1177 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1178 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1179 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1180 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1181 fields of the ImageContext structure must be valid prior to invoking this service.
1182
1183 If ImageContext is NULL, then ASSERT().
1184
1185 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1186 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1187 prior to transferring control to a PE/COFF image that is loaded using this library.
1188
1189 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1190 image that is being loaded.
1191
1192 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1193 the ImageAddress and ImageSize fields of ImageContext.
1194 Extended status information is in the ImageError field of ImageContext.
1195 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1196 Extended status information is in the ImageError field of ImageContext.
1197 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1198 Extended status information is in the ImageError field of ImageContext.
1199 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1200 Extended status information is in the ImageError field of ImageContext.
1201
1202 **/
1203 RETURN_STATUS
1204 EFIAPI
1205 PeCoffLoaderLoadImage (
1206 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1207 )
1208 {
1209 RETURN_STATUS Status;
1210 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1211 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
1212 EFI_IMAGE_SECTION_HEADER *FirstSection;
1213 EFI_IMAGE_SECTION_HEADER *Section;
1214 UINTN NumberOfSections;
1215 UINTN Index;
1216 CHAR8 *Base;
1217 CHAR8 *End;
1218 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
1219 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
1220 UINTN Size;
1221 UINT32 TempDebugEntryRva;
1222 UINT32 NumberOfRvaAndSizes;
1223 EFI_IMAGE_RESOURCE_DIRECTORY *ResourceDirectory;
1224 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *ResourceDirectoryEntry;
1225 EFI_IMAGE_RESOURCE_DIRECTORY_STRING *ResourceDirectoryString;
1226 EFI_IMAGE_RESOURCE_DATA_ENTRY *ResourceDataEntry;
1227 CHAR16 *String;
1228 UINT32 Offset;
1229 UINT32 TeStrippedOffset;
1230
1231 ASSERT (ImageContext != NULL);
1232
1233 //
1234 // Assume success
1235 //
1236 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
1237
1238 //
1239 // Copy the provided context information into our local version, get what we
1240 // can from the original image, and then use that to make sure everything
1241 // is legit.
1242 //
1243 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
1244
1245 Status = PeCoffLoaderGetImageInfo (&CheckContext);
1246 if (RETURN_ERROR (Status)) {
1247 return Status;
1248 }
1249
1250 //
1251 // Make sure there is enough allocated space for the image being loaded
1252 //
1253 if (ImageContext->ImageSize < CheckContext.ImageSize) {
1254 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
1255 return RETURN_BUFFER_TOO_SMALL;
1256 }
1257
1258 if (ImageContext->ImageAddress == 0) {
1259 //
1260 // Image cannot be loaded into 0 address.
1261 //
1262 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
1263 return RETURN_INVALID_PARAMETER;
1264 }
1265
1266 //
1267 // If there's no relocations, then make sure it's not a runtime driver,
1268 // and that it's being loaded at the linked address.
1269 //
1270 if (CheckContext.RelocationsStripped) {
1271 //
1272 // If the image does not contain relocations and it is a runtime driver
1273 // then return an error.
1274 //
1275 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
1276 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
1277 return RETURN_LOAD_ERROR;
1278 }
1279
1280 //
1281 // If the image does not contain relocations, and the requested load address
1282 // is not the linked address, then return an error.
1283 //
1284 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
1285 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
1286 return RETURN_INVALID_PARAMETER;
1287 }
1288 }
1289
1290 //
1291 // Make sure the allocated space has the proper section alignment
1292 //
1293 if (!(ImageContext->IsTeImage)) {
1294 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
1295 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
1296 return RETURN_INVALID_PARAMETER;
1297 }
1298 }
1299
1300 //
1301 // Read the entire PE/COFF or TE header into memory
1302 //
1303 if (!(ImageContext->IsTeImage)) {
1304 Status = ImageContext->ImageRead (
1305 ImageContext->Handle,
1306 0,
1307 &ImageContext->SizeOfHeaders,
1308 (VOID *)(UINTN)ImageContext->ImageAddress
1309 );
1310
1311 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
1312
1313 FirstSection = (EFI_IMAGE_SECTION_HEADER *)(
1314 (UINTN)ImageContext->ImageAddress +
1315 ImageContext->PeCoffHeaderOffset +
1316 sizeof (UINT32) +
1317 sizeof (EFI_IMAGE_FILE_HEADER) +
1318 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
1319 );
1320 NumberOfSections = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections);
1321 TeStrippedOffset = 0;
1322 } else {
1323 Status = ImageContext->ImageRead (
1324 ImageContext->Handle,
1325 0,
1326 &ImageContext->SizeOfHeaders,
1327 (void *)(UINTN)ImageContext->ImageAddress
1328 );
1329
1330 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
1331 FirstSection = (EFI_IMAGE_SECTION_HEADER *)(
1332 (UINTN)ImageContext->ImageAddress +
1333 sizeof (EFI_TE_IMAGE_HEADER)
1334 );
1335 NumberOfSections = (UINTN)(Hdr.Te->NumberOfSections);
1336 TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
1337 }
1338
1339 if (RETURN_ERROR (Status)) {
1340 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1341 return RETURN_LOAD_ERROR;
1342 }
1343
1344 //
1345 // Load each section of the image
1346 //
1347 Section = FirstSection;
1348 for (Index = 0; Index < NumberOfSections; Index++) {
1349 //
1350 // Read the section
1351 //
1352 Size = (UINTN)Section->Misc.VirtualSize;
1353 if ((Size == 0) || (Size > Section->SizeOfRawData)) {
1354 Size = (UINTN)Section->SizeOfRawData;
1355 }
1356
1357 //
1358 // Compute sections address
1359 //
1360 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress, TeStrippedOffset);
1361 End = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress + Section->Misc.VirtualSize - 1, TeStrippedOffset);
1362
1363 //
1364 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1365 //
1366 if ((Size > 0) && ((Base == NULL) || (End == NULL))) {
1367 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
1368 return RETURN_LOAD_ERROR;
1369 }
1370
1371 if (Section->SizeOfRawData > 0) {
1372 Status = ImageContext->ImageRead (
1373 ImageContext->Handle,
1374 Section->PointerToRawData - TeStrippedOffset,
1375 &Size,
1376 Base
1377 );
1378 if (RETURN_ERROR (Status)) {
1379 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1380 return Status;
1381 }
1382 }
1383
1384 //
1385 // If raw size is less then virtual size, zero fill the remaining
1386 //
1387
1388 if (Size < Section->Misc.VirtualSize) {
1389 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
1390 }
1391
1392 //
1393 // Next Section
1394 //
1395 Section += 1;
1396 }
1397
1398 //
1399 // Get image's entry point
1400 //
1401 if (!(ImageContext->IsTeImage)) {
1402 //
1403 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1404 //
1405 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1406 //
1407 // Use PE32 offset
1408 //
1409 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1410 ImageContext,
1411 (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint,
1412 0
1413 );
1414 } else {
1415 //
1416 // Use PE32+ offset
1417 //
1418 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1419 ImageContext,
1420 (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint,
1421 0
1422 );
1423 }
1424 } else {
1425 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
1426 ImageContext,
1427 (UINTN)Hdr.Te->AddressOfEntryPoint,
1428 TeStrippedOffset
1429 );
1430 }
1431
1432 //
1433 // Determine the size of the fixup data
1434 //
1435 // Per the PE/COFF spec, you can't assume that a given data directory
1436 // is present in the image. You have to check the NumberOfRvaAndSizes in
1437 // the optional header to verify a desired directory entry is there.
1438 //
1439 if (!(ImageContext->IsTeImage)) {
1440 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1441 //
1442 // Use PE32 offset
1443 //
1444 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1445 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1446 } else {
1447 //
1448 // Use PE32+ offset
1449 //
1450 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1451 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1452 }
1453
1454 //
1455 // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
1456 //
1457 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1458 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
1459 } else {
1460 ImageContext->FixupDataSize = 0;
1461 }
1462 } else {
1463 DirectoryEntry = &Hdr.Te->DataDirectory[0];
1464 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
1465 }
1466
1467 //
1468 // Consumer must allocate a buffer for the relocation fixup log.
1469 // Only used for runtime drivers.
1470 //
1471 ImageContext->FixupData = NULL;
1472
1473 //
1474 // Load the Codeview information if present
1475 //
1476 if (ImageContext->DebugDirectoryEntryRva != 0) {
1477 DebugEntry = PeCoffLoaderImageAddress (
1478 ImageContext,
1479 ImageContext->DebugDirectoryEntryRva,
1480 TeStrippedOffset
1481 );
1482 if (DebugEntry == NULL) {
1483 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1484 return RETURN_LOAD_ERROR;
1485 }
1486
1487 TempDebugEntryRva = DebugEntry->RVA;
1488 if ((DebugEntry->RVA == 0) && (DebugEntry->FileOffset != 0)) {
1489 Section--;
1490 if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
1491 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1492 } else {
1493 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1494 }
1495 }
1496
1497 if (TempDebugEntryRva != 0) {
1498 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva, TeStrippedOffset);
1499 if (ImageContext->CodeView == NULL) {
1500 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
1501 return RETURN_LOAD_ERROR;
1502 }
1503
1504 if (DebugEntry->RVA == 0) {
1505 Size = DebugEntry->SizeOfData;
1506 Status = ImageContext->ImageRead (
1507 ImageContext->Handle,
1508 DebugEntry->FileOffset - TeStrippedOffset,
1509 &Size,
1510 ImageContext->CodeView
1511 );
1512 //
1513 // Should we apply fix up to this field according to the size difference between PE and TE?
1514 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1515 // in original PE image.
1516 //
1517
1518 if (RETURN_ERROR (Status)) {
1519 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1520 return RETURN_LOAD_ERROR;
1521 }
1522
1523 DebugEntry->RVA = TempDebugEntryRva;
1524 }
1525
1526 switch (*(UINT32 *)ImageContext->CodeView) {
1527 case CODEVIEW_SIGNATURE_NB10:
1528 if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {
1529 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1530 return RETURN_UNSUPPORTED;
1531 }
1532
1533 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1534 break;
1535
1536 case CODEVIEW_SIGNATURE_RSDS:
1537 if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {
1538 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1539 return RETURN_UNSUPPORTED;
1540 }
1541
1542 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1543 break;
1544
1545 case CODEVIEW_SIGNATURE_MTOC:
1546 if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {
1547 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1548 return RETURN_UNSUPPORTED;
1549 }
1550
1551 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
1552 break;
1553
1554 default:
1555 break;
1556 }
1557 }
1558 }
1559
1560 //
1561 // Get Image's HII resource section
1562 //
1563 ImageContext->HiiResourceData = 0;
1564 if (!(ImageContext->IsTeImage)) {
1565 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1566 //
1567 // Use PE32 offset
1568 //
1569 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1570 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
1571 } else {
1572 //
1573 // Use PE32+ offset
1574 //
1575 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1576 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
1577 }
1578
1579 if ((NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) && (DirectoryEntry->Size != 0)) {
1580 Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress, 0);
1581 if (Base != NULL) {
1582 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)Base;
1583 Offset = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) *
1584 (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1585 if (Offset > DirectoryEntry->Size) {
1586 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1587 return RETURN_UNSUPPORTED;
1588 }
1589
1590 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
1591
1592 for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
1593 if (ResourceDirectoryEntry->u1.s.NameIsString) {
1594 //
1595 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1596 //
1597 if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {
1598 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1599 return RETURN_UNSUPPORTED;
1600 }
1601
1602 ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *)(Base + ResourceDirectoryEntry->u1.s.NameOffset);
1603 String = &ResourceDirectoryString->String[0];
1604
1605 if ((ResourceDirectoryString->Length == 3) &&
1606 (String[0] == L'H') &&
1607 (String[1] == L'I') &&
1608 (String[2] == L'I'))
1609 {
1610 //
1611 // Resource Type "HII" found
1612 //
1613 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1614 //
1615 // Move to next level - resource Name
1616 //
1617 if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
1618 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1619 return RETURN_UNSUPPORTED;
1620 }
1621
1622 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
1623 Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
1624 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1625 if (Offset > DirectoryEntry->Size) {
1626 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1627 return RETURN_UNSUPPORTED;
1628 }
1629
1630 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
1631
1632 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1633 //
1634 // Move to next level - resource Language
1635 //
1636 if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
1637 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1638 return RETURN_UNSUPPORTED;
1639 }
1640
1641 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
1642 Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
1643 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
1644 if (Offset > DirectoryEntry->Size) {
1645 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1646 return RETURN_UNSUPPORTED;
1647 }
1648
1649 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);
1650 }
1651 }
1652
1653 //
1654 // Now it ought to be resource Data
1655 //
1656 if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
1657 if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {
1658 ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
1659 return RETURN_UNSUPPORTED;
1660 }
1661
1662 ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *)(Base + ResourceDirectoryEntry->u2.OffsetToData);
1663 ImageContext->HiiResourceData = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData, 0);
1664 break;
1665 }
1666 }
1667 }
1668
1669 ResourceDirectoryEntry++;
1670 }
1671 }
1672 }
1673 }
1674
1675 return Status;
1676 }
1677
1678 /**
1679 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1680 runtime.
1681
1682 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1683 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1684 to the address specified by VirtualImageBase. RelocationData must be identical
1685 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1686 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1687
1688 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1689 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1690 prior to transferring control to a PE/COFF image that is loaded using this library.
1691
1692 @param ImageBase The base address of a PE/COFF image that has been loaded
1693 and relocated into system memory.
1694 @param VirtImageBase The request virtual address that the PE/COFF image is to
1695 be fixed up for.
1696 @param ImageSize The size, in bytes, of the PE/COFF image.
1697 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1698 image was relocated using PeCoffLoaderRelocateImage().
1699
1700 **/
1701 VOID
1702 EFIAPI
1703 PeCoffLoaderRelocateImageForRuntime (
1704 IN PHYSICAL_ADDRESS ImageBase,
1705 IN PHYSICAL_ADDRESS VirtImageBase,
1706 IN UINTN ImageSize,
1707 IN VOID *RelocationData
1708 )
1709 {
1710 CHAR8 *OldBase;
1711 CHAR8 *NewBase;
1712 EFI_IMAGE_DOS_HEADER *DosHdr;
1713 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1714 UINT32 NumberOfRvaAndSizes;
1715 EFI_IMAGE_DATA_DIRECTORY *DataDirectory;
1716 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
1717 EFI_IMAGE_BASE_RELOCATION *RelocBase;
1718 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
1719 EFI_IMAGE_BASE_RELOCATION *RelocBaseOrig;
1720 UINT16 *Reloc;
1721 UINT16 *RelocEnd;
1722 CHAR8 *Fixup;
1723 CHAR8 *FixupBase;
1724 UINT16 *Fixup16;
1725 UINT32 *Fixup32;
1726 UINT64 *Fixup64;
1727 CHAR8 *FixupData;
1728 UINTN Adjust;
1729 RETURN_STATUS Status;
1730 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
1731
1732 if ((RelocationData == NULL) || (ImageBase == 0x0) || (VirtImageBase == 0x0)) {
1733 return;
1734 }
1735
1736 OldBase = (CHAR8 *)((UINTN)ImageBase);
1737 NewBase = (CHAR8 *)((UINTN)VirtImageBase);
1738 Adjust = (UINTN)NewBase - (UINTN)OldBase;
1739
1740 ImageContext.ImageAddress = ImageBase;
1741 ImageContext.ImageSize = ImageSize;
1742
1743 //
1744 // Find the image's relocate dir info
1745 //
1746 DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;
1747 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1748 //
1749 // Valid DOS header so get address of PE header
1750 //
1751 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
1752 } else {
1753 //
1754 // No Dos header so assume image starts with PE header.
1755 //
1756 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
1757 }
1758
1759 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1760 //
1761 // Not a valid PE image so Exit
1762 //
1763 return;
1764 }
1765
1766 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1767 //
1768 // Use PE32 offset
1769 //
1770 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1771 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);
1772 } else {
1773 //
1774 // Use PE32+ offset
1775 //
1776 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1777 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);
1778 }
1779
1780 //
1781 // Find the relocation block
1782 //
1783 // Per the PE/COFF spec, you can't assume that a given data directory
1784 // is present in the image. You have to check the NumberOfRvaAndSizes in
1785 // the optional header to verify a desired directory entry is there.
1786 //
1787 RelocBase = NULL;
1788 RelocBaseEnd = NULL;
1789 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1790 RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
1791 if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
1792 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (&ImageContext, RelocDir->VirtualAddress, 0);
1793 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (
1794 &ImageContext,
1795 RelocDir->VirtualAddress + RelocDir->Size - 1,
1796 0
1797 );
1798 }
1799
1800 if ((RelocBase == NULL) || (RelocBaseEnd == NULL) || ((UINTN)RelocBaseEnd < (UINTN)RelocBase)) {
1801 //
1802 // relocation block is not valid, just return
1803 //
1804 return;
1805 }
1806 } else {
1807 //
1808 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1809 //
1810 ASSERT (FALSE);
1811 return;
1812 }
1813
1814 //
1815 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1816 //
1817 ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
1818
1819 if (Adjust != 0) {
1820 //
1821 // Run the whole relocation block. And re-fixup data that has not been
1822 // modified. The FixupData is used to see if the image has been modified
1823 // since it was relocated. This is so data sections that have been updated
1824 // by code will not be fixed up, since that would set them back to
1825 // defaults.
1826 //
1827 FixupData = RelocationData;
1828 RelocBaseOrig = RelocBase;
1829 while ((UINTN)RelocBase < (UINTN)RelocBaseEnd) {
1830 //
1831 // Add check for RelocBase->SizeOfBlock field.
1832 //
1833 if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {
1834 //
1835 // Data invalid, cannot continue to relocate the image, just return.
1836 //
1837 return;
1838 }
1839
1840 Reloc = (UINT16 *)((UINT8 *)RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1841 RelocEnd = (UINT16 *)((UINT8 *)RelocBase + RelocBase->SizeOfBlock);
1842 if ((UINTN)RelocEnd > (UINTN)RelocBaseOrig + RelocDir->Size) {
1843 return;
1844 }
1845
1846 FixupBase = PeCoffLoaderImageAddress (&ImageContext, RelocBase->VirtualAddress, 0);
1847 if (FixupBase == NULL) {
1848 return;
1849 }
1850
1851 //
1852 // Run this relocation record
1853 //
1854 while ((UINTN)Reloc < (UINTN)RelocEnd) {
1855 Fixup = PeCoffLoaderImageAddress (&ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), 0);
1856 if (Fixup == NULL) {
1857 return;
1858 }
1859
1860 switch ((*Reloc) >> 12) {
1861 case EFI_IMAGE_REL_BASED_ABSOLUTE:
1862 break;
1863
1864 case EFI_IMAGE_REL_BASED_HIGH:
1865 Fixup16 = (UINT16 *)Fixup;
1866 if (*(UINT16 *)FixupData == *Fixup16) {
1867 *Fixup16 = (UINT16)(*Fixup16 + ((UINT16)((UINT32)Adjust >> 16)));
1868 }
1869
1870 FixupData = FixupData + sizeof (UINT16);
1871 break;
1872
1873 case EFI_IMAGE_REL_BASED_LOW:
1874 Fixup16 = (UINT16 *)Fixup;
1875 if (*(UINT16 *)FixupData == *Fixup16) {
1876 *Fixup16 = (UINT16)(*Fixup16 + ((UINT16)Adjust & 0xffff));
1877 }
1878
1879 FixupData = FixupData + sizeof (UINT16);
1880 break;
1881
1882 case EFI_IMAGE_REL_BASED_HIGHLOW:
1883 Fixup32 = (UINT32 *)Fixup;
1884 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
1885 if (*(UINT32 *)FixupData == *Fixup32) {
1886 *Fixup32 = *Fixup32 + (UINT32)Adjust;
1887 }
1888
1889 FixupData = FixupData + sizeof (UINT32);
1890 break;
1891
1892 case EFI_IMAGE_REL_BASED_DIR64:
1893 Fixup64 = (UINT64 *)Fixup;
1894 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
1895 if (*(UINT64 *)FixupData == *Fixup64) {
1896 *Fixup64 = *Fixup64 + (UINT64)Adjust;
1897 }
1898
1899 FixupData = FixupData + sizeof (UINT64);
1900 break;
1901
1902 default:
1903 //
1904 // Only Itanium requires ConvertPeImage_Ex
1905 //
1906 Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1907 if (RETURN_ERROR (Status)) {
1908 return;
1909 }
1910 }
1911
1912 //
1913 // Next relocation record
1914 //
1915 Reloc += 1;
1916 }
1917
1918 //
1919 // next reloc block
1920 //
1921 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)RelocEnd;
1922 }
1923 }
1924 }
1925
1926 /**
1927 Reads contents of a PE/COFF image from a buffer in system memory.
1928
1929 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1930 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1931 This function reads contents of the PE/COFF image that starts at the system memory
1932 address specified by FileHandle. The read operation copies ReadSize bytes from the
1933 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1934 The size of the buffer actually read is returned in ReadSize.
1935
1936 The caller must make sure the FileOffset and ReadSize within the file scope.
1937
1938 If FileHandle is NULL, then ASSERT().
1939 If ReadSize is NULL, then ASSERT().
1940 If Buffer is NULL, then ASSERT().
1941
1942 @param FileHandle The pointer to base of the input stream
1943 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1944 @param ReadSize On input, the size in bytes of the requested read operation.
1945 On output, the number of bytes actually read.
1946 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1947
1948 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1949 the buffer.
1950 **/
1951 RETURN_STATUS
1952 EFIAPI
1953 PeCoffLoaderImageReadFromMemory (
1954 IN VOID *FileHandle,
1955 IN UINTN FileOffset,
1956 IN OUT UINTN *ReadSize,
1957 OUT VOID *Buffer
1958 )
1959 {
1960 ASSERT (ReadSize != NULL);
1961 ASSERT (FileHandle != NULL);
1962 ASSERT (Buffer != NULL);
1963
1964 CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);
1965 return RETURN_SUCCESS;
1966 }
1967
1968 /**
1969 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1970 Releases any environment specific resources that were allocated when the image
1971 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1972
1973 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1974 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1975 this function can simply return RETURN_SUCCESS.
1976
1977 If ImageContext is NULL, then ASSERT().
1978
1979 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1980 image to be unloaded.
1981
1982 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1983 **/
1984 RETURN_STATUS
1985 EFIAPI
1986 PeCoffLoaderUnloadImage (
1987 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1988 )
1989 {
1990 //
1991 // Applies additional environment specific actions to unload a
1992 // PE/COFF image if needed
1993 //
1994 PeCoffLoaderUnloadImageExtraAction (ImageContext);
1995 return RETURN_SUCCESS;
1996 }