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