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