3 Copyright (c) 2006 - 2007, 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.
18 Pei Core Load Image Support
23 // Include common header file for this module.
25 #include "CommonHeader.h"
33 IN EFI_PEI_SERVICES
**PeiServices
,
34 IN EFI_FFS_FILE_HEADER
*PeimFileHeader
,
41 Routine for loading file image.
45 PeiServices - The PEI core services table.
46 PeimFileHeader - Pointer to the FFS file header of the image.
47 EntryPoint - Pointer to entry point of specified image file for output.
51 Status - EFI_SUCCESS - Image is successfully loaded.
52 EFI_NOT_FOUND - Fail to locate necessary PPI
53 Others - Fail to load file.
59 EFI_PEI_FV_FILE_LOADER_PPI
*FvLoadFilePpi
;
60 EFI_PHYSICAL_ADDRESS ImageAddress
;
62 EFI_PHYSICAL_ADDRESS ImageEntryPoint
;
63 EFI_TE_IMAGE_HEADER
*TEImageHeader
;
70 // Try to find a PE32 section.
72 Status
= PeiServicesFfsFindSectionData (
78 // If we didn't find a PE32 section, try to find a TE section.
80 if (EFI_ERROR (Status
)) {
81 Status
= PeiServicesFfsFindSectionData (
84 (VOID
**) &TEImageHeader
86 if (EFI_ERROR (Status
) || TEImageHeader
== NULL
) {
88 // There was not a PE32 or a TE section, so assume that it's a Compressed section
89 // and use the LoadFile
91 Status
= PeiServicesLocatePpi (
92 &gEfiPeiFvFileLoaderPpiGuid
,
95 (VOID
**)&FvLoadFilePpi
97 if (EFI_ERROR (Status
)) {
101 Status
= FvLoadFilePpi
->FvLoadFile (
109 if (EFI_ERROR (Status
)) {
110 return EFI_NOT_FOUND
;
114 // Got the entry point from ImageEntryPoint and ImageStartAddress
116 Pe32Data
= (VOID
*) ((UINTN
) ImageAddress
);
117 *EntryPoint
= (VOID
*) ((UINTN
) ImageEntryPoint
);
120 // Retrieve the entry point from the TE image header
122 ImageAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) TEImageHeader
;
123 *EntryPoint
= (VOID
*)((UINTN
) TEImageHeader
+ sizeof (EFI_TE_IMAGE_HEADER
) +
124 TEImageHeader
->AddressOfEntryPoint
- TEImageHeader
->StrippedSize
);
128 // Retrieve the entry point from the PE/COFF image header
130 ImageAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) Pe32Data
;
131 Status
= PeCoffLoaderGetEntryPoint (Pe32Data
, EntryPoint
);
132 if (EFI_ERROR (Status
)) {
133 return EFI_NOT_FOUND
;
137 if (((EFI_TE_IMAGE_HEADER
*) (UINTN
) ImageAddress
)->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
138 TEImageHeader
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) ImageAddress
;
139 Machine
= TEImageHeader
->Machine
;
141 Machine
= PeCoffLoaderGetMachineType (Pe32Data
);
144 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine
)) {
145 return EFI_UNSUPPORTED
;
149 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
151 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading PEIM at 0x%08x EntryPoint=0x%08x ", (UINTN
) ImageAddress
, *EntryPoint
));
153 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
154 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
158 BOOLEAN FileNameFound
;
160 CHAR8 AsciiBuffer
[512];
161 VOID
*CodeViewEntryPointer
;
163 EFI_IMAGE_DOS_HEADER
*DosHeader
;
164 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
165 UINT32 NumberOfRvaAndSizes
;
168 if (TEImageHeader
== NULL
) {
169 DosHeader
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
170 if (DosHeader
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
172 // DOS image header is present, so read the PE header after the DOS image header
174 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)Pe32Data
+ (UINTN
)((DosHeader
->e_lfanew
) & 0x0ffff));
177 // DOS image header is not present, so PE header is at the image base
179 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
184 // Find the codeview info in the image and display the file name
187 // Per the PE/COFF spec, you can't assume that a given data directory
188 // is present in the image. You have to check the NumberOfRvaAndSizes in
189 // the optional header to verify a desired directory entry is there.
192 DirectoryEntry
= NULL
;
193 NumberOfRvaAndSizes
= 0;
196 if (TEImageHeader
== NULL
) {
197 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
199 // Use PE32 offset get Debug Directory Entry
201 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
202 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
203 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) ((UINTN
) Pe32Data
+ DirectoryEntry
->VirtualAddress
);
204 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
206 // Use PE32+ offset get Debug Directory Entry
208 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
209 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
210 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) ((UINTN
) Pe32Data
+ DirectoryEntry
->VirtualAddress
);
213 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
214 DirectoryEntry
= NULL
;
218 if (TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) {
219 DirectoryEntry
= &TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
];
220 TEImageAdjust
= sizeof (EFI_TE_IMAGE_HEADER
) - TEImageHeader
->StrippedSize
;
221 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)((UINTN
) TEImageHeader
+
222 TEImageHeader
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
+
227 if (DebugEntry
!= NULL
&& DirectoryEntry
!= NULL
) {
228 for (DirCount
= 0; DirCount
< DirectoryEntry
->Size
; DirCount
+= sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
), DebugEntry
++) {
229 if (DebugEntry
->Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
230 if (DebugEntry
->SizeOfData
> 0) {
231 CodeViewEntryPointer
= (VOID
*) ((UINTN
) DebugEntry
->RVA
+ (UINTN
) ImageAddress
+ (UINTN
)TEImageAdjust
);
232 switch (* (UINT32
*) CodeViewEntryPointer
) {
233 case CODEVIEW_SIGNATURE_NB10
:
234 AsciiString
= (CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
237 case CODEVIEW_SIGNATURE_RSDS
:
238 AsciiString
= (CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
245 if (AsciiString
!= NULL
) {
246 FileNameFound
= FALSE
;
247 for (Index
= 0, Index1
= 0; AsciiString
[Index
] != '\0'; Index
++) {
248 if (AsciiString
[Index
] == '\\') {
250 FileNameFound
= TRUE
;
255 for (Index
= Index1
+ 1; AsciiString
[Index
] != '.'; Index
++) {
256 AsciiBuffer
[Index
- (Index1
+ 1)] = AsciiString
[Index
];
258 AsciiBuffer
[Index
- (Index1
+ 1)] = 0;
259 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "%a.efi", AsciiBuffer
));
269 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "\n"));