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