]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Image/Image.c
Update PEI Core LoadImage() service to always call LoadAndRelocatePeCoffImage() even...
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Image / Image.c
1 /** @file
2 Pei Core Load Image Support
3
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PeiMain.h"
16
17
18 EFI_PEI_LOAD_FILE_PPI mPeiLoadImagePpi = {
19 PeiLoadImageLoadImageWrapper
20 };
21
22
23 EFI_PEI_PPI_DESCRIPTOR gPpiLoadFilePpiList = {
24 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
25 &gEfiPeiLoadFilePpiGuid,
26 &mPeiLoadImagePpi
27 };
28
29 /**
30
31 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
32
33
34 @param FileHandle - The handle to the PE/COFF file
35 @param FileOffset - The offset, in bytes, into the file to read
36 @param ReadSize - The number of bytes to read from the file starting at FileOffset
37 @param Buffer - A pointer to the buffer to read the data into.
38
39 @return EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
40
41 **/
42 EFI_STATUS
43 EFIAPI
44 PeiImageRead (
45 IN VOID *FileHandle,
46 IN UINTN FileOffset,
47 IN UINTN *ReadSize,
48 OUT VOID *Buffer
49 )
50 {
51 CHAR8 *Destination8;
52 CHAR8 *Source8;
53 UINTN Length;
54
55 Destination8 = Buffer;
56 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
57 if (Destination8 != Source8) {
58 Length = *ReadSize;
59 while ((Length--) > 0) {
60 *(Destination8++) = *(Source8++);
61 }
62 }
63
64 return EFI_SUCCESS;
65 }
66
67 /**
68
69 Support routine to get the Image read file function.
70
71 @param ImageContext - The context of the image being loaded
72
73 @retval EFI_SUCCESS - If Image function location is found
74
75 **/
76 EFI_STATUS
77 GetImageReadFunction (
78 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
79 )
80 {
81 PEI_CORE_INSTANCE *Private;
82 VOID* MemoryBuffer;
83
84 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
85
86 if (!Private->PeiMemoryInstalled) {
87 ImageContext->ImageRead = PeiImageRead;
88 } else {
89 MemoryBuffer = AllocatePages (0x400 / EFI_PAGE_SIZE + 1);
90 ASSERT (MemoryBuffer != NULL);
91
92 CopyMem (MemoryBuffer, (CONST VOID *) (UINTN) PeiImageRead, 0x400);
93
94 ImageContext->ImageRead = (PE_COFF_LOADER_READ_FILE) (UINTN) MemoryBuffer;
95 }
96
97 return EFI_SUCCESS;
98 }
99
100 /**
101
102 Loads and relocates a PE/COFF image into memory.
103
104
105 @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
106 @param ImageAddress - The base address of the relocated PE/COFF image
107 @param ImageSize - The size of the relocated PE/COFF image
108 @param EntryPoint - The entry point of the relocated PE/COFF image
109
110 @retval EFI_SUCCESS The file was loaded and relocated
111 @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
112 @retval EFI_INVALID_PARAMETER The image withou .reloc section can't be relocated.
113
114 **/
115 EFI_STATUS
116 LoadAndRelocatePeCoffImage (
117 IN VOID *Pe32Data,
118 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
119 OUT UINT64 *ImageSize,
120 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
121 )
122 {
123 EFI_STATUS Status;
124 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
125 PEI_CORE_INSTANCE *Private;
126
127 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
128
129 ZeroMem (&ImageContext, sizeof (ImageContext));
130 ImageContext.Handle = Pe32Data;
131 Status = GetImageReadFunction (&ImageContext);
132
133 ASSERT_EFI_ERROR (Status);
134
135 Status = PeCoffLoaderGetImageInfo (&ImageContext);
136 if (EFI_ERROR (Status)) {
137 return Status;
138 }
139 //
140 // When Image has no reloc section, it can't be relocated into memory.
141 //
142 if (ImageContext.RelocationsStripped) {
143 DEBUG ((EFI_D_ERROR, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
144 }
145 //
146 // Allocate Memory for the image
147 //
148 if (Private->PeiMemoryInstalled) {
149 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
150 ASSERT (ImageContext.ImageAddress != 0);
151
152 //
153 // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
154 //
155 if (ImageContext.IsTeImage) {
156 ImageContext.ImageAddress = ImageContext.ImageAddress +
157 ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
158 sizeof (EFI_TE_IMAGE_HEADER);
159 }
160 } else {
161 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
162 }
163
164 //
165 // Load the image to our new buffer
166 //
167 Status = PeCoffLoaderLoadImage (&ImageContext);
168 if (EFI_ERROR (Status)) {
169 return Status;
170 }
171 //
172 // Relocate the image in our new buffer
173 //
174 Status = PeCoffLoaderRelocateImage (&ImageContext);
175 if (EFI_ERROR (Status)) {
176 return Status;
177 }
178
179 //
180 // Flush the instruction cache so the image data is written before we execute it
181 //
182 if (Private->PeiMemoryInstalled) {
183 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
184 }
185
186 *ImageAddress = ImageContext.ImageAddress;
187 *ImageSize = ImageContext.ImageSize;
188 *EntryPoint = ImageContext.EntryPoint;
189
190 return EFI_SUCCESS;
191 }
192
193 /**
194 Loads a PEIM into memory for subsequent execution. If there are compressed
195 images or images that need to be relocated into memory for performance reasons,
196 this service performs that transformation.
197
198 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
199 @param FileHandle Pointer to the FFS file header of the image.
200 @param ImageAddressArg Pointer to PE/TE image.
201 @param ImageSizeArg Size of PE/TE image.
202 @param EntryPoint Pointer to entry point of specified image file for output.
203 @param AuthenticationState - Pointer to attestation authentication state of image.
204
205 @retval EFI_SUCCESS Image is successfully loaded.
206 @retval EFI_NOT_FOUND Fail to locate necessary PPI.
207 @retval EFI_UNSUPPORTED Image Machine Type is not supported.
208
209 **/
210 EFI_STATUS
211 PeiLoadImageLoadImage (
212 IN CONST EFI_PEI_SERVICES **PeiServices,
213 IN EFI_PEI_FILE_HANDLE FileHandle,
214 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
215 OUT UINT64 *ImageSizeArg, OPTIONAL
216 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
217 OUT UINT32 *AuthenticationState
218 )
219 {
220 EFI_STATUS Status;
221 VOID *Pe32Data;
222 EFI_PHYSICAL_ADDRESS ImageAddress;
223 UINT64 ImageSize;
224 EFI_PHYSICAL_ADDRESS ImageEntryPoint;
225 UINT16 Machine;
226 PEI_CORE_INSTANCE *Private;
227 EFI_SECTION_TYPE SearchType1;
228 EFI_SECTION_TYPE SearchType2;
229
230 *EntryPoint = 0;
231 ImageSize = 0;
232 *AuthenticationState = 0;
233
234 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
235 SearchType1 = EFI_SECTION_TE;
236 SearchType2 = EFI_SECTION_PE32;
237 } else {
238 SearchType1 = EFI_SECTION_PE32;
239 SearchType2 = EFI_SECTION_TE;
240 }
241 //
242 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
243 // is true, TE will be searched first).
244 //
245 Status = PeiServicesFfsFindSectionData (
246 SearchType1,
247 FileHandle,
248 &Pe32Data
249 );
250 //
251 // If we didn't find a first exe section, try to find the second exe section.
252 //
253 if (EFI_ERROR (Status)) {
254 Status = PeiServicesFfsFindSectionData (
255 SearchType2,
256 FileHandle,
257 &Pe32Data
258 );
259 if (EFI_ERROR (Status)) {
260 //
261 // PEI core only carry the loader function fro TE and PE32 executables
262 // If this two section does not exist, just return.
263 //
264 return Status;
265 }
266 }
267
268 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
269
270 //
271 // If memory is installed, perform the shadow operations
272 //
273 Status = LoadAndRelocatePeCoffImage (
274 Pe32Data,
275 &ImageAddress,
276 &ImageSize,
277 &ImageEntryPoint
278 );
279
280 ASSERT_EFI_ERROR (Status);
281
282
283 if (EFI_ERROR (Status)) {
284 return Status;
285 }
286
287 //
288 // Got the entry point from the loaded Pe32Data
289 //
290 Pe32Data = (VOID *) ((UINTN) ImageAddress);
291 *EntryPoint = ImageEntryPoint;
292
293 Machine = PeCoffLoaderGetMachineType (Pe32Data);
294
295 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
296 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
297 return EFI_UNSUPPORTED;
298 }
299 }
300
301 if (ImageAddressArg != NULL) {
302 *ImageAddressArg = ImageAddress;
303 }
304
305 if (ImageSizeArg != NULL) {
306 *ImageSizeArg = ImageSize;
307 }
308
309 DEBUG_CODE_BEGIN ();
310 CHAR8 *AsciiString;
311 CHAR8 AsciiBuffer[512];
312 INT32 Index;
313 INT32 Index1;
314
315 //
316 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
317 //
318 if (Machine != EFI_IMAGE_MACHINE_IA64) {
319 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
320 } else {
321 //
322 // For IPF Image, the real entry point should be print.
323 //
324 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
325 }
326
327 //
328 // Print Module Name by PeImage PDB file name.
329 //
330 AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
331
332 if (AsciiString != NULL) {
333 for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {
334 if (AsciiString[Index] == '\\') {
335 break;
336 }
337 }
338
339 if (Index != 0) {
340 for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) {
341 AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1];
342 }
343 AsciiBuffer [Index1] = '\0';
344 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));
345 }
346 }
347
348 DEBUG_CODE_END ();
349
350 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
351
352 return EFI_SUCCESS;
353
354 }
355
356
357 /**
358 The wrapper function of PeiLoadImageLoadImage().
359
360 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
361 @param FileHandle - Pointer to the FFS file header of the image.
362 @param ImageAddressArg - Pointer to PE/TE image.
363 @param ImageSizeArg - Size of PE/TE image.
364 @param EntryPoint - Pointer to entry point of specified image file for output.
365 @param AuthenticationState - Pointer to attestation authentication state of image.
366
367 @return Status of PeiLoadImageLoadImage().
368
369 **/
370 EFI_STATUS
371 EFIAPI
372 PeiLoadImageLoadImageWrapper (
373 IN CONST EFI_PEI_LOAD_FILE_PPI *This,
374 IN EFI_PEI_FILE_HANDLE FileHandle,
375 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
376 OUT UINT64 *ImageSizeArg, OPTIONAL
377 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
378 OUT UINT32 *AuthenticationState
379 )
380 {
381 return PeiLoadImageLoadImage (
382 GetPeiServicesTablePointer (),
383 FileHandle,
384 ImageAddressArg,
385 ImageSizeArg,
386 EntryPoint,
387 AuthenticationState
388 );
389 }
390
391 /**
392 Routine to load image file for subsequent execution by LoadFile Ppi.
393 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
394 XIP image format is used.
395
396 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
397 @param FileHandle - Pointer to the FFS file header of the image.
398 @param EntryPoint - Pointer to entry point of specified image file for output.
399 @param AuthenticationState - Pointer to attestation authentication state of image.
400
401 @retval EFI_SUCCESS - Image is successfully loaded.
402 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
403 @retval Others - Fail to load file.
404
405 **/
406 EFI_STATUS
407 PeiLoadImage (
408 IN CONST EFI_PEI_SERVICES **PeiServices,
409 IN EFI_PEI_FILE_HANDLE FileHandle,
410 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
411 OUT UINT32 *AuthenticationState
412 )
413 {
414 EFI_STATUS PpiStatus;
415 EFI_STATUS Status;
416 UINTN Index;
417 EFI_PEI_LOAD_FILE_PPI *LoadFile;
418 EFI_PHYSICAL_ADDRESS ImageAddress;
419 UINT64 ImageSize;
420
421 //
422 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
423 // one at a time, until one reports EFI_SUCCESS.
424 //
425 Index = 0;
426 do {
427 PpiStatus = PeiServicesLocatePpi (
428 &gEfiPeiLoadFilePpiGuid,
429 Index,
430 NULL,
431 (VOID **)&LoadFile
432 );
433 if (!EFI_ERROR (PpiStatus)) {
434 Status = LoadFile->LoadFile (
435 LoadFile,
436 FileHandle,
437 &ImageAddress,
438 &ImageSize,
439 EntryPoint,
440 AuthenticationState
441 );
442 if (!EFI_ERROR (Status)) {
443 //
444 // The image to be started must have the machine type supported by PeiCore.
445 //
446 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));
447 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {
448 return EFI_UNSUPPORTED;
449 }
450 return Status;
451 }
452 }
453 Index++;
454 } while (!EFI_ERROR (PpiStatus));
455
456 return PpiStatus;
457 }
458
459
460 /**
461
462 Install Pei Load File PPI.
463
464
465 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
466 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
467
468 **/
469 VOID
470 InitializeImageServices (
471 IN PEI_CORE_INSTANCE *PrivateData,
472 IN PEI_CORE_INSTANCE *OldCoreData
473 )
474 {
475 if (OldCoreData == NULL) {
476 //
477 // The first time we are XIP (running from FLASH). We need to remember the
478 // FLASH address so we can reinstall the memory version that runs faster
479 //
480 PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
481 PeiServicesInstallPpi (PrivateData->XipLoadFile);
482 } else {
483 //
484 // 2nd time we are running from memory so replace the XIP version with the
485 // new memory version.
486 //
487 PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
488 }
489 }
490
491
492