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