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
;
142 ZeroMem (&DosHdr
, sizeof(DosHdr
));
143 ZeroMem (&PeHdr
, sizeof(PeHdr
));
146 // Read image headers
149 EfiLdrPeCoffImageRead (FHand
, 0, sizeof(DosHdr
), &DosHdr
);
150 if (DosHdr
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
151 // DEBUG ((D_LOAD, "PeCoffLoadPeImage: Dos header signature not found\n"));
153 return EFI_UNSUPPORTED
;
156 EfiLdrPeCoffImageRead (FHand
, DosHdr
.e_lfanew
, sizeof(PeHdr
), &PeHdr
);
158 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
159 // DEBUG ((D_LOAD, "PeCoffLoadPeImage: PE image header signature not found\n"));
161 return EFI_UNSUPPORTED
;
165 // Set the image subsystem type
168 Status
= EfiLdrPeCoffSetImageType (Image
, PeHdr
.Pe32
.OptionalHeader
.Subsystem
);
169 if (EFI_ERROR(Status
)) {
170 // DEBUG ((D_LOAD, "PeCoffLoadPeImage: Subsystem type not known\n"));
176 // Verify machine type
179 Status
= EfiLdrPeCoffCheckImageMachineType (PeHdr
.Pe32
.FileHeader
.Machine
);
180 if (EFI_ERROR(Status
)) {
181 // DEBUG ((D_LOAD, "PeCoffLoadPeImage: Incorrect machine type\n"));
187 // Compute the amount of memory needed to load the image and
188 // allocate it. This will include all sections plus the codeview debug info.
189 // Since the codeview info is actually outside of the image, we calculate
190 // its size seperately and add it to the total.
192 // Memory starts off as data
196 CodeViewFileOffset
= 0;
197 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
198 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(PeHdr
.Pe32
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
199 } else if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
200 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(PeHdr
.Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
202 return EFI_UNSUPPORTED
;
205 (DirCount
< DirectoryEntry
->Size
/ sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) && (CodeViewSize
== 0);
207 Status
= EfiLdrPeCoffImageRead (
209 DirectoryEntry
->VirtualAddress
+ DirCount
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
),
210 sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
),
213 if (!EFI_ERROR (Status
)) {
214 if (TempDebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
215 CodeViewSize
= TempDebugEntry
.SizeOfData
;
216 CodeViewFileOffset
= TempDebugEntry
.FileOffset
;
221 CodeViewOffset
= PeHdr
.Pe32
.OptionalHeader
.SizeOfImage
+ PeHdr
.Pe32
.OptionalHeader
.SectionAlignment
;
222 Image
->NoPages
= EFI_SIZE_TO_PAGES (CodeViewOffset
+ CodeViewSize
);
225 // Compute the amount of memory needed to load the image and
226 // allocate it. Memory starts off as data
229 Image
->ImageBasePage
= (EFI_PHYSICAL_ADDRESS
)FindSpace (Image
->NoPages
, NumberOfMemoryMapEntries
, EfiMemoryDescriptor
, EfiRuntimeServicesCode
, EFI_MEMORY_WB
);
230 if (Image
->ImageBasePage
== 0) {
231 return EFI_OUT_OF_RESOURCES
;
234 if (EFI_ERROR(Status
)) {
239 // DEBUG((D_LOAD, "LoadPe: new image base %lx\n", Image->ImageBasePage));
240 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)Image
->ImageBasePage
;
241 Image
->Info
.ImageSize
= (Image
->NoPages
<< EFI_PAGE_SHIFT
) - 1;
242 Image
->ImageBase
= (UINT8
*)(UINTN
)Image
->ImageBasePage
;
243 Image
->ImageEof
= Image
->ImageBase
+ Image
->Info
.ImageSize
;
244 Image
->ImageAdjust
= Image
->ImageBase
;
247 // Copy the Image header to the base location
249 Status
= EfiLdrPeCoffImageRead (
252 PeHdr
.Pe32
.OptionalHeader
.SizeOfHeaders
,
256 if (EFI_ERROR(Status
)) {
262 // Load each directory of the image into memory...
263 // Save the address of the Debug directory for later
265 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
266 NumberOfRvaAndSizes
= PeHdr
.Pe32
.OptionalHeader
.NumberOfRvaAndSizes
;
267 DataDirectory
= PeHdr
.Pe32
.OptionalHeader
.DataDirectory
;
269 NumberOfRvaAndSizes
= PeHdr
.Pe32Plus
.OptionalHeader
.NumberOfRvaAndSizes
;
270 DataDirectory
= PeHdr
.Pe32Plus
.OptionalHeader
.DataDirectory
;
273 for (Index
= 0; Index
< NumberOfRvaAndSizes
; Index
++) {
274 if ((DataDirectory
[Index
].VirtualAddress
!= 0) && (DataDirectory
[Index
].Size
!= 0)) {
275 Status
= EfiLdrPeCoffImageRead (
277 DataDirectory
[Index
].VirtualAddress
,
278 DataDirectory
[Index
].Size
,
279 Image
->ImageBase
+ DataDirectory
[Index
].VirtualAddress
281 if (EFI_ERROR(Status
)) {
284 if (Index
== EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
285 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (Image
->ImageBase
+ DataDirectory
[Index
].VirtualAddress
);
291 // Load each section of the image
294 // BUGBUG: change this to use the in memory copy
295 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
296 OptionalHeaderSize
= sizeof(EFI_IMAGE_OPTIONAL_HEADER32
);
297 PeHeaderSize
= sizeof(EFI_IMAGE_NT_HEADERS32
);
299 OptionalHeaderSize
= sizeof(EFI_IMAGE_OPTIONAL_HEADER64
);
300 PeHeaderSize
= sizeof(EFI_IMAGE_NT_HEADERS64
);
302 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
306 PeHdr
.Pe32
.FileHeader
.SizeOfOptionalHeader
-
310 Section
= FirstSection
;
311 for (Index
=0; Index
< PeHdr
.Pe32
.FileHeader
.NumberOfSections
; Index
+= 1) {
314 // Compute sections address
317 Base
= EfiLdrPeCoffImageAddress (Image
, (UINTN
)Section
->VirtualAddress
);
318 End
= EfiLdrPeCoffImageAddress (Image
, (UINTN
)(Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
));
320 if (EFI_ERROR(Status
) || !Base
|| !End
) {
321 // DEBUG((D_LOAD|D_ERROR, "LoadPe: Section %d was not loaded\n", Index));
323 return EFI_LOAD_ERROR
;
326 // DEBUG((D_LOAD, "LoadPe: Section %d, loaded at %x\n", Index, Base));
332 if (Section
->SizeOfRawData
) {
333 Status
= EfiLdrPeCoffImageRead (FHand
, Section
->PointerToRawData
, Section
->SizeOfRawData
, Base
);
334 if (EFI_ERROR(Status
)) {
341 // If raw size is less then virt size, zero fill the remaining
344 if (Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
346 Base
+ Section
->SizeOfRawData
,
347 Section
->Misc
.VirtualSize
- Section
->SizeOfRawData
359 // Copy in CodeView information if it exists
361 if (CodeViewSize
!= 0) {
362 Status
= EfiLdrPeCoffImageRead (FHand
, CodeViewFileOffset
, CodeViewSize
, Image
->ImageBase
+ CodeViewOffset
);
363 DebugEntry
->RVA
= (UINT32
) (CodeViewOffset
);
367 // Apply relocations only if needed
369 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
370 ImageBase
= (UINT64
)PeHdr
.Pe32
.OptionalHeader
.ImageBase
;
372 ImageBase
= PeHdr
.Pe32Plus
.OptionalHeader
.ImageBase
;
374 if ((UINTN
)(Image
->ImageBase
) != (UINTN
) (ImageBase
)) {
375 Status
= EfiLdrPeCoffLoadPeRelocate (
377 &DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
],
378 (UINTN
) Image
->ImageBase
- (UINTN
)ImageBase
,
379 NumberOfMemoryMapEntries
,
383 if (EFI_ERROR(Status
)) {
390 // Use exported EFI specific interface if present, else use the image's entry point
392 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)
393 (EfiLdrPeCoffImageAddress(
395 PeHdr
.Pe32
.OptionalHeader
.AddressOfEntryPoint
403 EfiLdrPeCoffLoadPeRelocate (
404 IN EFILDR_LOADED_IMAGE
*Image
,
405 IN EFI_IMAGE_DATA_DIRECTORY
*RelocDir
,
407 IN UINTN
*NumberOfMemoryMapEntries
,
408 IN EFI_MEMORY_DESCRIPTOR
*EfiMemoryDescriptor
411 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
412 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
424 // Find the relocation block
427 RelocBase
= EfiLdrPeCoffImageAddress (Image
, RelocDir
->VirtualAddress
);
428 RelocBaseEnd
= EfiLdrPeCoffImageAddress (Image
, RelocDir
->VirtualAddress
+ RelocDir
->Size
);
429 if (!RelocBase
|| !RelocBaseEnd
) {
431 return EFI_LOAD_ERROR
;
434 NoFixupPages
= EFI_SIZE_TO_PAGES(RelocDir
->Size
/ sizeof(UINT16
) * sizeof(UINTN
));
435 Image
->FixupData
= (UINT8
*) FindSpace (NoFixupPages
, NumberOfMemoryMapEntries
, EfiMemoryDescriptor
, EfiRuntimeServicesData
, EFI_MEMORY_WB
);
436 if (Image
->FixupData
== 0) {
437 return EFI_OUT_OF_RESOURCES
;
441 // Run the whole relocation block
444 FixupData
= Image
->FixupData
;
445 while (RelocBase
< RelocBaseEnd
) {
447 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof(EFI_IMAGE_BASE_RELOCATION
));
448 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
449 FixupBase
= EfiLdrPeCoffImageAddress (Image
, RelocBase
->VirtualAddress
);
450 if ((UINT8
*) RelocEnd
< Image
->ImageBase
|| (UINT8
*) RelocEnd
> Image
->ImageEof
) {
452 return EFI_LOAD_ERROR
;
456 // Run this relocation record
459 while (Reloc
< RelocEnd
) {
461 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
462 switch ((*Reloc
) >> 12) {
464 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
467 case EFI_IMAGE_REL_BASED_HIGH
:
468 F16
= (UINT16
*) Fixup
;
469 *F16
= (UINT16
) (*F16
+ (UINT16
)(((UINT32
)Adjust
) >> 16));
470 if (FixupData
!= NULL
) {
471 *(UINT16
*) FixupData
= *F16
;
472 FixupData
= FixupData
+ sizeof(UINT16
);
476 case EFI_IMAGE_REL_BASED_LOW
:
477 F16
= (UINT16
*) Fixup
;
478 *F16
= *F16
+ (UINT16
) Adjust
;
479 if (FixupData
!= NULL
) {
480 *(UINT16
*) FixupData
= *F16
;
481 FixupData
= FixupData
+ sizeof(UINT16
);
485 case EFI_IMAGE_REL_BASED_HIGHLOW
:
486 F32
= (UINT32
*) Fixup
;
487 *F32
= *F32
+ (UINT32
) Adjust
;
488 if (FixupData
!= NULL
) {
489 FixupData
= ALIGN_POINTER(FixupData
, sizeof(UINT32
));
490 *(UINT32
*) FixupData
= *F32
;
491 FixupData
= FixupData
+ sizeof(UINT32
);
495 case EFI_IMAGE_REL_BASED_DIR64
:
496 F64
= (UINT64
*) Fixup
;
497 *F64
= *F64
+ (UINT64
) Adjust
;
498 if (FixupData
!= NULL
) {
499 FixupData
= ALIGN_POINTER(FixupData
, sizeof(UINT64
));
500 *(UINT64
*) FixupData
= *F64
;
501 FixupData
= FixupData
+ sizeof(UINT64
);
505 case EFI_IMAGE_REL_BASED_HIGHADJ
:
506 CpuDeadLoop(); // BUGBUG: not done
510 // DEBUG((D_LOAD|D_ERROR, "PeRelocate: unknown fixed type\n"));
513 return EFI_LOAD_ERROR
;
521 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
525 // Add Fixup data to whole Image (assume Fixup data just below the image), so that there is no hole in the descriptor.
526 // Because only NoPages or ImageBasePage will be used in EfiLoader(), we update these 2 fields.
528 Image
->NoPages
+= NoFixupPages
;
529 Image
->ImageBasePage
-= (NoFixupPages
<< EFI_PAGE_SHIFT
);
536 EfiLdrPeCoffImageRead (
539 IN OUT UINTN ReadSize
,
543 CopyMem (Buffer
, (VOID
*)((UINTN
)FHand
+ Offset
), ReadSize
);
550 EfiLdrPeCoffImageAddress (
551 IN EFILDR_LOADED_IMAGE
*Image
,
557 FixedAddress
= Image
->ImageAdjust
+ Address
;
559 if ((FixedAddress
< Image
->ImageBase
) || (FixedAddress
> Image
->ImageEof
)) {
560 // DEBUG((D_LOAD|D_ERROR, "PeCoffImageAddress: pointer is outside of image\n"));
566 // "PeCoffImageAddress: ImageBase %x, ImageEof %x, Address %x, FixedAddress %x\n",
577 EfiLdrPeCoffSetImageType (
578 IN OUT EFILDR_LOADED_IMAGE
*Image
,
582 EFI_MEMORY_TYPE CodeType
;
583 EFI_MEMORY_TYPE DataType
;
586 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
587 CodeType
= EfiLoaderCode
;
588 DataType
= EfiLoaderData
;
591 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
592 CodeType
= EfiBootServicesCode
;
593 DataType
= EfiBootServicesData
;
596 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
597 CodeType
= EfiRuntimeServicesCode
;
598 DataType
= EfiRuntimeServicesData
;
602 return EFI_INVALID_PARAMETER
;
605 Image
->Type
= ImageType
;
606 Image
->Info
.ImageCodeType
= CodeType
;
607 Image
->Info
.ImageDataType
= DataType
;
613 EfiLdrPeCoffCheckImageMachineType (
614 IN UINT16 MachineType
619 Status
= EFI_UNSUPPORTED
;
622 if (MachineType
== EFI_IMAGE_MACHINE_IA32
) {
623 Status
= EFI_SUCCESS
;
628 if (MachineType
== EFI_IMAGE_MACHINE_X64
) {
629 Status
= EFI_SUCCESS
;
634 if (MachineType
== EFI_IMAGE_MACHINE_IA64
) {
635 Status
= EFI_SUCCESS
;