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