]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
1. Replace PeCoffLoader library by PeCoff lib for PeiCore, DxeIpl and DxeMain.
[mirror_edk2.git] / MdePkg / Library / BasePeCoffLib / BasePeCoff.c
1 /** @file
2 Tiano PE/COFF loader.
3
4 This PE/COFF loader supports loading any PE32 or PE32+ image type, but
5 only supports relocating IA32, X64, IPF, and EBC images.
6
7 Copyright (c) 2006, Intel Corporation
8 All rights reserved. This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 //
19 // Include common header file for this module.
20 //
21
22
23 #include "BasePeCoffLibInternals.h"
24
25 /**
26 Retrieves the magic value from the PE/COFF header.
27
28 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
29
30 @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
31 @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
32
33 **/
34 UINT16
35 PeCoffLoaderGetPeHeaderMagicValue (
36 IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
37 )
38 {
39 //
40 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
41 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
42 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
43 // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
44 //
45 if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
46 return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
47 }
48 //
49 // Return the magic value from the PC/COFF Optional Header
50 //
51 return Hdr.Pe32->OptionalHeader.Magic;
52 }
53
54
55 /**
56 Retrieves the PE or TE Header from a PE/COFF or TE image.
57
58 @param ImageContext The context of the image being loaded.
59 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
60
61 @retval RETURN_SUCCESS The PE or TE Header is read.
62 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
63
64 **/
65 RETURN_STATUS
66 PeCoffLoaderGetPeHeader (
67 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
68 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
69 )
70 {
71 RETURN_STATUS Status;
72 EFI_IMAGE_DOS_HEADER DosHdr;
73 UINTN Size;
74 UINT16 Magic;
75
76 //
77 // Read the DOS image header to check for it's existance
78 //
79 Size = sizeof (EFI_IMAGE_DOS_HEADER);
80 Status = ImageContext->ImageRead (
81 ImageContext->Handle,
82 0,
83 &Size,
84 &DosHdr
85 );
86 if (RETURN_ERROR (Status)) {
87 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
88 return Status;
89 }
90
91 ImageContext->PeCoffHeaderOffset = 0;
92 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
93 //
94 // DOS image header is present, so read the PE header after the DOS image
95 // header
96 //
97 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
98 }
99
100 //
101 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
102 // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic
103 // determins if this is a PE32 or PE32+ image. The magic is in the same
104 // location in both images.
105 //
106 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
107 Status = ImageContext->ImageRead (
108 ImageContext->Handle,
109 ImageContext->PeCoffHeaderOffset,
110 &Size,
111 Hdr.Pe32
112 );
113 if (RETURN_ERROR (Status)) {
114 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
115 return Status;
116 }
117
118 //
119 // Use Signature to figure out if we understand the image format
120 //
121 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
122 ImageContext->IsTeImage = TRUE;
123 ImageContext->Machine = Hdr.Te->Machine;
124 ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);
125 ImageContext->ImageSize = 0;
126 ImageContext->SectionAlignment = 4096;
127 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
128
129 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
130 ImageContext->IsTeImage = FALSE;
131 ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;
132
133 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
134
135 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
136 //
137 // Use PE32 offset
138 //
139 ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;
140 ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;
141 ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
142 ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
143
144 } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
145 //
146 // Use PE32+ offset
147 //
148 ImageContext->ImageType = Hdr.Pe32Plus->OptionalHeader.Subsystem;
149 ImageContext->ImageSize = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
150 ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
151 ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
152 } else {
153 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
154 return RETURN_UNSUPPORTED;
155 }
156 } else {
157 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
158 return RETURN_UNSUPPORTED;
159 }
160
161 if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {
162 //
163 // If the PE/COFF loader does not support the image type return
164 // unsupported. This library can suport lots of types of images
165 // this does not mean the user of this library can call the entry
166 // point of the image.
167 //
168 return RETURN_UNSUPPORTED;
169 }
170
171 return RETURN_SUCCESS;
172 }
173
174
175 /**
176 Retrieves information about a PE/COFF image.
177
178 Computes the PeCoffHeaderOffset, ImageAddress, ImageSize, DestinationAddress, CodeView,
179 PdbPointer, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
180 fields of the ImageContext structure. If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
181 If the PE/COFF image accessed through the ImageRead service in the ImageContext structure is not
182 a supported PE/COFF image type, then return RETURN_UNSUPPORTED. If any errors occur while
183 computing the fields of ImageContext, then the error status is returned in the ImageError field of
184 ImageContext.
185
186 @param ImageContext Pointer to the image context structure that describes the PE/COFF
187 image that needs to be examined by this function.
188
189 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
190 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
191 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
192
193 **/
194 RETURN_STATUS
195 EFIAPI
196 PeCoffLoaderGetImageInfo (
197 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
198 )
199 {
200 RETURN_STATUS Status;
201 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
202 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
203 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
204 UINTN Size;
205 UINTN Index;
206 UINTN DebugDirectoryEntryRva;
207 UINTN DebugDirectoryEntryFileOffset;
208 UINTN SectionHeaderOffset;
209 EFI_IMAGE_SECTION_HEADER SectionHeader;
210 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
211 UINT32 NumberOfRvaAndSizes;
212 UINT16 Magic;
213
214 if (NULL == ImageContext) {
215 return RETURN_INVALID_PARAMETER;
216 }
217 //
218 // Assume success
219 //
220 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
221
222 Hdr.Union = &HdrData;
223 Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);
224 if (RETURN_ERROR (Status)) {
225 return Status;
226 }
227
228 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
229
230 //
231 // Retrieve the base address of the image
232 //
233 if (!(ImageContext->IsTeImage)) {
234 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
235 //
236 // Use PE32 offset
237 //
238 ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;
239 } else {
240 //
241 // Use PE32+ offset
242 //
243 ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;
244 }
245 } else {
246 ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
247 }
248
249 //
250 // Initialize the alternate destination address to 0 indicating that it
251 // should not be used.
252 //
253 ImageContext->DestinationAddress = 0;
254
255 //
256 // Initialize the codeview pointer.
257 //
258 ImageContext->CodeView = NULL;
259 ImageContext->PdbPointer = NULL;
260
261 //
262 // Three cases with regards to relocations:
263 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
264 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
265 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
266 // has no base relocs to apply
267 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
268 //
269 // Look at the file header to determine if relocations have been stripped, and
270 // save this info in the image context for later use.
271 //
272 if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
273 ImageContext->RelocationsStripped = TRUE;
274 } else {
275 ImageContext->RelocationsStripped = FALSE;
276 }
277
278 if (!(ImageContext->IsTeImage)) {
279 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
280 //
281 // Use PE32 offset
282 //
283 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
284 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
285 } else {
286 //
287 // Use PE32+ offset
288 //
289 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
290 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
291 }
292
293 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
294
295 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
296
297 //
298 // Determine the file offset of the debug directory... This means we walk
299 // the sections to find which section contains the RVA of the debug
300 // directory
301 //
302 DebugDirectoryEntryFileOffset = 0;
303
304 SectionHeaderOffset = (UINTN)(
305 ImageContext->PeCoffHeaderOffset +
306 sizeof (UINT32) +
307 sizeof (EFI_IMAGE_FILE_HEADER) +
308 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
309 );
310
311 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
312 //
313 // Read section header from file
314 //
315 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
316 Status = ImageContext->ImageRead (
317 ImageContext->Handle,
318 SectionHeaderOffset,
319 &Size,
320 &SectionHeader
321 );
322 if (RETURN_ERROR (Status)) {
323 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
324 return Status;
325 }
326
327 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
328 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
329
330 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
331 break;
332 }
333
334 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
335 }
336
337 if (DebugDirectoryEntryFileOffset != 0) {
338 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
339 //
340 // Read next debug directory entry
341 //
342 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
343 Status = ImageContext->ImageRead (
344 ImageContext->Handle,
345 DebugDirectoryEntryFileOffset,
346 &Size,
347 &DebugEntry
348 );
349 if (RETURN_ERROR (Status)) {
350 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
351 return Status;
352 }
353 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
354 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
355 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
356 ImageContext->ImageSize += DebugEntry.SizeOfData;
357 }
358
359 return RETURN_SUCCESS;
360 }
361 }
362 }
363 }
364 } else {
365
366 DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];
367 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
368 SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
369
370 DebugDirectoryEntryFileOffset = 0;
371
372 for (Index = 0; Index < Hdr.Te->NumberOfSections;) {
373 //
374 // Read section header from file
375 //
376 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
377 Status = ImageContext->ImageRead (
378 ImageContext->Handle,
379 SectionHeaderOffset,
380 &Size,
381 &SectionHeader
382 );
383 if (RETURN_ERROR (Status)) {
384 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
385 return Status;
386 }
387
388 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
389 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
390 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
391 SectionHeader.VirtualAddress +
392 SectionHeader.PointerToRawData +
393 sizeof (EFI_TE_IMAGE_HEADER) -
394 Hdr.Te->StrippedSize;
395
396 //
397 // File offset of the debug directory was found, if this is not the last
398 // section, then skip to the last section for calculating the image size.
399 //
400 if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {
401 SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
402 Index = Hdr.Te->NumberOfSections - 1;
403 continue;
404 }
405 }
406
407 //
408 // In Te image header there is not a field to describe the ImageSize.
409 // Actually, the ImageSize equals the RVA plus the VirtualSize of
410 // the last section mapped into memory (Must be rounded up to
411 // a mulitple of Section Alignment). Per the PE/COFF specification, the
412 // section headers in the Section Table must appear in order of the RVA
413 // values for the corresponding sections. So the ImageSize can be determined
414 // by the RVA and the VirtualSize of the last section header in the
415 // Section Table.
416 //
417 if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {
418 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +
419 ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);
420 }
421
422 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
423 }
424
425 if (DebugDirectoryEntryFileOffset != 0) {
426 for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
427 //
428 // Read next debug directory entry
429 //
430 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
431 Status = ImageContext->ImageRead (
432 ImageContext->Handle,
433 DebugDirectoryEntryFileOffset,
434 &Size,
435 &DebugEntry
436 );
437 if (RETURN_ERROR (Status)) {
438 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
439 return Status;
440 }
441
442 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
443 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
444 return RETURN_SUCCESS;
445 }
446 }
447 }
448 }
449
450 return RETURN_SUCCESS;
451 }
452
453
454 /**
455 Converts an image address to the loaded address.
456
457 @param ImageContext The context of the image being loaded.
458 @param Address The address to be converted to the loaded address.
459
460 @return The converted address or NULL if the address can not be converted.
461
462 **/
463 VOID *
464 PeCoffLoaderImageAddress (
465 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
466 IN UINTN Address
467 )
468 {
469 //
470 // @bug Check to make sure ImageSize is correct for the relocated image.
471 // it may only work for the file we start with and not the relocated image
472 //
473 if (Address >= ImageContext->ImageSize) {
474 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
475 return NULL;
476 }
477
478 return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address);
479 }
480
481 /**
482 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
483
484 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
485 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
486 of ImageContext as the relocation base address. The caller must allocate the relocation
487 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
488 If ImageContext is NULL, then ASSERT().
489
490 @param ImageContext Pointer to the image context structure that describes the PE/COFF
491 image that is being relocated.
492
493 @retval RETURN_SUCCESS The PE/COFF image was relocated.
494 Extended status information is in the ImageError field of ImageContext.
495 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
496 Extended status information is in the ImageError field of ImageContext.
497 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
498 Extended status information is in the ImageError field of ImageContext.
499
500 **/
501 RETURN_STATUS
502 EFIAPI
503 PeCoffLoaderRelocateImage (
504 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
505 )
506 {
507 RETURN_STATUS Status;
508 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
509 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
510 UINT64 Adjust;
511 EFI_IMAGE_BASE_RELOCATION *RelocBase;
512 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
513 UINT16 *Reloc;
514 UINT16 *RelocEnd;
515 CHAR8 *Fixup;
516 CHAR8 *FixupBase;
517 UINT16 *F16;
518 UINT32 *F32;
519 UINT64 *F64;
520 CHAR8 *FixupData;
521 PHYSICAL_ADDRESS BaseAddress;
522 UINT32 NumberOfRvaAndSizes;
523 UINT16 Magic;
524
525 ASSERT (ImageContext != NULL);
526
527 //
528 // Assume success
529 //
530 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
531
532 //
533 // If there are no relocation entries, then we are done
534 //
535 if (ImageContext->RelocationsStripped) {
536 return RETURN_SUCCESS;
537 }
538
539 //
540 // If the destination address is not 0, use that rather than the
541 // image address as the relocation target.
542 //
543 if (ImageContext->DestinationAddress != 0) {
544 BaseAddress = ImageContext->DestinationAddress;
545 } else if (!(ImageContext->IsTeImage)) {
546 BaseAddress = ImageContext->ImageAddress;
547 } else {
548 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
549 BaseAddress = ImageContext->ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
550 }
551
552 if (!(ImageContext->IsTeImage)) {
553 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
554
555 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
556
557 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
558 //
559 // Use PE32 offset
560 //
561 Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
562 Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
563
564 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
565 RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
566 } else {
567 //
568 // Use PE32+ offset
569 //
570 Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
571 Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
572
573 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
574 RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
575 }
576
577 //
578 // Find the relocation block
579 // Per the PE/COFF spec, you can't assume that a given data directory
580 // is present in the image. You have to check the NumberOfRvaAndSizes in
581 // the optional header to verify a desired directory entry is there.
582 //
583
584 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
585 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
586 RelocBaseEnd = PeCoffLoaderImageAddress (
587 ImageContext,
588 RelocDir->VirtualAddress + RelocDir->Size - 1
589 );
590 } else {
591 //
592 // Set base and end to bypass processing below.
593 //
594 RelocBase = RelocBaseEnd = 0;
595 }
596 } else {
597 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
598 Adjust = (UINT64) (BaseAddress - Hdr.Te->ImageBase);
599 Hdr.Te->ImageBase = (UINT64) (BaseAddress);
600
601 //
602 // Find the relocation block
603 //
604 RelocDir = &Hdr.Te->DataDirectory[0];
605 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
606 ImageContext->ImageAddress +
607 RelocDir->VirtualAddress +
608 sizeof(EFI_TE_IMAGE_HEADER) -
609 Hdr.Te->StrippedSize
610 );
611 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
612 }
613
614 //
615 // Run the relocation information and apply the fixups
616 //
617 FixupData = ImageContext->FixupData;
618 while (RelocBase < RelocBaseEnd) {
619
620 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
621 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
622 if (!(ImageContext->IsTeImage)) {
623 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
624 } else {
625 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
626 RelocBase->VirtualAddress +
627 sizeof(EFI_TE_IMAGE_HEADER) -
628 Hdr.Te->StrippedSize
629 );
630 }
631
632 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
633 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
634 (UINTN)ImageContext->ImageSize)) {
635 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
636 return RETURN_LOAD_ERROR;
637 }
638
639 //
640 // Run this relocation record
641 //
642 while (Reloc < RelocEnd) {
643
644 Fixup = FixupBase + (*Reloc & 0xFFF);
645 switch ((*Reloc) >> 12) {
646 case EFI_IMAGE_REL_BASED_ABSOLUTE:
647 break;
648
649 case EFI_IMAGE_REL_BASED_HIGH:
650 F16 = (UINT16 *) Fixup;
651 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
652 if (FixupData != NULL) {
653 *(UINT16 *) FixupData = *F16;
654 FixupData = FixupData + sizeof (UINT16);
655 }
656 break;
657
658 case EFI_IMAGE_REL_BASED_LOW:
659 F16 = (UINT16 *) Fixup;
660 *F16 = (UINT16) (*F16 + (UINT16) Adjust);
661 if (FixupData != NULL) {
662 *(UINT16 *) FixupData = *F16;
663 FixupData = FixupData + sizeof (UINT16);
664 }
665 break;
666
667 case EFI_IMAGE_REL_BASED_HIGHLOW:
668 F32 = (UINT32 *) Fixup;
669 *F32 = *F32 + (UINT32) Adjust;
670 if (FixupData != NULL) {
671 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
672 *(UINT32 *)FixupData = *F32;
673 FixupData = FixupData + sizeof (UINT32);
674 }
675 break;
676
677 case EFI_IMAGE_REL_BASED_DIR64:
678 F64 = (UINT64 *) Fixup;
679 *F64 = *F64 + (UINT64) Adjust;
680 if (FixupData != NULL) {
681 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
682 *(UINT64 *)(FixupData) = *F64;
683 FixupData = FixupData + sizeof(UINT64);
684 }
685 break;
686
687 default:
688 //
689 // The common code does not handle some of the stranger IPF relocations
690 // PeCoffLoaderRelocateImageEx () addes support for these complex fixups
691 // on IPF and is a No-Op on other archtiectures.
692 //
693 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
694 if (RETURN_ERROR (Status)) {
695 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
696 return Status;
697 }
698 }
699
700 //
701 // Next relocation record
702 //
703 Reloc += 1;
704 }
705
706 //
707 // Next reloc block
708 //
709 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
710 }
711
712 return RETURN_SUCCESS;
713 }
714
715 /**
716 Loads a PE/COFF image into memory.
717
718 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
719 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
720 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
721 The EntryPoint, FixupDataSize, CodeView, and PdbPointer fields of ImageContext are computed.
722 If ImageContext is NULL, then ASSERT().
723
724 @param ImageContext Pointer to the image context structure that describes the PE/COFF
725 image that is being loaded.
726
727 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
728 the ImageAddress and ImageSize fields of ImageContext.
729 Extended status information is in the ImageError field of ImageContext.
730 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
731 Extended status information is in the ImageError field of ImageContext.
732 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
733 Extended status information is in the ImageError field of ImageContext.
734 @retval RETURN_INVALID_PARAMETER The image address is invalid.
735 Extended status information is in the ImageError field of ImageContext.
736
737 **/
738 RETURN_STATUS
739 EFIAPI
740 PeCoffLoaderLoadImage (
741 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
742 )
743 {
744 RETURN_STATUS Status;
745 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
746 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
747 EFI_IMAGE_SECTION_HEADER *FirstSection;
748 EFI_IMAGE_SECTION_HEADER *Section;
749 UINTN NumberOfSections;
750 UINTN Index;
751 CHAR8 *Base;
752 CHAR8 *End;
753 CHAR8 *MaxEnd;
754 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
755 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
756 UINTN Size;
757 UINT32 TempDebugEntryRva;
758 UINT32 NumberOfRvaAndSizes;
759 UINT16 Magic;
760
761 ASSERT (ImageContext != NULL);
762
763 //
764 // Assume success
765 //
766 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
767
768 //
769 // Copy the provided context info into our local version, get what we
770 // can from the original image, and then use that to make sure everything
771 // is legit.
772 //
773 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
774
775 Status = PeCoffLoaderGetImageInfo (&CheckContext);
776 if (RETURN_ERROR (Status)) {
777 return Status;
778 }
779
780 //
781 // Make sure there is enough allocated space for the image being loaded
782 //
783 if (ImageContext->ImageSize < CheckContext.ImageSize) {
784 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
785 return RETURN_BUFFER_TOO_SMALL;
786 }
787 if (ImageContext->ImageAddress == 0) {
788 //
789 // Image cannot be loaded into 0 address.
790 //
791 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
792 return RETURN_INVALID_PARAMETER;
793 }
794 //
795 // If there's no relocations, then make sure it's not a runtime driver,
796 // and that it's being loaded at the linked address.
797 //
798 if (CheckContext.RelocationsStripped) {
799 //
800 // If the image does not contain relocations and it is a runtime driver
801 // then return an error.
802 //
803 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
804 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
805 return RETURN_LOAD_ERROR;
806 }
807 //
808 // If the image does not contain relocations, and the requested load address
809 // is not the linked address, then return an error.
810 //
811 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
812 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
813 return RETURN_INVALID_PARAMETER;
814 }
815 }
816 //
817 // Make sure the allocated space has the proper section alignment
818 //
819 if (!(ImageContext->IsTeImage)) {
820 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
821 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
822 return RETURN_INVALID_PARAMETER;
823 }
824 }
825 //
826 // Read the entire PE/COFF or TE header into memory
827 //
828 if (!(ImageContext->IsTeImage)) {
829 Status = ImageContext->ImageRead (
830 ImageContext->Handle,
831 0,
832 &ImageContext->SizeOfHeaders,
833 (VOID *) (UINTN) ImageContext->ImageAddress
834 );
835
836 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
837
838 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
839 (UINTN)ImageContext->ImageAddress +
840 ImageContext->PeCoffHeaderOffset +
841 sizeof(UINT32) +
842 sizeof(EFI_IMAGE_FILE_HEADER) +
843 Hdr.Pe32->FileHeader.SizeOfOptionalHeader
844 );
845 NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
846 } else {
847 Status = ImageContext->ImageRead (
848 ImageContext->Handle,
849 0,
850 &ImageContext->SizeOfHeaders,
851 (void *)(UINTN)ImageContext->ImageAddress
852 );
853
854 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
855
856 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
857 (UINTN)ImageContext->ImageAddress +
858 sizeof(EFI_TE_IMAGE_HEADER)
859 );
860 NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);
861
862 }
863
864 if (RETURN_ERROR (Status)) {
865 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
866 return RETURN_LOAD_ERROR;
867 }
868
869 //
870 // Load each section of the image
871 //
872 Section = FirstSection;
873 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
874
875 //
876 // Compute sections address
877 //
878 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
879 End = PeCoffLoaderImageAddress (
880 ImageContext,
881 Section->VirtualAddress + Section->Misc.VirtualSize - 1
882 );
883 if (ImageContext->IsTeImage) {
884 Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);
885 End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);
886 }
887
888 if (End > MaxEnd) {
889 MaxEnd = End;
890 }
891 //
892 // If the base start or end address resolved to 0, then fail.
893 //
894 if ((Base == NULL) || (End == NULL)) {
895 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
896 return RETURN_LOAD_ERROR;
897 }
898
899 //
900 // Read the section
901 //
902 Size = (UINTN) Section->Misc.VirtualSize;
903 if ((Size == 0) || (Size > Section->SizeOfRawData)) {
904 Size = (UINTN) Section->SizeOfRawData;
905 }
906
907 if (Section->SizeOfRawData) {
908 if (!(ImageContext->IsTeImage)) {
909 Status = ImageContext->ImageRead (
910 ImageContext->Handle,
911 Section->PointerToRawData,
912 &Size,
913 Base
914 );
915 } else {
916 Status = ImageContext->ImageRead (
917 ImageContext->Handle,
918 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,
919 &Size,
920 Base
921 );
922 }
923
924 if (RETURN_ERROR (Status)) {
925 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
926 return Status;
927 }
928 }
929
930 //
931 // If raw size is less then virt size, zero fill the remaining
932 //
933
934 if (Size < Section->Misc.VirtualSize) {
935 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
936 }
937
938 //
939 // Next Section
940 //
941 Section += 1;
942 }
943
944 //
945 // Get image's entry point
946 //
947 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
948 if (!(ImageContext->IsTeImage)) {
949 //
950 // Sizes of AddressOfEntryPoint are different so we need to do this safely
951 //
952 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
953 //
954 // Use PE32 offset
955 //
956 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
957 ImageContext,
958 (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint
959 );
960 } else {
961 //
962 // Use PE32+ offset
963 //
964 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
965 ImageContext,
966 (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint
967 );
968 }
969 } else {
970 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (
971 (UINTN)ImageContext->ImageAddress +
972 (UINTN)Hdr.Te->AddressOfEntryPoint +
973 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
974 (UINTN)Hdr.Te->StrippedSize
975 );
976 }
977
978 //
979 // Determine the size of the fixup data
980 //
981 // Per the PE/COFF spec, you can't assume that a given data directory
982 // is present in the image. You have to check the NumberOfRvaAndSizes in
983 // the optional header to verify a desired directory entry is there.
984 //
985 if (!(ImageContext->IsTeImage)) {
986 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
987 //
988 // Use PE32 offset
989 //
990 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
991 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
992 } else {
993 //
994 // Use PE32+ offset
995 //
996 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
997 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
998 }
999
1000 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1001 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1002 } else {
1003 ImageContext->FixupDataSize = 0;
1004 }
1005 } else {
1006 DirectoryEntry = &Hdr.Te->DataDirectory[0];
1007 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
1008 }
1009 //
1010 // Consumer must allocate a buffer for the relocation fixup log.
1011 // Only used for runtime drivers.
1012 //
1013 ImageContext->FixupData = NULL;
1014
1015 //
1016 // Load the Codeview info if present
1017 //
1018 if (ImageContext->DebugDirectoryEntryRva != 0) {
1019 if (!(ImageContext->IsTeImage)) {
1020 DebugEntry = PeCoffLoaderImageAddress (
1021 ImageContext,
1022 ImageContext->DebugDirectoryEntryRva
1023 );
1024 } else {
1025 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
1026 ImageContext->ImageAddress +
1027 ImageContext->DebugDirectoryEntryRva +
1028 sizeof(EFI_TE_IMAGE_HEADER) -
1029 Hdr.Te->StrippedSize
1030 );
1031 }
1032
1033 if (DebugEntry != NULL) {
1034 TempDebugEntryRva = DebugEntry->RVA;
1035 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
1036 Section--;
1037 if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
1038 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
1039 } else {
1040 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
1041 }
1042 }
1043
1044 if (TempDebugEntryRva != 0) {
1045 if (!(ImageContext->IsTeImage)) {
1046 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
1047 } else {
1048 ImageContext->CodeView = (VOID *)(
1049 (UINTN)ImageContext->ImageAddress +
1050 (UINTN)TempDebugEntryRva +
1051 (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -
1052 (UINTN) Hdr.Te->StrippedSize
1053 );
1054 }
1055
1056 if (ImageContext->CodeView == NULL) {
1057 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1058 return RETURN_LOAD_ERROR;
1059 }
1060
1061 if (DebugEntry->RVA == 0) {
1062 Size = DebugEntry->SizeOfData;
1063 if (!(ImageContext->IsTeImage)) {
1064 Status = ImageContext->ImageRead (
1065 ImageContext->Handle,
1066 DebugEntry->FileOffset,
1067 &Size,
1068 ImageContext->CodeView
1069 );
1070 } else {
1071 Status = ImageContext->ImageRead (
1072 ImageContext->Handle,
1073 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,
1074 &Size,
1075 ImageContext->CodeView
1076 );
1077 //
1078 // Should we apply fix up to this field according to the size difference between PE and TE?
1079 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1080 // in original PE image.
1081 //
1082 }
1083
1084 if (RETURN_ERROR (Status)) {
1085 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
1086 return RETURN_LOAD_ERROR;
1087 }
1088
1089 DebugEntry->RVA = TempDebugEntryRva;
1090 }
1091
1092 switch (*(UINT32 *) ImageContext->CodeView) {
1093 case CODEVIEW_SIGNATURE_NB10:
1094 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
1095 break;
1096
1097 case CODEVIEW_SIGNATURE_RSDS:
1098 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
1099 break;
1100
1101 default:
1102 break;
1103 }
1104 }
1105 }
1106 }
1107
1108 return Status;
1109 }
1110
1111
1112 /**
1113 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1114 runtime.
1115
1116 PE_COFF_LOADER_IMAGE_CONTEXT.FixupData stores information needed to reapply
1117 the fixups with a virtual mapping.
1118
1119
1120 @param ImageBase Base address of relocated image
1121 @param VirtImageBase Virtual mapping for ImageBase
1122 @param ImageSize Size of the image to relocate
1123 @param RelocationData Location to place results of read
1124
1125 **/
1126 VOID
1127 EFIAPI
1128 PeCoffLoaderRelocateImageForRuntime (
1129 IN PHYSICAL_ADDRESS ImageBase,
1130 IN PHYSICAL_ADDRESS VirtImageBase,
1131 IN UINTN ImageSize,
1132 IN VOID *RelocationData
1133 )
1134 {
1135 CHAR8 *OldBase;
1136 CHAR8 *NewBase;
1137 EFI_IMAGE_DOS_HEADER *DosHdr;
1138 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
1139 UINT32 NumberOfRvaAndSizes;
1140 EFI_IMAGE_DATA_DIRECTORY *DataDirectory;
1141 EFI_IMAGE_DATA_DIRECTORY *RelocDir;
1142 EFI_IMAGE_BASE_RELOCATION *RelocBase;
1143 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
1144 UINT16 *Reloc;
1145 UINT16 *RelocEnd;
1146 CHAR8 *Fixup;
1147 CHAR8 *FixupBase;
1148 UINT16 *F16;
1149 UINT32 *F32;
1150 UINT64 *F64;
1151 CHAR8 *FixupData;
1152 UINTN Adjust;
1153 RETURN_STATUS Status;
1154 UINT16 Magic;
1155
1156 OldBase = (CHAR8 *)((UINTN)ImageBase);
1157 NewBase = (CHAR8 *)((UINTN)VirtImageBase);
1158 Adjust = (UINTN) NewBase - (UINTN) OldBase;
1159
1160 //
1161 // Find the image's relocate dir info
1162 //
1163 DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;
1164 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
1165 //
1166 // Valid DOS header so get address of PE header
1167 //
1168 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
1169 } else {
1170 //
1171 // No Dos header so assume image starts with PE header.
1172 //
1173 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
1174 }
1175
1176 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
1177 //
1178 // Not a valid PE image so Exit
1179 //
1180 return ;
1181 }
1182
1183 Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
1184
1185 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1186 //
1187 // Use PE32 offset
1188 //
1189 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
1190 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);
1191 } else {
1192 //
1193 // Use PE32+ offset
1194 //
1195 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
1196 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);
1197 }
1198
1199 //
1200 // Find the relocation block
1201 //
1202 // Per the PE/COFF spec, you can't assume that a given data directory
1203 // is present in the image. You have to check the NumberOfRvaAndSizes in
1204 // the optional header to verify a desired directory entry is there.
1205 //
1206 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
1207 RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
1208 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);
1209 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);
1210 } else {
1211 //
1212 // Cannot find relocations, cannot continue
1213 //
1214 ASSERT (FALSE);
1215 return ;
1216 }
1217
1218 ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
1219
1220 //
1221 // Run the whole relocation block. And re-fixup data that has not been
1222 // modified. The FixupData is used to see if the image has been modified
1223 // since it was relocated. This is so data sections that have been updated
1224 // by code will not be fixed up, since that would set them back to
1225 // defaults.
1226 //
1227 FixupData = RelocationData;
1228 while (RelocBase < RelocBaseEnd) {
1229
1230 Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
1231 RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
1232 FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;
1233
1234 //
1235 // Run this relocation record
1236 //
1237 while (Reloc < RelocEnd) {
1238
1239 Fixup = FixupBase + (*Reloc & 0xFFF);
1240 switch ((*Reloc) >> 12) {
1241
1242 case EFI_IMAGE_REL_BASED_ABSOLUTE:
1243 break;
1244
1245 case EFI_IMAGE_REL_BASED_HIGH:
1246 F16 = (UINT16 *) Fixup;
1247 if (*(UINT16 *) FixupData == *F16) {
1248 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
1249 }
1250
1251 FixupData = FixupData + sizeof (UINT16);
1252 break;
1253
1254 case EFI_IMAGE_REL_BASED_LOW:
1255 F16 = (UINT16 *) Fixup;
1256 if (*(UINT16 *) FixupData == *F16) {
1257 *F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff));
1258 }
1259
1260 FixupData = FixupData + sizeof (UINT16);
1261 break;
1262
1263 case EFI_IMAGE_REL_BASED_HIGHLOW:
1264 F32 = (UINT32 *) Fixup;
1265 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
1266 if (*(UINT32 *) FixupData == *F32) {
1267 *F32 = *F32 + (UINT32) Adjust;
1268 }
1269
1270 FixupData = FixupData + sizeof (UINT32);
1271 break;
1272
1273 case EFI_IMAGE_REL_BASED_DIR64:
1274 F64 = (UINT64 *)Fixup;
1275 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
1276 if (*(UINT64 *) FixupData == *F64) {
1277 *F64 = *F64 + (UINT64)Adjust;
1278 }
1279
1280 FixupData = FixupData + sizeof (UINT64);
1281 break;
1282
1283 case EFI_IMAGE_REL_BASED_HIGHADJ:
1284 //
1285 // Not implemented, but not used in EFI 1.0
1286 //
1287 ASSERT (FALSE);
1288 break;
1289
1290 default:
1291 //
1292 // Only Itanium requires ConvertPeImage_Ex
1293 //
1294 Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
1295 if (RETURN_ERROR (Status)) {
1296 return ;
1297 }
1298 }
1299 //
1300 // Next relocation record
1301 //
1302 Reloc += 1;
1303 }
1304 //
1305 // next reloc block
1306 //
1307 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
1308 }
1309 }
1310
1311
1312 /**
1313 ImageRead function that operates on a memory buffer whos base is passed into
1314 FileHandle.
1315
1316 @param FileHandle Ponter to baes of the input stream
1317 @param FileOffset Offset to the start of the buffer
1318 @param ReadSize Number of bytes to copy into the buffer
1319 @param Buffer Location to place results of read
1320
1321 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1322 the buffer.
1323 **/
1324 RETURN_STATUS
1325 EFIAPI
1326 PeCoffLoaderImageReadFromMemory (
1327 IN VOID *FileHandle,
1328 IN UINTN FileOffset,
1329 IN OUT UINTN *ReadSize,
1330 OUT VOID *Buffer
1331 )
1332 {
1333 CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);
1334 return RETURN_SUCCESS;
1335 }
1336
1337 /**
1338 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1339
1340 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1341 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1342 this function can simply return RETURN_SUCCESS.
1343
1344 @param ImageContext Pointer to the image context structure that describes the PE/COFF
1345 image to be unloaded.
1346
1347 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1348 **/
1349 RETURN_STATUS
1350 EFIAPI
1351 PeCoffLoaderUnloadImage (
1352 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1353 )
1354 {
1355 return RETURN_SUCCESS;
1356 }