]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/DxeIplPeim/DxeLoad.c
Merge branch of PI tree to main trunk
[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_RECOVERY_MODULE_PPI *PeiRecovery;
189 EFI_PEI_S3_RESUME_PPI *S3Resume;
190 EFI_PEI_FV_HANDLE VolumeHandle;
191 EFI_PEI_FILE_HANDLE FileHandle;
192 UINTN Instance;
193
194 //
195 // if in S3 Resume, restore configure
196 //
197 Status = PeiServicesGetBootMode (&BootMode);
198 ASSERT_EFI_ERROR(Status);
199
200 if (BootMode == BOOT_ON_S3_RESUME) {
201 Status = PeiServicesLocatePpi (
202 &gEfiPeiS3ResumePpiGuid,
203 0,
204 NULL,
205 (VOID **)&S3Resume
206 );
207 ASSERT_EFI_ERROR (Status);
208
209 Status = S3Resume->S3RestoreConfig (PeiServices);
210 ASSERT_EFI_ERROR (Status);
211 } else if (BootMode == BOOT_IN_RECOVERY_MODE) {
212
213 Status = PeiServicesLocatePpi (
214 &gEfiPeiRecoveryModulePpiGuid,
215 0,
216 NULL,
217 (VOID **)&PeiRecovery
218 );
219 ASSERT_EFI_ERROR (Status);
220
221 Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);
222 if (EFI_ERROR (Status)) {
223 DEBUG ((EFI_D_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
224 CpuDeadLoop ();
225 }
226
227 //
228 // Now should have a HOB with the DXE core w/ the old HOB destroyed
229 //
230 }
231
232 //
233 // Install the PEI Protocols that are shared between PEI and DXE
234 //
235 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *) GetPeCoffLoaderProtocol ();
236 ASSERT (PeiEfiPeiPeCoffLoader != NULL);
237
238 //
239 // If any FV contains an encapsulated FV extract that FV
240 //
241 DxeIplAddEncapsulatedFirmwareVolumes ();
242
243 //
244 // Look in all the FVs present in PEI and find the DXE Core
245 //
246 Instance = 0;
247 Status = DxeIplFindFirmwareVolumeInstance (&Instance, EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle);
248 ASSERT_EFI_ERROR (Status);
249
250 CopyMem(&DxeCoreFileName, &(((EFI_FFS_FILE_HEADER*)FileHandle)->Name), sizeof (EFI_GUID));
251
252 //
253 // Load the DXE Core from a Firmware Volume
254 //
255 Status = PeiLoadFile (
256 FileHandle,
257 &DxeCoreAddress,
258 &DxeCoreSize,
259 &DxeCoreEntryPoint
260 );
261
262 ASSERT_EFI_ERROR (Status);
263
264 //
265 // Add HOB for the DXE Core
266 //
267 BuildModuleHob (
268 &DxeCoreFileName,
269 DxeCoreAddress,
270 DxeCoreSize,
271 DxeCoreEntryPoint
272 );
273
274 //
275 // Add HOB for the PE/COFF Loader Protocol
276 //
277 BuildGuidDataHob (
278 &gEfiPeiPeCoffLoaderGuid,
279 (VOID *)&PeiEfiPeiPeCoffLoader,
280 sizeof (VOID *)
281 );
282 //
283 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
284 //
285 REPORT_STATUS_CODE (
286 EFI_PROGRESS_CODE,
287 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT
288 );
289
290 //
291 // Transfer control to the DXE Core
292 // The handoff state is simply a pointer to the HOB list
293 //
294 DEBUG ((EFI_D_INFO, "DXE Core Entry Point 0x%08x\n", (UINTN) DxeCoreEntryPoint));
295 HandOffToDxeCore (DxeCoreEntryPoint, HobList, &mPpiSignal);
296 //
297 // If we get here, then the DXE Core returned. This is an error
298 // Dxe Core should not return.
299 //
300 ASSERT (FALSE);
301 CpuDeadLoop ();
302
303 return EFI_OUT_OF_RESOURCES;
304 }
305
306
307 STATIC
308 EFI_STATUS
309 GetFvAlignment (
310 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,
311 OUT UINT32 *FvAlignment
312 )
313 {
314 //
315 // Because FvLength in FvHeader is UINT64 type,
316 // so FvHeader must meed at least 8 bytes alignment.
317 // Get the appropriate alignment requirement.
318 //
319 if ((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) < EFI_FVB2_ALIGNMENT_8) {
320 return EFI_UNSUPPORTED;
321 }
322
323 *FvAlignment = 1 << ((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
324 return EFI_SUCCESS;
325 }
326
327 /**
328 Search EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE image and expand
329 as memory FV
330
331 @return EFI_OUT_OF_RESOURCES There are no memory space to exstract FV
332 @return EFI_SUCESS Sucess to find the FV
333 **/
334 EFI_STATUS
335 DxeIplAddEncapsulatedFirmwareVolumes (
336 VOID
337 )
338 {
339 EFI_STATUS Status;
340 EFI_STATUS VolumeStatus;
341 UINTN Index;
342 EFI_FV_INFO VolumeInfo;
343 EFI_PEI_FV_HANDLE VolumeHandle;
344 EFI_PEI_FILE_HANDLE FileHandle;
345 UINT32 SectionLength;
346 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
347 EFI_FIRMWARE_VOLUME_IMAGE_SECTION *SectionHeader;
348 VOID *DstBuffer;
349 UINT32 FvAlignment;
350 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *FvInfoPpi;
351 EFI_PEI_PPI_DESCRIPTOR *FvInfoPpiDescriptor;
352
353 Status = EFI_NOT_FOUND;
354 Index = 0;
355
356 do {
357 VolumeStatus = DxeIplFindFirmwareVolumeInstance (
358 &Index,
359 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
360 &VolumeHandle,
361 &FileHandle
362 );
363
364 if (!EFI_ERROR (VolumeStatus)) {
365 Status = PeiServicesFfsFindSectionData (
366 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
367 (EFI_FFS_FILE_HEADER *)FileHandle,
368 (VOID **)&FvHeader
369 );
370
371 if (!EFI_ERROR (Status)) {
372 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
373 //
374 // Because FvLength in FvHeader is UINT64 type,
375 // so FvHeader must meed at least 8 bytes alignment.
376 // If current FvImage base address doesn't meet its alignment,
377 // we need to reload this FvImage to another correct memory address.
378 //
379 Status = GetFvAlignment(FvHeader, &FvAlignment);
380 if (EFI_ERROR(Status)) {
381 return Status;
382 }
383 if (((UINTN) FvHeader % FvAlignment) != 0) {
384 SectionHeader = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)((UINTN)FvHeader - sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
385 SectionLength = *(UINT32 *)SectionHeader->Size & 0x00FFFFFF;
386
387 DstBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) SectionLength - sizeof (EFI_COMMON_SECTION_HEADER)), FvAlignment);
388 if (DstBuffer == NULL) {
389 return EFI_OUT_OF_RESOURCES;
390 }
391 CopyMem (DstBuffer, FvHeader, (UINTN) SectionLength - sizeof (EFI_COMMON_SECTION_HEADER));
392 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DstBuffer;
393 }
394
395 //
396 // This new Firmware Volume comes from a firmware file within a firmware volume.
397 // Record the original Firmware Volume Name.
398 //
399 PeiServicesFfsGetVolumeInfo (&VolumeHandle, &VolumeInfo);
400
401 //
402 // Prepare to install FirmwareVolumeInfo PPI to expose new FV to PeiCore.
403 //
404 FvInfoPpi = AllocateCopyPool (sizeof (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI), &mFvInfoPpiTemplate);
405 ASSERT(FvInfoPpi != NULL);
406
407 FvInfoPpi->FvInfo = (VOID*)FvHeader;
408 FvInfoPpi->FvInfoSize = (UINT32)FvHeader->FvLength;
409 CopyMem (
410 &FvInfoPpi->ParentFvName,
411 &(VolumeInfo.FvName),
412 sizeof (EFI_GUID)
413 );
414 CopyMem (
415 &FvInfoPpi->ParentFileName,
416 &(((EFI_FFS_FILE_HEADER*)FileHandle)->Name),
417 sizeof (EFI_GUID)
418 );
419
420 FvInfoPpiDescriptor = AllocatePool (sizeof(EFI_PEI_PPI_DESCRIPTOR));
421 ASSERT (FvInfoPpiDescriptor != NULL);
422
423 FvInfoPpiDescriptor->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI|EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
424 FvInfoPpiDescriptor->Guid = &gEfiPeiFirmwareVolumeInfoPpiGuid;
425 FvInfoPpiDescriptor->Ppi = (VOID *) FvInfoPpi;
426
427 Status = PeiServicesInstallPpi (FvInfoPpiDescriptor);
428 ASSERT_EFI_ERROR (Status);
429
430 //
431 // Makes the encapsulated volume show up in DXE phase to skip processing of
432 // encapsulated file again.
433 //
434 BuildFv2Hob (
435 (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,
436 FvHeader->FvLength,
437 &VolumeInfo.FvName,
438 &(((EFI_FFS_FILE_HEADER *)FileHandle)->Name)
439 );
440 return Status;
441 }
442 }
443 }
444 } while (!EFI_ERROR (VolumeStatus));
445
446 return Status;
447 }
448
449 /**
450 Find the First Volume that contains the first FileType.
451
452 @param Instance The Fv instance.
453 @param SeachType The type of file to search.
454 @param VolumeHandle Pointer to Fv which contains the file to search.
455 @param FileHandle Pointer to FFS file to search.
456
457 @return EFI_SUCESS Success to find the FFS in specificed FV
458 @return others Fail to find the FFS in specificed FV
459 */
460 EFI_STATUS
461 DxeIplFindFirmwareVolumeInstance (
462 IN OUT UINTN *Instance,
463 IN EFI_FV_FILETYPE SeachType,
464 OUT EFI_PEI_FV_HANDLE *VolumeHandle,
465 OUT EFI_PEI_FILE_HANDLE *FileHandle
466 )
467 {
468 EFI_STATUS Status;
469 EFI_STATUS VolumeStatus;
470
471 do {
472 VolumeStatus = PeiServicesFfsFindNextVolume (*Instance, VolumeHandle);
473 if (!EFI_ERROR (VolumeStatus)) {
474 *FileHandle = NULL;
475 Status = PeiServicesFfsFindNextFile (SeachType, *VolumeHandle, FileHandle);
476 if (!EFI_ERROR (Status)) {
477 return Status;
478 }
479 }
480 *Instance += 1;
481 } while (!EFI_ERROR (VolumeStatus));
482
483 return VolumeStatus;
484 }
485
486 /**
487 Loads and relocates a PE/COFF image into memory.
488
489 @param FileHandle The image file handle
490 @param ImageAddress The base address of the relocated PE/COFF image
491 @param ImageSize The size of the relocated PE/COFF image
492 @param EntryPoint The entry point of the relocated PE/COFF image
493
494 @return EFI_SUCCESS The file was loaded and relocated
495 @return EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
496 **/
497 EFI_STATUS
498 PeiLoadFile (
499 IN EFI_PEI_FILE_HANDLE FileHandle,
500 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
501 OUT UINT64 *ImageSize,
502 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
503 )
504 {
505
506 EFI_STATUS Status;
507 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
508 VOID *Pe32Data;
509 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;
510
511 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();
512 //
513 // First try to find the required section in this ffs file.
514 //
515 Status = PeiServicesFfsFindSectionData (
516 EFI_SECTION_PE32,
517 FileHandle,
518 &Pe32Data
519 );
520
521 if (EFI_ERROR (Status)) {
522 Status = PeiServicesFfsFindSectionData (
523 EFI_SECTION_TE,
524 FileHandle,
525 &Pe32Data
526 );
527 }
528
529 if (EFI_ERROR (Status)) {
530 //
531 // NO image types we support so exit.
532 //
533 return Status;
534 }
535
536 ZeroMem (&ImageContext, sizeof (ImageContext));
537 ImageContext.Handle = Pe32Data;
538 Status = GetImageReadFunction (&ImageContext);
539
540 ASSERT_EFI_ERROR (Status);
541
542 Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);
543 if (EFI_ERROR (Status)) {
544 return Status;
545 }
546 //
547 // Allocate Memory for the image
548 //
549 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
550 ASSERT (ImageContext.ImageAddress != 0);
551
552 //
553 // Load the image to our new buffer
554 //
555 Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);
556 if (EFI_ERROR (Status)) {
557 return Status;
558 }
559 //
560 // Relocate the image in our new buffer
561 //
562 Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);
563 if (EFI_ERROR (Status)) {
564 return Status;
565 }
566
567 //
568 // Flush the instruction cache so the image data is written before we execute it
569 //
570 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
571
572 *ImageAddress = ImageContext.ImageAddress;
573 *ImageSize = ImageContext.ImageSize;
574 *EntryPoint = ImageContext.EntryPoint;
575
576 return EFI_SUCCESS;
577 }
578
579 /**
580 The ExtractSection() function processes the input section and
581 returns a pointer to the section contents. If the section being
582 extracted does not require processing (if the section
583 GuidedSectionHeader.Attributes has the
584 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
585 OutputBuffer is just updated to point to the start of the
586 section's contents. Otherwise, *Buffer must be allocated
587 from PEI permanent memory.
588
589 @param This Indicates the
590 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
591 Buffer containing the input GUIDed section to be
592 processed. OutputBuffer OutputBuffer is
593 allocated from PEI permanent memory and contains
594 the new section stream.
595
596 @param OutputSize A pointer to a caller-allocated
597 UINTN in which the size of *OutputBuffer
598 allocation is stored. If the function
599 returns anything other than EFI_SUCCESS,
600 the value of OutputSize is undefined.
601
602 @param AuthenticationStatus A pointer to a caller-allocated
603 UINT32 that indicates the
604 authentication status of the
605 output buffer. If the input
606 section's GuidedSectionHeader.
607 Attributes field has the
608 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
609 bit as clear,
610 AuthenticationStatus must return
611 zero. These bits reflect the
612 status of the extraction
613 operation. If the function
614 returns anything other than
615 EFI_SUCCESS, the value of
616 AuthenticationStatus is
617 undefined.
618
619 @retval EFI_SUCCESS The InputSection was
620 successfully processed and the
621 section contents were returned.
622
623 @retval EFI_OUT_OF_RESOURCES The system has insufficient
624 resources to process the request.
625
626 @reteval EFI_INVALID_PARAMETER The GUID in InputSection does
627 not match this instance of the
628 GUIDed Section Extraction PPI.
629 **/
630 EFI_STATUS
631 CustomDecompressExtractSection (
632 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
633 IN CONST VOID *InputSection,
634 OUT VOID **OutputBuffer,
635 OUT UINTN *OutputSize,
636 OUT UINT32 *AuthenticationStatus
637 )
638 {
639 EFI_STATUS Status;
640 UINT8 *ScratchBuffer;
641 UINT32 ScratchSize;
642 UINT32 SectionLength;
643 UINT32 DestinationSize;
644
645 //
646 // Set authentic value to zero.
647 //
648 *AuthenticationStatus = 0;
649 //
650 // Calculate Section data Size
651 //
652 SectionLength = *(UINT32 *) (((EFI_COMMON_SECTION_HEADER *) InputSection)->Size) & 0x00ffffff;
653 //
654 // Get compressed data information
655 //
656 Status = CustomDecompressGetInfo (
657 (GUID *) ((UINT8 *) InputSection + sizeof (EFI_COMMON_SECTION_HEADER)),
658 (UINT8 *) InputSection + sizeof (EFI_GUID_DEFINED_SECTION),
659 SectionLength - sizeof (EFI_GUID_DEFINED_SECTION),
660 &DestinationSize,
661 &ScratchSize
662 );
663 if (EFI_ERROR (Status)) {
664 //
665 // GetInfo failed
666 //
667 DEBUG ((EFI_D_ERROR, "Extract guided section Failed - %r\n", Status));
668 return Status;
669 }
670
671 //
672 // Allocate scratch buffer
673 //
674 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchSize));
675 if (ScratchBuffer == NULL) {
676 return EFI_OUT_OF_RESOURCES;
677 }
678 //
679 // Allocate destination buffer
680 //
681 *OutputSize = (UINTN) DestinationSize;
682 *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (*OutputSize));
683 if (*OutputBuffer == NULL) {
684 return EFI_OUT_OF_RESOURCES;
685 }
686
687 //
688 // Call decompress function
689 //
690 Status = CustomDecompress (
691 (GUID *) ((UINT8 *) InputSection + sizeof (EFI_COMMON_SECTION_HEADER)),
692 (UINT8 *) InputSection + sizeof (EFI_GUID_DEFINED_SECTION),
693 *OutputBuffer,
694 ScratchBuffer
695 );
696
697 if (EFI_ERROR (Status)) {
698 //
699 // Decompress failed
700 //
701 DEBUG ((EFI_D_ERROR, "Extract guided section Failed - %r\n", Status));
702 return Status;
703 }
704
705 return EFI_SUCCESS;
706 }
707
708 STATIC
709 EFI_STATUS
710 EFIAPI
711 Decompress (
712 IN CONST EFI_PEI_DECOMPRESS_PPI *This,
713 IN CONST EFI_COMPRESSION_SECTION *CompressionSection,
714 OUT VOID **OutputBuffer,
715 OUT UINTN *OutputSize
716 )
717 {
718 EFI_STATUS Status;
719 UINT8 *DstBuffer;
720 UINT8 *ScratchBuffer;
721 UINTN DstBufferSize;
722 UINT32 ScratchBufferSize;
723 EFI_COMMON_SECTION_HEADER *Section;
724 UINTN SectionLength;
725
726 if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
727 ASSERT (FALSE);
728 return EFI_INVALID_PARAMETER;
729 }
730
731 Section = (EFI_COMMON_SECTION_HEADER *) CompressionSection;
732 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
733
734 //
735 // This is a compression set, expand it
736 //
737 switch (CompressionSection->CompressionType) {
738 case EFI_STANDARD_COMPRESSION:
739 //
740 // Load EFI standard compression.
741 // For compressed data, decompress them to dstbuffer.
742 //
743 Status = UefiDecompressGetInfo (
744 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
745 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
746 (UINT32 *) &DstBufferSize,
747 &ScratchBufferSize
748 );
749 if (EFI_ERROR (Status)) {
750 //
751 // GetInfo failed
752 //
753 DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));
754 return EFI_NOT_FOUND;
755 }
756 //
757 // Allocate scratch buffer
758 //
759 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
760 if (ScratchBuffer == NULL) {
761 return EFI_OUT_OF_RESOURCES;
762 }
763 //
764 // Allocate destination buffer
765 //
766 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
767 if (DstBuffer == NULL) {
768 return EFI_OUT_OF_RESOURCES;
769 }
770 //
771 // Call decompress function
772 //
773 Status = UefiDecompress (
774 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
775 DstBuffer,
776 ScratchBuffer
777 );
778 if (EFI_ERROR (Status)) {
779 //
780 // Decompress failed
781 //
782 DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));
783 return EFI_NOT_FOUND;
784 }
785 break;
786
787 // porting note the original branch for customized compress is removed, it should be change to use GUID compress
788
789 case EFI_NOT_COMPRESSED:
790 //
791 // Allocate destination buffer
792 //
793 DstBufferSize = CompressionSection->UncompressedLength;
794 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
795 if (DstBuffer == NULL) {
796 return EFI_OUT_OF_RESOURCES;
797 }
798 //
799 // stream is not actually compressed, just encapsulated. So just copy it.
800 //
801 CopyMem (DstBuffer, CompressionSection + 1, DstBufferSize);
802 break;
803
804 default:
805 //
806 // Don't support other unknown compression type.
807 //
808 ASSERT (FALSE);
809 return EFI_NOT_FOUND;
810 }
811
812 *OutputSize = DstBufferSize;
813 *OutputBuffer = DstBuffer;
814
815 return EFI_SUCCESS;
816 }
817