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