3 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
4 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.
25 EfiLdrPeCoffLoadPeRelocate (
26 IN EFILDR_LOADED_IMAGE
*Image
,
27 IN EFI_IMAGE_DATA_DIRECTORY
*RelocDir
,
29 IN UINTN
*NumberOfMemoryMapEntries
,
30 IN EFI_MEMORY_DESCRIPTOR
*EfiMemoryDescriptor
34 EfiLdrPeCoffImageRead (
37 IN OUT UINTN ReadSize
,
42 EfiLdrPeCoffImageAddress (
43 IN EFILDR_LOADED_IMAGE
*Image
,
49 EfiLdrPeCoffSetImageType (
50 IN OUT EFILDR_LOADED_IMAGE
*Image
,
55 EfiLdrPeCoffCheckImageMachineType (
60 EfiLdrGetPeImageInfo (
62 OUT UINT64
*ImageBase
,
67 EFI_IMAGE_DOS_HEADER DosHdr
;
68 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
70 ZeroMem (&DosHdr
, sizeof(DosHdr
));
71 ZeroMem (&PeHdr
, sizeof(PeHdr
));
77 EfiLdrPeCoffImageRead (FHand
, 0, sizeof(DosHdr
), &DosHdr
);
78 if (DosHdr
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
79 return EFI_UNSUPPORTED
;
82 EfiLdrPeCoffImageRead (FHand
, DosHdr
.e_lfanew
, sizeof(PeHdr
), &PeHdr
);
84 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
85 return EFI_UNSUPPORTED
;
89 // Verify machine type
92 Status
= EfiLdrPeCoffCheckImageMachineType (PeHdr
.Pe32
.FileHeader
.Machine
);
93 if (EFI_ERROR(Status
)) {
97 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
98 *ImageBase
= (UINT32
)PeHdr
.Pe32
.OptionalHeader
.ImageBase
;
99 } else if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
100 *ImageBase
= PeHdr
.Pe32Plus
.OptionalHeader
.ImageBase
;
102 return EFI_UNSUPPORTED
;
105 *ImageSize
= PeHdr
.Pe32
.OptionalHeader
.SizeOfImage
;
111 EfiLdrPeCoffLoadPeImage (
113 IN EFILDR_LOADED_IMAGE
*Image
,
114 IN UINTN
*NumberOfMemoryMapEntries
,
115 IN EFI_MEMORY_DESCRIPTOR
*EfiMemoryDescriptor
118 EFI_IMAGE_DOS_HEADER DosHdr
;
119 EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr
;
120 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
121 EFI_IMAGE_SECTION_HEADER
*Section
;
126 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
128 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY TempDebugEntry
;
129 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
131 UINTN CodeViewOffset
;
132 UINTN CodeViewFileOffset
;
133 UINTN OptionalHeaderSize
;
135 UINT32 NumberOfRvaAndSizes
;
136 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
138 CHAR8 PrintBuffer
[256];
140 ZeroMem (&DosHdr
, sizeof(DosHdr
));
141 ZeroMem (&PeHdr
, sizeof(PeHdr
));
144 // Read image headers
147 EfiLdrPeCoffImageRead (FHand
, 0, sizeof(DosHdr
), &DosHdr
);
148 if (DosHdr
.e_magic
!= EFI_IMAGE_DOS_SIGNATURE
) {
149 AsciiSPrint (PrintBuffer
, 256, "PeCoffLoadPeImage: Dos header signature not found\n");
150 PrintString (PrintBuffer
);
152 return EFI_UNSUPPORTED
;
155 EfiLdrPeCoffImageRead (FHand
, DosHdr
.e_lfanew
, sizeof(PeHdr
), &PeHdr
);
157 if (PeHdr
.Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
158 AsciiSPrint (PrintBuffer
, 256, "PeCoffLoadPeImage: PE image header signature not found\n");
159 PrintString (PrintBuffer
);
161 return EFI_UNSUPPORTED
;
165 // Set the image subsystem type
168 Status
= EfiLdrPeCoffSetImageType (Image
, PeHdr
.Pe32
.OptionalHeader
.Subsystem
);
169 if (EFI_ERROR(Status
)) {
170 AsciiSPrint (PrintBuffer
, 256, "PeCoffLoadPeImage: Subsystem type not known\n");
171 PrintString (PrintBuffer
);
177 // Verify machine type
180 Status
= EfiLdrPeCoffCheckImageMachineType (PeHdr
.Pe32
.FileHeader
.Machine
);
181 if (EFI_ERROR(Status
)) {
182 AsciiSPrint (PrintBuffer
, 256, "PeCoffLoadPeImage: Incorrect machine type\n");
183 PrintString (PrintBuffer
);
189 // Compute the amount of memory needed to load the image and
190 // allocate it. This will include all sections plus the codeview debug info.
191 // Since the codeview info is actually outside of the image, we calculate
192 // its size seperately and add it to the total.
194 // Memory starts off as data
198 CodeViewFileOffset
= 0;
199 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
200 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(PeHdr
.Pe32
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
201 } else if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
202 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(PeHdr
.Pe32Plus
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
204 return EFI_UNSUPPORTED
;
207 (DirCount
< DirectoryEntry
->Size
/ sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) && (CodeViewSize
== 0);
209 Status
= EfiLdrPeCoffImageRead (
211 DirectoryEntry
->VirtualAddress
+ DirCount
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
),
212 sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
),
215 if (!EFI_ERROR (Status
)) {
216 if (TempDebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
217 CodeViewSize
= TempDebugEntry
.SizeOfData
;
218 CodeViewFileOffset
= TempDebugEntry
.FileOffset
;
223 CodeViewOffset
= PeHdr
.Pe32
.OptionalHeader
.SizeOfImage
+ PeHdr
.Pe32
.OptionalHeader
.SectionAlignment
;
224 Image
->NoPages
= EFI_SIZE_TO_PAGES (CodeViewOffset
+ CodeViewSize
);
227 // Compute the amount of memory needed to load the image and
228 // allocate it. Memory starts off as data
231 Image
->ImageBasePage
= (EFI_PHYSICAL_ADDRESS
)FindSpace (Image
->NoPages
, NumberOfMemoryMapEntries
, EfiMemoryDescriptor
, EfiRuntimeServicesCode
, EFI_MEMORY_WB
);
232 if (Image
->ImageBasePage
== 0) {
233 return EFI_OUT_OF_RESOURCES
;
236 if (EFI_ERROR(Status
)) {
241 AsciiSPrint (PrintBuffer
, 256, "LoadPe: new image base %lx\n", Image
->ImageBasePage
);
242 PrintString (PrintBuffer
);
243 Image
->Info
.ImageBase
= (VOID
*)(UINTN
)Image
->ImageBasePage
;
244 Image
->Info
.ImageSize
= (Image
->NoPages
<< EFI_PAGE_SHIFT
) - 1;
245 Image
->ImageBase
= (UINT8
*)(UINTN
)Image
->ImageBasePage
;
246 Image
->ImageEof
= Image
->ImageBase
+ Image
->Info
.ImageSize
;
247 Image
->ImageAdjust
= Image
->ImageBase
;
250 // Copy the Image header to the base location
252 Status
= EfiLdrPeCoffImageRead (
255 PeHdr
.Pe32
.OptionalHeader
.SizeOfHeaders
,
259 if (EFI_ERROR(Status
)) {
265 // Load each directory of the image into memory...
266 // Save the address of the Debug directory for later
268 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
269 NumberOfRvaAndSizes
= PeHdr
.Pe32
.OptionalHeader
.NumberOfRvaAndSizes
;
270 DataDirectory
= PeHdr
.Pe32
.OptionalHeader
.DataDirectory
;
272 NumberOfRvaAndSizes
= PeHdr
.Pe32Plus
.OptionalHeader
.NumberOfRvaAndSizes
;
273 DataDirectory
= PeHdr
.Pe32Plus
.OptionalHeader
.DataDirectory
;
276 for (Index
= 0; Index
< NumberOfRvaAndSizes
; Index
++) {
277 if ((DataDirectory
[Index
].VirtualAddress
!= 0) && (DataDirectory
[Index
].Size
!= 0)) {
278 Status
= EfiLdrPeCoffImageRead (
280 DataDirectory
[Index
].VirtualAddress
,
281 DataDirectory
[Index
].Size
,
282 Image
->ImageBase
+ DataDirectory
[Index
].VirtualAddress
284 if (EFI_ERROR(Status
)) {
287 if (Index
== EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
288 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (Image
->ImageBase
+ DataDirectory
[Index
].VirtualAddress
);
294 // Load each section of the image
297 // BUGBUG: change this to use the in memory copy
298 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
299 OptionalHeaderSize
= sizeof(EFI_IMAGE_OPTIONAL_HEADER32
);
300 PeHeaderSize
= sizeof(EFI_IMAGE_NT_HEADERS32
);
302 OptionalHeaderSize
= sizeof(EFI_IMAGE_OPTIONAL_HEADER64
);
303 PeHeaderSize
= sizeof(EFI_IMAGE_NT_HEADERS64
);
305 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
309 PeHdr
.Pe32
.FileHeader
.SizeOfOptionalHeader
-
313 Section
= FirstSection
;
314 for (Index
=0; Index
< PeHdr
.Pe32
.FileHeader
.NumberOfSections
; Index
+= 1) {
317 // Compute sections address
320 Base
= EfiLdrPeCoffImageAddress (Image
, (UINTN
)Section
->VirtualAddress
);
321 End
= EfiLdrPeCoffImageAddress (Image
, (UINTN
)(Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
));
323 if (EFI_ERROR(Status
) || !Base
|| !End
) {
324 // DEBUG((D_LOAD|D_ERROR, "LoadPe: Section %d was not loaded\n", Index));
326 return EFI_LOAD_ERROR
;
329 // DEBUG((D_LOAD, "LoadPe: Section %d, loaded at %x\n", Index, Base));
335 if (Section
->SizeOfRawData
) {
336 Status
= EfiLdrPeCoffImageRead (FHand
, Section
->PointerToRawData
, Section
->SizeOfRawData
, Base
);
337 if (EFI_ERROR(Status
)) {
344 // If raw size is less then virt size, zero fill the remaining
347 if (Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
349 Base
+ Section
->SizeOfRawData
,
350 Section
->Misc
.VirtualSize
- Section
->SizeOfRawData
362 // Copy in CodeView information if it exists
364 if (CodeViewSize
!= 0) {
365 Status
= EfiLdrPeCoffImageRead (FHand
, CodeViewFileOffset
, CodeViewSize
, Image
->ImageBase
+ CodeViewOffset
);
366 DebugEntry
->RVA
= (UINT32
) (CodeViewOffset
);
370 // Apply relocations only if needed
372 if (PeHdr
.Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
373 ImageBase
= (UINT64
)PeHdr
.Pe32
.OptionalHeader
.ImageBase
;
375 ImageBase
= PeHdr
.Pe32Plus
.OptionalHeader
.ImageBase
;
377 if ((UINTN
)(Image
->ImageBase
) != (UINTN
) (ImageBase
)) {
378 Status
= EfiLdrPeCoffLoadPeRelocate (
380 &DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
],
381 (UINTN
) Image
->ImageBase
- (UINTN
)ImageBase
,
382 NumberOfMemoryMapEntries
,
386 if (EFI_ERROR(Status
)) {
393 // Use exported EFI specific interface if present, else use the image's entry point
395 Image
->EntryPoint
= (EFI_IMAGE_ENTRY_POINT
)(UINTN
)
396 (EfiLdrPeCoffImageAddress(
398 PeHdr
.Pe32
.OptionalHeader
.AddressOfEntryPoint
405 EfiLdrPeCoffLoadPeRelocate (
406 IN EFILDR_LOADED_IMAGE
*Image
,
407 IN EFI_IMAGE_DATA_DIRECTORY
*RelocDir
,
409 IN UINTN
*NumberOfMemoryMapEntries
,
410 IN EFI_MEMORY_DESCRIPTOR
*EfiMemoryDescriptor
413 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
414 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
426 // Find the relocation block
429 RelocBase
= EfiLdrPeCoffImageAddress (Image
, RelocDir
->VirtualAddress
);
430 RelocBaseEnd
= EfiLdrPeCoffImageAddress (Image
, RelocDir
->VirtualAddress
+ RelocDir
->Size
);
431 if (!RelocBase
|| !RelocBaseEnd
) {
433 return EFI_LOAD_ERROR
;
436 NoFixupPages
= EFI_SIZE_TO_PAGES(RelocDir
->Size
/ sizeof(UINT16
) * sizeof(UINTN
));
437 Image
->FixupData
= (UINT8
*) FindSpace (NoFixupPages
, NumberOfMemoryMapEntries
, EfiMemoryDescriptor
, EfiRuntimeServicesData
, EFI_MEMORY_WB
);
438 if (Image
->FixupData
== 0) {
439 return EFI_OUT_OF_RESOURCES
;
443 // Run the whole relocation block
446 FixupData
= Image
->FixupData
;
447 while (RelocBase
< RelocBaseEnd
) {
449 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof(EFI_IMAGE_BASE_RELOCATION
));
450 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
451 FixupBase
= EfiLdrPeCoffImageAddress (Image
, RelocBase
->VirtualAddress
);
452 if ((UINT8
*) RelocEnd
< Image
->ImageBase
|| (UINT8
*) RelocEnd
> Image
->ImageEof
) {
454 return EFI_LOAD_ERROR
;
458 // Run this relocation record
461 while (Reloc
< RelocEnd
) {
463 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
464 switch ((*Reloc
) >> 12) {
466 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
469 case EFI_IMAGE_REL_BASED_HIGH
:
470 F16
= (UINT16
*) Fixup
;
471 *F16
= (UINT16
) (*F16
+ (UINT16
)(((UINT32
)Adjust
) >> 16));
472 if (FixupData
!= NULL
) {
473 *(UINT16
*) FixupData
= *F16
;
474 FixupData
= FixupData
+ sizeof(UINT16
);
478 case EFI_IMAGE_REL_BASED_LOW
:
479 F16
= (UINT16
*) Fixup
;
480 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
481 if (FixupData
!= NULL
) {
482 *(UINT16
*) FixupData
= *F16
;
483 FixupData
= FixupData
+ sizeof(UINT16
);
487 case EFI_IMAGE_REL_BASED_HIGHLOW
:
488 F32
= (UINT32
*) Fixup
;
489 *F32
= *F32
+ (UINT32
) Adjust
;
490 if (FixupData
!= NULL
) {
491 FixupData
= ALIGN_POINTER(FixupData
, sizeof(UINT32
));
492 *(UINT32
*) FixupData
= *F32
;
493 FixupData
= FixupData
+ sizeof(UINT32
);
497 case EFI_IMAGE_REL_BASED_DIR64
:
498 F64
= (UINT64
*) Fixup
;
499 *F64
= *F64
+ (UINT64
) Adjust
;
500 if (FixupData
!= NULL
) {
501 FixupData
= ALIGN_POINTER(FixupData
, sizeof(UINT64
));
502 *(UINT64
*) FixupData
= *F64
;
503 FixupData
= FixupData
+ sizeof(UINT64
);
507 case EFI_IMAGE_REL_BASED_HIGHADJ
:
508 CpuDeadLoop(); // BUGBUG: not done
512 // DEBUG((D_LOAD|D_ERROR, "PeRelocate: unknown fixed type\n"));
515 return EFI_LOAD_ERROR
;
523 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
527 // Add Fixup data to whole Image (assume Fixup data just below the image), so that there is no hole in the descriptor.
528 // Because only NoPages or ImageBasePage will be used in EfiLoader(), we update these 2 fields.
530 Image
->NoPages
+= NoFixupPages
;
531 Image
->ImageBasePage
-= (NoFixupPages
<< EFI_PAGE_SHIFT
);
537 EfiLdrPeCoffImageRead (
540 IN OUT UINTN ReadSize
,
544 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
;