VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware2/VBoxPkg/Library/VBoxPeCoffLib/BasePeCoff.c@ 35644

Last change on this file since 35644 was 35644, checked in by vboxsync, 14 years ago

EFI: more log clean up.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette