]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
Change the behavior of DxeIplLoadFile to load EFI_SECTION_TE first. If failed, LOAD...
[mirror_edk2.git] / MdeModulePkg / Core / DxeIplPeim / DxeLoad.c
CommitLineData
95276127 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
95276127 23#include "DxeIpl.h"\r
d8c79a81 24#include <Ppi/GuidedSectionExtraction.h>\r
95276127 25\r
26// porting note remove later\r
95276127 27#include "FrameworkPei.h"\r
28// end of remove later\r
29\r
d8c79a81
LG
30EFI_STATUS\r
31CustomDecompressExtractSection (\r
32 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,\r
33 IN CONST VOID *InputSection,\r
34 OUT VOID **OutputBuffer,\r
35 OUT UINTN *OutputSize,\r
36 OUT UINT32 *AuthenticationStatus\r
37);\r
38\r
95276127 39BOOLEAN gInMemory = FALSE;\r
40\r
41//\r
42// Module Globals used in the DXE to PEI handoff\r
43// These must be module globals, so the stack can be switched\r
44//\r
45static EFI_DXE_IPL_PPI mDxeIplPpi = {\r
46 DxeLoadCore\r
47};\r
48\r
49static EFI_PEI_FV_FILE_LOADER_PPI mLoadFilePpi = {\r
50 DxeIplLoadFile\r
51};\r
52\r
d8c79a81
LG
53static EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomDecompressExtractiongPpi = {\r
54 CustomDecompressExtractSection\r
55};\r
56\r
95276127 57static EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {\r
58 {\r
59 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
60 &gEfiPeiFvFileLoaderPpiGuid,\r
61 &mLoadFilePpi\r
62 },\r
63 {\r
64 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
65 &gEfiDxeIplPpiGuid,\r
66 &mDxeIplPpi\r
67 }\r
68};\r
69\r
70static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = {\r
71 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
72 &gEfiEndOfPeiSignalPpiGuid,\r
73 NULL\r
74};\r
75\r
95276127 76EFI_STATUS\r
77EFIAPI\r
78PeimInitializeDxeIpl (\r
79 IN EFI_FFS_FILE_HEADER *FfsHeader,\r
80 IN EFI_PEI_SERVICES **PeiServices\r
81 )\r
82/*++\r
83\r
84Routine Description:\r
85\r
86 Initializes the Dxe Ipl PPI\r
87\r
88Arguments:\r
89\r
90 FfsHeader - Pointer to FFS file header\r
91 PeiServices - General purpose services available to every PEIM.\r
92\r
93Returns:\r
94\r
95 EFI_SUCCESS\r
96\r
97--*/\r
98{\r
99 EFI_STATUS Status;\r
100 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r
101 EFI_BOOT_MODE BootMode;\r
d8c79a81
LG
102 EFI_GUID **DecompressGuidList;\r
103 UINT32 DecompressMethodNumber;\r
104 EFI_PEI_PPI_DESCRIPTOR *GuidPpi;\r
105 \r
95276127 106 Status = PeiServicesGetBootMode (&BootMode);\r
107 ASSERT_EFI_ERROR (Status);\r
108\r
109 if (!gInMemory && (BootMode != BOOT_ON_S3_RESUME)) { \r
110 //\r
111 // The DxeIpl has not yet been shadowed\r
112 //\r
113 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r
114\r
115 //\r
116 // Shadow DxeIpl and then re-run its entry point\r
117 //\r
118 Status = ShadowDxeIpl (FfsHeader, PeiEfiPeiPeCoffLoader);\r
119 } else {\r
d8c79a81
LG
120 //\r
121 // Get custom decompress method guid list \r
122 //\r
123 DecompressGuidList = NULL;\r
124 DecompressMethodNumber = 0;\r
125 Status = CustomDecompressGetAlgorithms (DecompressGuidList, &DecompressMethodNumber);\r
126 if (Status == EFI_OUT_OF_RESOURCES) {\r
127 DecompressGuidList = (EFI_GUID **) AllocatePages (EFI_SIZE_TO_PAGES (DecompressMethodNumber * sizeof (EFI_GUID *)));\r
128 ASSERT (DecompressGuidList != NULL);\r
129 Status = CustomDecompressGetAlgorithms (DecompressGuidList, &DecompressMethodNumber);\r
130 }\r
131 ASSERT_EFI_ERROR(Status);\r
132\r
133 //\r
134 // Install custom decompress extraction guid ppi\r
135 //\r
136 if (DecompressMethodNumber > 0) {\r
137 GuidPpi = NULL;\r
138 GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePages (EFI_SIZE_TO_PAGES (DecompressMethodNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR)));\r
139 ASSERT (GuidPpi != NULL);\r
140 while (DecompressMethodNumber-- > 0) {\r
141 GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;\r
142 GuidPpi->Ppi = &mCustomDecompressExtractiongPpi;\r
143 GuidPpi->Guid = DecompressGuidList [DecompressMethodNumber];\r
144 Status = PeiServicesInstallPpi (GuidPpi++);\r
145 ASSERT_EFI_ERROR(Status);\r
146 }\r
147 }\r
148 \r
95276127 149 //\r
150 // Install FvFileLoader and DxeIpl PPIs.\r
151 //\r
152 Status = PeiServicesInstallPpi (mPpiList);\r
153 ASSERT_EFI_ERROR(Status);\r
154 }\r
155 \r
156 return Status;\r
157}\r
158\r
159EFI_STATUS\r
160EFIAPI\r
161DxeLoadCore (\r
162 IN EFI_DXE_IPL_PPI *This,\r
163 IN EFI_PEI_SERVICES **PeiServices,\r
164 IN EFI_PEI_HOB_POINTERS HobList\r
165 )\r
166/*++\r
167\r
168Routine Description:\r
169\r
170 Main entry point to last PEIM\r
171\r
172Arguments:\r
173 This - Entry point for DXE IPL PPI\r
174 PeiServices - General purpose services available to every PEIM.\r
175 HobList - Address to the Pei HOB list\r
176\r
177Returns:\r
178\r
179 EFI_SUCCESS - DEX core was successfully loaded.\r
180 EFI_OUT_OF_RESOURCES - There are not enough resources to load DXE core.\r
181\r
182--*/\r
183{\r
184 EFI_STATUS Status;\r
185 EFI_GUID DxeCoreFileName;\r
186 EFI_GUID FirmwareFileName;\r
187 VOID *Pe32Data;\r
188 VOID *FvImageData; \r
189 EFI_PHYSICAL_ADDRESS DxeCoreAddress;\r
190 UINT64 DxeCoreSize;\r
191 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;\r
192 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r
193 EFI_BOOT_MODE BootMode;\r
194 EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;\r
195 EFI_PEI_S3_RESUME_PPI *S3Resume;\r
196\r
197// PERF_START (PeiServices, L"DxeIpl", NULL, 0);\r
198\r
199 //\r
200 // if in S3 Resume, restore configure\r
201 //\r
202 Status = PeiServicesGetBootMode (&BootMode);\r
203 ASSERT_EFI_ERROR(Status);\r
204\r
205 if (BootMode == BOOT_ON_S3_RESUME) {\r
206 Status = PeiServicesLocatePpi (\r
207 &gEfiPeiS3ResumePpiGuid,\r
208 0,\r
209 NULL,\r
210 (VOID **)&S3Resume\r
211 );\r
212 ASSERT_EFI_ERROR (Status);\r
213\r
214 Status = S3Resume->S3RestoreConfig (PeiServices);\r
215 ASSERT_EFI_ERROR (Status);\r
216 } else if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
217\r
218 Status = PeiServicesLocatePpi (\r
219 &gEfiPeiRecoveryModulePpiGuid,\r
220 0,\r
221 NULL,\r
222 (VOID **)&PeiRecovery\r
223 );\r
224 ASSERT_EFI_ERROR (Status);\r
225\r
226 Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);\r
227 if (EFI_ERROR (Status)) {\r
228 DEBUG ((EFI_D_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));\r
229 CpuDeadLoop ();\r
230 }\r
231\r
232 //\r
233 // Now should have a HOB with the DXE core w/ the old HOB destroyed\r
234 //\r
235 }\r
236\r
237 //\r
238 // Install the PEI Protocols that are shared between PEI and DXE\r
239 //\r
240 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r
241 ASSERT (PeiEfiPeiPeCoffLoader != NULL);\r
242\r
95276127 243 //\r
244 // Find the EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE type compressed Firmware Volume file\r
245 // The file found will be processed by PeiProcessFile: It will first be decompressed to\r
246 // a normal FV, then a corresponding FV type hob will be built. \r
247 //\r
248 Status = PeiFindFile (\r
249 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,\r
250 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,\r
251 &FirmwareFileName,\r
252 &FvImageData\r
253 );\r
254\r
255 //\r
256 // Find the DXE Core in a Firmware Volume\r
257 //\r
258 Status = PeiFindFile (\r
259 EFI_FV_FILETYPE_DXE_CORE,\r
260 EFI_SECTION_PE32,\r
261 &DxeCoreFileName,\r
262 &Pe32Data\r
263 );\r
264 ASSERT_EFI_ERROR (Status);\r
265\r
266 //\r
267 // Load the DXE Core from a Firmware Volume\r
268 //\r
269 Status = PeiLoadFile (\r
270 PeiEfiPeiPeCoffLoader,\r
271 Pe32Data,\r
272 &DxeCoreAddress,\r
273 &DxeCoreSize,\r
274 &DxeCoreEntryPoint\r
275 );\r
276 ASSERT_EFI_ERROR (Status);\r
277\r
278 //\r
279 // Add HOB for the DXE Core\r
280 //\r
281 BuildModuleHob (\r
282 &DxeCoreFileName,\r
283 DxeCoreAddress,\r
284 DxeCoreSize,\r
285 DxeCoreEntryPoint\r
286 );\r
287\r
288 //\r
d8c79a81
LG
289 // Add HOB for the PE/COFF Loader Protocol\r
290 //\r
291 BuildGuidDataHob (\r
292 &gEfiPeiPeCoffLoaderGuid,\r
293 (VOID *)&PeiEfiPeiPeCoffLoader,\r
294 sizeof (VOID *)\r
295 );\r
296 //\r
95276127 297 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT\r
298 //\r
299 REPORT_STATUS_CODE (\r
300 EFI_PROGRESS_CODE,\r
301 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT\r
302 );\r
303\r
95276127 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
d8c79a81 324 IN EFI_SECTION_TYPE SectionType,\r
95276127 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) ((EFI_PEI_FILE_HANDLE *) 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
d156c2a8 596 Status = PeiProcessFile (\r
597 EFI_SECTION_TE,\r
95276127 598 FfsHeader,\r
599 &Pe32Data,\r
600 NULL\r
601 );\r
95276127 602 if (EFI_ERROR (Status)) {\r
d156c2a8 603 Status = PeiProcessFile (\r
604 EFI_SECTION_PE32,\r
605 FfsHeader,\r
606 &Pe32Data,\r
607 NULL\r
608 );\r
609 \r
610 if (EFI_ERROR (Status)) {\r
611 return Status;\r
612 }\r
95276127 613 }\r
614 //\r
615 // Load the PE image from the FFS file\r
616 //\r
617 Status = PeiLoadFile (\r
618 PeiEfiPeiPeCoffLoader,\r
619 Pe32Data,\r
620 ImageAddress,\r
621 ImageSize,\r
622 EntryPoint\r
623 );\r
624\r
625 return Status;\r
626}\r
627\r
628EFI_STATUS\r
629PeiProcessFile (\r
d8c79a81 630 IN EFI_SECTION_TYPE SectionType,\r
95276127 631 IN EFI_FFS_FILE_HEADER *FfsFileHeader,\r
632 OUT VOID **Pe32Data,\r
633 IN EFI_PEI_HOB_POINTERS *OrigHob\r
634 )\r
635/*++\r
636\r
637Routine Description:\r
638\r
639Arguments:\r
640\r
641 SectionType - The type of section in the FFS file to process.\r
642\r
643 FfsFileHeader - Pointer to the FFS file to process, looking for the\r
644 specified SectionType\r
645\r
646 Pe32Data - returned pointer to the start of the PE32 image found\r
647 in the FFS file.\r
648\r
649Returns:\r
650\r
651 EFI_SUCCESS - found the PE32 section in the FFS file\r
652\r
653--*/\r
654{\r
655 EFI_STATUS Status;\r
95276127 656 UINT8 *DstBuffer;\r
657 UINT8 *ScratchBuffer;\r
1b0d0cc5 658 UINTN DstBufferSize;\r
95276127 659 UINT32 ScratchBufferSize;\r
660 EFI_COMMON_SECTION_HEADER *CmpSection;\r
661 UINTN CmpSectionLength;\r
662 UINTN OccupiedCmpSectionLength;\r
663 VOID *CmpFileData;\r
664 UINTN CmpFileSize;\r
665 EFI_COMMON_SECTION_HEADER *Section;\r
666 UINTN SectionLength;\r
667 UINTN OccupiedSectionLength;\r
d8c79a81 668 UINTN FileSize;\r
95276127 669 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
670 EFI_COMPRESSION_SECTION *CompressionSection;\r
d8c79a81
LG
671 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *SectionExtract;\r
672 UINT32 AuthenticationStatus;\r
95276127 673\r
674 //\r
d8c79a81 675 // First try to find the required section in this ffs file.\r
95276127 676 //\r
95276127 677 Status = PeiServicesFfsFindSectionData (\r
d8c79a81 678 SectionType,\r
95276127 679 FfsFileHeader,\r
d8c79a81 680 Pe32Data\r
95276127 681 );\r
d8c79a81
LG
682 if (!EFI_ERROR (Status)) {\r
683 return Status;\r
684 }\r
685 \r
95276127 686 //\r
d8c79a81
LG
687 // If not found, the required section may be in guided or compressed section.\r
688 // So, search guided or compressed section to process\r
95276127 689 //\r
d8c79a81
LG
690 Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));\r
691 FileSize = FfsFileHeader->Size[0] & 0xFF;\r
692 FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;\r
693 FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;\r
694 FileSize &= 0x00FFFFFF;\r
695 OccupiedSectionLength = 0;\r
696\r
697 do {\r
95276127 698 //\r
d8c79a81 699 // Initialize local variables.\r
95276127 700 //\r
d8c79a81
LG
701 DstBuffer = NULL;\r
702 DstBufferSize = 0; \r
95276127 703\r
d8c79a81
LG
704 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r
705 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r
706 OccupiedSectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r
95276127 707\r
d8c79a81
LG
708 //\r
709 // Was the DXE Core file encapsulated in a GUID'd section?\r
710 //\r
711 if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
95276127 712 //\r
d8c79a81 713 // Set a default authenticatino state\r
95276127 714 //\r
d8c79a81
LG
715 AuthenticationStatus = 0;\r
716 //\r
717 // Locate extract guid section ppi\r
718 //\r
719 Status = PeiServicesLocatePpi (\r
720 (EFI_GUID *) (Section + 1),\r
721 0,\r
722 NULL,\r
723 (VOID **)&SectionExtract\r
724 );\r
95276127 725\r
d8c79a81 726 if (EFI_ERROR (Status)) {\r
95276127 727 //\r
d8c79a81 728 // ignore the unknown guid section\r
95276127 729 //\r
d8c79a81
LG
730 continue;\r
731 }\r
732 //\r
733 // Extract the contents from guid section\r
734 //\r
735 Status = SectionExtract->ExtractSection (\r
736 SectionExtract,\r
737 (VOID *) Section,\r
738 (VOID **) &DstBuffer,\r
1b0d0cc5 739 &DstBufferSize,\r
d8c79a81
LG
740 &AuthenticationStatus\r
741 );\r
742\r
743 if (EFI_ERROR (Status)) {\r
744 DEBUG ((EFI_D_ERROR, "Extract section content failed - %r\n", Status));\r
745 return Status;\r
746 }\r
1b0d0cc5 747 \r
d8c79a81
LG
748 //\r
749 // Todo check AuthenticationStatus and do the verify\r
750 //\r
751 } else if (Section->Type == EFI_SECTION_COMPRESSION) {\r
752 //\r
753 // This is a compression set, expand it\r
754 //\r
755 CompressionSection = (EFI_COMPRESSION_SECTION *) Section;\r
756\r
757 switch (CompressionSection->CompressionType) {\r
758 case EFI_STANDARD_COMPRESSION:\r
95276127 759 //\r
d8c79a81
LG
760 // Load EFI standard compression.\r
761 // For compressed data, decompress them to dstbuffer.\r
95276127 762 //\r
d8c79a81
LG
763 Status = UefiDecompressGetInfo (\r
764 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r
765 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),\r
1b0d0cc5 766 (UINT32 *) &DstBufferSize,\r
d8c79a81 767 &ScratchBufferSize\r
95276127 768 );\r
95276127 769 if (EFI_ERROR (Status)) {\r
d8c79a81
LG
770 //\r
771 // GetInfo failed\r
772 //\r
773 DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));\r
774 return EFI_NOT_FOUND;\r
95276127 775 }\r
776 //\r
d8c79a81 777 // Allocate scratch buffer\r
95276127 778 //\r
d8c79a81
LG
779 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r
780 if (ScratchBuffer == NULL) {\r
781 return EFI_OUT_OF_RESOURCES;\r
95276127 782 }\r
783 //\r
d8c79a81
LG
784 // Allocate destination buffer\r
785 //\r
786 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r
787 if (DstBuffer == NULL) {\r
788 return EFI_OUT_OF_RESOURCES;\r
789 }\r
95276127 790 //\r
d8c79a81 791 // Call decompress function\r
95276127 792 //\r
d8c79a81
LG
793 Status = UefiDecompress (\r
794 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r
795 DstBuffer,\r
796 ScratchBuffer\r
797 );\r
95276127 798 if (EFI_ERROR (Status)) {\r
d8c79a81
LG
799 //\r
800 // Decompress failed\r
801 //\r
802 DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));\r
803 return EFI_NOT_FOUND;\r
95276127 804 }\r
d8c79a81 805 break;\r
95276127 806\r
d8c79a81 807 // porting note the original branch for customized compress is removed, it should be change to use GUID compress\r
95276127 808\r
d8c79a81 809 case EFI_NOT_COMPRESSED:\r
95276127 810 //\r
d8c79a81 811 // Allocate destination buffer\r
95276127 812 //\r
d8c79a81
LG
813 DstBufferSize = CompressionSection->UncompressedLength;\r
814 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r
815 if (DstBuffer == NULL) {\r
816 return EFI_OUT_OF_RESOURCES;\r
95276127 817 }\r
95276127 818 //\r
d8c79a81 819 // stream is not actually compressed, just encapsulated. So just copy it.\r
95276127 820 //\r
d8c79a81
LG
821 CopyMem (DstBuffer, CompressionSection + 1, DstBufferSize);\r
822 break;\r
823\r
824 default:\r
95276127 825 //\r
d8c79a81 826 // Don't support other unknown compression type.\r
95276127 827 //\r
d8c79a81
LG
828 ASSERT_EFI_ERROR (Status);\r
829 return EFI_NOT_FOUND;\r
830 }\r
831 } else {\r
832 //\r
833 // ignore other type sections\r
834 //\r
835 continue;\r
836 }\r
95276127 837\r
d8c79a81
LG
838 //\r
839 // Extract contents from guided or compressed sections.\r
840 // Loop the decompressed data searching for expected section.\r
841 //\r
842 CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;\r
843 CmpFileData = (VOID *) DstBuffer;\r
844 CmpFileSize = DstBufferSize;\r
845 do {\r
846 CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;\r
847 if (CmpSection->Type == SectionType) {\r
848 //\r
849 // This is what we want\r
850 //\r
851 if (SectionType == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {\r
852 // \r
853 // Firmware Volume Image in this Section\r
854 // Skip the section header to get FvHeader\r
95276127 855 //\r
d8c79a81 856 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (CmpSection + 1);\r
95276127 857\r
d8c79a81 858 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {\r
95276127 859 //\r
d8c79a81
LG
860 // Because FvLength in FvHeader is UINT64 type, \r
861 // so FvHeader must meed at least 8 bytes alignment.\r
862 // If current FvImage base address doesn't meet its alignment,\r
863 // we need to reload this FvImage to another correct memory address.\r
95276127 864 //\r
d8c79a81
LG
865 if (((UINTN) FvHeader % sizeof (UINT64)) != 0) {\r
866 CopyMem (DstBuffer, FvHeader, (UINTN) CmpSectionLength - sizeof (EFI_COMMON_SECTION_HEADER));\r
867 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DstBuffer; \r
868 }\r
869\r
95276127 870 //\r
d8c79a81 871 // Build new FvHob for new decompressed Fv image.\r
95276127 872 //\r
d8c79a81
LG
873 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);\r
874 \r
95276127 875 //\r
d8c79a81 876 // Set the original FvHob to unused.\r
95276127 877 //\r
d8c79a81
LG
878 if (OrigHob != NULL) {\r
879 OrigHob->Header->HobType = EFI_HOB_TYPE_UNUSED;\r
95276127 880 }\r
d8c79a81
LG
881 //\r
882 // return found FvImage data.\r
883 //\r
884 *Pe32Data = (VOID *) FvHeader;\r
885 return EFI_SUCCESS;\r
95276127 886 }\r
d8c79a81
LG
887 } else {\r
888 //\r
889 // direct return the found section.\r
890 //\r
891 *Pe32Data = (VOID *) (CmpSection + 1);\r
892 return EFI_SUCCESS;\r
893 }\r
95276127 894 }\r
d8c79a81
LG
895 OccupiedCmpSectionLength = GET_OCCUPIED_SIZE (CmpSectionLength, 4);\r
896 CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);\r
897 } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);\r
898 } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section + OccupiedSectionLength - (UINT8 *) FfsFileHeader) < FileSize);\r
95276127 899\r
d8c79a81
LG
900 //\r
901 // search all sections (compression and non compression) in this FFS, don't \r
902 // find expected section.\r
903 //\r
904 return EFI_NOT_FOUND;\r
905}\r
906\r
907/**\r
908 The ExtractSection() function processes the input section and\r
909 returns a pointer to the section contents. If the section being\r
910 extracted does not require processing (if the section\r
911 GuidedSectionHeader.Attributes has the\r
912 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then\r
913 OutputBuffer is just updated to point to the start of the\r
914 section's contents. Otherwise, *Buffer must be allocated\r
915 from PEI permanent memory.\r
916\r
917 @param This Indicates the\r
918 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.\r
919 Buffer containing the input GUIDed section to be\r
920 processed. OutputBuffer OutputBuffer is\r
921 allocated from PEI permanent memory and contains\r
922 the new section stream.\r
923 \r
924 @param OutputSize A pointer to a caller-allocated\r
925 UINTN in which the size of *OutputBuffer\r
926 allocation is stored. If the function\r
927 returns anything other than EFI_SUCCESS,\r
928 the value of OutputSize is undefined.\r
929 \r
930 @param AuthenticationStatus A pointer to a caller-allocated\r
931 UINT32 that indicates the\r
932 authentication status of the\r
933 output buffer. If the input\r
934 section's GuidedSectionHeader.\r
935 Attributes field has the\r
936 EFI_GUIDED_SECTION_AUTH_STATUS_VALID \r
937 bit as clear,\r
938 AuthenticationStatus must return\r
939 zero. These bits reflect the\r
940 status of the extraction\r
941 operation. If the function\r
942 returns anything other than\r
943 EFI_SUCCESS, the value of\r
944 AuthenticationStatus is\r
945 undefined.\r
946 \r
947 @retval EFI_SUCCESS The InputSection was\r
948 successfully processed and the\r
949 section contents were returned.\r
950 \r
951 @retval EFI_OUT_OF_RESOURCES The system has insufficient\r
952 resources to process the request.\r
953 \r
954 @reteval EFI_INVALID_PARAMETER The GUID in InputSection does\r
955 not match this instance of the\r
956 GUIDed Section Extraction PPI.\r
957**/\r
958EFI_STATUS\r
959CustomDecompressExtractSection (\r
960 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,\r
961 IN CONST VOID *InputSection,\r
962 OUT VOID **OutputBuffer,\r
963 OUT UINTN *OutputSize,\r
964 OUT UINT32 *AuthenticationStatus\r
965)\r
966{\r
967 EFI_STATUS Status;\r
968 UINT8 *ScratchBuffer;\r
969 UINT32 ScratchSize;\r
88ce0209
LG
970 UINT32 SectionLength;\r
971 UINT32 DestinationSize; \r
d8c79a81
LG
972 \r
973 //\r
974 // Set authentic value to zero.\r
975 //\r
976 *AuthenticationStatus = 0;\r
977 //\r
978 // Calculate Section data Size\r
979 //\r
980 SectionLength = *(UINT32 *) (((EFI_COMMON_SECTION_HEADER *) InputSection)->Size) & 0x00ffffff;\r
981 //\r
982 // Get compressed data information\r
983 //\r
984 Status = CustomDecompressGetInfo (\r
985 (GUID *) ((UINT8 *) InputSection + sizeof (EFI_COMMON_SECTION_HEADER)),\r
986 (UINT8 *) InputSection + sizeof (EFI_GUID_DEFINED_SECTION),\r
987 SectionLength - sizeof (EFI_GUID_DEFINED_SECTION),\r
88ce0209 988 &DestinationSize,\r
d8c79a81
LG
989 &ScratchSize\r
990 );\r
991 if (EFI_ERROR (Status)) {\r
95276127 992 //\r
d8c79a81 993 // GetInfo failed\r
95276127 994 //\r
d8c79a81
LG
995 DEBUG ((EFI_D_ERROR, "Extract guided section Failed - %r\n", Status));\r
996 return Status;\r
997 }\r
95276127 998\r
d8c79a81
LG
999 //\r
1000 // Allocate scratch buffer\r
1001 //\r
1002 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchSize));\r
1003 if (ScratchBuffer == NULL) {\r
1004 return EFI_OUT_OF_RESOURCES;\r
1005 }\r
1006 //\r
1007 // Allocate destination buffer\r
1008 //\r
88ce0209 1009 *OutputSize = (UINTN) DestinationSize;\r
d8c79a81
LG
1010 *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (*OutputSize));\r
1011 if (*OutputBuffer == NULL) {\r
1012 return EFI_OUT_OF_RESOURCES;\r
95276127 1013 }\r
1014\r
d8c79a81
LG
1015 //\r
1016 // Call decompress function\r
1017 //\r
1018 Status = CustomDecompress (\r
1019 (GUID *) ((UINT8 *) InputSection + sizeof (EFI_COMMON_SECTION_HEADER)),\r
1020 (UINT8 *) InputSection + sizeof (EFI_GUID_DEFINED_SECTION),\r
1021 *OutputBuffer,\r
1022 ScratchBuffer\r
1023 );\r
95276127 1024\r
d8c79a81
LG
1025 if (EFI_ERROR (Status)) {\r
1026 //\r
1027 // Decompress failed\r
1028 //\r
1029 DEBUG ((EFI_D_ERROR, "Extract guided section Failed - %r\n", Status));\r
1030 return Status;\r
1031 }\r
1032 \r
95276127 1033 return EFI_SUCCESS;\r
1034}\r