]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Image/Image.c
391290d018e4f54368884185e28bf90f2cb88c13
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Image / Image.c
1 /*++
2
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
8
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.
11
12 Module Name:
13
14 Image.c
15
16 Abstract:
17
18 Pei Core Load Image Support
19
20 --*/
21
22 //
23 // Include common header file for this module.
24 //
25 #include "CommonHeader.h"
26
27 #include <PeiMain.h>
28
29
30
31 EFI_STATUS
32 PeiLoadImage (
33 IN EFI_PEI_SERVICES **PeiServices,
34 IN EFI_FFS_FILE_HEADER *PeimFileHeader,
35 OUT VOID **EntryPoint
36 )
37 /*++
38
39 Routine Description:
40
41 Routine for loading file image.
42
43 Arguments:
44
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.
48
49 Returns:
50
51 Status - EFI_SUCCESS - Image is successfully loaded.
52 EFI_NOT_FOUND - Fail to locate necessary PPI
53 Others - Fail to load file.
54
55 --*/
56 {
57 EFI_STATUS Status;
58 VOID *Pe32Data;
59 EFI_PEI_FV_FILE_LOADER_PPI *FvLoadFilePpi;
60 EFI_PHYSICAL_ADDRESS ImageAddress;
61 UINT64 ImageSize;
62 EFI_PHYSICAL_ADDRESS ImageEntryPoint;
63 EFI_TE_IMAGE_HEADER *TEImageHeader;
64 UINT16 Machine;
65
66 *EntryPoint = NULL;
67 TEImageHeader = NULL;
68
69 //
70 // Try to find a PE32 section.
71 //
72 Status = PeiServicesFfsFindSectionData (
73 EFI_SECTION_PE32,
74 PeimFileHeader,
75 &Pe32Data
76 );
77 //
78 // If we didn't find a PE32 section, try to find a TE section.
79 //
80 if (EFI_ERROR (Status)) {
81 Status = PeiServicesFfsFindSectionData (
82 EFI_SECTION_TE,
83 PeimFileHeader,
84 (VOID **) &TEImageHeader
85 );
86 if (EFI_ERROR (Status) || TEImageHeader == NULL) {
87 //
88 // There was not a PE32 or a TE section, so assume that it's a Compressed section
89 // and use the LoadFile
90 //
91 Status = PeiServicesLocatePpi (
92 &gEfiPeiFvFileLoaderPpiGuid,
93 0,
94 NULL,
95 (VOID **)&FvLoadFilePpi
96 );
97 if (EFI_ERROR (Status)) {
98 return EFI_NOT_FOUND;
99 }
100
101 Status = FvLoadFilePpi->FvLoadFile (
102 FvLoadFilePpi,
103 PeimFileHeader,
104 &ImageAddress,
105 &ImageSize,
106 &ImageEntryPoint
107 );
108
109 if (EFI_ERROR (Status)) {
110 return EFI_NOT_FOUND;
111 }
112
113 //
114 // Got the entry point from ImageEntryPoint and ImageStartAddress
115 //
116 Pe32Data = (VOID *) ((UINTN) ImageAddress);
117 *EntryPoint = (VOID *) ((UINTN) ImageEntryPoint);
118 } else {
119 //
120 // Retrieve the entry point from the TE image header
121 //
122 ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) TEImageHeader;
123 *EntryPoint = (VOID *)((UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) +
124 TEImageHeader->AddressOfEntryPoint - TEImageHeader->StrippedSize);
125 }
126 } else {
127 //
128 // Retrieve the entry point from the PE/COFF image header
129 //
130 ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Pe32Data;
131 Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);
132 if (EFI_ERROR (Status)) {
133 return EFI_NOT_FOUND;
134 }
135 }
136
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;
140 } else {
141 Machine = PeCoffLoaderGetMachineType (Pe32Data);
142 }
143
144 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
145 return EFI_UNSUPPORTED;
146 }
147
148 //
149 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
150 //
151 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%08x EntryPoint=0x%08x ", (UINTN) ImageAddress, *EntryPoint));
152 DEBUG_CODE_BEGIN ();
153 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
154 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
155 UINTN DirCount;
156 UINTN Index;
157 UINTN Index1;
158 BOOLEAN FileNameFound;
159 CHAR8 *AsciiString;
160 CHAR8 AsciiBuffer[512];
161 VOID *CodeViewEntryPointer;
162 INTN TEImageAdjust;
163 EFI_IMAGE_DOS_HEADER *DosHeader;
164 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
165 UINT32 NumberOfRvaAndSizes;
166
167 Hdr.Pe32 = NULL;
168 if (TEImageHeader == NULL) {
169 DosHeader = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
170 if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
171 //
172 // DOS image header is present, so read the PE header after the DOS image header
173 //
174 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHeader->e_lfanew) & 0x0ffff));
175 } else {
176 //
177 // DOS image header is not present, so PE header is at the image base
178 //
179 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
180 }
181 }
182
183 //
184 // Find the codeview info in the image and display the file name
185 // being loaded.
186 //
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.
190 //
191 DebugEntry = NULL;
192 DirectoryEntry = NULL;
193 NumberOfRvaAndSizes = 0;
194 TEImageAdjust = 0;
195
196 if (TEImageHeader == NULL) {
197 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
198 //
199 // Use PE32 offset get Debug Directory Entry
200 //
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) {
205 //
206 // Use PE32+ offset get Debug Directory Entry
207 //
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);
211 }
212
213 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
214 DirectoryEntry = NULL;
215 DebugEntry = NULL;
216 }
217 } else {
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 +
223 TEImageAdjust);
224 }
225 }
226
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);
235 break;
236
237 case CODEVIEW_SIGNATURE_RSDS:
238 AsciiString = (CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
239 break;
240
241 default:
242 AsciiString = NULL;
243 break;
244 }
245 if (AsciiString != NULL) {
246 FileNameFound = FALSE;
247 for (Index = 0, Index1 = 0; AsciiString[Index] != '\0'; Index++) {
248 if (AsciiString[Index] == '\\') {
249 Index1 = Index;
250 FileNameFound = TRUE;
251 }
252 }
253
254 if (FileNameFound) {
255 for (Index = Index1 + 1; AsciiString[Index] != '.'; Index++) {
256 AsciiBuffer[Index - (Index1 + 1)] = AsciiString[Index];
257 }
258 AsciiBuffer[Index - (Index1 + 1)] = 0;
259 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));
260 break;
261 }
262 }
263 }
264 }
265 }
266 }
267 DEBUG_CODE_END ();
268
269 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
270
271 return EFI_SUCCESS;
272 }