3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 EfiLdrPeCoffLoadPeRelocate (
27 IN EFILDR_LOADED_IMAGE
*Image
,
28 IN EFI_IMAGE_DATA_DIRECTORY
*RelocDir
,
30 IN UINTN
*NumberOfMemoryMapEntries
,
31 IN EFI_MEMORY_DESCRIPTOR
*EfiMemoryDescriptor
36 EfiLdrPeCoffImageRead (
39 IN OUT UINTN ReadSize
,
45 EfiLdrPeCoffImageAddress (
46 IN EFILDR_LOADED_IMAGE
*Image
,
52 EfiLdrPeCoffSetImageType (
53 IN OUT EFILDR_LOADED_IMAGE
*Image
,
58 EfiLdrPeCoffCheckImageMachineType (
63 EfiLdrGetPeImageInfo (
65 OUT UINT64
*ImageBase
,
70 EFI_IMAGE_DOS_HEADER DosHdr
;
71 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
73 ZeroMem (&DosHdr
, sizeof(DosHdr
));
74 ZeroMem (&PeHdr
, sizeof(PeHdr
));
80 EfiLdrPeCoffImageRead (FHand
, 0, sizeof(DosHdr
), &DosHdr
);
81 if (DosHdr
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
82 return EFI_UNSUPPORTED
;
85 EfiLdrPeCoffImageRead (FHand
, DosHdr
.e_lfanew
, sizeof(PeHdr
), &PeHdr
);
87 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
88 return EFI_UNSUPPORTED
;
92 // Verify machine type
95 Status
= EfiLdrPeCoffCheckImageMachineType (PeHdr
.Pe32
.FileHeader
.Machine
);
96 if (EFI_ERROR(Status
)) {
100 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
101 *ImageBase
= (UINT32
)PeHdr
.Pe32
.OptionalHeader
.ImageBase
;
102 } else if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
103 *ImageBase
= PeHdr
.Pe32Plus
.OptionalHeader
.ImageBase
;
105 return EFI_UNSUPPORTED
;
108 *ImageSize
= PeHdr
.Pe32
.OptionalHeader
.SizeOfImage
;
114 EfiLdrPeCoffLoadPeImage (
116 IN EFILDR_LOADED_IMAGE
*Image
,
117 IN UINTN
*NumberOfMemoryMapEntries
,
118 IN EFI_MEMORY_DESCRIPTOR
*EfiMemoryDescriptor
121 EFI_IMAGE_DOS_HEADER DosHdr
;
122 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
123 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
124 EFI_IMAGE_SECTION_HEADER
*Section
;
129 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
131 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY TempDebugEntry
;
132 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
134 UINTN CodeViewOffset
;
135 UINTN CodeViewFileOffset
;
136 UINTN OptionalHeaderSize
;
138 UINT32 NumberOfRvaAndSizes
;
139 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
141 CHAR8 PrintBuffer
[256];
143 ZeroMem (&DosHdr
, sizeof(DosHdr
));
144 ZeroMem (&PeHdr
, sizeof(PeHdr
));
147 // Read image headers
150 EfiLdrPeCoffImageRead (FHand
, 0, sizeof(DosHdr
), &DosHdr
);
151 if (DosHdr
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
152 AsciiSPrint (PrintBuffer
, 256, "PeCoffLoadPeImage: Dos header signature not found\n");
153 PrintString (PrintBuffer
);
155 return EFI_UNSUPPORTED
;
158 EfiLdrPeCoffImageRead (FHand
, DosHdr
.e_lfanew
, sizeof(PeHdr
), &PeHdr
);
160 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
161 AsciiSPrint (PrintBuffer
, 256, "PeCoffLoadPeImage: PE image header signature not found\n");
162 PrintString (PrintBuffer
);
164 return EFI_UNSUPPORTED
;
168 // Set the image subsystem type
171 Status
= EfiLdrPeCoffSetImageType (Image
, PeHdr
.Pe32
.OptionalHeader
.Subsystem
);
172 if (EFI_ERROR(Status
)) {
173 AsciiSPrint (PrintBuffer
, 256, "PeCoffLoadPeImage: Subsystem type not known\n");
174 PrintString (PrintBuffer
);
180 // Verify machine type
183 Status
= EfiLdrPeCoffCheckImageMachineType (PeHdr
.Pe32
.FileHeader
.Machine
);
184 if (EFI_ERROR(Status
)) {
185 AsciiSPrint (PrintBuffer
, 256, "PeCoffLoadPeImage: Incorrect machine type\n");
186 PrintString (PrintBuffer
);
192 // Compute the amount of memory needed to load the image and
193 // allocate it. This will include all sections plus the codeview debug info.
194 // Since the codeview info is actually outside of the image, we calculate
195 // its size seperately and add it to the total.
197 // Memory starts off as data
201 CodeViewFileOffset
= 0;
202 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
203 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(PeHdr
.Pe32
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
204 } else if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
205 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(PeHdr
.Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
207 return EFI_UNSUPPORTED
;
210 (DirCount
< DirectoryEntry
->Size
/ sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) && (CodeViewSize
== 0);
212 Status
= EfiLdrPeCoffImageRead (
214 DirectoryEntry
->VirtualAddress
+ DirCount
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
),
215 sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
),
218 if (!EFI_ERROR (Status
)) {
219 if (TempDebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
220 CodeViewSize
= TempDebugEntry
.SizeOfData
;
221 CodeViewFileOffset
= TempDebugEntry
.FileOffset
;
226 CodeViewOffset
= PeHdr
.Pe32
.OptionalHeader
.SizeOfImage
+ PeHdr
.Pe32
.OptionalHeader
.SectionAlignment
;
227 Image
->NoPages
= EFI_SIZE_TO_PAGES (CodeViewOffset
+ CodeViewSize
);
230 // Compute the amount of memory needed to load the image and
231 // allocate it. Memory starts off as data
234 Image
->ImageBasePage
= (EFI_PHYSICAL_ADDRESS
)FindSpace (Image
->NoPages
, NumberOfMemoryMapEntries
, EfiMemoryDescriptor
, EfiRuntimeServicesCode
, EFI_MEMORY_WB
);
235 if (Image
->ImageBasePage
== 0) {
236 return EFI_OUT_OF_RESOURCES
;
239 if (EFI_ERROR(Status
)) {
244 AsciiSPrint (PrintBuffer
, 256, "LoadPe: new image base %lx\n", Image
->ImageBasePage
);
245 PrintString (PrintBuffer
);
246 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)Image
->ImageBasePage
;
247 Image
->Info
.ImageSize
= (Image
->NoPages
<< EFI_PAGE_SHIFT
) - 1;
248 Image
->ImageBase
= (UINT8
*)(UINTN
)Image
->ImageBasePage
;
249 Image
->ImageEof
= Image
->ImageBase
+ Image
->Info
.ImageSize
;
250 Image
->ImageAdjust
= Image
->ImageBase
;
253 // Copy the Image header to the base location
255 Status
= EfiLdrPeCoffImageRead (
258 PeHdr
.Pe32
.OptionalHeader
.SizeOfHeaders
,
262 if (EFI_ERROR(Status
)) {
268 // Load each directory of the image into memory...
269 // Save the address of the Debug directory for later
271 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
272 NumberOfRvaAndSizes
= PeHdr
.Pe32
.OptionalHeader
.NumberOfRvaAndSizes
;
273 DataDirectory
= PeHdr
.Pe32
.OptionalHeader
.DataDirectory
;
275 NumberOfRvaAndSizes
= PeHdr
.Pe32Plus
.OptionalHeader
.NumberOfRvaAndSizes
;
276 DataDirectory
= PeHdr
.Pe32Plus
.OptionalHeader
.DataDirectory
;
279 for (Index
= 0; Index
< NumberOfRvaAndSizes
; Index
++) {
280 if ((DataDirectory
[Index
].VirtualAddress
!= 0) && (DataDirectory
[Index
].Size
!= 0)) {
281 Status
= EfiLdrPeCoffImageRead (
283 DataDirectory
[Index
].VirtualAddress
,
284 DataDirectory
[Index
].Size
,
285 Image
->ImageBase
+ DataDirectory
[Index
].VirtualAddress
287 if (EFI_ERROR(Status
)) {
290 if (Index
== EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
291 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (Image
->ImageBase
+ DataDirectory
[Index
].VirtualAddress
);
297 // Load each section of the image
300 // BUGBUG: change this to use the in memory copy
301 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
302 OptionalHeaderSize
= sizeof(EFI_IMAGE_OPTIONAL_HEADER32
);
303 PeHeaderSize
= sizeof(EFI_IMAGE_NT_HEADERS32
);
305 OptionalHeaderSize
= sizeof(EFI_IMAGE_OPTIONAL_HEADER64
);
306 PeHeaderSize
= sizeof(EFI_IMAGE_NT_HEADERS64
);
308 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
312 PeHdr
.Pe32
.FileHeader
.SizeOfOptionalHeader
-
316 Section
= FirstSection
;
317 for (Index
=0; Index
< PeHdr
.Pe32
.FileHeader
.NumberOfSections
; Index
+= 1) {
320 // Compute sections address
323 Base
= EfiLdrPeCoffImageAddress (Image
, (UINTN
)Section
->VirtualAddress
);
324 End
= EfiLdrPeCoffImageAddress (Image
, (UINTN
)(Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
));
326 if (EFI_ERROR(Status
) || !Base
|| !End
) {
327 // DEBUG((D_LOAD|D_ERROR, "LoadPe: Section %d was not loaded\n", Index));
329 return EFI_LOAD_ERROR
;
332 // DEBUG((D_LOAD, "LoadPe: Section %d, loaded at %x\n", Index, Base));
338 if (Section
->SizeOfRawData
) {
339 Status
= EfiLdrPeCoffImageRead (FHand
, Section
->PointerToRawData
, Section
->SizeOfRawData
, Base
);
340 if (EFI_ERROR(Status
)) {
347 // If raw size is less then virt size, zero fill the remaining
350 if (Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
352 Base
+ Section
->SizeOfRawData
,
353 Section
->Misc
.VirtualSize
- Section
->SizeOfRawData
365 // Copy in CodeView information if it exists
367 if (CodeViewSize
!= 0) {
368 Status
= EfiLdrPeCoffImageRead (FHand
, CodeViewFileOffset
, CodeViewSize
, Image
->ImageBase
+ CodeViewOffset
);
369 DebugEntry
->RVA
= (UINT32
) (CodeViewOffset
);
373 // Apply relocations only if needed
375 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
376 ImageBase
= (UINT64
)PeHdr
.Pe32
.OptionalHeader
.ImageBase
;
378 ImageBase
= PeHdr
.Pe32Plus
.OptionalHeader
.ImageBase
;
380 if ((UINTN
)(Image
->ImageBase
) != (UINTN
) (ImageBase
)) {
381 Status
= EfiLdrPeCoffLoadPeRelocate (
383 &DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
],
384 (UINTN
) Image
->ImageBase
- (UINTN
)ImageBase
,
385 NumberOfMemoryMapEntries
,
389 if (EFI_ERROR(Status
)) {
396 // Use exported EFI specific interface if present, else use the image's entry point
398 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)
399 (EfiLdrPeCoffImageAddress(
401 PeHdr
.Pe32
.OptionalHeader
.AddressOfEntryPoint
409 EfiLdrPeCoffLoadPeRelocate (
410 IN EFILDR_LOADED_IMAGE
*Image
,
411 IN EFI_IMAGE_DATA_DIRECTORY
*RelocDir
,
413 IN UINTN
*NumberOfMemoryMapEntries
,
414 IN EFI_MEMORY_DESCRIPTOR
*EfiMemoryDescriptor
417 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
418 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
430 // Find the relocation block
433 RelocBase
= EfiLdrPeCoffImageAddress (Image
, RelocDir
->VirtualAddress
);
434 RelocBaseEnd
= EfiLdrPeCoffImageAddress (Image
, RelocDir
->VirtualAddress
+ RelocDir
->Size
);
435 if (!RelocBase
|| !RelocBaseEnd
) {
437 return EFI_LOAD_ERROR
;
440 NoFixupPages
= EFI_SIZE_TO_PAGES(RelocDir
->Size
/ sizeof(UINT16
) * sizeof(UINTN
));
441 Image
->FixupData
= (UINT8
*) FindSpace (NoFixupPages
, NumberOfMemoryMapEntries
, EfiMemoryDescriptor
, EfiRuntimeServicesData
, EFI_MEMORY_WB
);
442 if (Image
->FixupData
== 0) {
443 return EFI_OUT_OF_RESOURCES
;
447 // Run the whole relocation block
450 FixupData
= Image
->FixupData
;
451 while (RelocBase
< RelocBaseEnd
) {
453 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof(EFI_IMAGE_BASE_RELOCATION
));
454 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
455 FixupBase
= EfiLdrPeCoffImageAddress (Image
, RelocBase
->VirtualAddress
);
456 if ((UINT8
*) RelocEnd
< Image
->ImageBase
|| (UINT8
*) RelocEnd
> Image
->ImageEof
) {
458 return EFI_LOAD_ERROR
;
462 // Run this relocation record
465 while (Reloc
< RelocEnd
) {
467 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
468 switch ((*Reloc
) >> 12) {
470 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
473 case EFI_IMAGE_REL_BASED_HIGH
:
474 F16
= (UINT16
*) Fixup
;
475 *F16
= (UINT16
) (*F16
+ (UINT16
)(((UINT32
)Adjust
) >> 16));
476 if (FixupData
!= NULL
) {
477 *(UINT16
*) FixupData
= *F16
;
478 FixupData
= FixupData
+ sizeof(UINT16
);
482 case EFI_IMAGE_REL_BASED_LOW
:
483 F16
= (UINT16
*) Fixup
;
484 *F16
= *F16
+ (UINT16
) Adjust
;
485 if (FixupData
!= NULL
) {
486 *(UINT16
*) FixupData
= *F16
;
487 FixupData
= FixupData
+ sizeof(UINT16
);
491 case EFI_IMAGE_REL_BASED_HIGHLOW
:
492 F32
= (UINT32
*) Fixup
;
493 *F32
= *F32
+ (UINT32
) Adjust
;
494 if (FixupData
!= NULL
) {
495 FixupData
= ALIGN_POINTER(FixupData
, sizeof(UINT32
));
496 *(UINT32
*) FixupData
= *F32
;
497 FixupData
= FixupData
+ sizeof(UINT32
);
501 case EFI_IMAGE_REL_BASED_DIR64
:
502 F64
= (UINT64
*) Fixup
;
503 *F64
= *F64
+ (UINT64
) Adjust
;
504 if (FixupData
!= NULL
) {
505 FixupData
= ALIGN_POINTER(FixupData
, sizeof(UINT64
));
506 *(UINT64
*) FixupData
= *F64
;
507 FixupData
= FixupData
+ sizeof(UINT64
);
511 case EFI_IMAGE_REL_BASED_HIGHADJ
:
512 CpuDeadLoop(); // BUGBUG: not done
516 // DEBUG((D_LOAD|D_ERROR, "PeRelocate: unknown fixed type\n"));
519 return EFI_LOAD_ERROR
;
527 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
531 // Add Fixup data to whole Image (assume Fixup data just below the image), so that there is no hole in the descriptor.
532 // Because only NoPages or ImageBasePage will be used in EfiLoader(), we update these 2 fields.
534 Image
->NoPages
+= NoFixupPages
;
535 Image
->ImageBasePage
-= (NoFixupPages
<< EFI_PAGE_SHIFT
);
542 EfiLdrPeCoffImageRead (
545 IN OUT UINTN ReadSize
,
549 CopyMem (Buffer
, (VOID
*)((UINTN
)FHand
+ Offset
), ReadSize
);
556 EfiLdrPeCoffImageAddress (
557 IN EFILDR_LOADED_IMAGE
*Image
,
563 FixedAddress
= Image
->ImageAdjust
+ Address
;
565 if ((FixedAddress
< Image
->ImageBase
) || (FixedAddress
> Image
->ImageEof
)) {
566 // DEBUG((D_LOAD|D_ERROR, "PeCoffImageAddress: pointer is outside of image\n"));
572 // "PeCoffImageAddress: ImageBase %x, ImageEof %x, Address %x, FixedAddress %x\n",
583 EfiLdrPeCoffSetImageType (
584 IN OUT EFILDR_LOADED_IMAGE
*Image
,
588 EFI_MEMORY_TYPE CodeType
;
589 EFI_MEMORY_TYPE DataType
;
592 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
593 CodeType
= EfiLoaderCode
;
594 DataType
= EfiLoaderData
;
597 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
598 CodeType
= EfiBootServicesCode
;
599 DataType
= EfiBootServicesData
;
602 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
603 CodeType
= EfiRuntimeServicesCode
;
604 DataType
= EfiRuntimeServicesData
;
608 return EFI_INVALID_PARAMETER
;
611 Image
->Type
= ImageType
;
612 Image
->Info
.ImageCodeType
= CodeType
;
613 Image
->Info
.ImageDataType
= DataType
;
619 EfiLdrPeCoffCheckImageMachineType (
620 IN UINT16 MachineType
625 Status
= EFI_UNSUPPORTED
;
628 if (MachineType
== EFI_IMAGE_MACHINE_IA32
) {
629 Status
= EFI_SUCCESS
;
634 if (MachineType
== EFI_IMAGE_MACHINE_X64
) {
635 Status
= EFI_SUCCESS
;
640 if (MachineType
== EFI_IMAGE_MACHINE_IA64
) {
641 Status
= EFI_SUCCESS
;