]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Core/DxeIplPeim/DxeLoad.c
Introduce PcdDxeIplSwitchToLongMode to DxeIplPeim and remove DxeIplX64Peim.
[mirror_edk2.git] / EdkModulePkg / Core / DxeIplPeim / DxeLoad.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 mPpiList[] = {
44 {
45 EFI_PEI_PPI_DESCRIPTOR_PPI,
46 &gEfiPeiFvFileLoaderPpiGuid,
47 &mLoadFilePpi
48 },
49 {
50 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
51 &gEfiDxeIplPpiGuid,
52 &mDxeIplPpi
53 }
54 };
55
56 static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = {
57 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
58 &gEfiEndOfPeiSignalPpiGuid,
59 NULL
60 };
61
62 GLOBAL_REMOVE_IF_UNREFERENCED DECOMPRESS_LIBRARY gEfiDecompress = {
63 UefiDecompressGetInfo,
64 UefiDecompress
65 };
66
67 GLOBAL_REMOVE_IF_UNREFERENCED DECOMPRESS_LIBRARY gTianoDecompress = {
68 TianoDecompressGetInfo,
69 TianoDecompress
70 };
71
72 GLOBAL_REMOVE_IF_UNREFERENCED DECOMPRESS_LIBRARY gCustomDecompress = {
73 CustomDecompressGetInfo,
74 CustomDecompress
75 };
76
77 EFI_STATUS
78 EFIAPI
79 PeimInitializeDxeIpl (
80 IN EFI_FFS_FILE_HEADER *FfsHeader,
81 IN EFI_PEI_SERVICES **PeiServices
82 )
83 /*++
84
85 Routine Description:
86
87 Initializes the Dxe Ipl PPI
88
89 Arguments:
90
91 FfsHeader - Pointer to FFS file header
92 PeiServices - General purpose services available to every PEIM.
93
94 Returns:
95
96 EFI_SUCCESS
97
98 --*/
99 {
100 EFI_STATUS Status;
101 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;
102 EFI_BOOT_MODE BootMode;
103
104 Status = PeiServicesGetBootMode (&BootMode);
105 ASSERT_EFI_ERROR (Status);
106
107 if (!gInMemory && (BootMode != BOOT_ON_S3_RESUME)) {
108 //
109 // The DxeIpl has not yet been shadowed
110 //
111 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();
112
113 //
114 // Shadow DxeIpl and then re-run its entry point
115 //
116 Status = ShadowDxeIpl (FfsHeader, PeiEfiPeiPeCoffLoader);
117 } else {
118 //
119 // Install FvFileLoader and DxeIpl PPIs.
120 //
121 Status = PeiServicesInstallPpi (mPpiList);
122 ASSERT_EFI_ERROR(Status);
123 }
124
125 return Status;
126 }
127
128 EFI_STATUS
129 EFIAPI
130 DxeLoadCore (
131 IN EFI_DXE_IPL_PPI *This,
132 IN EFI_PEI_SERVICES **PeiServices,
133 IN EFI_PEI_HOB_POINTERS HobList
134 )
135 /*++
136
137 Routine Description:
138
139 Main entry point to last PEIM
140
141 Arguments:
142 This - Entry point for DXE IPL PPI
143 PeiServices - General purpose services available to every PEIM.
144 HobList - Address to the Pei HOB list
145
146 Returns:
147
148 EFI_SUCCESS - DEX core was successfully loaded.
149 EFI_OUT_OF_RESOURCES - There are not enough resources to load DXE core.
150
151 --*/
152 {
153 EFI_STATUS Status;
154 EFI_PHYSICAL_ADDRESS TopOfStack;
155 EFI_PHYSICAL_ADDRESS BaseOfStack;
156 EFI_PHYSICAL_ADDRESS BspStore;
157 EFI_GUID DxeCoreFileName;
158 EFI_GUID FirmwareFileName;
159 VOID *Pe32Data;
160 VOID *FvImageData;
161 EFI_PHYSICAL_ADDRESS DxeCoreAddress;
162 UINT64 DxeCoreSize;
163 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;
164 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;
165 EFI_BOOT_MODE BootMode;
166 EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;
167 EFI_PEI_S3_RESUME_PPI *S3Resume;
168 EFI_PHYSICAL_ADDRESS PageTables;
169
170 // PERF_START (PeiServices, L"DxeIpl", NULL, 0);
171 TopOfStack = 0;
172 BaseOfStack = 0;
173 BspStore = 0;
174 PageTables = 0;
175
176 //
177 // if in S3 Resume, restore configure
178 //
179 Status = PeiServicesGetBootMode (&BootMode);
180 ASSERT_EFI_ERROR(Status);
181
182 if (BootMode == BOOT_ON_S3_RESUME) {
183 Status = PeiServicesLocatePpi (
184 &gEfiPeiS3ResumePpiGuid,
185 0,
186 NULL,
187 (VOID **)&S3Resume
188 );
189 ASSERT_EFI_ERROR (Status);
190
191 Status = S3Resume->S3RestoreConfig (PeiServices);
192 ASSERT_EFI_ERROR (Status);
193 } else if (BootMode == BOOT_IN_RECOVERY_MODE) {
194
195 Status = PeiServicesLocatePpi (
196 &gEfiPeiRecoveryModulePpiGuid,
197 0,
198 NULL,
199 (VOID **)&PeiRecovery
200 );
201 ASSERT_EFI_ERROR (Status);
202
203 Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);
204 if (EFI_ERROR (Status)) {
205 DEBUG ((EFI_D_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
206 CpuDeadLoop ();
207 }
208
209 //
210 // Now should have a HOB with the DXE core w/ the old HOB destroyed
211 //
212 }
213
214 //
215 // Install the PEI Protocols that are shared between PEI and DXE
216 //
217 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();
218 ASSERT (PeiEfiPeiPeCoffLoader != NULL);
219
220 //
221 // Allocate 128KB for the Stack
222 //
223 PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);
224 ASSERT (BaseOfStack != 0);
225
226 //
227 // Add architecture-specifc HOBs (including the BspStore HOB)
228 //
229 Status = CreateArchSpecificHobs (&BspStore);
230 ASSERT_EFI_ERROR (Status);
231
232 //
233 // Find the EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE type compressed Firmware Volume file
234 // The file found will be processed by PeiProcessFile: It will first be decompressed to
235 // a normal FV, then a corresponding FV type hob will be built.
236 //
237 Status = PeiFindFile (
238 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
239 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
240 &FirmwareFileName,
241 &FvImageData
242 );
243
244 //
245 // Find the DXE Core in a Firmware Volume
246 //
247 Status = PeiFindFile (
248 EFI_FV_FILETYPE_DXE_CORE,
249 EFI_SECTION_PE32,
250 &DxeCoreFileName,
251 &Pe32Data
252 );
253 ASSERT_EFI_ERROR (Status);
254
255 //
256 // Load the DXE Core from a Firmware Volume
257 //
258 Status = PeiLoadFile (
259 PeiEfiPeiPeCoffLoader,
260 Pe32Data,
261 &DxeCoreAddress,
262 &DxeCoreSize,
263 &DxeCoreEntryPoint
264 );
265 ASSERT_EFI_ERROR (Status);
266
267 //
268 // Transfer control to the DXE Core
269 // The handoff state is simply a pointer to the HOB list
270 //
271
272 Status = PeiServicesInstallPpi (&mPpiSignal);
273 ASSERT_EFI_ERROR (Status);
274
275 //
276 // Add HOB for the DXE Core
277 //
278 BuildModuleHob (
279 &DxeCoreFileName,
280 DxeCoreAddress,
281 DxeCoreSize,
282 DxeCoreEntryPoint
283 );
284
285 //
286 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
287 //
288 REPORT_STATUS_CODE (
289 EFI_PROGRESS_CODE,
290 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT
291 );
292
293 DEBUG ((EFI_D_INFO, "DXE Core Entry\n"));
294 if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) {
295 //
296 // Compute the top of the stack we were allocated, which is used to load X64 dxe core.
297 // Pre-allocate a 32 bytes which confroms to x64 calling convention.
298 //
299 // The first four parameters to a function are passed in rcx, rdx, r8 and r9.
300 // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the
301 // register parameters is reserved on the stack, in case the called function
302 // wants to spill them; this is important if the function is variadic.
303 //
304 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;
305
306 //
307 // X64 Calling Conventions requires that the stack must be aligned to 16 bytes
308 //
309 TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16);
310 //
311 // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA
312 // memory, it may be corrupted when copying FV to high-end memory
313 //
314 LoadGo64Gdt();
315 //
316 // Limit to 36 bits of addressing for debug. Should get it from CPU
317 //
318 PageTables = CreateIdentityMappingPageTables (36);
319 //
320 // Go to Long Mode. Interrupts will not get turned on until the CPU AP is loaded.
321 // Call x64 drivers passing in single argument, a pointer to the HOBs.
322 //
323 ActivateLongMode (
324 PageTables,
325 (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw),
326 TopOfStack,
327 0x00000000,
328 DxeCoreEntryPoint
329 );
330 } else {
331 //
332 // Add HOB for the EFI Decompress Protocol
333 //
334 BuildGuidDataHob (
335 &gEfiDecompressProtocolGuid,
336 (VOID *)&gEfiDecompress,
337 sizeof (gEfiDecompress)
338 );
339
340 //
341 // Add HOB for the Tiano Decompress Protocol
342 //
343 BuildGuidDataHob (
344 &gEfiTianoDecompressProtocolGuid,
345 (VOID *)&gTianoDecompress,
346 sizeof (gTianoDecompress)
347 );
348
349 //
350 // Add HOB for the user customized Decompress Protocol
351 //
352 BuildGuidDataHob (
353 &gEfiCustomizedDecompressProtocolGuid,
354 (VOID *)&gCustomDecompress,
355 sizeof (gCustomDecompress)
356 );
357
358 //
359 // Add HOB for the PE/COFF Loader Protocol
360 //
361 BuildGuidDataHob (
362 &gEfiPeiPeCoffLoaderGuid,
363 (VOID *)&PeiEfiPeiPeCoffLoader,
364 sizeof (VOID *)
365 );
366 //
367 // Compute the top of the stack we were allocated. Pre-allocate a UINTN
368 // for safety.
369 //
370 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;
371 TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
372
373 SwitchIplStacks (
374 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,
375 HobList.Raw,
376 NULL,
377 (VOID *) (UINTN) TopOfStack,
378 (VOID *) (UINTN) BspStore
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 PeiLoadFile (
469 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,
470 IN VOID *Pe32Data,
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
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
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 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
518 ASSERT (ImageContext.ImageAddress != 0);
519
520 //
521 // Load the image to our new buffer
522 //
523 Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);
524 if (EFI_ERROR (Status)) {
525 return Status;
526 }
527 //
528 // Relocate the image in our new buffer
529 //
530 Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);
531 if (EFI_ERROR (Status)) {
532 return Status;
533 }
534
535 //
536 // Flush the instruction cache so the image data is written before we execute it
537 //
538 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
539
540 *ImageAddress = ImageContext.ImageAddress;
541 *ImageSize = ImageContext.ImageSize;
542 *EntryPoint = ImageContext.EntryPoint;
543
544 return EFI_SUCCESS;
545 }
546
547 EFI_STATUS
548 ShadowDxeIpl (
549 IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,
550 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader
551 )
552 /*++
553
554 Routine Description:
555
556 Shadow the DXE IPL to a different memory location. This occurs after permanent
557 memory has been discovered.
558
559 Arguments:
560
561 DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver
562
563 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol
564
565 Returns:
566
567 EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.
568
569 EFI_ ERROR - The shadow was unsuccessful.
570
571
572 --*/
573 {
574 UINTN SectionLength;
575 UINTN OccupiedSectionLength;
576 EFI_PHYSICAL_ADDRESS DxeIplAddress;
577 UINT64 DxeIplSize;
578 EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;
579 EFI_STATUS Status;
580 EFI_COMMON_SECTION_HEADER *Section;
581
582 Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);
583
584 while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {
585 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
586 OccupiedSectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
587 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);
588 }
589 //
590 // Relocate DxeIpl into memory by using loadfile service
591 //
592 Status = PeiLoadFile (
593 PeiEfiPeiPeCoffLoader,
594 (VOID *) (Section + 1),
595 &DxeIplAddress,
596 &DxeIplSize,
597 &DxeIplEntryPoint
598 );
599
600 if (Status == EFI_SUCCESS) {
601 //
602 // Set gInMemory global variable to TRUE to indicate the dxeipl is shadowed.
603 //
604 *(BOOLEAN *) ((UINTN) &gInMemory + (UINTN) DxeIplEntryPoint - (UINTN) _ModuleEntryPoint) = TRUE;
605 Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer());
606 }
607
608 return Status;
609 }
610
611 EFI_STATUS
612 EFIAPI
613 DxeIplLoadFile (
614 IN EFI_PEI_FV_FILE_LOADER_PPI *This,
615 IN EFI_FFS_FILE_HEADER *FfsHeader,
616 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
617 OUT UINT64 *ImageSize,
618 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
619 )
620 /*++
621
622 Routine Description:
623
624 Given a pointer to an FFS file containing a PE32 image, get the
625 information on the PE32 image, and then "load" it so that it
626 can be executed.
627
628 Arguments:
629
630 This - pointer to our file loader protocol
631
632 FfsHeader - pointer to the FFS file header of the FFS file that
633 contains the PE32 image we want to load
634
635 ImageAddress - returned address where the PE32 image is loaded
636
637 ImageSize - returned size of the loaded PE32 image
638
639 EntryPoint - entry point to the loaded PE32 image
640
641 Returns:
642
643 EFI_SUCCESS - The FFS file was successfully loaded.
644
645 EFI_ERROR - Unable to load the FFS file.
646
647 --*/
648 {
649 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;
650 EFI_STATUS Status;
651 VOID *Pe32Data;
652
653 Pe32Data = NULL;
654 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();
655
656 //
657 // Preprocess the FFS file to get a pointer to the PE32 information
658 // in the enclosed PE32 image.
659 //
660 Status = PeiProcessFile (
661 EFI_SECTION_PE32,
662 FfsHeader,
663 &Pe32Data,
664 NULL
665 );
666
667 if (EFI_ERROR (Status)) {
668 return Status;
669 }
670 //
671 // Load the PE image from the FFS file
672 //
673 Status = PeiLoadFile (
674 PeiEfiPeiPeCoffLoader,
675 Pe32Data,
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 = GET_OCCUPIED_SIZE (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 = GET_OCCUPIED_SIZE (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