]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Image/Image.c
PEI Core: Remove unused variable in PeiLoadImageLoadImage function.
[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) {
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 (Private->PeiMemoryInstalled) {
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) {
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 // Try to find a first exe section (if PcdPeiCoreImageLoaderSearchTeSectionFirst
242 // is true, TE will be searched first).
243 //
244 Status = PeiServicesFfsFindSectionData (
245 SearchType1,
246 FileHandle,
247 &Pe32Data
248 );
249 //
250 // If we didn't find a first exe section, try to find the second exe section.
251 //
252 if (EFI_ERROR (Status)) {
253 Status = PeiServicesFfsFindSectionData (
254 SearchType2,
255 FileHandle,
256 &Pe32Data
257 );
258 if (EFI_ERROR (Status)) {
259 //
260 // PEI core only carry the loader function fro TE and PE32 executables
261 // If this two section does not exist, just return.
262 //
263 return Status;
264 }
265 }
266
267 //
268 // If memory is installed, perform the shadow operations
269 //
270 Status = LoadAndRelocatePeCoffImage (
271 Pe32Data,
272 &ImageAddress,
273 &ImageSize,
274 &ImageEntryPoint
275 );
276
277 ASSERT_EFI_ERROR (Status);
278
279
280 if (EFI_ERROR (Status)) {
281 return Status;
282 }
283
284 //
285 // Got the entry point from the loaded Pe32Data
286 //
287 Pe32Data = (VOID *) ((UINTN) ImageAddress);
288 *EntryPoint = ImageEntryPoint;
289
290 Machine = PeCoffLoaderGetMachineType (Pe32Data);
291
292 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Machine)) {
293 if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Machine)) {
294 return EFI_UNSUPPORTED;
295 }
296 }
297
298 if (ImageAddressArg != NULL) {
299 *ImageAddressArg = ImageAddress;
300 }
301
302 if (ImageSizeArg != NULL) {
303 *ImageSizeArg = ImageSize;
304 }
305
306 DEBUG_CODE_BEGIN ();
307 CHAR8 *AsciiString;
308 CHAR8 AsciiBuffer[512];
309 INT32 Index;
310 INT32 Index1;
311
312 //
313 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi
314 //
315 if (Machine != EFI_IMAGE_MACHINE_IA64) {
316 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)*EntryPoint));
317 } else {
318 //
319 // For IPF Image, the real entry point should be print.
320 //
321 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN)ImageAddress, (VOID *)(UINTN)(*(UINT64 *)(UINTN)*EntryPoint)));
322 }
323
324 //
325 // Print Module Name by PeImage PDB file name.
326 //
327 AsciiString = PeCoffLoaderGetPdbPointer (Pe32Data);
328
329 if (AsciiString != NULL) {
330 for (Index = (INT32) AsciiStrLen (AsciiString) - 1; Index >= 0; Index --) {
331 if (AsciiString[Index] == '\\') {
332 break;
333 }
334 }
335
336 if (Index != 0) {
337 for (Index1 = 0; AsciiString[Index + 1 + Index1] != '.'; Index1 ++) {
338 AsciiBuffer [Index1] = AsciiString[Index + 1 + Index1];
339 }
340 AsciiBuffer [Index1] = '\0';
341 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));
342 }
343 }
344
345 DEBUG_CODE_END ();
346
347 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
348
349 return EFI_SUCCESS;
350
351 }
352
353
354 /**
355 The wrapper function of PeiLoadImageLoadImage().
356
357 @param This - Pointer to EFI_PEI_LOAD_FILE_PPI.
358 @param FileHandle - Pointer to the FFS file header of the image.
359 @param ImageAddressArg - Pointer to PE/TE image.
360 @param ImageSizeArg - Size of PE/TE image.
361 @param EntryPoint - Pointer to entry point of specified image file for output.
362 @param AuthenticationState - Pointer to attestation authentication state of image.
363
364 @return Status of PeiLoadImageLoadImage().
365
366 **/
367 EFI_STATUS
368 EFIAPI
369 PeiLoadImageLoadImageWrapper (
370 IN CONST EFI_PEI_LOAD_FILE_PPI *This,
371 IN EFI_PEI_FILE_HANDLE FileHandle,
372 OUT EFI_PHYSICAL_ADDRESS *ImageAddressArg, OPTIONAL
373 OUT UINT64 *ImageSizeArg, OPTIONAL
374 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
375 OUT UINT32 *AuthenticationState
376 )
377 {
378 return PeiLoadImageLoadImage (
379 GetPeiServicesTablePointer (),
380 FileHandle,
381 ImageAddressArg,
382 ImageSizeArg,
383 EntryPoint,
384 AuthenticationState
385 );
386 }
387
388 /**
389 Routine to load image file for subsequent execution by LoadFile Ppi.
390 If any LoadFile Ppi is not found, the build-in support function for the PE32+/TE
391 XIP image format is used.
392
393 @param PeiServices - An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
394 @param FileHandle - Pointer to the FFS file header of the image.
395 @param EntryPoint - Pointer to entry point of specified image file for output.
396 @param AuthenticationState - Pointer to attestation authentication state of image.
397
398 @retval EFI_SUCCESS - Image is successfully loaded.
399 @retval EFI_NOT_FOUND - Fail to locate necessary PPI
400 @retval Others - Fail to load file.
401
402 **/
403 EFI_STATUS
404 PeiLoadImage (
405 IN CONST EFI_PEI_SERVICES **PeiServices,
406 IN EFI_PEI_FILE_HANDLE FileHandle,
407 OUT EFI_PHYSICAL_ADDRESS *EntryPoint,
408 OUT UINT32 *AuthenticationState
409 )
410 {
411 EFI_STATUS PpiStatus;
412 EFI_STATUS Status;
413 UINTN Index;
414 EFI_PEI_LOAD_FILE_PPI *LoadFile;
415 EFI_PHYSICAL_ADDRESS ImageAddress;
416 UINT64 ImageSize;
417
418 //
419 // If any instances of PEI_LOAD_FILE_PPI are installed, they are called.
420 // one at a time, until one reports EFI_SUCCESS.
421 //
422 Index = 0;
423 do {
424 PpiStatus = PeiServicesLocatePpi (
425 &gEfiPeiLoadFilePpiGuid,
426 Index,
427 NULL,
428 (VOID **)&LoadFile
429 );
430 if (!EFI_ERROR (PpiStatus)) {
431 Status = LoadFile->LoadFile (
432 LoadFile,
433 FileHandle,
434 &ImageAddress,
435 &ImageSize,
436 EntryPoint,
437 AuthenticationState
438 );
439 if (!EFI_ERROR (Status)) {
440 //
441 // The image to be started must have the machine type supported by PeiCore.
442 //
443 ASSERT (EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress)));
444 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeCoffLoaderGetMachineType ((VOID *) (UINTN) ImageAddress))) {
445 return EFI_UNSUPPORTED;
446 }
447 return Status;
448 }
449 }
450 Index++;
451 } while (!EFI_ERROR (PpiStatus));
452
453 return PpiStatus;
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