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