95276127 |
1 | /*++\r |
2 | \r |
3 | Copyright (c) 2006, Intel Corporation\r |
4 | All rights reserved. This program and the accompanying materials\r |
5 | are licensed and made available under the terms and conditions of the BSD License\r |
6 | which accompanies this distribution. The full text of the license may be found at\r |
7 | http://opensource.org/licenses/bsd-license.php\r |
8 | \r |
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
11 | \r |
12 | Module Name:\r |
13 | \r |
14 | DxeLoad.c\r |
15 | \r |
16 | Abstract:\r |
17 | \r |
18 | Last PEIM.\r |
19 | Responsibility of this module is to load the DXE Core from a Firmware Volume.\r |
20 | \r |
21 | --*/\r |
22 | \r |
95276127 |
23 | #include "DxeIpl.h"\r |
24 | \r |
25 | // porting note remove later\r |
26 | #include "Common/DecompressLibraryHob.h"\r |
27 | #include "FrameworkPei.h"\r |
28 | // end of remove later\r |
29 | \r |
30 | BOOLEAN gInMemory = FALSE;\r |
31 | \r |
32 | //\r |
33 | // Module Globals used in the DXE to PEI handoff\r |
34 | // These must be module globals, so the stack can be switched\r |
35 | //\r |
36 | static EFI_DXE_IPL_PPI mDxeIplPpi = {\r |
37 | DxeLoadCore\r |
38 | };\r |
39 | \r |
40 | static EFI_PEI_FV_FILE_LOADER_PPI mLoadFilePpi = {\r |
41 | DxeIplLoadFile\r |
42 | };\r |
43 | \r |
44 | static EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {\r |
45 | {\r |
46 | EFI_PEI_PPI_DESCRIPTOR_PPI,\r |
47 | &gEfiPeiFvFileLoaderPpiGuid,\r |
48 | &mLoadFilePpi\r |
49 | },\r |
50 | {\r |
51 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
52 | &gEfiDxeIplPpiGuid,\r |
53 | &mDxeIplPpi\r |
54 | }\r |
55 | };\r |
56 | \r |
57 | static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = {\r |
58 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
59 | &gEfiEndOfPeiSignalPpiGuid,\r |
60 | NULL\r |
61 | };\r |
62 | \r |
63 | GLOBAL_REMOVE_IF_UNREFERENCED DECOMPRESS_LIBRARY gEfiDecompress = {\r |
64 | UefiDecompressGetInfo,\r |
65 | UefiDecompress\r |
66 | };\r |
67 | \r |
68 | GLOBAL_REMOVE_IF_UNREFERENCED DECOMPRESS_LIBRARY gCustomDecompress = {\r |
69 | CustomDecompressGetInfo,\r |
70 | CustomDecompress\r |
71 | };\r |
72 | \r |
73 | EFI_STATUS\r |
74 | EFIAPI\r |
75 | PeimInitializeDxeIpl (\r |
76 | IN EFI_FFS_FILE_HEADER *FfsHeader,\r |
77 | IN EFI_PEI_SERVICES **PeiServices\r |
78 | )\r |
79 | /*++\r |
80 | \r |
81 | Routine Description:\r |
82 | \r |
83 | Initializes the Dxe Ipl PPI\r |
84 | \r |
85 | Arguments:\r |
86 | \r |
87 | FfsHeader - Pointer to FFS file header\r |
88 | PeiServices - General purpose services available to every PEIM.\r |
89 | \r |
90 | Returns:\r |
91 | \r |
92 | EFI_SUCCESS\r |
93 | \r |
94 | --*/\r |
95 | {\r |
96 | EFI_STATUS Status;\r |
97 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
98 | EFI_BOOT_MODE BootMode;\r |
99 | \r |
100 | Status = PeiServicesGetBootMode (&BootMode);\r |
101 | ASSERT_EFI_ERROR (Status);\r |
102 | \r |
103 | if (!gInMemory && (BootMode != BOOT_ON_S3_RESUME)) { \r |
104 | //\r |
105 | // The DxeIpl has not yet been shadowed\r |
106 | //\r |
107 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
108 | \r |
109 | //\r |
110 | // Shadow DxeIpl and then re-run its entry point\r |
111 | //\r |
112 | Status = ShadowDxeIpl (FfsHeader, PeiEfiPeiPeCoffLoader);\r |
113 | } else {\r |
114 | //\r |
115 | // Install FvFileLoader and DxeIpl PPIs.\r |
116 | //\r |
117 | Status = PeiServicesInstallPpi (mPpiList);\r |
118 | ASSERT_EFI_ERROR(Status);\r |
119 | }\r |
120 | \r |
121 | return Status;\r |
122 | }\r |
123 | \r |
124 | EFI_STATUS\r |
125 | EFIAPI\r |
126 | DxeLoadCore (\r |
127 | IN EFI_DXE_IPL_PPI *This,\r |
128 | IN EFI_PEI_SERVICES **PeiServices,\r |
129 | IN EFI_PEI_HOB_POINTERS HobList\r |
130 | )\r |
131 | /*++\r |
132 | \r |
133 | Routine Description:\r |
134 | \r |
135 | Main entry point to last PEIM\r |
136 | \r |
137 | Arguments:\r |
138 | This - Entry point for DXE IPL PPI\r |
139 | PeiServices - General purpose services available to every PEIM.\r |
140 | HobList - Address to the Pei HOB list\r |
141 | \r |
142 | Returns:\r |
143 | \r |
144 | EFI_SUCCESS - DEX core was successfully loaded.\r |
145 | EFI_OUT_OF_RESOURCES - There are not enough resources to load DXE core.\r |
146 | \r |
147 | --*/\r |
148 | {\r |
149 | EFI_STATUS Status;\r |
150 | EFI_GUID DxeCoreFileName;\r |
151 | EFI_GUID FirmwareFileName;\r |
152 | VOID *Pe32Data;\r |
153 | VOID *FvImageData; \r |
154 | EFI_PHYSICAL_ADDRESS DxeCoreAddress;\r |
155 | UINT64 DxeCoreSize;\r |
156 | EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;\r |
157 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
158 | EFI_BOOT_MODE BootMode;\r |
159 | EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;\r |
160 | EFI_PEI_S3_RESUME_PPI *S3Resume;\r |
161 | \r |
162 | // PERF_START (PeiServices, L"DxeIpl", NULL, 0);\r |
163 | \r |
164 | //\r |
165 | // if in S3 Resume, restore configure\r |
166 | //\r |
167 | Status = PeiServicesGetBootMode (&BootMode);\r |
168 | ASSERT_EFI_ERROR(Status);\r |
169 | \r |
170 | if (BootMode == BOOT_ON_S3_RESUME) {\r |
171 | Status = PeiServicesLocatePpi (\r |
172 | &gEfiPeiS3ResumePpiGuid,\r |
173 | 0,\r |
174 | NULL,\r |
175 | (VOID **)&S3Resume\r |
176 | );\r |
177 | ASSERT_EFI_ERROR (Status);\r |
178 | \r |
179 | Status = S3Resume->S3RestoreConfig (PeiServices);\r |
180 | ASSERT_EFI_ERROR (Status);\r |
181 | } else if (BootMode == BOOT_IN_RECOVERY_MODE) {\r |
182 | \r |
183 | Status = PeiServicesLocatePpi (\r |
184 | &gEfiPeiRecoveryModulePpiGuid,\r |
185 | 0,\r |
186 | NULL,\r |
187 | (VOID **)&PeiRecovery\r |
188 | );\r |
189 | ASSERT_EFI_ERROR (Status);\r |
190 | \r |
191 | Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);\r |
192 | if (EFI_ERROR (Status)) {\r |
193 | DEBUG ((EFI_D_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));\r |
194 | CpuDeadLoop ();\r |
195 | }\r |
196 | \r |
197 | //\r |
198 | // Now should have a HOB with the DXE core w/ the old HOB destroyed\r |
199 | //\r |
200 | }\r |
201 | \r |
202 | //\r |
203 | // Install the PEI Protocols that are shared between PEI and DXE\r |
204 | //\r |
205 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
206 | ASSERT (PeiEfiPeiPeCoffLoader != NULL);\r |
207 | \r |
208 | \r |
209 | //\r |
210 | // Find the EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE type compressed Firmware Volume file\r |
211 | // The file found will be processed by PeiProcessFile: It will first be decompressed to\r |
212 | // a normal FV, then a corresponding FV type hob will be built. \r |
213 | //\r |
214 | Status = PeiFindFile (\r |
215 | EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,\r |
216 | EFI_SECTION_FIRMWARE_VOLUME_IMAGE,\r |
217 | &FirmwareFileName,\r |
218 | &FvImageData\r |
219 | );\r |
220 | \r |
221 | //\r |
222 | // Find the DXE Core in a Firmware Volume\r |
223 | //\r |
224 | Status = PeiFindFile (\r |
225 | EFI_FV_FILETYPE_DXE_CORE,\r |
226 | EFI_SECTION_PE32,\r |
227 | &DxeCoreFileName,\r |
228 | &Pe32Data\r |
229 | );\r |
230 | ASSERT_EFI_ERROR (Status);\r |
231 | \r |
232 | //\r |
233 | // Load the DXE Core from a Firmware Volume\r |
234 | //\r |
235 | Status = PeiLoadFile (\r |
236 | PeiEfiPeiPeCoffLoader,\r |
237 | Pe32Data,\r |
238 | &DxeCoreAddress,\r |
239 | &DxeCoreSize,\r |
240 | &DxeCoreEntryPoint\r |
241 | );\r |
242 | ASSERT_EFI_ERROR (Status);\r |
243 | \r |
244 | //\r |
245 | // Add HOB for the DXE Core\r |
246 | //\r |
247 | BuildModuleHob (\r |
248 | &DxeCoreFileName,\r |
249 | DxeCoreAddress,\r |
250 | DxeCoreSize,\r |
251 | DxeCoreEntryPoint\r |
252 | );\r |
253 | \r |
254 | //\r |
255 | // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT\r |
256 | //\r |
257 | REPORT_STATUS_CODE (\r |
258 | EFI_PROGRESS_CODE,\r |
259 | EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT\r |
260 | );\r |
261 | \r |
262 | if (FeaturePcdGet (PcdDxeIplBuildShareCodeHobs)) {\r |
263 | if (FeaturePcdGet (PcdDxeIplSupportEfiDecompress)) {\r |
264 | //\r |
265 | // Add HOB for the EFI Decompress Protocol\r |
266 | //\r |
267 | BuildGuidDataHob (\r |
268 | &gEfiDecompressProtocolGuid,\r |
269 | (VOID *)&gEfiDecompress,\r |
270 | sizeof (gEfiDecompress)\r |
271 | );\r |
272 | }\r |
273 | if (FeaturePcdGet (PcdDxeIplSupportCustomDecompress)) {\r |
274 | //\r |
275 | // Add HOB for the user customized Decompress Protocol\r |
276 | //\r |
277 | BuildGuidDataHob (\r |
278 | &gEfiCustomizedDecompressProtocolGuid,\r |
279 | (VOID *)&gCustomDecompress,\r |
280 | sizeof (gCustomDecompress)\r |
281 | );\r |
282 | }\r |
283 | \r |
284 | //\r |
285 | // Add HOB for the PE/COFF Loader Protocol\r |
286 | //\r |
287 | BuildGuidDataHob (\r |
288 | &gEfiPeiPeCoffLoaderGuid,\r |
289 | (VOID *)&PeiEfiPeiPeCoffLoader,\r |
290 | sizeof (VOID *)\r |
291 | );\r |
292 | }\r |
293 | \r |
294 | //\r |
295 | // Transfer control to the DXE Core\r |
296 | // The handoff state is simply a pointer to the HOB list\r |
297 | //\r |
298 | \r |
299 | DEBUG ((EFI_D_INFO, "DXE Core Entry Point 0x%08x\n", (UINTN) DxeCoreEntryPoint));\r |
300 | HandOffToDxeCore (DxeCoreEntryPoint, HobList, &mPpiSignal);\r |
301 | //\r |
302 | // If we get here, then the DXE Core returned. This is an error\r |
303 | // Dxe Core should not return.\r |
304 | //\r |
305 | ASSERT (FALSE);\r |
306 | CpuDeadLoop ();\r |
307 | \r |
308 | return EFI_OUT_OF_RESOURCES;\r |
309 | }\r |
310 | \r |
311 | EFI_STATUS\r |
312 | PeiFindFile (\r |
313 | IN UINT8 Type,\r |
314 | IN UINT16 SectionType,\r |
315 | OUT EFI_GUID *FileName,\r |
316 | OUT VOID **Pe32Data\r |
317 | )\r |
318 | /*++\r |
319 | \r |
320 | Routine Description:\r |
321 | \r |
322 | Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes\r |
323 | described in the HOB list. Able to search in a compression set in a FFS file.\r |
324 | But only one level of compression is supported, that is, not able to search\r |
325 | in a compression set that is within another compression set.\r |
326 | \r |
327 | Arguments:\r |
328 | \r |
329 | Type - The Type of file to retrieve\r |
330 | \r |
331 | SectionType - The type of section to retrieve from a file\r |
332 | \r |
333 | FileName - The name of the file found in the Firmware Volume\r |
334 | \r |
335 | Pe32Data - Pointer to the beginning of the PE/COFF file found in the Firmware Volume\r |
336 | \r |
337 | Returns:\r |
338 | \r |
339 | EFI_SUCCESS - The file was found, and the name is returned in FileName, and a pointer to\r |
340 | the PE/COFF image is returned in Pe32Data\r |
341 | \r |
342 | EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List\r |
343 | \r |
344 | --*/\r |
345 | {\r |
346 | EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r |
347 | EFI_FFS_FILE_HEADER *FfsFileHeader;\r |
348 | EFI_STATUS Status;\r |
349 | EFI_PEI_HOB_POINTERS Hob;\r |
350 | \r |
351 | \r |
352 | FwVolHeader = NULL;\r |
353 | FfsFileHeader = NULL;\r |
354 | Status = EFI_SUCCESS;\r |
355 | \r |
356 | //\r |
357 | // For each Firmware Volume, look for a specified type\r |
358 | // of file and break out until no one is found \r |
359 | //\r |
360 | Hob.Raw = GetHobList ();\r |
361 | while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw)) != NULL) {\r |
362 | FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress);\r |
363 | //\r |
364 | // Make sure the FV HOB does not get corrupted.\r |
365 | //\r |
366 | ASSERT (FwVolHeader->Signature == EFI_FVH_SIGNATURE);\r |
367 | \r |
368 | Status = PeiServicesFfsFindNextFile (\r |
369 | Type,\r |
370 | FwVolHeader,\r |
371 | &FfsFileHeader\r |
372 | );\r |
373 | if (!EFI_ERROR (Status)) {\r |
374 | Status = PeiProcessFile (\r |
375 | SectionType,\r |
376 | FfsFileHeader,\r |
377 | Pe32Data,\r |
378 | &Hob\r |
379 | );\r |
380 | CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));\r |
381 | //\r |
382 | // Find all Fv type ffs to get all FvImage and add them into FvHob\r |
383 | //\r |
384 | if (!EFI_ERROR (Status) && (Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE)) {\r |
385 | return EFI_SUCCESS;\r |
386 | }\r |
387 | }\r |
388 | Hob.Raw = GET_NEXT_HOB (Hob);\r |
389 | }\r |
390 | return EFI_NOT_FOUND;\r |
391 | }\r |
392 | \r |
393 | EFI_STATUS\r |
394 | PeiLoadFile (\r |
395 | IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,\r |
396 | IN VOID *Pe32Data,\r |
397 | OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r |
398 | OUT UINT64 *ImageSize,\r |
399 | OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r |
400 | )\r |
401 | /*++\r |
402 | \r |
403 | Routine Description:\r |
404 | \r |
405 | Loads and relocates a PE/COFF image into memory.\r |
406 | \r |
407 | Arguments:\r |
408 | \r |
409 | PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r |
410 | \r |
411 | Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r |
412 | \r |
413 | ImageAddress - The base address of the relocated PE/COFF image\r |
414 | \r |
415 | ImageSize - The size of the relocated PE/COFF image\r |
416 | \r |
417 | EntryPoint - The entry point of the relocated PE/COFF image\r |
418 | \r |
419 | Returns:\r |
420 | \r |
421 | EFI_SUCCESS - The file was loaded and relocated\r |
422 | \r |
423 | EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r |
424 | \r |
425 | --*/\r |
426 | {\r |
427 | EFI_STATUS Status;\r |
428 | PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r |
429 | \r |
430 | ZeroMem (&ImageContext, sizeof (ImageContext));\r |
431 | ImageContext.Handle = Pe32Data;\r |
432 | Status = GetImageReadFunction (&ImageContext);\r |
433 | \r |
434 | ASSERT_EFI_ERROR (Status);\r |
435 | \r |
436 | Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);\r |
437 | if (EFI_ERROR (Status)) {\r |
438 | return Status;\r |
439 | }\r |
440 | //\r |
441 | // Allocate Memory for the image\r |
442 | //\r |
443 | ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));\r |
444 | ASSERT (ImageContext.ImageAddress != 0);\r |
445 | \r |
446 | //\r |
447 | // Load the image to our new buffer\r |
448 | //\r |
449 | Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r |
450 | if (EFI_ERROR (Status)) {\r |
451 | return Status;\r |
452 | }\r |
453 | //\r |
454 | // Relocate the image in our new buffer\r |
455 | //\r |
456 | Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r |
457 | if (EFI_ERROR (Status)) {\r |
458 | return Status;\r |
459 | }\r |
460 | \r |
461 | //\r |
462 | // Flush the instruction cache so the image data is written before we execute it\r |
463 | //\r |
464 | InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r |
465 | \r |
466 | *ImageAddress = ImageContext.ImageAddress;\r |
467 | *ImageSize = ImageContext.ImageSize;\r |
468 | *EntryPoint = ImageContext.EntryPoint;\r |
469 | \r |
470 | return EFI_SUCCESS;\r |
471 | }\r |
472 | \r |
473 | EFI_STATUS\r |
474 | ShadowDxeIpl (\r |
475 | IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,\r |
476 | IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader\r |
477 | )\r |
478 | /*++\r |
479 | \r |
480 | Routine Description:\r |
481 | \r |
482 | Shadow the DXE IPL to a different memory location. This occurs after permanent\r |
483 | memory has been discovered.\r |
484 | \r |
485 | Arguments:\r |
486 | \r |
487 | DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver\r |
488 | \r |
489 | PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r |
490 | \r |
491 | Returns:\r |
492 | \r |
493 | EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.\r |
494 | \r |
495 | EFI_ ERROR - The shadow was unsuccessful.\r |
496 | \r |
497 | \r |
498 | --*/\r |
499 | {\r |
500 | UINTN SectionLength;\r |
501 | UINTN OccupiedSectionLength;\r |
502 | EFI_PHYSICAL_ADDRESS DxeIplAddress;\r |
503 | UINT64 DxeIplSize;\r |
504 | EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;\r |
505 | EFI_STATUS Status;\r |
506 | EFI_COMMON_SECTION_HEADER *Section;\r |
507 | \r |
508 | Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);\r |
509 | \r |
510 | while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {\r |
511 | SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r |
512 | OccupiedSectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r |
513 | Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r |
514 | }\r |
515 | //\r |
516 | // Relocate DxeIpl into memory by using loadfile service\r |
517 | //\r |
518 | Status = PeiLoadFile (\r |
519 | PeiEfiPeiPeCoffLoader,\r |
520 | (VOID *) (Section + 1),\r |
521 | &DxeIplAddress,\r |
522 | &DxeIplSize,\r |
523 | &DxeIplEntryPoint\r |
524 | );\r |
525 | \r |
526 | if (Status == EFI_SUCCESS) {\r |
527 | //\r |
528 | // Set gInMemory global variable to TRUE to indicate the dxeipl is shadowed.\r |
529 | //\r |
530 | *(BOOLEAN *) ((UINTN) &gInMemory + (UINTN) DxeIplEntryPoint - (UINTN) _ModuleEntryPoint) = TRUE;\r |
531 | Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) ((EFI_PEI_FILE_HANDLE *) DxeIplFileHeader, GetPeiServicesTablePointer());\r |
532 | }\r |
533 | \r |
534 | return Status;\r |
535 | }\r |
536 | \r |
537 | EFI_STATUS\r |
538 | EFIAPI\r |
539 | DxeIplLoadFile (\r |
540 | IN EFI_PEI_FV_FILE_LOADER_PPI *This,\r |
541 | IN EFI_FFS_FILE_HEADER *FfsHeader,\r |
542 | OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r |
543 | OUT UINT64 *ImageSize,\r |
544 | OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r |
545 | )\r |
546 | /*++\r |
547 | \r |
548 | Routine Description:\r |
549 | \r |
550 | Given a pointer to an FFS file containing a PE32 image, get the\r |
551 | information on the PE32 image, and then "load" it so that it\r |
552 | can be executed.\r |
553 | \r |
554 | Arguments:\r |
555 | \r |
556 | This - pointer to our file loader protocol\r |
557 | \r |
558 | FfsHeader - pointer to the FFS file header of the FFS file that\r |
559 | contains the PE32 image we want to load\r |
560 | \r |
561 | ImageAddress - returned address where the PE32 image is loaded\r |
562 | \r |
563 | ImageSize - returned size of the loaded PE32 image\r |
564 | \r |
565 | EntryPoint - entry point to the loaded PE32 image\r |
566 | \r |
567 | Returns:\r |
568 | \r |
569 | EFI_SUCCESS - The FFS file was successfully loaded.\r |
570 | \r |
571 | EFI_ERROR - Unable to load the FFS file.\r |
572 | \r |
573 | --*/\r |
574 | {\r |
575 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
576 | EFI_STATUS Status;\r |
577 | VOID *Pe32Data;\r |
578 | \r |
579 | Pe32Data = NULL;\r |
580 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
581 | \r |
582 | //\r |
583 | // Preprocess the FFS file to get a pointer to the PE32 information\r |
584 | // in the enclosed PE32 image.\r |
585 | //\r |
586 | Status = PeiProcessFile (\r |
587 | EFI_SECTION_PE32,\r |
588 | FfsHeader,\r |
589 | &Pe32Data,\r |
590 | NULL\r |
591 | );\r |
592 | \r |
593 | if (EFI_ERROR (Status)) {\r |
594 | return Status;\r |
595 | }\r |
596 | //\r |
597 | // Load the PE image from the FFS file\r |
598 | //\r |
599 | Status = PeiLoadFile (\r |
600 | PeiEfiPeiPeCoffLoader,\r |
601 | Pe32Data,\r |
602 | ImageAddress,\r |
603 | ImageSize,\r |
604 | EntryPoint\r |
605 | );\r |
606 | \r |
607 | return Status;\r |
608 | }\r |
609 | \r |
610 | EFI_STATUS\r |
611 | PeiProcessFile (\r |
612 | IN UINT16 SectionType,\r |
613 | IN EFI_FFS_FILE_HEADER *FfsFileHeader,\r |
614 | OUT VOID **Pe32Data,\r |
615 | IN EFI_PEI_HOB_POINTERS *OrigHob\r |
616 | )\r |
617 | /*++\r |
618 | \r |
619 | Routine Description:\r |
620 | \r |
621 | Arguments:\r |
622 | \r |
623 | SectionType - The type of section in the FFS file to process.\r |
624 | \r |
625 | FfsFileHeader - Pointer to the FFS file to process, looking for the\r |
626 | specified SectionType\r |
627 | \r |
628 | Pe32Data - returned pointer to the start of the PE32 image found\r |
629 | in the FFS file.\r |
630 | \r |
631 | Returns:\r |
632 | \r |
633 | EFI_SUCCESS - found the PE32 section in the FFS file\r |
634 | \r |
635 | --*/\r |
636 | {\r |
637 | EFI_STATUS Status;\r |
638 | VOID *SectionData;\r |
639 | DECOMPRESS_LIBRARY *DecompressLibrary;\r |
640 | UINT8 *DstBuffer;\r |
641 | UINT8 *ScratchBuffer;\r |
642 | UINT32 DstBufferSize;\r |
643 | UINT32 ScratchBufferSize;\r |
644 | EFI_COMMON_SECTION_HEADER *CmpSection;\r |
645 | UINTN CmpSectionLength;\r |
646 | UINTN OccupiedCmpSectionLength;\r |
647 | VOID *CmpFileData;\r |
648 | UINTN CmpFileSize;\r |
649 | EFI_COMMON_SECTION_HEADER *Section;\r |
650 | UINTN SectionLength;\r |
651 | UINTN OccupiedSectionLength;\r |
652 | UINT64 FileSize;\r |
653 | UINT32 AuthenticationStatus;\r |
654 | EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract;\r |
655 | UINT32 BufferSize;\r |
656 | UINT8 *Buffer;\r |
657 | EFI_PEI_SECURITY_PPI *Security;\r |
658 | BOOLEAN StartCrisisRecovery;\r |
659 | EFI_GUID TempGuid;\r |
660 | EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r |
661 | EFI_COMPRESSION_SECTION *CompressionSection;\r |
662 | \r |
663 | //\r |
664 | // Initialize local variables.\r |
665 | //\r |
666 | DecompressLibrary = NULL;\r |
667 | DstBuffer = NULL;\r |
668 | DstBufferSize = 0;\r |
669 | \r |
670 | Status = PeiServicesFfsFindSectionData (\r |
671 | EFI_SECTION_COMPRESSION,\r |
672 | FfsFileHeader,\r |
673 | &SectionData\r |
674 | );\r |
675 | \r |
676 | //\r |
677 | // First process the compression section\r |
678 | //\r |
679 | if (!EFI_ERROR (Status)) {\r |
680 | //\r |
681 | // Yes, there is a compression section, so extract the contents\r |
682 | // Decompress the image here\r |
683 | //\r |
684 | Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));\r |
685 | \r |
686 | do {\r |
687 | SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r |
688 | OccupiedSectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);\r |
689 | \r |
690 | //\r |
691 | // Was the DXE Core file encapsulated in a GUID'd section?\r |
692 | //\r |
693 | if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r |
694 | \r |
695 | //\r |
696 | // This following code constitutes the addition of the security model\r |
697 | // to the DXE IPL.\r |
698 | //\r |
699 | //\r |
700 | // Set a default authenticatino state\r |
701 | //\r |
702 | AuthenticationStatus = 0;\r |
703 | \r |
704 | Status = PeiServicesLocatePpi (\r |
705 | &gEfiPeiSectionExtractionPpiGuid,\r |
706 | 0,\r |
707 | NULL,\r |
708 | (VOID **)&SectionExtract\r |
709 | );\r |
710 | \r |
711 | if (EFI_ERROR (Status)) {\r |
712 | return Status;\r |
713 | }\r |
714 | //\r |
715 | // Verify Authentication State\r |
716 | //\r |
717 | CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));\r |
718 | \r |
719 | Status = SectionExtract->PeiGetSection (\r |
720 | GetPeiServicesTablePointer(),\r |
721 | SectionExtract,\r |
722 | (EFI_SECTION_TYPE *) &SectionType,\r |
723 | &TempGuid,\r |
724 | 0,\r |
725 | (VOID **) &Buffer,\r |
726 | &BufferSize,\r |
727 | &AuthenticationStatus\r |
728 | );\r |
729 | \r |
730 | if (EFI_ERROR (Status)) {\r |
731 | return Status;\r |
732 | }\r |
733 | //\r |
734 | // If not ask the Security PPI, if exists, for disposition\r |
735 | //\r |
736 | //\r |
737 | Status = PeiServicesLocatePpi (\r |
738 | &gEfiPeiSecurityPpiGuid,\r |
739 | 0,\r |
740 | NULL,\r |
741 | (VOID **)&Security\r |
742 | );\r |
743 | if (EFI_ERROR (Status)) {\r |
744 | return Status;\r |
745 | }\r |
746 | \r |
747 | Status = Security->AuthenticationState (\r |
748 | GetPeiServicesTablePointer(),\r |
749 | (struct _EFI_PEI_SECURITY_PPI *) Security,\r |
750 | AuthenticationStatus,\r |
751 | FfsFileHeader,\r |
752 | &StartCrisisRecovery\r |
753 | );\r |
754 | \r |
755 | if (EFI_ERROR (Status)) {\r |
756 | return Status;\r |
757 | }\r |
758 | //\r |
759 | // If there is a security violation, report to caller and have\r |
760 | // the upper-level logic possible engender a crisis recovery\r |
761 | //\r |
762 | if (StartCrisisRecovery) {\r |
763 | return EFI_SECURITY_VIOLATION;\r |
764 | }\r |
765 | }\r |
766 | \r |
767 | if (Section->Type == EFI_SECTION_PE32) {\r |
768 | //\r |
769 | // This is what we want\r |
770 | //\r |
771 | *Pe32Data = (VOID *) (Section + 1);\r |
772 | return EFI_SUCCESS;\r |
773 | } else if (Section->Type == EFI_SECTION_COMPRESSION) {\r |
774 | //\r |
775 | // This is a compression set, expand it\r |
776 | //\r |
777 | CompressionSection = (EFI_COMPRESSION_SECTION *) Section;\r |
778 | \r |
779 | switch (CompressionSection->CompressionType) {\r |
780 | case EFI_STANDARD_COMPRESSION:\r |
781 | //\r |
782 | // Load EFI standard compression.\r |
783 | //\r |
784 | if (FeaturePcdGet (PcdDxeIplSupportTianoDecompress)) {\r |
785 | DecompressLibrary = &gEfiDecompress;\r |
786 | } else {\r |
787 | ASSERT (FALSE);\r |
788 | return EFI_NOT_FOUND;\r |
789 | }\r |
790 | break;\r |
791 | \r |
792 | // porting note the original branch for customized compress is removed, it should be change to use GUID compress\r |
793 | \r |
794 | case EFI_NOT_COMPRESSED:\r |
795 | //\r |
796 | // Allocate destination buffer\r |
797 | //\r |
798 | DstBufferSize = CompressionSection->UncompressedLength;\r |
799 | DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r |
800 | if (DstBuffer == NULL) {\r |
801 | return EFI_OUT_OF_RESOURCES;\r |
802 | }\r |
803 | //\r |
804 | // stream is not actually compressed, just encapsulated. So just copy it.\r |
805 | //\r |
806 | CopyMem (DstBuffer, CompressionSection + 1, DstBufferSize);\r |
807 | break;\r |
808 | \r |
809 | default:\r |
810 | //\r |
811 | // Don't support other unknown compression type.\r |
812 | //\r |
813 | ASSERT_EFI_ERROR (Status);\r |
814 | return EFI_NOT_FOUND;\r |
815 | }\r |
816 | \r |
817 | if (CompressionSection->CompressionType != EFI_NOT_COMPRESSED) {\r |
818 | //\r |
819 | // For compressed data, decompress them to dstbuffer.\r |
820 | //\r |
821 | Status = DecompressLibrary->GetInfo (\r |
822 | (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r |
823 | (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),\r |
824 | &DstBufferSize,\r |
825 | &ScratchBufferSize\r |
826 | );\r |
827 | if (EFI_ERROR (Status)) {\r |
828 | //\r |
829 | // GetInfo failed\r |
830 | //\r |
831 | DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));\r |
832 | return EFI_NOT_FOUND;\r |
833 | }\r |
834 | \r |
835 | //\r |
836 | // Allocate scratch buffer\r |
837 | //\r |
838 | ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r |
839 | if (ScratchBuffer == NULL) {\r |
840 | return EFI_OUT_OF_RESOURCES;\r |
841 | }\r |
842 | \r |
843 | //\r |
844 | // Allocate destination buffer\r |
845 | //\r |
846 | DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r |
847 | if (DstBuffer == NULL) {\r |
848 | return EFI_OUT_OF_RESOURCES;\r |
849 | }\r |
850 | \r |
851 | //\r |
852 | // Call decompress function\r |
853 | //\r |
854 | Status = DecompressLibrary->Decompress (\r |
855 | (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r |
856 | DstBuffer,\r |
857 | ScratchBuffer\r |
858 | );\r |
859 | if (EFI_ERROR (Status)) {\r |
860 | //\r |
861 | // Decompress failed\r |
862 | //\r |
863 | DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));\r |
864 | return EFI_NOT_FOUND;\r |
865 | }\r |
866 | }\r |
867 | \r |
868 | //\r |
869 | // Decompress successfully.\r |
870 | // Loop the decompressed data searching for expected section.\r |
871 | //\r |
872 | CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;\r |
873 | CmpFileData = (VOID *) DstBuffer;\r |
874 | CmpFileSize = DstBufferSize;\r |
875 | do {\r |
876 | CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;\r |
877 | if (CmpSection->Type == SectionType) {\r |
878 | //\r |
879 | // This is what we want\r |
880 | //\r |
881 | if (SectionType == EFI_SECTION_PE32) {\r |
882 | *Pe32Data = (VOID *) (CmpSection + 1);\r |
883 | return EFI_SUCCESS;\r |
884 | } else if (SectionType == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {\r |
885 | // \r |
886 | // Firmware Volume Image in this Section\r |
887 | // Skip the section header to get FvHeader\r |
888 | //\r |
889 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (CmpSection + 1);\r |
890 | \r |
891 | if (FvHeader->Signature == EFI_FVH_SIGNATURE) {\r |
892 | //\r |
893 | // Because FvLength in FvHeader is UINT64 type, \r |
894 | // so FvHeader must meed at least 8 bytes alignment.\r |
895 | // If current FvImage base address doesn't meet its alignment,\r |
896 | // we need to reload this FvImage to another correct memory address.\r |
897 | //\r |
898 | if (((UINTN) FvHeader % sizeof (UINT64)) != 0) {\r |
899 | DstBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) CmpSectionLength - sizeof (EFI_COMMON_SECTION_HEADER)), sizeof (UINT64));\r |
900 | if (DstBuffer == NULL) {\r |
901 | return EFI_OUT_OF_RESOURCES;\r |
902 | }\r |
903 | CopyMem (DstBuffer, FvHeader, (UINTN) CmpSectionLength - sizeof (EFI_COMMON_SECTION_HEADER));\r |
904 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DstBuffer; \r |
905 | }\r |
906 | \r |
907 | //\r |
908 | // Build new FvHob for new decompressed Fv image.\r |
909 | //\r |
910 | BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);\r |
911 | \r |
912 | //\r |
913 | // Set the original FvHob to unused.\r |
914 | //\r |
915 | if (OrigHob != NULL) {\r |
916 | OrigHob->Header->HobType = EFI_HOB_TYPE_UNUSED;\r |
917 | }\r |
918 | \r |
919 | //\r |
920 | // return found FvImage data.\r |
921 | //\r |
922 | *Pe32Data = (VOID *) FvHeader;\r |
923 | return EFI_SUCCESS;\r |
924 | }\r |
925 | }\r |
926 | }\r |
927 | OccupiedCmpSectionLength = GET_OCCUPIED_SIZE (CmpSectionLength, 4);\r |
928 | CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);\r |
929 | } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);\r |
930 | }\r |
931 | //\r |
932 | // End of the decompression activity\r |
933 | //\r |
934 | \r |
935 | Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r |
936 | FileSize = FfsFileHeader->Size[0] & 0xFF;\r |
937 | FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;\r |
938 | FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;\r |
939 | FileSize &= 0x00FFFFFF;\r |
940 | } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);\r |
941 | \r |
942 | //\r |
943 | // search all sections (compression and non compression) in this FFS, don't \r |
944 | // find expected section.\r |
945 | //\r |
946 | return EFI_NOT_FOUND;\r |
947 | } else {\r |
948 | //\r |
949 | // For those FFS that doesn't contain compression section, directly search \r |
950 | // PE or TE section in this FFS.\r |
951 | //\r |
952 | \r |
953 | Status = PeiServicesFfsFindSectionData (\r |
954 | EFI_SECTION_PE32,\r |
955 | FfsFileHeader,\r |
956 | &SectionData\r |
957 | );\r |
958 | \r |
959 | if (EFI_ERROR (Status)) {\r |
960 | Status = PeiServicesFfsFindSectionData (\r |
961 | EFI_SECTION_TE,\r |
962 | FfsFileHeader,\r |
963 | &SectionData\r |
964 | );\r |
965 | if (EFI_ERROR (Status)) {\r |
966 | return Status;\r |
967 | }\r |
968 | }\r |
969 | }\r |
970 | \r |
971 | *Pe32Data = SectionData;\r |
972 | \r |
973 | return EFI_SUCCESS;\r |
974 | }\r |
975 | \r |