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