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