]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Image/Image.c
Global variables have been moved backward ahead of functions.
[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 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 return EFI_UNSUPPORTED;
291 }
292
293 if (ImageAddressArg != NULL) {
294 *ImageAddressArg = ImageAddress;
295 }
296
297 if (ImageSizeArg != NULL) {
298 *ImageSizeArg = ImageSize;
299 }
300
301 DEBUG_CODE_BEGIN ();
302 CHAR8 *AsciiString;
303 CHAR8 AsciiBuffer[512];
304 INT32 Index;
305 INT32 Index1;
306
307 //
308 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
309 //
310 if (Machine != IMAGE_FILE_MACHINE_IA64) {
311 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
312 } else {
313 //
314 // For IPF Image, the real entry point should be print.
315 //
316 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
317 }
318
319 //
320 // Print Module Name by PeImage PDB file name.
321 //
322 AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
323
324 if (AsciiString != NULL) {
325 for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {
326 if (AsciiString[Index] == '\\') {
327 break;
328 }
329 }
330
331 if (Index != 0) {
332 for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) {
333 AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1];
334 }
335 AsciiBuffer [Index1] = '\0';
336 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));
337 }
338 }
339
340 DEBUG_CODE_END ();
341
342 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
343
344 return EFI_SUCCESS;
345
346 }
347
348
349 /**
350 The wrapper function of PeiLoadImageLoadImage().
351
352 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
353 @param FileHandle - Pointer to the FFS file header of the image.
354 @param ImageAddressArg - Pointer to PE/TE image.
355 @param ImageSizeArg - Size of PE/TE image.
356 @param EntryPoint - Pointer to entry point of specified image file for output.
357 @param AuthenticationState - Pointer to attestation authentication state of image.
358
359 @return Status of PeiLoadImageLoadImage().
360
361 **/
362 EFI_STATUS
363 EFIAPI
364 PeiLoadImageLoadImageWrapper (
365 IN CONST EFI_PEI_LOAD_FILE_PPI *This,
366 IN EFI_PEI_FILE_HANDLE FileHandle,
367 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
368 OUT UINT64 *ImageSizeArg, OPTIONAL
369 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
370 OUT UINT32 *AuthenticationState
371 )
372 {
373 return PeiLoadImageLoadImage (
374 GetPeiServicesTablePointer (),
375 FileHandle,
376 ImageAddressArg,
377 ImageSizeArg,
378 EntryPoint,
379 AuthenticationState
380 );
381 }
382
383 /**
384 Routine to load image file for subsequent execution by LoadFile Ppi.
385 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
386 XIP image format is used.
387
388 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
389 @param FileHandle - Pointer to the FFS file header of the image.
390 @param EntryPoint - Pointer to entry point of specified image file for output.
391 @param AuthenticationState - Pointer to attestation authentication state of image.
392
393 @retval EFI_SUCCESS - Image is successfully loaded.
394 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
395 @retval Others - Fail to load file.
396
397 **/
398 EFI_STATUS
399 PeiLoadImage (
400 IN CONST EFI_PEI_SERVICES **PeiServices,
401 IN EFI_PEI_FILE_HANDLE FileHandle,
402 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
403 OUT UINT32 *AuthenticationState
404 )
405 {
406 EFI_STATUS PpiStatus;
407 EFI_STATUS Status;
408 UINTN Index;
409 EFI_PEI_LOAD_FILE_PPI *LoadFile;
410 EFI_PHYSICAL_ADDRESS ImageAddress;
411 UINT64 ImageSize;
412
413 //
414 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
415 // one at a time, until one reports EFI_SUCCESS.
416 //
417 Index = 0;
418 do {
419 PpiStatus = PeiServicesLocatePpi (
420 &gEfiPeiLoadFilePpiGuid,
421 Index,
422 NULL,
423 (VOID **)&LoadFile
424 );
425 if (!EFI_ERROR (PpiStatus)) {
426 Status = LoadFile->LoadFile (
427 LoadFile,
428 FileHandle,
429 &ImageAddress,
430 &ImageSize,
431 EntryPoint,
432 AuthenticationState
433 );
434 if (!EFI_ERROR (Status)) {
435 return Status;
436 }
437 }
438 Index++;
439 } while (!EFI_ERROR (PpiStatus));
440
441 //
442 // If no instances reports EFI_SUCCESS, then build-in support for
443 // the PE32+/TE XIP image format is used.
444 //
445 Status = PeiLoadImageLoadImage (
446 PeiServices,
447 FileHandle,
448 NULL,
449 NULL,
450 EntryPoint,
451 AuthenticationState
452 );
453 return Status;
454 }
455
456
457 /**
458
459 Install Pei Load File PPI.
460
461
462 @param PrivateData - Pointer to PEI_CORE_INSTANCE.
463 @param OldCoreData - Pointer to PEI_CORE_INSTANCE.
464
465 **/
466 VOID
467 InitializeImageServices (
468 IN PEI_CORE_INSTANCE *PrivateData,
469 IN PEI_CORE_INSTANCE *OldCoreData
470 )
471 {
472 if (OldCoreData == NULL) {
473 //
474 // The first time we are XIP (running from FLASH). We need to remember the
475 // FLASH address so we can reinstall the memory version that runs faster
476 //
477 PrivateData->XipLoadFile = &gPpiLoadFilePpiList;
478 PeiServicesInstallPpi (PrivateData->XipLoadFile);
479 } else {
480 //
481 // 2nd time we are running from memory so replace the XIP version with the
482 // new memory version.
483 //
484 PeiServicesReInstallPpi (PrivateData->XipLoadFile, &gPpiLoadFilePpiList);
485 }
486 }
487
488
489