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