]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EdkModulePkg/Core/DxeIplPeim/DxeLoad.c
Remove autogen.h from all dxs files, because autogen.h file has been included by...
[mirror_edk2.git] / EdkModulePkg / Core / DxeIplPeim / DxeLoad.c
... / ...
CommitLineData
1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 DxeLoad.c\r
15\r
16Abstract:\r
17\r
18 Last PEIM.\r
19 Responsibility of this module is to load the DXE Core from a Firmware Volume.\r
20\r
21--*/\r
22\r
23#include "DxeIpl.h"\r
24\r
25BOOLEAN gInMemory = FALSE;\r
26\r
27//\r
28// Module Globals used in the DXE to PEI handoff\r
29// These must be module globals, so the stack can be switched\r
30//\r
31static EFI_DXE_IPL_PPI mDxeIplPpi = {\r
32 DxeLoadCore\r
33};\r
34\r
35static EFI_PEI_FV_FILE_LOADER_PPI mLoadFilePpi = {\r
36 DxeIplLoadFile\r
37};\r
38\r
39static EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {\r
40 {\r
41 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
42 &gEfiPeiFvFileLoaderPpiGuid,\r
43 &mLoadFilePpi\r
44 },\r
45 {\r
46 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
47 &gEfiDxeIplPpiGuid,\r
48 &mDxeIplPpi\r
49 }\r
50};\r
51\r
52static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = {\r
53 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
54 &gEfiEndOfPeiSignalPpiGuid,\r
55 NULL\r
56};\r
57\r
58GLOBAL_REMOVE_IF_UNREFERENCED DECOMPRESS_LIBRARY gEfiDecompress = {\r
59 UefiDecompressGetInfo,\r
60 UefiDecompress\r
61};\r
62\r
63GLOBAL_REMOVE_IF_UNREFERENCED DECOMPRESS_LIBRARY gTianoDecompress = {\r
64 TianoDecompressGetInfo,\r
65 TianoDecompress\r
66};\r
67\r
68GLOBAL_REMOVE_IF_UNREFERENCED DECOMPRESS_LIBRARY gCustomDecompress = {\r
69 CustomDecompressGetInfo,\r
70 CustomDecompress\r
71};\r
72\r
73EFI_STATUS\r
74EFIAPI\r
75PeimInitializeDxeIpl (\r
76 IN EFI_FFS_FILE_HEADER *FfsHeader,\r
77 IN EFI_PEI_SERVICES **PeiServices\r
78 )\r
79/*++\r
80\r
81Routine Description:\r
82\r
83 Initializes the Dxe Ipl PPI\r
84\r
85Arguments:\r
86\r
87 FfsHeader - Pointer to FFS file header\r
88 PeiServices - General purpose services available to every PEIM.\r
89\r
90Returns:\r
91\r
92 EFI_SUCCESS\r
93\r
94--*/\r
95{\r
96 EFI_STATUS Status;\r
97 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r
98 EFI_BOOT_MODE BootMode;\r
99\r
100 Status = PeiServicesGetBootMode (&BootMode);\r
101 ASSERT_EFI_ERROR (Status);\r
102\r
103 if (!gInMemory && (BootMode != BOOT_ON_S3_RESUME)) { \r
104 //\r
105 // The DxeIpl has not yet been shadowed\r
106 //\r
107 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r
108\r
109 //\r
110 // Shadow DxeIpl and then re-run its entry point\r
111 //\r
112 Status = ShadowDxeIpl (FfsHeader, PeiEfiPeiPeCoffLoader);\r
113 } else {\r
114 //\r
115 // Install FvFileLoader and DxeIpl PPIs.\r
116 //\r
117 Status = PeiServicesInstallPpi (mPpiList);\r
118 ASSERT_EFI_ERROR(Status);\r
119 }\r
120 \r
121 return Status;\r
122}\r
123\r
124EFI_STATUS\r
125EFIAPI\r
126DxeLoadCore (\r
127 IN EFI_DXE_IPL_PPI *This,\r
128 IN EFI_PEI_SERVICES **PeiServices,\r
129 IN EFI_PEI_HOB_POINTERS HobList\r
130 )\r
131/*++\r
132\r
133Routine Description:\r
134\r
135 Main entry point to last PEIM\r
136\r
137Arguments:\r
138 This - Entry point for DXE IPL PPI\r
139 PeiServices - General purpose services available to every PEIM.\r
140 HobList - Address to the Pei HOB list\r
141\r
142Returns:\r
143\r
144 EFI_SUCCESS - DEX core was successfully loaded.\r
145 EFI_OUT_OF_RESOURCES - There are not enough resources to load DXE core.\r
146\r
147--*/\r
148{\r
149 EFI_STATUS Status;\r
150 EFI_GUID DxeCoreFileName;\r
151 EFI_GUID FirmwareFileName;\r
152 VOID *Pe32Data;\r
153 VOID *FvImageData; \r
154 EFI_PHYSICAL_ADDRESS DxeCoreAddress;\r
155 UINT64 DxeCoreSize;\r
156 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;\r
157 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r
158 EFI_BOOT_MODE BootMode;\r
159 EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;\r
160 EFI_PEI_S3_RESUME_PPI *S3Resume;\r
161\r
162// PERF_START (PeiServices, L"DxeIpl", NULL, 0);\r
163\r
164 //\r
165 // if in S3 Resume, restore configure\r
166 //\r
167 Status = PeiServicesGetBootMode (&BootMode);\r
168 ASSERT_EFI_ERROR(Status);\r
169\r
170 if (BootMode == BOOT_ON_S3_RESUME) {\r
171 Status = PeiServicesLocatePpi (\r
172 &gEfiPeiS3ResumePpiGuid,\r
173 0,\r
174 NULL,\r
175 (VOID **)&S3Resume\r
176 );\r
177 ASSERT_EFI_ERROR (Status);\r
178\r
179 Status = S3Resume->S3RestoreConfig (PeiServices);\r
180 ASSERT_EFI_ERROR (Status);\r
181 } else if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
182\r
183 Status = PeiServicesLocatePpi (\r
184 &gEfiPeiRecoveryModulePpiGuid,\r
185 0,\r
186 NULL,\r
187 (VOID **)&PeiRecovery\r
188 );\r
189 ASSERT_EFI_ERROR (Status);\r
190\r
191 Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);\r
192 if (EFI_ERROR (Status)) {\r
193 DEBUG ((EFI_D_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));\r
194 CpuDeadLoop ();\r
195 }\r
196\r
197 //\r
198 // Now should have a HOB with the DXE core w/ the old HOB destroyed\r
199 //\r
200 }\r
201\r
202 //\r
203 // Install the PEI Protocols that are shared between PEI and DXE\r
204 //\r
205 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r
206 ASSERT (PeiEfiPeiPeCoffLoader != NULL);\r
207\r
208\r
209 //\r
210 // Find the EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE type compressed Firmware Volume file\r
211 // The file found will be processed by PeiProcessFile: It will first be decompressed to\r
212 // a normal FV, then a corresponding FV type hob will be built. \r
213 //\r
214 Status = PeiFindFile (\r
215 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,\r
216 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,\r
217 &FirmwareFileName,\r
218 &FvImageData\r
219 );\r
220\r
221 //\r
222 // Find the DXE Core in a Firmware Volume\r
223 //\r
224 Status = PeiFindFile (\r
225 EFI_FV_FILETYPE_DXE_CORE,\r
226 EFI_SECTION_PE32,\r
227 &DxeCoreFileName,\r
228 &Pe32Data\r
229 );\r
230 ASSERT_EFI_ERROR (Status);\r
231\r
232 //\r
233 // Load the DXE Core from a Firmware Volume\r
234 //\r
235 Status = PeiLoadFile (\r
236 PeiEfiPeiPeCoffLoader,\r
237 Pe32Data,\r
238 &DxeCoreAddress,\r
239 &DxeCoreSize,\r
240 &DxeCoreEntryPoint\r
241 );\r
242 ASSERT_EFI_ERROR (Status);\r
243\r
244 //\r
245 // Add HOB for the DXE Core\r
246 //\r
247 BuildModuleHob (\r
248 &DxeCoreFileName,\r
249 DxeCoreAddress,\r
250 DxeCoreSize,\r
251 DxeCoreEntryPoint\r
252 );\r
253\r
254 //\r
255 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT\r
256 //\r
257 REPORT_STATUS_CODE (\r
258 EFI_PROGRESS_CODE,\r
259 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT\r
260 );\r
261\r
262 if (FeaturePcdGet (PcdDxeIplBuildShareCodeHobs)) {\r
263 if (FeaturePcdGet (PcdDxeIplSupportEfiDecompress)) {\r
264 //\r
265 // Add HOB for the EFI Decompress Protocol\r
266 //\r
267 BuildGuidDataHob (\r
268 &gEfiDecompressProtocolGuid,\r
269 (VOID *)&gEfiDecompress,\r
270 sizeof (gEfiDecompress)\r
271 );\r
272 }\r
273 if (FeaturePcdGet (PcdDxeIplSupportTianoDecompress)) {\r
274 //\r
275 // Add HOB for the Tiano Decompress Protocol\r
276 //\r
277 BuildGuidDataHob (\r
278 &gEfiTianoDecompressProtocolGuid,\r
279 (VOID *)&gTianoDecompress,\r
280 sizeof (gTianoDecompress)\r
281 );\r
282 }\r
283 if (FeaturePcdGet (PcdDxeIplSupportCustomDecompress)) {\r
284 //\r
285 // Add HOB for the user customized Decompress Protocol\r
286 //\r
287 BuildGuidDataHob (\r
288 &gEfiCustomizedDecompressProtocolGuid,\r
289 (VOID *)&gCustomDecompress,\r
290 sizeof (gCustomDecompress)\r
291 );\r
292 }\r
293\r
294 //\r
295 // Add HOB for the PE/COFF Loader Protocol\r
296 //\r
297 BuildGuidDataHob (\r
298 &gEfiPeiPeCoffLoaderGuid,\r
299 (VOID *)&PeiEfiPeiPeCoffLoader,\r
300 sizeof (VOID *)\r
301 );\r
302 }\r
303\r
304 //\r
305 // Transfer control to the DXE Core\r
306 // The handoff state is simply a pointer to the HOB list\r
307 //\r
308\r
309 DEBUG ((EFI_D_INFO, "DXE Core Entry Point 0x%08x\n", (UINTN) DxeCoreEntryPoint));\r
310 HandOffToDxeCore (DxeCoreEntryPoint, HobList, &mPpiSignal);\r
311 //\r
312 // If we get here, then the DXE Core returned. This is an error\r
313 // Dxe Core should not return.\r
314 //\r
315 ASSERT (FALSE);\r
316 CpuDeadLoop ();\r
317\r
318 return EFI_OUT_OF_RESOURCES;\r
319}\r
320\r
321EFI_STATUS\r
322PeiFindFile (\r
323 IN UINT8 Type,\r
324 IN UINT16 SectionType,\r
325 OUT EFI_GUID *FileName,\r
326 OUT VOID **Pe32Data\r
327 )\r
328/*++\r
329\r
330Routine Description:\r
331\r
332 Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes\r
333 described in the HOB list. Able to search in a compression set in a FFS file.\r
334 But only one level of compression is supported, that is, not able to search\r
335 in a compression set that is within another compression set.\r
336\r
337Arguments:\r
338\r
339 Type - The Type of file to retrieve\r
340\r
341 SectionType - The type of section to retrieve from a file\r
342\r
343 FileName - The name of the file found in the Firmware Volume\r
344\r
345 Pe32Data - Pointer to the beginning of the PE/COFF file found in the Firmware Volume\r
346\r
347Returns:\r
348\r
349 EFI_SUCCESS - The file was found, and the name is returned in FileName, and a pointer to\r
350 the PE/COFF image is returned in Pe32Data\r
351\r
352 EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List\r
353\r
354--*/\r
355{\r
356 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
357 EFI_FFS_FILE_HEADER *FfsFileHeader;\r
358 EFI_STATUS Status;\r
359 EFI_PEI_HOB_POINTERS Hob;\r
360\r
361\r
362 FwVolHeader = NULL;\r
363 FfsFileHeader = NULL;\r
364 Status = EFI_SUCCESS;\r
365\r
366 //\r
367 // For each Firmware Volume, look for a specified type\r
368 // of file and break out until no one is found \r
369 //\r
370 Hob.Raw = GetHobList ();\r
371 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw)) != NULL) {\r
372 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress);\r
373 //\r
374 // Make sure the FV HOB does not get corrupted.\r
375 //\r
376 ASSERT (FwVolHeader->Signature == EFI_FVH_SIGNATURE);\r
377\r
378 Status = PeiServicesFfsFindNextFile (\r
379 Type,\r
380 FwVolHeader,\r
381 &FfsFileHeader\r
382 );\r
383 if (!EFI_ERROR (Status)) {\r
384 Status = PeiProcessFile (\r
385 SectionType,\r
386 FfsFileHeader,\r
387 Pe32Data,\r
388 &Hob\r
389 );\r
390 CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));\r
391 //\r
392 // Find all Fv type ffs to get all FvImage and add them into FvHob\r
393 //\r
394 if (!EFI_ERROR (Status) && (Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE)) {\r
395 return EFI_SUCCESS;\r
396 }\r
397 }\r
398 Hob.Raw = GET_NEXT_HOB (Hob);\r
399 }\r
400 return EFI_NOT_FOUND;\r
401}\r
402\r
403EFI_STATUS\r
404PeiLoadFile (\r
405 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,\r
406 IN VOID *Pe32Data,\r
407 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r
408 OUT UINT64 *ImageSize,\r
409 OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r
410 )\r
411/*++\r
412\r
413Routine Description:\r
414\r
415 Loads and relocates a PE/COFF image into memory.\r
416\r
417Arguments:\r
418\r
419 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r
420\r
421 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r
422\r
423 ImageAddress - The base address of the relocated PE/COFF image\r
424\r
425 ImageSize - The size of the relocated PE/COFF image\r
426\r
427 EntryPoint - The entry point of the relocated PE/COFF image\r
428\r
429Returns:\r
430\r
431 EFI_SUCCESS - The file was loaded and relocated\r
432\r
433 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r
434\r
435--*/\r
436{\r
437 EFI_STATUS Status;\r
438 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
439\r
440 ZeroMem (&ImageContext, sizeof (ImageContext));\r
441 ImageContext.Handle = Pe32Data;\r
442 Status = GetImageReadFunction (&ImageContext);\r
443\r
444 ASSERT_EFI_ERROR (Status);\r
445\r
446 Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);\r
447 if (EFI_ERROR (Status)) {\r
448 return Status;\r
449 }\r
450 //\r
451 // Allocate Memory for the image\r
452 //\r
453 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r
454 ASSERT (ImageContext.ImageAddress != 0);\r
455\r
456 //\r
457 // Load the image to our new buffer\r
458 //\r
459 Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r
460 if (EFI_ERROR (Status)) {\r
461 return Status;\r
462 }\r
463 //\r
464 // Relocate the image in our new buffer\r
465 //\r
466 Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r
467 if (EFI_ERROR (Status)) {\r
468 return Status;\r
469 }\r
470\r
471 //\r
472 // Flush the instruction cache so the image data is written before we execute it\r
473 //\r
474 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
475\r
476 *ImageAddress = ImageContext.ImageAddress;\r
477 *ImageSize = ImageContext.ImageSize;\r
478 *EntryPoint = ImageContext.EntryPoint;\r
479\r
480 return EFI_SUCCESS;\r
481}\r
482\r
483EFI_STATUS\r
484ShadowDxeIpl (\r
485 IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,\r
486 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader\r
487 )\r
488/*++\r
489\r
490Routine Description:\r
491\r
492 Shadow the DXE IPL to a different memory location. This occurs after permanent\r
493 memory has been discovered.\r
494\r
495Arguments:\r
496\r
497 DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver\r
498\r
499 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r
500\r
501Returns:\r
502\r
503 EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.\r
504\r
505 EFI_ ERROR - The shadow was unsuccessful.\r
506\r
507\r
508--*/\r
509{\r
510 UINTN SectionLength;\r
511 UINTN OccupiedSectionLength;\r
512 EFI_PHYSICAL_ADDRESS DxeIplAddress;\r
513 UINT64 DxeIplSize;\r
514 EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;\r
515 EFI_STATUS Status;\r
516 EFI_COMMON_SECTION_HEADER *Section;\r
517\r
518 Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);\r
519\r
520 while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {\r
521 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r
522 OccupiedSectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r
523 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r
524 }\r
525 //\r
526 // Relocate DxeIpl into memory by using loadfile service\r
527 //\r
528 Status = PeiLoadFile (\r
529 PeiEfiPeiPeCoffLoader,\r
530 (VOID *) (Section + 1),\r
531 &DxeIplAddress,\r
532 &DxeIplSize,\r
533 &DxeIplEntryPoint\r
534 );\r
535\r
536 if (Status == EFI_SUCCESS) {\r
537 //\r
538 // Set gInMemory global variable to TRUE to indicate the dxeipl is shadowed.\r
539 //\r
540 *(BOOLEAN *) ((UINTN) &gInMemory + (UINTN) DxeIplEntryPoint - (UINTN) _ModuleEntryPoint) = TRUE;\r
541 Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer());\r
542 }\r
543\r
544 return Status;\r
545}\r
546\r
547EFI_STATUS\r
548EFIAPI\r
549DxeIplLoadFile (\r
550 IN EFI_PEI_FV_FILE_LOADER_PPI *This,\r
551 IN EFI_FFS_FILE_HEADER *FfsHeader,\r
552 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r
553 OUT UINT64 *ImageSize,\r
554 OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r
555 )\r
556/*++\r
557\r
558Routine Description:\r
559\r
560 Given a pointer to an FFS file containing a PE32 image, get the\r
561 information on the PE32 image, and then "load" it so that it\r
562 can be executed.\r
563\r
564Arguments:\r
565\r
566 This - pointer to our file loader protocol\r
567\r
568 FfsHeader - pointer to the FFS file header of the FFS file that\r
569 contains the PE32 image we want to load\r
570\r
571 ImageAddress - returned address where the PE32 image is loaded\r
572\r
573 ImageSize - returned size of the loaded PE32 image\r
574\r
575 EntryPoint - entry point to the loaded PE32 image\r
576\r
577Returns:\r
578\r
579 EFI_SUCCESS - The FFS file was successfully loaded.\r
580\r
581 EFI_ERROR - Unable to load the FFS file.\r
582\r
583--*/\r
584{\r
585 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r
586 EFI_STATUS Status;\r
587 VOID *Pe32Data;\r
588\r
589 Pe32Data = NULL;\r
590 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r
591\r
592 //\r
593 // Preprocess the FFS file to get a pointer to the PE32 information\r
594 // in the enclosed PE32 image.\r
595 //\r
596 Status = PeiProcessFile (\r
597 EFI_SECTION_PE32,\r
598 FfsHeader,\r
599 &Pe32Data,\r
600 NULL\r
601 );\r
602\r
603 if (EFI_ERROR (Status)) {\r
604 return Status;\r
605 }\r
606 //\r
607 // Load the PE image from the FFS file\r
608 //\r
609 Status = PeiLoadFile (\r
610 PeiEfiPeiPeCoffLoader,\r
611 Pe32Data,\r
612 ImageAddress,\r
613 ImageSize,\r
614 EntryPoint\r
615 );\r
616\r
617 return Status;\r
618}\r
619\r
620EFI_STATUS\r
621PeiProcessFile (\r
622 IN UINT16 SectionType,\r
623 IN EFI_FFS_FILE_HEADER *FfsFileHeader,\r
624 OUT VOID **Pe32Data,\r
625 IN EFI_PEI_HOB_POINTERS *OrigHob\r
626 )\r
627/*++\r
628\r
629Routine Description:\r
630\r
631Arguments:\r
632\r
633 SectionType - The type of section in the FFS file to process.\r
634\r
635 FfsFileHeader - Pointer to the FFS file to process, looking for the\r
636 specified SectionType\r
637\r
638 Pe32Data - returned pointer to the start of the PE32 image found\r
639 in the FFS file.\r
640\r
641Returns:\r
642\r
643 EFI_SUCCESS - found the PE32 section in the FFS file\r
644\r
645--*/\r
646{\r
647 EFI_STATUS Status;\r
648 VOID *SectionData;\r
649 DECOMPRESS_LIBRARY *DecompressLibrary;\r
650 UINT8 *DstBuffer;\r
651 UINT8 *ScratchBuffer;\r
652 UINT32 DstBufferSize;\r
653 UINT32 ScratchBufferSize;\r
654 EFI_COMMON_SECTION_HEADER *CmpSection;\r
655 UINTN CmpSectionLength;\r
656 UINTN OccupiedCmpSectionLength;\r
657 VOID *CmpFileData;\r
658 UINTN CmpFileSize;\r
659 EFI_COMMON_SECTION_HEADER *Section;\r
660 UINTN SectionLength;\r
661 UINTN OccupiedSectionLength;\r
662 UINT64 FileSize;\r
663 UINT32 AuthenticationStatus;\r
664 EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract;\r
665 UINT32 BufferSize;\r
666 UINT8 *Buffer;\r
667 EFI_PEI_SECURITY_PPI *Security;\r
668 BOOLEAN StartCrisisRecovery;\r
669 EFI_GUID TempGuid;\r
670 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
671 EFI_COMPRESSION_SECTION *CompressionSection;\r
672\r
673 //\r
674 // Initialize local variables.\r
675 //\r
676 DecompressLibrary = NULL;\r
677 DstBuffer = NULL;\r
678 DstBufferSize = 0;\r
679\r
680 Status = PeiServicesFfsFindSectionData (\r
681 EFI_SECTION_COMPRESSION,\r
682 FfsFileHeader,\r
683 &SectionData\r
684 );\r
685\r
686 //\r
687 // First process the compression section\r
688 //\r
689 if (!EFI_ERROR (Status)) {\r
690 //\r
691 // Yes, there is a compression section, so extract the contents\r
692 // Decompress the image here\r
693 //\r
694 Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));\r
695\r
696 do {\r
697 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r
698 OccupiedSectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r
699\r
700 //\r
701 // Was the DXE Core file encapsulated in a GUID'd section?\r
702 //\r
703 if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
704\r
705 //\r
706 // This following code constitutes the addition of the security model\r
707 // to the DXE IPL.\r
708 //\r
709 //\r
710 // Set a default authenticatino state\r
711 //\r
712 AuthenticationStatus = 0;\r
713\r
714 Status = PeiServicesLocatePpi (\r
715 &gEfiPeiSectionExtractionPpiGuid,\r
716 0,\r
717 NULL,\r
718 (VOID **)&SectionExtract\r
719 );\r
720\r
721 if (EFI_ERROR (Status)) {\r
722 return Status;\r
723 }\r
724 //\r
725 // Verify Authentication State\r
726 //\r
727 CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));\r
728\r
729 Status = SectionExtract->PeiGetSection (\r
730 GetPeiServicesTablePointer(),\r
731 SectionExtract,\r
732 (EFI_SECTION_TYPE *) &SectionType,\r
733 &TempGuid,\r
734 0,\r
735 (VOID **) &Buffer,\r
736 &BufferSize,\r
737 &AuthenticationStatus\r
738 );\r
739\r
740 if (EFI_ERROR (Status)) {\r
741 return Status;\r
742 }\r
743 //\r
744 // If not ask the Security PPI, if exists, for disposition\r
745 //\r
746 //\r
747 Status = PeiServicesLocatePpi (\r
748 &gEfiPeiSecurityPpiGuid,\r
749 0,\r
750 NULL,\r
751 (VOID **)&Security\r
752 );\r
753 if (EFI_ERROR (Status)) {\r
754 return Status;\r
755 }\r
756\r
757 Status = Security->AuthenticationState (\r
758 GetPeiServicesTablePointer(),\r
759 (struct _EFI_PEI_SECURITY_PPI *) Security,\r
760 AuthenticationStatus,\r
761 FfsFileHeader,\r
762 &StartCrisisRecovery\r
763 );\r
764\r
765 if (EFI_ERROR (Status)) {\r
766 return Status;\r
767 }\r
768 //\r
769 // If there is a security violation, report to caller and have\r
770 // the upper-level logic possible engender a crisis recovery\r
771 //\r
772 if (StartCrisisRecovery) {\r
773 return EFI_SECURITY_VIOLATION;\r
774 }\r
775 }\r
776\r
777 if (Section->Type == EFI_SECTION_PE32) {\r
778 //\r
779 // This is what we want\r
780 //\r
781 *Pe32Data = (VOID *) (Section + 1);\r
782 return EFI_SUCCESS;\r
783 } else if (Section->Type == EFI_SECTION_COMPRESSION) {\r
784 //\r
785 // This is a compression set, expand it\r
786 //\r
787 CompressionSection = (EFI_COMPRESSION_SECTION *) Section;\r
788\r
789 switch (CompressionSection->CompressionType) {\r
790 case EFI_STANDARD_COMPRESSION:\r
791 //\r
792 // Load EFI standard compression.\r
793 //\r
794 if (FeaturePcdGet (PcdDxeIplSupportTianoDecompress)) {\r
795 DecompressLibrary = &gEfiDecompress;\r
796 } else {\r
797 ASSERT (FALSE);\r
798 return EFI_NOT_FOUND;\r
799 }\r
800 break;\r
801\r
802 case EFI_CUSTOMIZED_COMPRESSION:\r
803 //\r
804 // Load user customized compression.\r
805 //\r
806 if (FeaturePcdGet (PcdDxeIplSupportCustomDecompress)) {\r
807 DecompressLibrary = &gCustomDecompress;\r
808 } else {\r
809 ASSERT (FALSE);\r
810 return EFI_NOT_FOUND;\r
811 }\r
812 break;\r
813\r
814 case EFI_NOT_COMPRESSED:\r
815 //\r
816 // Allocate destination buffer\r
817 //\r
818 DstBufferSize = CompressionSection->UncompressedLength;\r
819 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r
820 if (DstBuffer == NULL) {\r
821 return EFI_OUT_OF_RESOURCES;\r
822 }\r
823 //\r
824 // stream is not actually compressed, just encapsulated. So just copy it.\r
825 //\r
826 CopyMem (DstBuffer, CompressionSection + 1, DstBufferSize);\r
827 break;\r
828\r
829 default:\r
830 //\r
831 // Don't support other unknown compression type.\r
832 //\r
833 ASSERT_EFI_ERROR (Status);\r
834 return EFI_NOT_FOUND;\r
835 }\r
836 \r
837 if (CompressionSection->CompressionType != EFI_NOT_COMPRESSED) {\r
838 //\r
839 // For compressed data, decompress them to dstbuffer.\r
840 //\r
841 Status = DecompressLibrary->GetInfo (\r
842 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r
843 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),\r
844 &DstBufferSize,\r
845 &ScratchBufferSize\r
846 );\r
847 if (EFI_ERROR (Status)) {\r
848 //\r
849 // GetInfo failed\r
850 //\r
851 DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));\r
852 return EFI_NOT_FOUND;\r
853 }\r
854 \r
855 //\r
856 // Allocate scratch buffer\r
857 //\r
858 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r
859 if (ScratchBuffer == NULL) {\r
860 return EFI_OUT_OF_RESOURCES;\r
861 }\r
862 \r
863 //\r
864 // Allocate destination buffer\r
865 //\r
866 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r
867 if (DstBuffer == NULL) {\r
868 return EFI_OUT_OF_RESOURCES;\r
869 }\r
870 \r
871 //\r
872 // Call decompress function\r
873 //\r
874 Status = DecompressLibrary->Decompress (\r
875 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r
876 DstBuffer,\r
877 ScratchBuffer\r
878 );\r
879 if (EFI_ERROR (Status)) {\r
880 //\r
881 // Decompress failed\r
882 //\r
883 DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));\r
884 return EFI_NOT_FOUND;\r
885 }\r
886 }\r
887\r
888 //\r
889 // Decompress successfully.\r
890 // Loop the decompressed data searching for expected section.\r
891 //\r
892 CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;\r
893 CmpFileData = (VOID *) DstBuffer;\r
894 CmpFileSize = DstBufferSize;\r
895 do {\r
896 CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;\r
897 if (CmpSection->Type == SectionType) {\r
898 //\r
899 // This is what we want\r
900 //\r
901 if (SectionType == EFI_SECTION_PE32) {\r
902 *Pe32Data = (VOID *) (CmpSection + 1);\r
903 return EFI_SUCCESS;\r
904 } else if (SectionType == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {\r
905 // \r
906 // Firmware Volume Image in this Section\r
907 // Skip the section header to get FvHeader\r
908 //\r
909 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (CmpSection + 1);\r
910 \r
911 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {\r
912 //\r
913 // Because FvLength in FvHeader is UINT64 type, \r
914 // so FvHeader must meed at least 8 bytes alignment.\r
915 // If current FvImage base address doesn't meet its alignment,\r
916 // we need to reload this FvImage to another correct memory address.\r
917 //\r
918 if (((UINTN) FvHeader % sizeof (UINT64)) != 0) {\r
919 DstBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) CmpSectionLength - sizeof (EFI_COMMON_SECTION_HEADER)), sizeof (UINT64));\r
920 if (DstBuffer == NULL) {\r
921 return EFI_OUT_OF_RESOURCES;\r
922 }\r
923 CopyMem (DstBuffer, FvHeader, (UINTN) CmpSectionLength - sizeof (EFI_COMMON_SECTION_HEADER));\r
924 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DstBuffer; \r
925 }\r
926\r
927 //\r
928 // Build new FvHob for new decompressed Fv image.\r
929 //\r
930 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);\r
931 \r
932 //\r
933 // Set the original FvHob to unused.\r
934 //\r
935 if (OrigHob != NULL) {\r
936 OrigHob->Header->HobType = EFI_HOB_TYPE_UNUSED;\r
937 }\r
938 \r
939 //\r
940 // return found FvImage data.\r
941 //\r
942 *Pe32Data = (VOID *) FvHeader;\r
943 return EFI_SUCCESS;\r
944 }\r
945 }\r
946 }\r
947 OccupiedCmpSectionLength = GET_OCCUPIED_SIZE (CmpSectionLength, 4);\r
948 CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);\r
949 } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);\r
950 }\r
951 //\r
952 // End of the decompression activity\r
953 //\r
954\r
955 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r
956 FileSize = FfsFileHeader->Size[0] & 0xFF;\r
957 FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;\r
958 FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;\r
959 FileSize &= 0x00FFFFFF;\r
960 } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);\r
961 \r
962 //\r
963 // search all sections (compression and non compression) in this FFS, don't \r
964 // find expected section.\r
965 //\r
966 return EFI_NOT_FOUND;\r
967 } else {\r
968 //\r
969 // For those FFS that doesn't contain compression section, directly search \r
970 // PE or TE section in this FFS.\r
971 //\r
972\r
973 Status = PeiServicesFfsFindSectionData (\r
974 EFI_SECTION_PE32,\r
975 FfsFileHeader,\r
976 &SectionData\r
977 );\r
978\r
979 if (EFI_ERROR (Status)) {\r
980 Status = PeiServicesFfsFindSectionData (\r
981 EFI_SECTION_TE,\r
982 FfsFileHeader,\r
983 &SectionData\r
984 );\r
985 if (EFI_ERROR (Status)) {\r
986 return Status;\r
987 }\r
988 }\r
989 }\r
990\r
991 *Pe32Data = SectionData;\r
992\r
993 return EFI_SUCCESS;\r
994}\r
995\r