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