]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Image/Image.c
63c8868894a163e92a4fcfc25649376c9f34eb1e
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Image / Image.c
1 /** @file
2 Pei Core Load Image Support
3
4 Copyright (c) 2006 - 2010, 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 || (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME)) {
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 If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image.
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
113 **/
114 EFI_STATUS
115 LoadAndRelocatePeCoffImage (
116 IN VOID *Pe32Data,
117 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
118 OUT UINT64 *ImageSize,
119 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
120 )
121 {
122 EFI_STATUS Status;
123 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
124 PEI_CORE_INSTANCE *Private;
125
126 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
127
128 ZeroMem (&ImageContext, sizeof (ImageContext));
129 ImageContext.Handle = Pe32Data;
130 Status = GetImageReadFunction (&ImageContext);
131
132 ASSERT_EFI_ERROR (Status);
133
134 Status = PeCoffLoaderGetImageInfo (&ImageContext);
135 if (EFI_ERROR (Status)) {
136 return Status;
137 }
138 //
139 // When Image has no reloc section, it can't be relocated into memory.
140 //
141 if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
142 DEBUG ((EFI_D_INFO, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data));
143 }
144
145 //
146 // Set default base address to current image address.
147 //
148 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data;
149
150 //
151 // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable.
152 //
153 if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
154 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
155 ASSERT (ImageContext.ImageAddress != 0);
156 if (ImageContext.ImageAddress == 0) {
157 return EFI_OUT_OF_RESOURCES;
158 }
159
160 //
161 // Skip the reserved space for the stripped PeHeader when load TeImage into memory.
162 //
163 if (ImageContext.IsTeImage) {
164 ImageContext.ImageAddress = ImageContext.ImageAddress +
165 ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize -
166 sizeof (EFI_TE_IMAGE_HEADER);
167 }
168 }
169
170 //
171 // Load the image to our new buffer
172 //
173 Status = PeCoffLoaderLoadImage (&ImageContext);
174 if (EFI_ERROR (Status)) {
175 return Status;
176 }
177 //
178 // Relocate the image in our new buffer
179 //
180 Status = PeCoffLoaderRelocateImage (&ImageContext);
181 if (EFI_ERROR (Status)) {
182 return Status;
183 }
184
185 //
186 // Flush the instruction cache so the image data is written before we execute it
187 //
188 if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
189 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
190 }
191
192 *ImageAddress = ImageContext.ImageAddress;
193 *ImageSize = ImageContext.ImageSize;
194 *EntryPoint = ImageContext.EntryPoint;
195
196 return EFI_SUCCESS;
197 }
198
199 /**
200 Loads a PEIM into memory for subsequent execution. If there are compressed
201 images or images that need to be relocated into memory for performance reasons,
202 this service performs that transformation.
203
204 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
205 @param FileHandle Pointer to the FFS file header of the image.
206 @param ImageAddressArg Pointer to PE/TE image.
207 @param ImageSizeArg Size of PE/TE image.
208 @param EntryPoint Pointer to entry point of specified image file for output.
209 @param AuthenticationState - Pointer to attestation authentication state of image.
210
211 @retval EFI_SUCCESS Image is successfully loaded.
212 @retval EFI_NOT_FOUND Fail to locate necessary PPI.
213 @retval EFI_UNSUPPORTED Image Machine Type is not supported.
214
215 **/
216 EFI_STATUS
217 PeiLoadImageLoadImage (
218 IN CONST EFI_PEI_SERVICES **PeiServices,
219 IN EFI_PEI_FILE_HANDLE FileHandle,
220 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
221 OUT UINT64 *ImageSizeArg, OPTIONAL
222 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
223 OUT UINT32 *AuthenticationState
224 )
225 {
226 EFI_STATUS Status;
227 VOID *Pe32Data;
228 EFI_PHYSICAL_ADDRESS ImageAddress;
229 UINT64 ImageSize;
230 EFI_PHYSICAL_ADDRESS ImageEntryPoint;
231 UINT16 Machine;
232 EFI_SECTION_TYPE SearchType1;
233 EFI_SECTION_TYPE SearchType2;
234
235 *EntryPoint = 0;
236 ImageSize = 0;
237 *AuthenticationState = 0;
238
239 if (FeaturePcdGet (PcdPeiCoreImageLoaderSearchTeSectionFirst)) {
240 SearchType1 = EFI_SECTION_TE;
241 SearchType2 = EFI_SECTION_PE32;
242 } else {
243 SearchType1 = EFI_SECTION_PE32;
244 SearchType2 = EFI_SECTION_TE;
245 }
246
247 //
248 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
249 // is true, TE will be searched first).
250 //
251 Status = PeiServicesFfsFindSectionData (
252 SearchType1,
253 FileHandle,
254 &Pe32Data
255 );
256 //
257 // If we didn't find a first exe section, try to find the second exe section.
258 //
259 if (EFI_ERROR (Status)) {
260 Status = PeiServicesFfsFindSectionData (
261 SearchType2,
262 FileHandle,
263 &Pe32Data
264 );
265 if (EFI_ERROR (Status)) {
266 //
267 // PEI core only carry the loader function fro TE and PE32 executables
268 // If this two section does not exist, just return.
269 //
270 return Status;
271 }
272 }
273
274 //
275 // If memory is installed, perform the shadow operations
276 //
277 Status = LoadAndRelocatePeCoffImage (
278 Pe32Data,
279 &ImageAddress,
280 &ImageSize,
281 &ImageEntryPoint
282 );
283
284 ASSERT_EFI_ERROR (Status);
285
286
287 if (EFI_ERROR (Status)) {
288 return Status;
289 }
290
291 //
292 // Got the entry point from the loaded Pe32Data
293 //
294 Pe32Data = (VOID *) ((UINTN) ImageAddress);
295 *EntryPoint = ImageEntryPoint;
296
297 Machine = PeCoffLoaderGetMachineType (Pe32Data);
298
299 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
300 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
301 return EFI_UNSUPPORTED;
302 }
303 }
304
305 if (ImageAddressArg != NULL) {
306 *ImageAddressArg = ImageAddress;
307 }
308
309 if (ImageSizeArg != NULL) {
310 *ImageSizeArg = ImageSize;
311 }
312
313 DEBUG_CODE_BEGIN ();
314 CHAR8 *AsciiString;
315 CHAR8 AsciiBuffer[512];
316 INT32 Index;
317 INT32 Index1;
318
319 //
320 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
321 //
322 if (Machine != EFI_IMAGE_MACHINE_IA64) {
323 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
324 } else {
325 //
326 // For IPF Image, the real entry point should be print.
327 //
328 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
329 }
330
331 //
332 // Print Module Name by PeImage PDB file name.
333 //
334 AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
335
336 if (AsciiString != NULL) {
337 for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {
338 if (AsciiString[Index] == '\\') {
339 break;
340 }
341 }
342
343 if (Index != 0) {
344 for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) {
345 AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1];
346 }
347 AsciiBuffer [Index1] = '\0';
348 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));
349 }
350 }
351
352 DEBUG_CODE_END ();
353
354 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
355
356 return EFI_SUCCESS;
357
358 }
359
360
361 /**
362 The wrapper function of PeiLoadImageLoadImage().
363
364 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
365 @param FileHandle - Pointer to the FFS file header of the image.
366 @param ImageAddressArg - Pointer to PE/TE image.
367 @param ImageSizeArg - Size of PE/TE image.
368 @param EntryPoint - Pointer to entry point of specified image file for output.
369 @param AuthenticationState - Pointer to attestation authentication state of image.
370
371 @return Status of PeiLoadImageLoadImage().
372
373 **/
374 EFI_STATUS
375 EFIAPI
376 PeiLoadImageLoadImageWrapper (
377 IN CONST EFI_PEI_LOAD_FILE_PPI *This,
378 IN EFI_PEI_FILE_HANDLE FileHandle,
379 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
380 OUT UINT64 *ImageSizeArg, OPTIONAL
381 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
382 OUT UINT32 *AuthenticationState
383 )
384 {
385 return PeiLoadImageLoadImage (
386 GetPeiServicesTablePointer (),
387 FileHandle,
388 ImageAddressArg,
389 ImageSizeArg,
390 EntryPoint,
391 AuthenticationState
392 );
393 }
394
395 /**
396 Check whether the input image has the relocation.
397
398 @param Pe32Data Pointer to the PE/COFF or TE image.
399
400 @retval TRUE Relocation is stripped.
401 @retval FALSE Relocation is not stripped.
402
403 **/
404 BOOLEAN
405 RelocationIsStrip (
406 IN VOID *Pe32Data
407 )
408 {
409 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
410 EFI_IMAGE_DOS_HEADER *DosHdr;
411
412 ASSERT (Pe32Data != NULL);
413
414 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
415 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
416 //
417 // DOS image header is present, so read the PE header after the DOS image header.
418 //
419 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
420 } else {
421 //
422 // DOS image header is not present, so PE header is at the image base.
423 //
424 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
425 }
426
427 //
428 // Three cases with regards to relocations:
429 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
430 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
431 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
432 // has no base relocs to apply
433 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
434 //
435 // Look at the file header to determine if relocations have been stripped, and
436 // save this info in the image context for later use.
437 //
438 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
439 if ((Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
440 return TRUE;
441 } else {
442 return FALSE;
443 }
444 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
445 if ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0) {
446 return TRUE;
447 } else {
448 return FALSE;
449 }
450 }
451
452 return FALSE;
453 }
454
455 /**
456 Routine to load image file for subsequent execution by LoadFile Ppi.
457 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
458 XIP image format is used.
459
460 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
461 @param FileHandle - Pointer to the FFS file header of the image.
462 @param PeimState - The dispatch state of the input PEIM handle.
463 @param EntryPoint - Pointer to entry point of specified image file for output.
464 @param AuthenticationState - Pointer to attestation authentication state of image.
465
466 @retval EFI_SUCCESS - Image is successfully loaded.
467 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
468 @retval Others - Fail to load file.
469
470 **/
471 EFI_STATUS
472 PeiLoadImage (
473 IN CONST EFI_PEI_SERVICES **PeiServices,
474 IN EFI_PEI_FILE_HANDLE FileHandle,
475 IN UINT8 PeimState,
476 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
477 OUT UINT32 *AuthenticationState
478 )
479 {
480 EFI_STATUS PpiStatus;
481 EFI_STATUS Status;
482 UINTN Index;
483 EFI_PEI_LOAD_FILE_PPI *LoadFile;
484 EFI_PHYSICAL_ADDRESS ImageAddress;
485 UINT64 ImageSize;
486 BOOLEAN IsStrip;
487
488 IsStrip = FALSE;
489 //
490 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
491 // one at a time, until one reports EFI_SUCCESS.
492 //
493 Index = 0;
494 do {
495 PpiStatus = PeiServicesLocatePpi (
496 &gEfiPeiLoadFilePpiGuid,
497 Index,
498 NULL,
499 (VOID **)&LoadFile
500 );
501 if (!EFI_ERROR (PpiStatus)) {
502 Status = LoadFile->LoadFile (
503 LoadFile,
504 FileHandle,
505 &ImageAddress,
506 &ImageSize,
507 EntryPoint,
508 AuthenticationState
509 );
510 if (!EFI_ERROR (Status)) {
511 //
512 // The shadowed PEIM must be relocatable.
513 //
514 if (PeimState == PEIM_STATE_REGISITER_FOR_SHADOW) {
515 IsStrip = RelocationIsStrip ((VOID *) (UINTN) ImageAddress);
516 ASSERT (!IsStrip);
517 if (IsStrip) {
518 return EFI_UNSUPPORTED;
519 }
520 }
521
522 //
523 // The image to be started must have the machine type supported by PeiCore.
524 //
525 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));
526 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {
527 return EFI_UNSUPPORTED;
528 }
529 return Status;
530 }
531 }
532 Index++;
533 } while (!EFI_ERROR (PpiStatus));
534
535 return PpiStatus;
536 }
537
538
539 /**
540
541 Install Pei Load File PPI.
542
543
544 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
545 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
546
547 **/
548 VOID
549 InitializeImageServices (
550 IN PEI_CORE_INSTANCE *PrivateData,
551 IN PEI_CORE_INSTANCE *OldCoreData
552 )
553 {
554 if (OldCoreData == NULL) {
555 //
556 // The first time we are XIP (running from FLASH). We need to remember the
557 // FLASH address so we can reinstall the memory version that runs faster
558 //
559 PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
560 PeiServicesInstallPpi (PrivateData->XipLoadFile);
561 } else {
562 //
563 // 2nd time we are running from memory so replace the XIP version with the
564 // new memory version.
565 //
566 PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
567 }
568 }
569
570
571
572