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