git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@150 6f19259b...
[mirror_edk2.git] / EdkModulePkg / Core / DxeIplPeim / 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 // 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 }
36 EFI_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 //
42 static EFI_DXE_IPL_PPI mDxeIplPpi = {
43 DxeLoadCore
44 };
45
46 static EFI_PEI_FV_FILE_LOADER_PPI mLoadFilePpi = {
47 DxeIplLoadFile
48 };
49
50 static EFI_PEI_PPI_DESCRIPTOR mPpiLoadFile = {
51 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
52 &gEfiPeiFvFileLoaderPpiGuid,
53 &mLoadFilePpi
54 };
55
56 static EFI_PEI_PPI_DESCRIPTOR mPpiList = {
57 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
58 &gEfiDxeIplPpiGuid,
59 &mDxeIplPpi
60 };
61
62 static EFI_PEI_PPI_DESCRIPTOR mPpiPeiInMemory = {
63 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
64 &gPeiInMemoryGuid,
65 NULL
66 };
67
68 static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = {
69 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
70 &gEfiEndOfPeiSignalPpiGuid,
71 NULL
72 };
73
74 DECOMPRESS_LIBRARY gEfiDecompress = {
75 UefiDecompressGetInfo,
76 UefiDecompress
77 };
78
79 DECOMPRESS_LIBRARY gTianoDecompress = {
80 TianoDecompressGetInfo,
81 TianoDecompress
82 };
83
84 DECOMPRESS_LIBRARY gCustomDecompress = {
85 CustomDecompressGetInfo,
86 CustomDecompress
87 };
88
89 STATIC
90 UINTN
91 GetOccupiedSize (
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
106 EFI_STATUS
107 EFIAPI
108 PeimInitializeDxeIpl (
109 IN EFI_FFS_FILE_HEADER *FfsHeader,
110 IN EFI_PEI_SERVICES **PeiServices
111 )
112 /*++
113
114 Routine Description:
115
116 Initializes the Dxe Ipl PPI
117
118 Arguments:
119
120 FfsHeader - Pointer to FFS file header
121 PeiServices - General purpose services available to every PEIM.
122
123 Returns:
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
188 EFI_STATUS
189 EFIAPI
190 DxeLoadCore (
191 IN EFI_DXE_IPL_PPI *This,
192 IN EFI_PEI_SERVICES **PeiServices,
193 IN EFI_PEI_HOB_POINTERS HobList
194 )
195 /*++
196
197 Routine Description:
198
199 Main entry point to last PEIM
200
201 Arguments:
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
207 Returns:
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
389 EFI_STATUS
390 PeiFindFile (
391 IN UINT8 Type,
392 IN UINT16 SectionType,
393 OUT EFI_GUID *FileName,
394 OUT VOID **Pe32Data
395 )
396 /*++
397
398 Routine 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
405 Arguments:
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
415 Returns:
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
461 EFI_STATUS
462 PeiLoadx64File (
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
472 Routine Description:
473
474 Loads and relocates a PE/COFF image into memory.
475
476 Arguments:
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
488 Returns:
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
548 EFI_STATUS
549 ShadowDxeIpl (
550 IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,
551 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader
552 )
553 /*++
554
555 Routine Description:
556
557 Shadow the DXE IPL to a different memory location. This occurs after permanent
558 memory has been discovered.
559
560 Arguments:
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
566 Returns:
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
619 EFI_STATUS
620 EFIAPI
621 DxeIplLoadFile (
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
630 Routine 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
636 Arguments:
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
645 Returns:
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
687 EFI_STATUS
688 PeiProcessFile (
689 IN UINT16 SectionType,
690 IN EFI_FFS_FILE_HEADER *FfsFileHeader,
691 OUT VOID **Pe32Data
692 )
693 /*++
694
695 Routine Description:
696
697 Arguments:
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
707 Returns:
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;
990 }