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