VirtualBox

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

Last change on this file since 48674 was 48674, checked in by vboxsync, 11 years ago

EFI: Export newly imported tinaocore UEFI sources to OSE.

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