VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

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