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