]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Core/DxeIplPeim/DxeLoadX64.c
cbb7595dac7bdaf2ffe1762bbc250f6ef0157a45
[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 = PeiServicesGetBootMode (&BootMode);
134
135 ASSERT_EFI_ERROR (Status);
136
137 Status = PeiServicesLocatePpi (
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 = PeiServicesInstallPpi (&mPpiLoadFile);
169
170 if (EFI_ERROR (Status)) {
171 return Status;
172 }
173 }
174 //
175 // Install DxeIpl PPI
176 //
177 PeiServicesInstallPpi (&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 = PeiServicesGetBootMode (&BootMode);
238
239 if (!EFI_ERROR (Status) && (BootMode == BOOT_ON_S3_RESUME)) {
240 Status = PeiServicesLocatePpi (
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 PeiServicesAllocatePages (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 = PeiServicesGetBootMode (&BootMode);
292 if (!EFI_ERROR (Status) && (BootMode == BOOT_IN_RECOVERY_MODE)) {
293 Status = PeiServicesLocatePpi (
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 = PeiServicesInstallPpi (&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 = PeiServicesFfsFindNextFile (
443 Type,
444 FwVolHeader,
445 &FfsFileHeader
446 );
447 if (!EFI_ERROR (Status)) {
448 Status = PeiProcessFile (
449 SectionType,
450 &FfsFileHeader,
451 Pe32Data
452 );
453 CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));
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 PeiServicesAllocatePages (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 = PeiServicesInstallPpi (&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 OUT EFI_FFS_FILE_HEADER **RealFfsFileHeader,
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 EFI_FFS_FILE_HEADER *FfsFileHeader;
740
741 FfsFileHeader = *RealFfsFileHeader;
742
743 Status = PeiServicesFfsFindSectionData (
744 EFI_SECTION_COMPRESSION,
745 FfsFileHeader,
746 &SectionData
747 );
748
749 //
750 // Upon finding a DXE Core file, see if there is first a compression section
751 //
752 if (!EFI_ERROR (Status)) {
753 //
754 // Yes, there is a compression section, so extract the contents
755 // Decompress the image here
756 //
757 Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));
758
759 do {
760 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
761 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);
762
763 //
764 // Was the DXE Core file encapsulated in a GUID'd section?
765 //
766 if (Section->Type == EFI_SECTION_GUID_DEFINED) {
767 //
768 // Locate the GUID'd Section Extractor
769 //
770 GuidedSectionHeader = (VOID *) (Section + 1);
771
772 //
773 // This following code constitutes the addition of the security model
774 // to the DXE IPL.
775 //
776 //
777 // Set a default authenticatino state
778 //
779 AuthenticationStatus = 0;
780
781 Status = PeiServicesLocatePpi (
782 &gEfiPeiSectionExtractionPpiGuid,
783 0,
784 NULL,
785 (VOID **)&SectionExtract
786 );
787
788 if (EFI_ERROR (Status)) {
789 return Status;
790 }
791 //
792 // Verify Authentication State
793 //
794 CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));
795
796 Status = SectionExtract->PeiGetSection (
797 GetPeiServicesTablePointer(),
798 SectionExtract,
799 (EFI_SECTION_TYPE *) &SectionType,
800 &TempGuid,
801 0,
802 (VOID **) &Buffer,
803 &BufferSize,
804 &AuthenticationStatus
805 );
806
807 if (EFI_ERROR (Status)) {
808 return Status;
809 }
810 //
811 // If not ask the Security PPI, if exists, for disposition
812 //
813 //
814 Status = PeiServicesLocatePpi (
815 &gEfiPeiSecurityPpiGuid,
816 0,
817 NULL,
818 (VOID **)&Security
819 );
820 if (EFI_ERROR (Status)) {
821 return Status;
822 }
823
824 Status = Security->AuthenticationState (
825 GetPeiServicesTablePointer(),
826 (struct _EFI_PEI_SECURITY_PPI *) Security,
827 AuthenticationStatus,
828 FfsFileHeader,
829 &StartCrisisRecovery
830 );
831
832 if (EFI_ERROR (Status)) {
833 return Status;
834 }
835 //
836 // If there is a security violation, report to caller and have
837 // the upper-level logic possible engender a crisis recovery
838 //
839 if (StartCrisisRecovery) {
840 return EFI_SECURITY_VIOLATION;
841 }
842 }
843
844 if (Section->Type == EFI_SECTION_PE32) {
845 //
846 // This is what we want
847 //
848 *Pe32Data = (VOID *) (Section + 1);
849 return EFI_SUCCESS;
850 } else if (Section->Type == EFI_SECTION_COMPRESSION) {
851 //
852 // This is a compression set, expand it
853 //
854 CompressionSection = (EFI_COMPRESSION_SECTION *) Section;
855
856 switch (CompressionSection->CompressionType) {
857 case EFI_STANDARD_COMPRESSION:
858 DecompressLibrary = &gTianoDecompress;
859 break;
860
861 case EFI_CUSTOMIZED_COMPRESSION:
862 //
863 // Load user customized compression protocol.
864 //
865 DecompressLibrary = &gCustomDecompress;
866 break;
867
868 case EFI_NOT_COMPRESSED:
869 default:
870 //
871 // Need to support not compressed file
872 //
873 ASSERT_EFI_ERROR (Status);
874 return EFI_NOT_FOUND;
875 }
876
877 Status = DecompressLibrary->GetInfo (
878 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
879 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
880 &DstBufferSize,
881 &ScratchBufferSize
882 );
883 if (EFI_ERROR (Status)) {
884 //
885 // GetInfo failed
886 //
887 return EFI_NOT_FOUND;
888 }
889
890 //
891 // Allocate scratch buffer
892 //
893 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
894 if (ScratchBuffer == NULL) {
895 return EFI_OUT_OF_RESOURCES;
896 }
897
898 //
899 // Allocate destination buffer
900 //
901 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
902 if (DstBuffer == NULL) {
903 return EFI_OUT_OF_RESOURCES;
904 }
905
906 //
907 // Call decompress function
908 //
909 Status = DecompressLibrary->Decompress (
910 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
911 DstBuffer,
912 ScratchBuffer
913 );
914
915 CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;
916 if (CmpSection->Type == EFI_SECTION_RAW) {
917 //
918 // Skip the section header and
919 // adjust the pointer alignment to 16
920 //
921 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16);
922
923 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
924 FfsFileHeader = NULL;
925 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);
926 Status = PeiServicesFfsFindNextFile (
927 EFI_FV_FILETYPE_DXE_CORE,
928 FvHeader,
929 &FfsFileHeader
930 );
931
932 if (EFI_ERROR (Status)) {
933 return EFI_NOT_FOUND;
934 }
935
936 //
937 // Reture the FfsHeader that contain Pe32Data.
938 //
939 *RealFfsFileHeader = FfsFileHeader;
940 return PeiProcessFile (SectionType, RealFfsFileHeader, Pe32Data);
941 }
942 }
943 //
944 // Decompress successfully.
945 // Loop the decompressed data searching for expected section.
946 //
947 CmpFileData = (VOID *) DstBuffer;
948 CmpFileSize = DstBufferSize;
949 do {
950 CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;
951 if (CmpSection->Type == EFI_SECTION_PE32) {
952 //
953 // This is what we want
954 //
955 *Pe32Data = (VOID *) (CmpSection + 1);
956 return EFI_SUCCESS;
957 }
958
959 OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4);
960 CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);
961 } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);
962 }
963
964 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);
965 FileSize = FfsFileHeader->Size[0] & 0xFF;
966 FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;
967 FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;
968 FileSize &= 0x00FFFFFF;
969 } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);
970
971 //
972 // End of the decompression activity
973 //
974 } else {
975
976 Status = PeiServicesFfsFindSectionData (
977 EFI_SECTION_PE32,
978 FfsFileHeader,
979 &SectionData
980 );
981
982 if (EFI_ERROR (Status)) {
983 Status = PeiServicesFfsFindSectionData (
984 EFI_SECTION_TE,
985 FfsFileHeader,
986 &SectionData
987 );
988 if (EFI_ERROR (Status)) {
989 return Status;
990 }
991 }
992 }
993
994 *Pe32Data = SectionData;
995
996 return EFI_SUCCESS;
997 }