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