]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Core/DxeIplX64Peim/DxeLoadX64.c
c9792eeaa194cb5abe8e1220542e7bb866b12e4d
[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 safety (PpisNeededByDxe and DxeCore).
264 //
265 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;
266 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
267
268 //
269 // Add architecture-specifc HOBs (including the BspStore HOB)
270 //
271 Status = CreateArchSpecificHobs (&BspStore);
272 ASSERT_EFI_ERROR (Status);
273
274 //
275 // See if we are in crisis recovery
276 //
277 Status = PeiServicesGetBootMode (&BootMode);
278 if (!EFI_ERROR (Status) && (BootMode == BOOT_IN_RECOVERY_MODE)) {
279 Status = PeiServicesLocatePpi (
280 &gEfiPeiRecoveryModulePpiGuid,
281 0,
282 NULL,
283 (VOID **)&PeiRecovery
284 );
285
286 ASSERT_EFI_ERROR (Status);
287 Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);
288 if (EFI_ERROR (Status)) {
289 DEBUG ((EFI_D_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
290 CpuDeadLoop ();
291 }
292 }
293
294 //
295 // Find the EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE type compressed Firmware Volume file
296 // The file found will be processed by PeiProcessFile: It will first be decompressed to
297 // a normal FV, then a corresponding FV type hob will be built.
298 //
299 Status = PeiFindFile (
300 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
301 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
302 &FirmwareFileName,
303 &FvImageData
304 );
305
306 //
307 // Find the DXE Core in a Firmware Volume
308 //
309 Status = PeiFindFile (
310 EFI_FV_FILETYPE_DXE_CORE,
311 EFI_SECTION_PE32,
312 &DxeCoreFileName,
313 &DxeCorePe32Data
314 );
315 ASSERT_EFI_ERROR (Status);
316
317 //
318 // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA \
319 // memory, it may be corrupted when copying FV to high-end memory
320 LoadGo64Gdt();
321
322 //
323 // Limit to 36 bits of addressing for debug. Should get it from CPU
324 //
325 PageTables = CreateIdentityMappingPageTables (36);
326
327
328 //
329 // Load the DXE Core from a Firmware Volume
330 //
331 Status = PeiLoadPeImage (
332 PeiEfiPeiPeCoffLoader,
333 DxeCorePe32Data,
334 EfiBootServicesData,
335 &DxeCoreAddress,
336 &DxeCoreSize,
337 &DxeCoreEntryPoint
338 );
339 ASSERT_EFI_ERROR (Status);
340
341 //
342 // Transfer control to the DXE Core
343 // The handoff state is simply a pointer to the HOB list
344 //
345
346 Status = PeiServicesInstallPpi (&mPpiSignal);
347 ASSERT_EFI_ERROR (Status);
348
349 //
350 //
351 // Add HOB for the DXE Core
352 //
353 BuildModuleHob (
354 &DxeCoreFileName,
355 DxeCoreAddress,
356 DxeCoreSize,
357 DxeCoreEntryPoint
358 );
359
360 //
361 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
362 //
363 REPORT_STATUS_CODE (
364 EFI_PROGRESS_CODE,
365 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT
366 );
367
368 DEBUG ((EFI_D_INFO, "DXE Core Entry\n"));
369 //
370 // Go to Long Mode. Interrupts will not get turned on until the CPU AP is loaded.
371 // Call x64 drivers passing in single argument, a pointer to the HOBs.
372 //
373 ActivateLongMode (
374 PageTables,
375 (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw),
376 TopOfStack,
377 0x00000000,
378 DxeCoreEntryPoint
379 );
380
381 //
382 // If we get here, then the DXE Core returned. This is an error
383 // Dxe Core should not return.
384 //
385 ASSERT (FALSE);
386 CpuDeadLoop ();
387
388 return EFI_OUT_OF_RESOURCES;
389 }
390
391 EFI_STATUS
392 PeiFindFile (
393 IN UINT8 Type,
394 IN UINT16 SectionType,
395 OUT EFI_GUID *FileName,
396 OUT VOID **Pe32Data
397 )
398 /*++
399
400 Routine Description:
401
402 Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes
403 described in the HOB list. Able to search in a compression set in a FFS file.
404 But only one level of compression is supported, that is, not able to search
405 in a compression set that is within another compression set.
406
407 Arguments:
408
409 Type - The Type of file to retrieve
410
411 SectionType - The type of section to retrieve from a file
412
413 FileName - The name of the file found in the Firmware Volume
414
415 Pe32Data - Pointer to the beginning of the PE/COFF file found in the Firmware Volume
416
417 Returns:
418
419 EFI_SUCCESS - The file was found, and the name is returned in FileName, and a pointer to
420 the PE/COFF image is returned in Pe32Data
421
422 EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List
423
424 --*/
425 {
426 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
427 EFI_FFS_FILE_HEADER *FfsFileHeader;
428 VOID *SectionData;
429 EFI_STATUS Status;
430 EFI_PEI_HOB_POINTERS Hob;
431
432
433 FwVolHeader = NULL;
434 FfsFileHeader = NULL;
435 SectionData = NULL;
436 Status = EFI_SUCCESS;
437
438 //
439 // For each Firmware Volume, look for a specified type
440 // of file and break out until no one is found
441 //
442 Hob.Raw = GetHobList ();
443 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw)) != NULL) {
444 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress);
445 Status = PeiServicesFfsFindNextFile (
446 Type,
447 FwVolHeader,
448 &FfsFileHeader
449 );
450 if (!EFI_ERROR (Status)) {
451 Status = PeiProcessFile (
452 SectionType,
453 FfsFileHeader,
454 Pe32Data,
455 &Hob
456 );
457 CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));
458 if (!EFI_ERROR (Status)) {
459 return EFI_SUCCESS;
460 }
461 }
462 Hob.Raw = GET_NEXT_HOB (Hob);
463 }
464 return EFI_NOT_FOUND;
465 }
466
467 EFI_STATUS
468 PeiLoadPeImage (
469 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,
470 IN VOID *Pe32Data,
471 IN EFI_MEMORY_TYPE MemoryType,
472 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
473 OUT UINT64 *ImageSize,
474 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
475 )
476 /*++
477
478 Routine Description:
479
480 Loads and relocates a PE/COFF image into memory.
481
482 Arguments:
483
484 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol
485
486 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
487
488 ImageAddress - The base address of the relocated PE/COFF image
489
490 ImageSize - The size of the relocated PE/COFF image
491
492 EntryPoint - The entry point of the relocated PE/COFF image
493
494 Returns:
495
496 EFI_SUCCESS - The file was loaded and relocated
497 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
498
499 --*/
500 {
501 EFI_STATUS Status;
502 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
503 EFI_PHYSICAL_ADDRESS MemoryBuffer;
504
505 ZeroMem (&ImageContext, sizeof (ImageContext));
506 ImageContext.Handle = Pe32Data;
507 Status = GetImageReadFunction (&ImageContext);
508
509 ASSERT_EFI_ERROR (Status);
510
511 Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);
512 if (EFI_ERROR (Status)) {
513 return Status;
514 }
515 //
516 // Allocate Memory for the image
517 //
518 //
519 // Allocate Memory for the image
520 //
521 PeiServicesAllocatePages (MemoryType, EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize), &MemoryBuffer);
522 ImageContext.ImageAddress = MemoryBuffer;
523 ASSERT (ImageContext.ImageAddress != 0);
524
525 //
526 // Load the image to our new buffer
527 //
528
529 Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);
530 if (EFI_ERROR (Status)) {
531 return Status;
532 }
533
534 //
535 // Relocate the image in our new buffer
536 //
537 Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);
538 if (EFI_ERROR (Status)) {
539 return Status;
540 }
541
542 //
543 // Flush the instruction cache so the image data is written before we execute it
544 //
545 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
546
547 *ImageAddress = ImageContext.ImageAddress;
548 *ImageSize = ImageContext.ImageSize;
549 *EntryPoint = ImageContext.EntryPoint;
550
551 return EFI_SUCCESS;
552 }
553
554 EFI_STATUS
555 ShadowDxeIpl (
556 IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,
557 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader
558 )
559 /*++
560
561 Routine Description:
562
563 Shadow the DXE IPL to a different memory location. This occurs after permanent
564 memory has been discovered.
565
566 Arguments:
567
568 DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver
569
570 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol
571
572 Returns:
573
574 EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.
575
576 EFI_ ERROR - The shadow was unsuccessful.
577
578
579 --*/
580 {
581 UINTN SectionLength;
582 UINTN OccupiedSectionLength;
583 EFI_PHYSICAL_ADDRESS DxeIplAddress;
584 UINT64 DxeIplSize;
585 EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;
586 EFI_STATUS Status;
587 EFI_COMMON_SECTION_HEADER *Section;
588
589 Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);
590
591 while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {
592 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
593 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);
594 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);
595 }
596
597 //
598 // Relocate DxeIpl into memory by using loadfile service
599 //
600 Status = PeiLoadPeImage (
601 PeiEfiPeiPeCoffLoader,
602 (VOID *) (Section + 1),
603 EfiBootServicesData,
604 &DxeIplAddress,
605 &DxeIplSize,
606 &DxeIplEntryPoint
607 );
608
609 if (Status == EFI_SUCCESS) {
610 //
611 // Install PeiInMemory to indicate the Dxeipl is shadowed
612 //
613 Status = PeiServicesInstallPpi (&mPpiPeiInMemory);
614
615 if (EFI_ERROR (Status)) {
616 return Status;
617 }
618
619 Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer());
620 }
621
622 return Status;
623 }
624
625 EFI_STATUS
626 EFIAPI
627 DxeIplLoadFile (
628 IN EFI_PEI_FV_FILE_LOADER_PPI *This,
629 IN EFI_FFS_FILE_HEADER *FfsHeader,
630 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
631 OUT UINT64 *ImageSize,
632 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
633 )
634 /*++
635
636 Routine Description:
637
638 Given a pointer to an FFS file containing a PE32 image, get the
639 information on the PE32 image, and then "load" it so that it
640 can be executed.
641
642 Arguments:
643
644 This - pointer to our file loader protocol
645 FfsHeader - pointer to the FFS file header of the FFS file that
646 contains the PE32 image we want to load
647 ImageAddress - returned address where the PE32 image is loaded
648 ImageSize - returned size of the loaded PE32 image
649 EntryPoint - entry point to the loaded PE32 image
650
651 Returns:
652
653 EFI_SUCCESS - The FFS file was successfully loaded.
654 EFI_ERROR - Unable to load the FFS file.
655
656 --*/
657 {
658 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;
659 EFI_STATUS Status;
660 VOID *Pe32Data;
661
662 Pe32Data = NULL;
663 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();
664
665 //
666 // Preprocess the FFS file to get a pointer to the PE32 information
667 // in the enclosed PE32 image.
668 //
669 Status = PeiProcessFile (
670 EFI_SECTION_PE32,
671 FfsHeader,
672 &Pe32Data,
673 NULL
674 );
675
676 if (EFI_ERROR (Status)) {
677 return Status;
678 }
679 //
680 // Load the PE image from the FFS file
681 //
682 Status = PeiLoadPeImage (
683 PeiEfiPeiPeCoffLoader,
684 Pe32Data,
685 EfiBootServicesData,
686 ImageAddress,
687 ImageSize,
688 EntryPoint
689 );
690
691 return Status;
692 }
693
694 EFI_STATUS
695 PeiProcessFile (
696 IN UINT16 SectionType,
697 IN EFI_FFS_FILE_HEADER *FfsFileHeader,
698 OUT VOID **Pe32Data,
699 IN EFI_PEI_HOB_POINTERS *OrigHob
700 )
701 /*++
702
703 Routine Description:
704
705 Arguments:
706
707 SectionType - The type of section in the FFS file to process.
708
709 FfsFileHeader - Pointer to the FFS file to process, looking for the
710 specified SectionType
711
712 Pe32Data - returned pointer to the start of the PE32 image found
713 in the FFS file.
714
715 Returns:
716
717 EFI_SUCCESS - found the PE32 section in the FFS file
718
719 --*/
720 {
721 EFI_STATUS Status;
722 VOID *SectionData;
723 DECOMPRESS_LIBRARY *DecompressLibrary;
724 UINT8 *DstBuffer;
725 UINT8 *ScratchBuffer;
726 UINT32 DstBufferSize;
727 UINT32 ScratchBufferSize;
728 EFI_COMMON_SECTION_HEADER *CmpSection;
729 UINTN CmpSectionLength;
730 UINTN OccupiedCmpSectionLength;
731 VOID *CmpFileData;
732 UINTN CmpFileSize;
733 EFI_COMMON_SECTION_HEADER *Section;
734 UINTN SectionLength;
735 UINTN OccupiedSectionLength;
736 UINT64 FileSize;
737 EFI_GUID_DEFINED_SECTION *GuidedSectionHeader;
738 UINT32 AuthenticationStatus;
739 EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract;
740 UINT32 BufferSize;
741 UINT8 *Buffer;
742 EFI_PEI_SECURITY_PPI *Security;
743 BOOLEAN StartCrisisRecovery;
744 EFI_GUID TempGuid;
745 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
746 EFI_COMPRESSION_SECTION *CompressionSection;
747 UINT32 FvAlignment;
748
749 Status = PeiServicesFfsFindSectionData (
750 EFI_SECTION_COMPRESSION,
751 FfsFileHeader,
752 &SectionData
753 );
754
755 //
756 // First process the compression section
757 //
758 if (!EFI_ERROR (Status)) {
759 //
760 // Yes, there is a compression section, so extract the contents
761 // Decompress the image here
762 //
763 Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));
764
765 do {
766 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
767 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);
768
769 //
770 // Was the DXE Core file encapsulated in a GUID'd section?
771 //
772 if (Section->Type == EFI_SECTION_GUID_DEFINED) {
773 //
774 // Locate the GUID'd Section Extractor
775 //
776 GuidedSectionHeader = (VOID *) (Section + 1);
777
778 //
779 // This following code constitutes the addition of the security model
780 // to the DXE IPL.
781 //
782 //
783 // Set a default authenticatino state
784 //
785 AuthenticationStatus = 0;
786
787 Status = PeiServicesLocatePpi (
788 &gEfiPeiSectionExtractionPpiGuid,
789 0,
790 NULL,
791 (VOID **)&SectionExtract
792 );
793
794 if (EFI_ERROR (Status)) {
795 return Status;
796 }
797 //
798 // Verify Authentication State
799 //
800 CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));
801
802 Status = SectionExtract->PeiGetSection (
803 GetPeiServicesTablePointer(),
804 SectionExtract,
805 (EFI_SECTION_TYPE *) &SectionType,
806 &TempGuid,
807 0,
808 (VOID **) &Buffer,
809 &BufferSize,
810 &AuthenticationStatus
811 );
812
813 if (EFI_ERROR (Status)) {
814 return Status;
815 }
816 //
817 // If not ask the Security PPI, if exists, for disposition
818 //
819 //
820 Status = PeiServicesLocatePpi (
821 &gEfiPeiSecurityPpiGuid,
822 0,
823 NULL,
824 (VOID **)&Security
825 );
826 if (EFI_ERROR (Status)) {
827 return Status;
828 }
829
830 Status = Security->AuthenticationState (
831 GetPeiServicesTablePointer(),
832 (struct _EFI_PEI_SECURITY_PPI *) Security,
833 AuthenticationStatus,
834 FfsFileHeader,
835 &StartCrisisRecovery
836 );
837
838 if (EFI_ERROR (Status)) {
839 return Status;
840 }
841 //
842 // If there is a security violation, report to caller and have
843 // the upper-level logic possible engender a crisis recovery
844 //
845 if (StartCrisisRecovery) {
846 return EFI_SECURITY_VIOLATION;
847 }
848 }
849
850 if (Section->Type == EFI_SECTION_PE32) {
851 //
852 // This is what we want
853 //
854 *Pe32Data = (VOID *) (Section + 1);
855 return EFI_SUCCESS;
856 } else if (Section->Type == EFI_SECTION_COMPRESSION) {
857 //
858 // This is a compression set, expand it
859 //
860 CompressionSection = (EFI_COMPRESSION_SECTION *) Section;
861
862 switch (CompressionSection->CompressionType) {
863 case EFI_STANDARD_COMPRESSION:
864 if (FeaturePcdGet (PcdDxeIplSupportTianoDecompress)) {
865 DecompressLibrary = &gTianoDecompress;
866 } else {
867 ASSERT (FALSE);
868 return EFI_NOT_FOUND;
869 }
870 break;
871
872 case EFI_CUSTOMIZED_COMPRESSION:
873 //
874 // Load user customized compression protocol.
875 //
876 if (FeaturePcdGet (PcdDxeIplSupportCustomDecompress)) {
877 DecompressLibrary = &gCustomDecompress;
878 } else {
879 ASSERT (FALSE);
880 return EFI_NOT_FOUND;
881 }
882 break;
883
884 case EFI_NOT_COMPRESSED:
885 default:
886 //
887 // Need to support not compressed file
888 //
889 ASSERT_EFI_ERROR (Status);
890 return EFI_NOT_FOUND;
891 }
892
893 Status = DecompressLibrary->GetInfo (
894 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
895 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
896 &DstBufferSize,
897 &ScratchBufferSize
898 );
899 if (EFI_ERROR (Status)) {
900 //
901 // GetInfo failed
902 //
903 return EFI_NOT_FOUND;
904 }
905
906 //
907 // Allocate scratch buffer
908 //
909 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
910 if (ScratchBuffer == NULL) {
911 return EFI_OUT_OF_RESOURCES;
912 }
913
914 //
915 // Allocate destination buffer
916 //
917 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
918 if (DstBuffer == NULL) {
919 return EFI_OUT_OF_RESOURCES;
920 }
921
922 //
923 // Call decompress function
924 //
925 Status = DecompressLibrary->Decompress (
926 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
927 DstBuffer,
928 ScratchBuffer
929 );
930
931 CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;
932 if (CmpSection->Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {
933 //
934 // Firmware Volume Image in this Section
935 // Skip the section header to get FvHeader
936 //
937 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (CmpSection + 1);
938
939 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
940 //
941 // Adjust Fv Base Address Alignment based on Align Attributes in Fv Header
942 //
943
944 //
945 // When FvImage support Alignment, we need to check whether
946 // its alignment is correct.
947 //
948 if (FvHeader->Attributes | EFI_FVB_ALIGNMENT_CAP) {
949
950 //
951 // Calculate the mini alignment for this FvImage
952 //
953 FvAlignment = 1 << (LowBitSet32 (FvHeader->Attributes >> 16) + 1);
954
955 //
956 // If current FvImage base address doesn't meet the its alignment,
957 // we need to reload this FvImage to another correct memory address.
958 //
959 if (((UINTN) FvHeader % FvAlignment) != 0) {
960 DstBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) FvHeader->FvLength), FvAlignment);
961 if (DstBuffer == NULL) {
962 return EFI_OUT_OF_RESOURCES;
963 }
964 CopyMem (DstBuffer, FvHeader, (UINTN) FvHeader->FvLength);
965 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DstBuffer;
966 }
967 }
968 //
969 // Build new FvHob for new decompressed Fv image.
970 //
971 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);
972
973 //
974 // Set the original FvHob to unused.
975 //
976 if (OrigHob != NULL) {
977 OrigHob->Header->HobType = EFI_HOB_TYPE_UNUSED;
978 }
979
980 //
981 // when search FvImage Section return true.
982 //
983 if (SectionType == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {
984 *Pe32Data = (VOID *) FvHeader;
985 return EFI_SUCCESS;
986 } else {
987 return EFI_NOT_FOUND;
988 }
989
990 }
991 }
992 //
993 // Decompress successfully.
994 // Loop the decompressed data searching for expected section.
995 //
996 CmpFileData = (VOID *) DstBuffer;
997 CmpFileSize = DstBufferSize;
998 do {
999 CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;
1000 if (CmpSection->Type == EFI_SECTION_PE32) {
1001 //
1002 // This is what we want
1003 //
1004 *Pe32Data = (VOID *) (CmpSection + 1);
1005 return EFI_SUCCESS;
1006 }
1007
1008 OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4);
1009 CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);
1010 } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);
1011 }
1012 //
1013 // End of the decompression activity
1014 //
1015
1016 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);
1017 FileSize = FfsFileHeader->Size[0] & 0xFF;
1018 FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;
1019 FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;
1020 FileSize &= 0x00FFFFFF;
1021 } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);
1022
1023 //
1024 // search all sections (compression and non compression) in this FFS, don't
1025 // find expected section.
1026 //
1027 return EFI_NOT_FOUND;
1028 } else {
1029 //
1030 // For those FFS that doesn't contain compression section, directly search
1031 // PE or TE section in this FFS.
1032 //
1033
1034 Status = PeiServicesFfsFindSectionData (
1035 EFI_SECTION_PE32,
1036 FfsFileHeader,
1037 &SectionData
1038 );
1039
1040 if (EFI_ERROR (Status)) {
1041 Status = PeiServicesFfsFindSectionData (
1042 EFI_SECTION_TE,
1043 FfsFileHeader,
1044 &SectionData
1045 );
1046 if (EFI_ERROR (Status)) {
1047 return Status;
1048 }
1049 }
1050 }
1051
1052 *Pe32Data = SectionData;
1053
1054 return EFI_SUCCESS;
1055 }