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