2042efae6dd697ee91c0585e0d0dc4f6fdd372b4
[mirror_edk2.git] / MdeModulePkg / Core / DxeIplPeim / DxeLoad.c
1 /**@file
2 Last PEIM.
3 Responsibility of this module is to load the DXE Core from a Firmware Volume.
4
5 Copyright (c) 2006 - 2007 Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "DxeIpl.h"
17 #include <Ppi/GuidedSectionExtraction.h>
18 #include <FrameworkPei.h>
19
20 EFI_STATUS
21 CustomDecompressExtractSection (
22 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
23 IN CONST VOID *InputSection,
24 OUT VOID **OutputBuffer,
25 OUT UINTN *OutputSize,
26 OUT UINT32 *AuthenticationStatus
27 );
28
29 STATIC
30 EFI_STATUS
31 EFIAPI
32 Decompress (
33 IN CONST EFI_PEI_DECOMPRESS_PPI *This,
34 IN CONST EFI_COMPRESSION_SECTION *InputSection,
35 OUT VOID **OutputBuffer,
36 OUT UINTN *OutputSize
37 );
38
39
40 BOOLEAN gInMemory = FALSE;
41
42 //
43 // Module Globals used in the DXE to PEI handoff
44 // These must be module globals, so the stack can be switched
45 //
46 static EFI_DXE_IPL_PPI mDxeIplPpi = {
47 DxeLoadCore
48 };
49
50 STATIC EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomDecompressExtractiongPpi = {
51 CustomDecompressExtractSection
52 };
53
54 STATIC EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
55 Decompress
56 };
57
58 static EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {
59 {
60 EFI_PEI_PPI_DESCRIPTOR_PPI,
61 &gEfiDxeIplPpiGuid,
62 &mDxeIplPpi
63 },
64 {
65 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
66 &gEfiPeiDecompressPpiGuid,
67 &mDecompressPpi
68 }
69 };
70
71 static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = {
72 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
73 &gEfiEndOfPeiSignalPpiGuid,
74 NULL
75 };
76
77 STATIC EFI_PEI_FIRMWARE_VOLUME_INFO_PPI mFvInfoPpiTemplate = {
78 EFI_FIRMWARE_FILE_SYSTEM2_GUID,
79 NULL,
80 0, //FvInfoSize
81 NULL, //ParentFvName
82 NULL //ParentFileName;
83 };
84
85 /**
86 Initializes the Dxe Ipl PPI
87
88 @param FfsHandle The handle of FFS file.
89 @param PeiServices General purpose services available to
90 every PEIM.
91 @return EFI_SUCESS
92 */
93 EFI_STATUS
94 EFIAPI
95 PeimInitializeDxeIpl (
96 IN EFI_PEI_FILE_HANDLE FfsHandle,
97 IN EFI_PEI_SERVICES **PeiServices
98 )
99 {
100 EFI_STATUS Status;
101 EFI_BOOT_MODE BootMode;
102 EFI_GUID **DecompressGuidList;
103 UINT32 DecompressMethodNumber;
104 EFI_PEI_PPI_DESCRIPTOR *GuidPpi;
105
106 Status = PeiServicesGetBootMode (&BootMode);
107 ASSERT_EFI_ERROR (Status);
108
109 if (BootMode != BOOT_ON_S3_RESUME) {
110 Status = PeiServicesRegisterForShadow (FfsHandle);
111 if (Status == EFI_SUCCESS) {
112
113 gInMemory = TRUE;
114 //
115 // EFI_SUCESS means the first time call register for shadow
116 //
117 return Status;
118 } else if (Status == EFI_ALREADY_STARTED) {
119
120
121 //
122 // Get custom decompress method guid list
123 //
124 DecompressGuidList = NULL;
125 DecompressMethodNumber = 0;
126 Status = CustomDecompressGetAlgorithms (DecompressGuidList, &DecompressMethodNumber);
127 if (Status == EFI_OUT_OF_RESOURCES) {
128 DecompressGuidList = (EFI_GUID **) AllocatePages (EFI_SIZE_TO_PAGES (DecompressMethodNumber * sizeof (EFI_GUID *)));
129 ASSERT (DecompressGuidList != NULL);
130 Status = CustomDecompressGetAlgorithms (DecompressGuidList, &DecompressMethodNumber);
131 }
132 ASSERT_EFI_ERROR(Status);
133
134 //
135 // Install custom decompress extraction guid ppi
136 //
137 if (DecompressMethodNumber > 0) {
138 GuidPpi = NULL;
139 GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePages (EFI_SIZE_TO_PAGES (DecompressMethodNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR)));
140 ASSERT (GuidPpi != NULL);
141 while (DecompressMethodNumber-- > 0) {
142 GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
143 GuidPpi->Ppi = &mCustomDecompressExtractiongPpi;
144 GuidPpi->Guid = DecompressGuidList [DecompressMethodNumber];
145 Status = PeiServicesInstallPpi (GuidPpi++);
146 ASSERT_EFI_ERROR(Status);
147 }
148 }
149 } else {
150 ASSERT_EFI_ERROR (FALSE);
151 }
152 }
153
154 //
155 // Install FvFileLoader and DxeIpl PPIs.
156 //
157 Status = PeiServicesInstallPpi (mPpiList);
158 ASSERT_EFI_ERROR(Status);
159
160 return Status;
161 }
162
163 /**
164 Main entry point to last PEIM
165
166 @param This Entry point for DXE IPL PPI
167 @param PeiServices General purpose services available to every PEIM.
168 @param HobList Address to the Pei HOB list
169
170 @return EFI_SUCCESS DXE core was successfully loaded.
171 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
172 **/
173 EFI_STATUS
174 EFIAPI
175 DxeLoadCore (
176 IN EFI_DXE_IPL_PPI *This,
177 IN EFI_PEI_SERVICES **PeiServices,
178 IN EFI_PEI_HOB_POINTERS HobList
179 )
180 {
181 EFI_STATUS Status;
182 EFI_GUID DxeCoreFileName;
183 EFI_PHYSICAL_ADDRESS DxeCoreAddress;
184 UINT64 DxeCoreSize;
185 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;
186 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;
187 EFI_BOOT_MODE BootMode;
188 EFI_PEI_FV_HANDLE VolumeHandle;
189 EFI_PEI_FILE_HANDLE FileHandle;
190 UINTN Instance;
191
192 //
193 // if in S3 Resume, restore configure
194 //
195 Status = PeiServicesGetBootMode (&BootMode);
196 ASSERT_EFI_ERROR(Status);
197
198 if (BootMode == BOOT_ON_S3_RESUME) {
199 Status = S3RestoreConfig();
200 ASSERT_EFI_ERROR (Status);
201 } else if (BootMode == BOOT_IN_RECOVERY_MODE) {
202 Status = Recovery ();
203 if (EFI_ERROR (Status)) {
204 DEBUG ((EFI_D_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
205 CpuDeadLoop ();
206 }
207
208 //
209 // Now should have a HOB with the DXE core w/ the old HOB destroyed
210 //
211 }
212
213 //
214 // Install the PEI Protocols that are shared between PEI and DXE
215 //
216 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *) GetPeCoffLoaderProtocol ();
217 ASSERT (PeiEfiPeiPeCoffLoader != NULL);
218
219 //
220 // If any FV contains an encapsulated FV extract that FV
221 //
222 DxeIplAddEncapsulatedFirmwareVolumes ();
223
224 //
225 // Look in all the FVs present in PEI and find the DXE Core
226 //
227 Instance = 0;
228 Status = DxeIplFindFirmwareVolumeInstance (&Instance, EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle);
229 ASSERT_EFI_ERROR (Status);
230
231 CopyMem(&DxeCoreFileName, &(((EFI_FFS_FILE_HEADER*)FileHandle)->Name), sizeof (EFI_GUID));
232
233 //
234 // Load the DXE Core from a Firmware Volume
235 //
236 Status = PeiLoadFile (
237 FileHandle,
238 &DxeCoreAddress,
239 &DxeCoreSize,
240 &DxeCoreEntryPoint
241 );
242
243 ASSERT_EFI_ERROR (Status);
244
245 //
246 // Add HOB for the DXE Core
247 //
248 BuildModuleHob (
249 &DxeCoreFileName,
250 DxeCoreAddress,
251 DxeCoreSize,
252 DxeCoreEntryPoint
253 );
254
255 //
256 // Add HOB for the PE/COFF Loader Protocol
257 //
258 BuildGuidDataHob (
259 &gEfiPeiPeCoffLoaderGuid,
260 (VOID *)&PeiEfiPeiPeCoffLoader,
261 sizeof (VOID *)
262 );
263 //
264 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
265 //
266 REPORT_STATUS_CODE (
267 EFI_PROGRESS_CODE,
268 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT
269 );
270
271 //
272 // Transfer control to the DXE Core
273 // The handoff state is simply a pointer to the HOB list
274 //
275 DEBUG ((EFI_D_INFO, "DXE Core Entry Point 0x%08x\n", (UINTN) DxeCoreEntryPoint));
276 HandOffToDxeCore (DxeCoreEntryPoint, HobList, &mPpiSignal);
277 //
278 // If we get here, then the DXE Core returned. This is an error
279 // Dxe Core should not return.
280 //
281 ASSERT (FALSE);
282 CpuDeadLoop ();
283
284 return EFI_OUT_OF_RESOURCES;
285 }
286
287
288 STATIC
289 EFI_STATUS
290 GetFvAlignment (
291 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
292 OUT UINT32 *FvAlignment
293 )
294 {
295 //
296 // Because FvLength in FvHeader is UINT64 type,
297 // so FvHeader must meed at least 8 bytes alignment.
298 // Get the appropriate alignment requirement.
299 //
300 if ((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) < EFI_FVB2_ALIGNMENT_8) {
301 return EFI_UNSUPPORTED;
302 }
303
304 *FvAlignment = 1 << ((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
305 return EFI_SUCCESS;
306 }
307
308 /**
309 Search EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE image and expand
310 as memory FV
311
312 @return EFI_OUT_OF_RESOURCES There are no memory space to exstract FV
313 @return EFI_SUCESS Sucess to find the FV
314 **/
315 EFI_STATUS
316 DxeIplAddEncapsulatedFirmwareVolumes (
317 VOID
318 )
319 {
320 EFI_STATUS Status;
321 EFI_STATUS VolumeStatus;
322 UINTN Index;
323 EFI_FV_INFO VolumeInfo;
324 EFI_PEI_FV_HANDLE VolumeHandle;
325 EFI_PEI_FILE_HANDLE FileHandle;
326 UINT32 SectionLength;
327 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
328 EFI_FIRMWARE_VOLUME_IMAGE_SECTION *SectionHeader;
329 VOID *DstBuffer;
330 UINT32 FvAlignment;
331 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *FvInfoPpi;
332 EFI_PEI_PPI_DESCRIPTOR *FvInfoPpiDescriptor;
333
334 Status = EFI_NOT_FOUND;
335 Index = 0;
336
337 do {
338 VolumeStatus = DxeIplFindFirmwareVolumeInstance (
339 &Index,
340 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
341 &VolumeHandle,
342 &FileHandle
343 );
344
345 if (!EFI_ERROR (VolumeStatus)) {
346 Status = PeiServicesFfsFindSectionData (
347 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
348 (EFI_FFS_FILE_HEADER *)FileHandle,
349 (VOID **)&FvHeader
350 );
351
352 if (!EFI_ERROR (Status)) {
353 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
354 //
355 // Because FvLength in FvHeader is UINT64 type,
356 // so FvHeader must meed at least 8 bytes alignment.
357 // If current FvImage base address doesn't meet its alignment,
358 // we need to reload this FvImage to another correct memory address.
359 //
360 Status = GetFvAlignment(FvHeader, &FvAlignment);
361 if (EFI_ERROR(Status)) {
362 return Status;
363 }
364 if (((UINTN) FvHeader % FvAlignment) != 0) {
365 SectionHeader = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)((UINTN)FvHeader - sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
366 SectionLength = *(UINT32 *)SectionHeader->Size & 0x00FFFFFF;
367
368 DstBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) SectionLength - sizeof (EFI_COMMON_SECTION_HEADER)), FvAlignment);
369 if (DstBuffer == NULL) {
370 return EFI_OUT_OF_RESOURCES;
371 }
372 CopyMem (DstBuffer, FvHeader, (UINTN) SectionLength - sizeof (EFI_COMMON_SECTION_HEADER));
373 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DstBuffer;
374 }
375
376 //
377 // This new Firmware Volume comes from a firmware file within a firmware volume.
378 // Record the original Firmware Volume Name.
379 //
380 PeiServicesFfsGetVolumeInfo (&VolumeHandle, &VolumeInfo);
381
382 //
383 // Prepare to install FirmwareVolumeInfo PPI to expose new FV to PeiCore.
384 //
385 FvInfoPpi = AllocateCopyPool (sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI), &mFvInfoPpiTemplate);
386 ASSERT(FvInfoPpi != NULL);
387
388 FvInfoPpi->FvInfo = (VOID*)FvHeader;
389 FvInfoPpi->FvInfoSize = (UINT32)FvHeader->FvLength;
390 CopyMem (
391 &FvInfoPpi->ParentFvName,
392 &(VolumeInfo.FvName),
393 sizeof (EFI_GUID)
394 );
395 CopyMem (
396 &FvInfoPpi->ParentFileName,
397 &(((EFI_FFS_FILE_HEADER*)FileHandle)->Name),
398 sizeof (EFI_GUID)
399 );
400
401 FvInfoPpiDescriptor = AllocatePool (sizeof(EFI_PEI_PPI_DESCRIPTOR));
402 ASSERT (FvInfoPpiDescriptor != NULL);
403
404 FvInfoPpiDescriptor->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI|EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
405 FvInfoPpiDescriptor->Guid = &gEfiPeiFirmwareVolumeInfoPpiGuid;
406 FvInfoPpiDescriptor->Ppi = (VOID *) FvInfoPpi;
407
408 Status = PeiServicesInstallPpi (FvInfoPpiDescriptor);
409 ASSERT_EFI_ERROR (Status);
410
411 //
412 // Makes the encapsulated volume show up in DXE phase to skip processing of
413 // encapsulated file again.
414 //
415 BuildFv2Hob (
416 (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,
417 FvHeader->FvLength,
418 &VolumeInfo.FvName,
419 &(((EFI_FFS_FILE_HEADER *)FileHandle)->Name)
420 );
421 return Status;
422 }
423 }
424 }
425 } while (!EFI_ERROR (VolumeStatus));
426
427 return Status;
428 }
429
430 /**
431 Find the First Volume that contains the first FileType.
432
433 @param Instance The Fv instance.
434 @param SeachType The type of file to search.
435 @param VolumeHandle Pointer to Fv which contains the file to search.
436 @param FileHandle Pointer to FFS file to search.
437
438 @return EFI_SUCESS Success to find the FFS in specificed FV
439 @return others Fail to find the FFS in specificed FV
440 */
441 EFI_STATUS
442 DxeIplFindFirmwareVolumeInstance (
443 IN OUT UINTN *Instance,
444 IN EFI_FV_FILETYPE SeachType,
445 OUT EFI_PEI_FV_HANDLE *VolumeHandle,
446 OUT EFI_PEI_FILE_HANDLE *FileHandle
447 )
448 {
449 EFI_STATUS Status;
450 EFI_STATUS VolumeStatus;
451
452 do {
453 VolumeStatus = PeiServicesFfsFindNextVolume (*Instance, VolumeHandle);
454 if (!EFI_ERROR (VolumeStatus)) {
455 *FileHandle = NULL;
456 Status = PeiServicesFfsFindNextFile (SeachType, *VolumeHandle, FileHandle);
457 if (!EFI_ERROR (Status)) {
458 return Status;
459 }
460 }
461 *Instance += 1;
462 } while (!EFI_ERROR (VolumeStatus));
463
464 return VolumeStatus;
465 }
466
467 /**
468 Loads and relocates a PE/COFF image into memory.
469
470 @param FileHandle The image file handle
471 @param ImageAddress The base address of the relocated PE/COFF image
472 @param ImageSize The size of the relocated PE/COFF image
473 @param EntryPoint The entry point of the relocated PE/COFF image
474
475 @return EFI_SUCCESS The file was loaded and relocated
476 @return EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
477 **/
478 EFI_STATUS
479 PeiLoadFile (
480 IN EFI_PEI_FILE_HANDLE FileHandle,
481 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
482 OUT UINT64 *ImageSize,
483 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
484 )
485 {
486
487 EFI_STATUS Status;
488 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
489 VOID *Pe32Data;
490 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;
491
492 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();
493 //
494 // First try to find the required section in this ffs file.
495 //
496 Status = PeiServicesFfsFindSectionData (
497 EFI_SECTION_PE32,
498 FileHandle,
499 &Pe32Data
500 );
501
502 if (EFI_ERROR (Status)) {
503 Status = PeiServicesFfsFindSectionData (
504 EFI_SECTION_TE,
505 FileHandle,
506 &Pe32Data
507 );
508 }
509
510 if (EFI_ERROR (Status)) {
511 //
512 // NO image types we support so exit.
513 //
514 return Status;
515 }
516
517 ZeroMem (&ImageContext, sizeof (ImageContext));
518 ImageContext.Handle = Pe32Data;
519 Status = GetImageReadFunction (&ImageContext);
520
521 ASSERT_EFI_ERROR (Status);
522
523 Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);
524 if (EFI_ERROR (Status)) {
525 return Status;
526 }
527 //
528 // Allocate Memory for the image
529 //
530 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
531 ASSERT (ImageContext.ImageAddress != 0);
532
533 //
534 // Load the image to our new buffer
535 //
536 Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);
537 if (EFI_ERROR (Status)) {
538 return Status;
539 }
540 //
541 // Relocate the image in our new buffer
542 //
543 Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);
544 if (EFI_ERROR (Status)) {
545 return Status;
546 }
547
548 //
549 // Flush the instruction cache so the image data is written before we execute it
550 //
551 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
552
553 *ImageAddress = ImageContext.ImageAddress;
554 *ImageSize = ImageContext.ImageSize;
555 *EntryPoint = ImageContext.EntryPoint;
556
557 return EFI_SUCCESS;
558 }
559
560 /**
561 The ExtractSection() function processes the input section and
562 returns a pointer to the section contents. If the section being
563 extracted does not require processing (if the section
564 GuidedSectionHeader.Attributes has the
565 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
566 OutputBuffer is just updated to point to the start of the
567 section's contents. Otherwise, *Buffer must be allocated
568 from PEI permanent memory.
569
570 @param This Indicates the
571 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
572 Buffer containing the input GUIDed section to be
573 processed. OutputBuffer OutputBuffer is
574 allocated from PEI permanent memory and contains
575 the new section stream.
576
577 @param OutputSize A pointer to a caller-allocated
578 UINTN in which the size of *OutputBuffer
579 allocation is stored. If the function
580 returns anything other than EFI_SUCCESS,
581 the value of OutputSize is undefined.
582
583 @param AuthenticationStatus A pointer to a caller-allocated
584 UINT32 that indicates the
585 authentication status of the
586 output buffer. If the input
587 section's GuidedSectionHeader.
588 Attributes field has the
589 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
590 bit as clear,
591 AuthenticationStatus must return
592 zero. These bits reflect the
593 status of the extraction
594 operation. If the function
595 returns anything other than
596 EFI_SUCCESS, the value of
597 AuthenticationStatus is
598 undefined.
599
600 @retval EFI_SUCCESS The InputSection was
601 successfully processed and the
602 section contents were returned.
603
604 @retval EFI_OUT_OF_RESOURCES The system has insufficient
605 resources to process the request.
606
607 @reteval EFI_INVALID_PARAMETER The GUID in InputSection does
608 not match this instance of the
609 GUIDed Section Extraction PPI.
610 **/
611 EFI_STATUS
612 CustomDecompressExtractSection (
613 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
614 IN CONST VOID *InputSection,
615 OUT VOID **OutputBuffer,
616 OUT UINTN *OutputSize,
617 OUT UINT32 *AuthenticationStatus
618 )
619 {
620 EFI_STATUS Status;
621 UINT8 *ScratchBuffer;
622 UINT32 ScratchSize;
623 UINT32 SectionLength;
624 UINT32 DestinationSize;
625
626 //
627 // Set authentic value to zero.
628 //
629 *AuthenticationStatus = 0;
630 //
631 // Calculate Section data Size
632 //
633 SectionLength = *(UINT32 *) (((EFI_COMMON_SECTION_HEADER *) InputSection)->Size) & 0x00ffffff;
634 //
635 // Get compressed data information
636 //
637 Status = CustomDecompressGetInfo (
638 (GUID *) ((UINT8 *) InputSection + sizeof (EFI_COMMON_SECTION_HEADER)),
639 (UINT8 *) InputSection + sizeof (EFI_GUID_DEFINED_SECTION),
640 SectionLength - sizeof (EFI_GUID_DEFINED_SECTION),
641 &DestinationSize,
642 &ScratchSize
643 );
644 if (EFI_ERROR (Status)) {
645 //
646 // GetInfo failed
647 //
648 DEBUG ((EFI_D_ERROR, "Extract guided section Failed - %r\n", Status));
649 return Status;
650 }
651
652 //
653 // Allocate scratch buffer
654 //
655 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchSize));
656 if (ScratchBuffer == NULL) {
657 return EFI_OUT_OF_RESOURCES;
658 }
659 //
660 // Allocate destination buffer
661 //
662 *OutputSize = (UINTN) DestinationSize;
663 *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (*OutputSize));
664 if (*OutputBuffer == NULL) {
665 return EFI_OUT_OF_RESOURCES;
666 }
667
668 //
669 // Call decompress function
670 //
671 Status = CustomDecompress (
672 (GUID *) ((UINT8 *) InputSection + sizeof (EFI_COMMON_SECTION_HEADER)),
673 (UINT8 *) InputSection + sizeof (EFI_GUID_DEFINED_SECTION),
674 *OutputBuffer,
675 ScratchBuffer
676 );
677
678 if (EFI_ERROR (Status)) {
679 //
680 // Decompress failed
681 //
682 DEBUG ((EFI_D_ERROR, "Extract guided section Failed - %r\n", Status));
683 return Status;
684 }
685
686 return EFI_SUCCESS;
687 }
688
689 STATIC
690 EFI_STATUS
691 EFIAPI
692 Decompress (
693 IN CONST EFI_PEI_DECOMPRESS_PPI *This,
694 IN CONST EFI_COMPRESSION_SECTION *CompressionSection,
695 OUT VOID **OutputBuffer,
696 OUT UINTN *OutputSize
697 )
698 {
699 EFI_STATUS Status;
700 UINT8 *DstBuffer;
701 UINT8 *ScratchBuffer;
702 UINTN DstBufferSize;
703 UINT32 ScratchBufferSize;
704 EFI_COMMON_SECTION_HEADER *Section;
705 UINTN SectionLength;
706
707 if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
708 ASSERT (FALSE);
709 return EFI_INVALID_PARAMETER;
710 }
711
712 Section = (EFI_COMMON_SECTION_HEADER *) CompressionSection;
713 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
714
715 //
716 // This is a compression set, expand it
717 //
718 switch (CompressionSection->CompressionType) {
719 case EFI_STANDARD_COMPRESSION:
720 //
721 // Load EFI standard compression.
722 // For compressed data, decompress them to dstbuffer.
723 //
724 Status = UefiDecompressGetInfo (
725 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
726 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
727 (UINT32 *) &DstBufferSize,
728 &ScratchBufferSize
729 );
730 if (EFI_ERROR (Status)) {
731 //
732 // GetInfo failed
733 //
734 DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));
735 return EFI_NOT_FOUND;
736 }
737 //
738 // Allocate scratch buffer
739 //
740 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
741 if (ScratchBuffer == NULL) {
742 return EFI_OUT_OF_RESOURCES;
743 }
744 //
745 // Allocate destination buffer
746 //
747 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
748 if (DstBuffer == NULL) {
749 return EFI_OUT_OF_RESOURCES;
750 }
751 //
752 // Call decompress function
753 //
754 Status = UefiDecompress (
755 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
756 DstBuffer,
757 ScratchBuffer
758 );
759 if (EFI_ERROR (Status)) {
760 //
761 // Decompress failed
762 //
763 DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));
764 return EFI_NOT_FOUND;
765 }
766 break;
767
768 // porting note the original branch for customized compress is removed, it should be change to use GUID compress
769
770 case EFI_NOT_COMPRESSED:
771 //
772 // Allocate destination buffer
773 //
774 DstBufferSize = CompressionSection->UncompressedLength;
775 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
776 if (DstBuffer == NULL) {
777 return EFI_OUT_OF_RESOURCES;
778 }
779 //
780 // stream is not actually compressed, just encapsulated. So just copy it.
781 //
782 CopyMem (DstBuffer, CompressionSection + 1, DstBufferSize);
783 break;
784
785 default:
786 //
787 // Don't support other unknown compression type.
788 //
789 ASSERT (FALSE);
790 return EFI_NOT_FOUND;
791 }
792
793 *OutputSize = DstBufferSize;
794 *OutputBuffer = DstBuffer;
795
796 return EFI_SUCCESS;
797 }
798