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