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