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//
21CONST EFI_DXE_IPL_PPI mDxeIplPpi = {
22  DxeLoadCore
23};
24
25CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {
26  CustomGuidedSectionExtract
27};
28
29CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
30  Decompress
31};
32
33CONST 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
46CONST 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**/
65EFI_STATUS
66EFIAPI
67PeimInitializeDxeIpl (
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**/
160EFI_STATUS
161EFIAPI
162CustomGuidedSectionExtract (
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**/
263EFI_STATUS
264EFIAPI
265Decompress (
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**/
405EFI_STATUS
406EFIAPI
407DxeLoadCore (
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