1 /** @file
2 
3   Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
4   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 **/
13 
14 #include "DxeIpl.h"
15 
16 
17 //
18 // Module Globals used in the DXE to PEI hand off
19 // These must be module globals, so the stack can be switched
20 //
21 CONST EFI_DXE_IPL_PPI mDxeIplPpi = {
22   DxeLoadCore
23 };
24 
25 CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {
26   CustomGuidedSectionExtract
27 };
28 
29 CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
30   Decompress
31 };
32 
33 CONST EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {
34   {
35     EFI_PEI_PPI_DESCRIPTOR_PPI,
36     &gEfiDxeIplPpiGuid,
37     (VOID *) &mDxeIplPpi
38   },
39   {
40     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
41     &gEfiPeiDecompressPpiGuid,
42     (VOID *) &mDecompressPpi
43   }
44 };
45 
46 CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = {
47   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
48   &gEfiEndOfPeiSignalPpiGuid,
49   NULL
50 };
51 
52 /**
53   Entry point of DXE IPL PEIM.
54 
55   This function installs DXE IPL PPI and Decompress PPI.  It also reloads
56   itself to memory on non-S3 resume boot path.
57 
58   @param[in] FileHandle  Handle of the file being invoked.
59   @param[in] PeiServices Describes the list of possible PEI Services.
60 
61   @retval EFI_SUCESS  The entry point of DXE IPL PEIM executes successfully.
62   @retval Others      Some error occurs during the execution of this function.
63 
64 **/
65 EFI_STATUS
66 EFIAPI
PeimInitializeDxeIpl(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)67 PeimInitializeDxeIpl (
68   IN       EFI_PEI_FILE_HANDLE  FileHandle,
69   IN CONST EFI_PEI_SERVICES     **PeiServices
70   )
71 {
72   EFI_STATUS                                Status;
73   EFI_GUID                                  *ExtractHandlerGuidTable;
74   UINTN                                     ExtractHandlerNumber;
75   EFI_PEI_PPI_DESCRIPTOR                    *GuidPpi;
76 
77   //
78   // Get custom extract guided section method guid list
79   //
80   ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);
81 
82   //
83   // Install custom extraction guid PPI
84   //
85   if (ExtractHandlerNumber > 0) {
86     GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR));
87     ASSERT (GuidPpi != NULL);
88     while (ExtractHandlerNumber-- > 0) {
89       GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
90       GuidPpi->Ppi   = (VOID *) &mCustomGuidedSectionExtractionPpi;
91       GuidPpi->Guid  = &ExtractHandlerGuidTable[ExtractHandlerNumber];
92       Status = PeiServicesInstallPpi (GuidPpi++);
93       ASSERT_EFI_ERROR(Status);
94     }
95   }
96 
97   //
98   // Install DxeIpl and Decompress PPIs.
99   //
100   Status = PeiServicesInstallPpi (mPpiList);
101   ASSERT_EFI_ERROR(Status);
102 
103   return Status;
104 }
105 
106 /**
107   The ExtractSection() function processes the input section and
108   returns a pointer to the section contents. If the section being
109   extracted does not require processing (if the section
110   GuidedSectionHeader.Attributes has the
111   EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
112   OutputBuffer is just updated to point to the start of the
113   section's contents. Otherwise, *Buffer must be allocated
114   from PEI permanent memory.
115 
116   @param[in]  This                   Indicates the
117                                      EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
118                                      Buffer containing the input GUIDed section to be
119                                      processed. OutputBuffer OutputBuffer is
120                                      allocated from PEI permanent memory and contains
121                                      the new section stream.
122   @param[in]  InputSection           A pointer to the input buffer, which contains
123                                      the input section to be processed.
124   @param[out] OutputBuffer           A pointer to a caller-allocated buffer, whose
125                                      size is specified by the contents of OutputSize.
126   @param[out] OutputSize             A pointer to a caller-allocated
127                                      UINTN in which the size of *OutputBuffer
128                                      allocation is stored. If the function
129                                      returns anything other than EFI_SUCCESS,
130                                      the value of OutputSize is undefined.
131   @param[out] AuthenticationStatus   A pointer to a caller-allocated
132                                      UINT32 that indicates the
133                                      authentication status of the
134                                      output buffer. If the input
135                                      section's GuidedSectionHeader.
136                                      Attributes field has the
137                                      EFI_GUIDED_SECTION_AUTH_STATUS_VALID
138                                      bit as clear,
139                                      AuthenticationStatus must return
140                                      zero. These bits reflect the
141                                      status of the extraction
142                                      operation. If the function
143                                      returns anything other than
144                                      EFI_SUCCESS, the value of
145                                      AuthenticationStatus is
146                                      undefined.
147 
148   @retval EFI_SUCCESS           The InputSection was
149                                 successfully processed and the
150                                 section contents were returned.
151 
152   @retval EFI_OUT_OF_RESOURCES  The system has insufficient
153                                 resources to process the request.
154 
155   @retval EFI_INVALID_PARAMETER The GUID in InputSection does
156                                 not match this instance of the
157                                 GUIDed Section Extraction PPI.
158 
159 **/
160 EFI_STATUS
161 EFIAPI
CustomGuidedSectionExtract(IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI * This,IN CONST VOID * InputSection,OUT VOID ** OutputBuffer,OUT UINTN * OutputSize,OUT UINT32 * AuthenticationStatus)162 CustomGuidedSectionExtract (
163   IN CONST  EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
164   IN CONST  VOID                                  *InputSection,
165   OUT       VOID                                  **OutputBuffer,
166   OUT       UINTN                                 *OutputSize,
167   OUT       UINT32                                *AuthenticationStatus
168 )
169 {
170   EFI_STATUS      Status;
171   UINT8           *ScratchBuffer;
172   UINT32          ScratchBufferSize;
173   UINT32          OutputBufferSize;
174   UINT16          SectionAttribute;
175 
176   //
177   // Init local variable
178   //
179   ScratchBuffer = NULL;
180 
181   //
182   // Call GetInfo to get the size and attribute of input guided section data.
183   //
184   Status = ExtractGuidedSectionGetInfo (
185              InputSection,
186              &OutputBufferSize,
187              &ScratchBufferSize,
188              &SectionAttribute
189              );
190 
191   if (EFI_ERROR (Status)) {
192     DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
193     return Status;
194   }
195 
196   if (ScratchBufferSize != 0) {
197     //
198     // Allocate scratch buffer
199     //
200     ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
201     if (ScratchBuffer == NULL) {
202       return EFI_OUT_OF_RESOURCES;
203     }
204   }
205 
206   if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) {
207     //
208     // Allocate output buffer
209     //
210     *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1);
211     if (*OutputBuffer == NULL) {
212       return EFI_OUT_OF_RESOURCES;
213     }
214     DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer));
215     //
216     // *OutputBuffer still is one section. Adjust *OutputBuffer offset,
217     // skip EFI section header to make section data at page alignment.
218     //
219     *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER));
220   }
221 
222   Status = ExtractGuidedSectionDecode (
223              InputSection,
224              OutputBuffer,
225              ScratchBuffer,
226              AuthenticationStatus
227              );
228   if (EFI_ERROR (Status)) {
229     //
230     // Decode failed
231     //
232     DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
233     return Status;
234   }
235 
236   *OutputSize = (UINTN) OutputBufferSize;
237 
238   return EFI_SUCCESS;
239 }
240 
241 
242 
243 /**
244    Decompresses a section to the output buffer.
245 
246    This function looks up the compression type field in the input section and
247    applies the appropriate compression algorithm to compress the section to a
248    callee allocated buffer.
249 
250    @param[in]  This                  Points to this instance of the
251                                      EFI_PEI_DECOMPRESS_PEI PPI.
252    @param[in]  CompressionSection    Points to the compressed section.
253    @param[out] OutputBuffer          Holds the returned pointer to the decompressed
254                                      sections.
255    @param[out] OutputSize            Holds the returned size of the decompress
256                                      section streams.
257 
258    @retval EFI_SUCCESS           The section was decompressed successfully.
259                                  OutputBuffer contains the resulting data and
260                                  OutputSize contains the resulting size.
261 
262 **/
263 EFI_STATUS
264 EFIAPI
Decompress(IN CONST EFI_PEI_DECOMPRESS_PPI * This,IN CONST EFI_COMPRESSION_SECTION * CompressionSection,OUT VOID ** OutputBuffer,OUT UINTN * OutputSize)265 Decompress (
266   IN CONST  EFI_PEI_DECOMPRESS_PPI  *This,
267   IN CONST  EFI_COMPRESSION_SECTION *CompressionSection,
268   OUT       VOID                    **OutputBuffer,
269   OUT       UINTN                   *OutputSize
270  )
271 {
272   EFI_STATUS                      Status;
273   UINT8                           *DstBuffer;
274   UINT8                           *ScratchBuffer;
275   UINT32                          DstBufferSize;
276   UINT32                          ScratchBufferSize;
277   VOID                            *CompressionSource;
278   UINT32                          CompressionSourceSize;
279   UINT32                          UncompressedLength;
280   UINT8                           CompressionType;
281 
282   if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
283     ASSERT (FALSE);
284     return EFI_INVALID_PARAMETER;
285   }
286 
287   if (IS_SECTION2 (CompressionSection)) {
288     CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2));
289     CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2));
290     UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength;
291     CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType;
292   } else {
293     CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION));
294     CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION));
295     UncompressedLength = CompressionSection->UncompressedLength;
296     CompressionType = CompressionSection->CompressionType;
297   }
298 
299   //
300   // This is a compression set, expand it
301   //
302   switch (CompressionType) {
303   case EFI_STANDARD_COMPRESSION:
304     //
305     // Load EFI standard compression.
306     // For compressed data, decompress them to destination buffer.
307     //
308     Status = UefiDecompressGetInfo (
309                CompressionSource,
310                CompressionSourceSize,
311                &DstBufferSize,
312                &ScratchBufferSize
313                );
314     if (EFI_ERROR (Status)) {
315       //
316       // GetInfo failed
317       //
318       DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));
319       return EFI_NOT_FOUND;
320     }
321     //
322     // Allocate scratch buffer
323     //
324     ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
325     if (ScratchBuffer == NULL) {
326       return EFI_OUT_OF_RESOURCES;
327     }
328     //
329     // Allocate destination buffer, extra one page for adjustment
330     //
331     DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
332     if (DstBuffer == NULL) {
333       return EFI_OUT_OF_RESOURCES;
334     }
335     //
336     // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
337     // to make section data at page alignment.
338     //
339     DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
340     //
341     // Call decompress function
342     //
343     Status = UefiDecompress (
344                 CompressionSource,
345                 DstBuffer,
346                 ScratchBuffer
347                 );
348     if (EFI_ERROR (Status)) {
349       //
350       // Decompress failed
351       //
352       DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));
353       return EFI_NOT_FOUND;
354     }
355     break;
356 
357   case EFI_NOT_COMPRESSED:
358     //
359     // Allocate destination buffer
360     //
361     DstBufferSize = UncompressedLength;
362     DstBuffer     = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
363     if (DstBuffer == NULL) {
364       return EFI_OUT_OF_RESOURCES;
365     }
366     //
367     // Adjust DstBuffer offset, skip EFI section header
368     // to make section data at page alignment.
369     //
370     DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
371     //
372     // stream is not actually compressed, just encapsulated.  So just copy it.
373     //
374     CopyMem (DstBuffer, CompressionSource, DstBufferSize);
375     break;
376 
377   default:
378     //
379     // Don't support other unknown compression type.
380     //
381     ASSERT (FALSE);
382     return EFI_NOT_FOUND;
383   }
384 
385   *OutputSize = DstBufferSize;
386   *OutputBuffer = DstBuffer;
387 
388   return EFI_SUCCESS;
389 }
390 
391 /**
392    Main entry point to last PEIM.
393 
394    This function finds DXE Core in the firmware volume and transfer the control to
395    DXE core.
396 
397    @param[in] This          Entry point for DXE IPL PPI.
398    @param[in] PeiServices   General purpose services available to every PEIM.
399    @param[in] HobList       Address to the Pei HOB list.
400 
401    @return EFI_SUCCESS              DXE core was successfully loaded.
402    @return EFI_OUT_OF_RESOURCES     There are not enough resources to load DXE core.
403 
404 **/
405 EFI_STATUS
406 EFIAPI
DxeLoadCore(IN CONST EFI_DXE_IPL_PPI * This,IN EFI_PEI_SERVICES ** PeiServices,IN EFI_PEI_HOB_POINTERS HobList)407 DxeLoadCore (
408   IN CONST EFI_DXE_IPL_PPI *This,
409   IN EFI_PEI_SERVICES      **PeiServices,
410   IN EFI_PEI_HOB_POINTERS  HobList
411   )
412 {
413   EFI_STATUS   Status;
414 
415   DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP HOB is located at 0x%08X\n", HobList));
416 
417   //
418   // End of PEI phase signal
419   //
420   Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);
421   ASSERT_EFI_ERROR (Status);
422 
423   //
424   // Give control back to BootLoader after FspInit
425   //
426   DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP is waiting for NOTIFY\n"));
427   FspInitDone ();
428 
429   //
430   // BootLoader called FSP again through NotifyPhase
431   //
432   FspWaitForNotify ();
433 
434 
435   //
436   // Give control back to the boot loader framework caller
437   //
438   DEBUG ((DEBUG_INFO | DEBUG_INIT,   "============= PEIM FSP is Completed =============\n\n"));
439 
440   SetFspApiReturnStatus(EFI_SUCCESS);
441 
442   SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_RDYBOOT_EXIT);
443 
444   Pei2LoaderSwitchStack();
445 
446   //
447   // Should not come here
448   //
449   while (TRUE) {
450     DEBUG ((DEBUG_ERROR, "No FSP API should be called after FSP is DONE!\n"));
451     SetFspApiReturnStatus(EFI_UNSUPPORTED);
452     Pei2LoaderSwitchStack();
453   }
454 
455   return EFI_SUCCESS;
456 }
457