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