9a036e62466edd490ceec3f716233698c07fd63a
[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 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 = PeiLoadx64File (
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 );
440 CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));
441 return Status;
442 }
443 Hob.Raw = GET_NEXT_HOB (Hob);
444 }
445 return EFI_NOT_FOUND;
446 }
447
448 EFI_STATUS
449 PeiLoadx64File (
450 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,
451 IN VOID *Pe32Data,
452 IN EFI_MEMORY_TYPE MemoryType,
453 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
454 OUT UINT64 *ImageSize,
455 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
456 )
457 /*++
458
459 Routine Description:
460
461 Loads and relocates a PE/COFF image into memory.
462
463 Arguments:
464
465 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol
466
467 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
468
469 ImageAddress - The base address of the relocated PE/COFF image
470
471 ImageSize - The size of the relocated PE/COFF image
472
473 EntryPoint - The entry point of the relocated PE/COFF image
474
475 Returns:
476
477 EFI_SUCCESS - The file was loaded and relocated
478 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
479
480 --*/
481 {
482 EFI_STATUS Status;
483 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
484 EFI_PHYSICAL_ADDRESS MemoryBuffer;
485
486 ZeroMem (&ImageContext, sizeof (ImageContext));
487 ImageContext.Handle = Pe32Data;
488 Status = GetImageReadFunction (&ImageContext);
489
490 ASSERT_EFI_ERROR (Status);
491
492 Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);
493 if (EFI_ERROR (Status)) {
494 return Status;
495 }
496 //
497 // Allocate Memory for the image
498 //
499 //
500 // Allocate Memory for the image
501 //
502 PeiServicesAllocatePages (MemoryType, EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize), &MemoryBuffer);
503 ImageContext.ImageAddress = MemoryBuffer;
504 ASSERT (ImageContext.ImageAddress != 0);
505
506 //
507 // Load the image to our new buffer
508 //
509
510 Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);
511 if (EFI_ERROR (Status)) {
512 return Status;
513 }
514
515 //
516 // Relocate the image in our new buffer
517 //
518 Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);
519 if (EFI_ERROR (Status)) {
520 return Status;
521 }
522
523 //
524 // Flush the instruction cache so the image data is written before we execute it
525 //
526 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
527
528 *ImageAddress = ImageContext.ImageAddress;
529 *ImageSize = ImageContext.ImageSize;
530 *EntryPoint = ImageContext.EntryPoint;
531
532 return EFI_SUCCESS;
533 }
534
535 EFI_STATUS
536 ShadowDxeIpl (
537 IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,
538 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader
539 )
540 /*++
541
542 Routine Description:
543
544 Shadow the DXE IPL to a different memory location. This occurs after permanent
545 memory has been discovered.
546
547 Arguments:
548
549 DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver
550
551 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol
552
553 Returns:
554
555 EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.
556
557 EFI_ ERROR - The shadow was unsuccessful.
558
559
560 --*/
561 {
562 UINTN SectionLength;
563 UINTN OccupiedSectionLength;
564 EFI_PHYSICAL_ADDRESS DxeIplAddress;
565 UINT64 DxeIplSize;
566 EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;
567 EFI_STATUS Status;
568 EFI_COMMON_SECTION_HEADER *Section;
569
570 Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);
571
572 while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {
573 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
574 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);
575 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);
576 }
577
578 //
579 // Relocate DxeIpl into memory by using loadfile service
580 //
581 Status = PeiLoadx64File (
582 PeiEfiPeiPeCoffLoader,
583 (VOID *) (Section + 1),
584 EfiBootServicesData,
585 &DxeIplAddress,
586 &DxeIplSize,
587 &DxeIplEntryPoint
588 );
589
590 if (Status == EFI_SUCCESS) {
591 //
592 // Install PeiInMemory to indicate the Dxeipl is shadowed
593 //
594 Status = PeiServicesInstallPpi (&mPpiPeiInMemory);
595
596 if (EFI_ERROR (Status)) {
597 return Status;
598 }
599
600 Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer());
601 }
602
603 return Status;
604 }
605
606 EFI_STATUS
607 EFIAPI
608 DxeIplLoadFile (
609 IN EFI_PEI_FV_FILE_LOADER_PPI *This,
610 IN EFI_FFS_FILE_HEADER *FfsHeader,
611 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
612 OUT UINT64 *ImageSize,
613 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
614 )
615 /*++
616
617 Routine Description:
618
619 Given a pointer to an FFS file containing a PE32 image, get the
620 information on the PE32 image, and then "load" it so that it
621 can be executed.
622
623 Arguments:
624
625 This - pointer to our file loader protocol
626 FfsHeader - pointer to the FFS file header of the FFS file that
627 contains the PE32 image we want to load
628 ImageAddress - returned address where the PE32 image is loaded
629 ImageSize - returned size of the loaded PE32 image
630 EntryPoint - entry point to the loaded PE32 image
631
632 Returns:
633
634 EFI_SUCCESS - The FFS file was successfully loaded.
635 EFI_ERROR - Unable to load the FFS file.
636
637 --*/
638 {
639 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;
640 EFI_STATUS Status;
641 VOID *Pe32Data;
642
643 Pe32Data = NULL;
644 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();
645
646 //
647 // Preprocess the FFS file to get a pointer to the PE32 information
648 // in the enclosed PE32 image.
649 //
650 Status = PeiProcessFile (
651 EFI_SECTION_PE32,
652 &FfsHeader,
653 &Pe32Data
654 );
655
656 if (EFI_ERROR (Status)) {
657 return Status;
658 }
659 //
660 // Load the PE image from the FFS file
661 //
662 Status = PeiLoadx64File (
663 PeiEfiPeiPeCoffLoader,
664 Pe32Data,
665 EfiBootServicesData,
666 ImageAddress,
667 ImageSize,
668 EntryPoint
669 );
670
671 return Status;
672 }
673
674 EFI_STATUS
675 PeiProcessFile (
676 IN UINT16 SectionType,
677 IN OUT EFI_FFS_FILE_HEADER **RealFfsFileHeader,
678 OUT VOID **Pe32Data
679 )
680 /*++
681
682 Routine Description:
683
684 Arguments:
685
686 SectionType - The type of section in the FFS file to process.
687
688 FfsFileHeader - Pointer to the FFS file to process, looking for the
689 specified SectionType
690
691 Pe32Data - returned pointer to the start of the PE32 image found
692 in the FFS file.
693
694 Returns:
695
696 EFI_SUCCESS - found the PE32 section in the FFS file
697
698 --*/
699 {
700 EFI_STATUS Status;
701 VOID *SectionData;
702 DECOMPRESS_LIBRARY *DecompressLibrary;
703 UINT8 *DstBuffer;
704 UINT8 *ScratchBuffer;
705 UINT32 DstBufferSize;
706 UINT32 ScratchBufferSize;
707 EFI_COMMON_SECTION_HEADER *CmpSection;
708 UINTN CmpSectionLength;
709 UINTN OccupiedCmpSectionLength;
710 VOID *CmpFileData;
711 UINTN CmpFileSize;
712 EFI_COMMON_SECTION_HEADER *Section;
713 UINTN SectionLength;
714 UINTN OccupiedSectionLength;
715 UINT64 FileSize;
716 EFI_GUID_DEFINED_SECTION *GuidedSectionHeader;
717 UINT32 AuthenticationStatus;
718 EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract;
719 UINT32 BufferSize;
720 UINT8 *Buffer;
721 EFI_PEI_SECURITY_PPI *Security;
722 BOOLEAN StartCrisisRecovery;
723 EFI_GUID TempGuid;
724 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
725 EFI_COMPRESSION_SECTION *CompressionSection;
726 EFI_FFS_FILE_HEADER *FfsFileHeader;
727
728 FfsFileHeader = *RealFfsFileHeader;
729
730 Status = PeiServicesFfsFindSectionData (
731 EFI_SECTION_COMPRESSION,
732 FfsFileHeader,
733 &SectionData
734 );
735
736 //
737 // Upon finding a DXE Core file, see if there is first a compression section
738 //
739 if (!EFI_ERROR (Status)) {
740 //
741 // Yes, there is a compression section, so extract the contents
742 // Decompress the image here
743 //
744 Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));
745
746 do {
747 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
748 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);
749
750 //
751 // Was the DXE Core file encapsulated in a GUID'd section?
752 //
753 if (Section->Type == EFI_SECTION_GUID_DEFINED) {
754 //
755 // Locate the GUID'd Section Extractor
756 //
757 GuidedSectionHeader = (VOID *) (Section + 1);
758
759 //
760 // This following code constitutes the addition of the security model
761 // to the DXE IPL.
762 //
763 //
764 // Set a default authenticatino state
765 //
766 AuthenticationStatus = 0;
767
768 Status = PeiServicesLocatePpi (
769 &gEfiPeiSectionExtractionPpiGuid,
770 0,
771 NULL,
772 (VOID **)&SectionExtract
773 );
774
775 if (EFI_ERROR (Status)) {
776 return Status;
777 }
778 //
779 // Verify Authentication State
780 //
781 CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));
782
783 Status = SectionExtract->PeiGetSection (
784 GetPeiServicesTablePointer(),
785 SectionExtract,
786 (EFI_SECTION_TYPE *) &SectionType,
787 &TempGuid,
788 0,
789 (VOID **) &Buffer,
790 &BufferSize,
791 &AuthenticationStatus
792 );
793
794 if (EFI_ERROR (Status)) {
795 return Status;
796 }
797 //
798 // If not ask the Security PPI, if exists, for disposition
799 //
800 //
801 Status = PeiServicesLocatePpi (
802 &gEfiPeiSecurityPpiGuid,
803 0,
804 NULL,
805 (VOID **)&Security
806 );
807 if (EFI_ERROR (Status)) {
808 return Status;
809 }
810
811 Status = Security->AuthenticationState (
812 GetPeiServicesTablePointer(),
813 (struct _EFI_PEI_SECURITY_PPI *) Security,
814 AuthenticationStatus,
815 FfsFileHeader,
816 &StartCrisisRecovery
817 );
818
819 if (EFI_ERROR (Status)) {
820 return Status;
821 }
822 //
823 // If there is a security violation, report to caller and have
824 // the upper-level logic possible engender a crisis recovery
825 //
826 if (StartCrisisRecovery) {
827 return EFI_SECURITY_VIOLATION;
828 }
829 }
830
831 if (Section->Type == EFI_SECTION_PE32) {
832 //
833 // This is what we want
834 //
835 *Pe32Data = (VOID *) (Section + 1);
836 return EFI_SUCCESS;
837 } else if (Section->Type == EFI_SECTION_COMPRESSION) {
838 //
839 // This is a compression set, expand it
840 //
841 CompressionSection = (EFI_COMPRESSION_SECTION *) Section;
842
843 switch (CompressionSection->CompressionType) {
844 case EFI_STANDARD_COMPRESSION:
845 DecompressLibrary = &gTianoDecompress;
846 break;
847
848 case EFI_CUSTOMIZED_COMPRESSION:
849 //
850 // Load user customized compression protocol.
851 //
852 DecompressLibrary = &gCustomDecompress;
853 break;
854
855 case EFI_NOT_COMPRESSED:
856 default:
857 //
858 // Need to support not compressed file
859 //
860 ASSERT_EFI_ERROR (Status);
861 return EFI_NOT_FOUND;
862 }
863
864 Status = DecompressLibrary->GetInfo (
865 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
866 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
867 &DstBufferSize,
868 &ScratchBufferSize
869 );
870 if (EFI_ERROR (Status)) {
871 //
872 // GetInfo failed
873 //
874 return EFI_NOT_FOUND;
875 }
876
877 //
878 // Allocate scratch buffer
879 //
880 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
881 if (ScratchBuffer == NULL) {
882 return EFI_OUT_OF_RESOURCES;
883 }
884
885 //
886 // Allocate destination buffer
887 //
888 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
889 if (DstBuffer == NULL) {
890 return EFI_OUT_OF_RESOURCES;
891 }
892
893 //
894 // Call decompress function
895 //
896 Status = DecompressLibrary->Decompress (
897 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
898 DstBuffer,
899 ScratchBuffer
900 );
901
902 CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;
903 if (CmpSection->Type == EFI_SECTION_RAW) {
904 //
905 // Skip the section header and
906 // adjust the pointer alignment to 16
907 //
908 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16);
909
910 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
911 FfsFileHeader = NULL;
912 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);
913 Status = PeiServicesFfsFindNextFile (
914 EFI_FV_FILETYPE_DXE_CORE,
915 FvHeader,
916 &FfsFileHeader
917 );
918
919 if (EFI_ERROR (Status)) {
920 return EFI_NOT_FOUND;
921 }
922
923 //
924 // Reture the FfsHeader that contain Pe32Data.
925 //
926 *RealFfsFileHeader = FfsFileHeader;
927 return PeiProcessFile (SectionType, RealFfsFileHeader, Pe32Data);
928 }
929 }
930 //
931 // Decompress successfully.
932 // Loop the decompressed data searching for expected section.
933 //
934 CmpFileData = (VOID *) DstBuffer;
935 CmpFileSize = DstBufferSize;
936 do {
937 CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;
938 if (CmpSection->Type == EFI_SECTION_PE32) {
939 //
940 // This is what we want
941 //
942 *Pe32Data = (VOID *) (CmpSection + 1);
943 return EFI_SUCCESS;
944 }
945
946 OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4);
947 CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);
948 } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);
949 }
950
951 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);
952 FileSize = FfsFileHeader->Size[0] & 0xFF;
953 FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;
954 FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;
955 FileSize &= 0x00FFFFFF;
956 } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);
957
958 //
959 // End of the decompression activity
960 //
961 } else {
962
963 Status = PeiServicesFfsFindSectionData (
964 EFI_SECTION_PE32,
965 FfsFileHeader,
966 &SectionData
967 );
968
969 if (EFI_ERROR (Status)) {
970 Status = PeiServicesFfsFindSectionData (
971 EFI_SECTION_TE,
972 FfsFileHeader,
973 &SectionData
974 );
975 if (EFI_ERROR (Status)) {
976 return Status;
977 }
978 }
979 }
980
981 *Pe32Data = SectionData;
982
983 return EFI_SUCCESS;
984 }