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