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