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