Identify SupArch for .msa
[mirror_edk2.git] / EdkModulePkg / Core / DxeIplX64Peim / 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
84a99d48 133 Status = PeiServicesGetBootMode (&BootMode);\r
3005648d 134\r
135 ASSERT_EFI_ERROR (Status);\r
136\r
84a99d48 137 Status = PeiServicesLocatePpi (\r
3005648d 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
84a99d48 168 Status = PeiServicesInstallPpi (&mPpiLoadFile);\r
3005648d 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
84a99d48 177 PeiServicesInstallPpi (&mPpiList);\r
3005648d 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
84a99d48 237 Status = PeiServicesGetBootMode (&BootMode);\r
3005648d 238\r
239 if (!EFI_ERROR (Status) && (BootMode == BOOT_ON_S3_RESUME)) {\r
84a99d48 240 Status = PeiServicesLocatePpi (\r
3005648d 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
3005648d 266 //\r
267 // Allocate 128KB for the Stack\r
268 //\r
84a99d48 269 PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r
3005648d 270 ASSERT (BaseOfStack != 0);\r
271\r
272 //\r
273 // Compute the top of the stack we were allocated. Pre-allocate a 32 bytes\r
274 // for safety (PpisNeededByDxe and DxeCore).\r
275 //\r
276 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;\r
277\r
278 //\r
279 // Add architecture-specifc HOBs (including the BspStore HOB)\r
280 //\r
281 Status = CreateArchSpecificHobs (&BspStore);\r
282 ASSERT_EFI_ERROR (Status);\r
283\r
284 //\r
285 // See if we are in crisis recovery\r
286 //\r
84a99d48 287 Status = PeiServicesGetBootMode (&BootMode);\r
3005648d 288 if (!EFI_ERROR (Status) && (BootMode == BOOT_IN_RECOVERY_MODE)) {\r
84a99d48 289 Status = PeiServicesLocatePpi (\r
3005648d 290 &gEfiPeiRecoveryModulePpiGuid,\r
291 0,\r
292 NULL,\r
293 (VOID **)&PeiRecovery\r
294 );\r
295\r
296 ASSERT_EFI_ERROR (Status);\r
297 Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);\r
298 ASSERT_EFI_ERROR (Status);\r
299 }\r
300\r
301 //\r
302 // Find the DXE Core in a Firmware Volume\r
303 //\r
304 Status = PeiFindFile (\r
305 EFI_FV_FILETYPE_DXE_CORE,\r
306 EFI_SECTION_PE32,\r
307 &DxeCoreFileName,\r
308 &DxeCorePe32Data\r
309 );\r
310 ASSERT_EFI_ERROR (Status);\r
311\r
312 //\r
313 // Transfer control to the DXE Core\r
314 // The handoff state is simply a pointer to the HOB list\r
315 //\r
316 // PEI_PERF_END (PeiServices, L"DxeIpl", NULL, 0);\r
317\r
84a99d48 318 Status = PeiServicesInstallPpi (&mPpiSignal);\r
3005648d 319 ASSERT_EFI_ERROR (Status);\r
320\r
321 //\r
322 // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA \\r
323 // memory, it may be corrupted when copying FV to high-end memory \r
324 LoadGo64Gdt();\r
325\r
326 //\r
327 // Limit to 36 bits of addressing for debug. Should get it from CPU\r
328 //\r
329 PageTables = CreateIdentityMappingPageTables (36);\r
330\r
331\r
332 //\r
333 // Load the DXE Core from a Firmware Volume\r
334 //\r
335 Status = PeiLoadx64File (\r
336 PeiEfiPeiPeCoffLoader,\r
337 DxeCorePe32Data,\r
338 EfiBootServicesData,\r
339 &DxeCoreAddress,\r
340 &DxeCoreSize,\r
341 &DxeCoreEntryPoint\r
342 );\r
343 ASSERT_EFI_ERROR (Status);\r
344\r
345 //\r
346 //\r
347 // Add HOB for the DXE Core\r
348 //\r
349 BuildModuleHob (\r
350 &DxeCoreFileName,\r
351 DxeCoreAddress,\r
352 DxeCoreSize,\r
353 DxeCoreEntryPoint\r
354 );\r
355\r
356 //\r
357 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT\r
358 //\r
359 REPORT_STATUS_CODE (\r
360 EFI_PROGRESS_CODE,\r
361 EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT\r
362 );\r
363\r
364 DEBUG ((EFI_D_INFO, "DXE Core Entry\n"));\r
365 //\r
366 // Go to Long Mode. Interrupts will not get turned on until the CPU AP is loaded.\r
367 // Call x64 drivers passing in single argument, a pointer to the HOBs.\r
368 //\r
369 ActivateLongMode (\r
370 PageTables, \r
371 (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw), \r
372 TopOfStack,\r
373 0x00000000,\r
374 DxeCoreEntryPoint\r
375 );\r
376\r
377 //\r
378 // If we get here, then the DXE Core returned. This is an error\r
379 //\r
380 ASSERT_EFI_ERROR (Status);\r
381\r
382 return EFI_OUT_OF_RESOURCES;\r
383}\r
384\r
385EFI_STATUS\r
386PeiFindFile (\r
387 IN UINT8 Type,\r
388 IN UINT16 SectionType,\r
389 OUT EFI_GUID *FileName,\r
390 OUT VOID **Pe32Data\r
391 )\r
392/*++\r
393\r
394Routine Description:\r
395\r
396 Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes\r
397 described in the HOB list. Able to search in a compression set in a FFS file.\r
398 But only one level of compression is supported, that is, not able to search\r
399 in a compression set that is within another compression set.\r
400\r
401Arguments:\r
402\r
403 Type - The Type of file to retrieve\r
404\r
405 SectionType - The type of section to retrieve from a file\r
406\r
407 FileName - The name of the file found in the Firmware Volume\r
408\r
409 Pe32Data - Pointer to the beginning of the PE/COFF file found in the Firmware Volume\r
410\r
411Returns:\r
412\r
413 EFI_SUCCESS - The file was found, and the name is returned in FileName, and a pointer to\r
414 the PE/COFF image is returned in Pe32Data\r
415\r
416 EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List\r
417\r
418--*/\r
419{\r
420 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
421 EFI_FFS_FILE_HEADER *FfsFileHeader;\r
422 VOID *SectionData;\r
423 EFI_STATUS Status;\r
424 EFI_PEI_HOB_POINTERS Hob;\r
425\r
426\r
427 FwVolHeader = NULL;\r
428 FfsFileHeader = NULL;\r
429 SectionData = NULL;\r
430\r
431 //\r
432 // Foreach Firmware Volume, look for a specified type\r
433 // of file and break out when one is found\r
434 //\r
435 Hob.Raw = GetHobList ();\r
436 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw)) != NULL) {\r
437 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress);\r
84a99d48 438 Status = PeiServicesFfsFindNextFile (\r
3005648d 439 Type,\r
440 FwVolHeader,\r
441 &FfsFileHeader\r
442 );\r
443 if (!EFI_ERROR (Status)) {\r
3005648d 444 Status = PeiProcessFile (\r
445 SectionType,\r
6326ee4e 446 &FfsFileHeader,\r
3005648d 447 Pe32Data\r
448 );\r
6326ee4e 449 CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));\r
3005648d 450 return Status;\r
451 }\r
452 Hob.Raw = GET_NEXT_HOB (Hob);\r
453 }\r
454 return EFI_NOT_FOUND;\r
455}\r
456\r
457EFI_STATUS\r
458PeiLoadx64File (\r
459 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,\r
460 IN VOID *Pe32Data,\r
461 IN EFI_MEMORY_TYPE MemoryType,\r
462 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r
463 OUT UINT64 *ImageSize,\r
464 OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r
465 )\r
466/*++\r
467\r
468Routine Description:\r
469\r
470 Loads and relocates a PE/COFF image into memory.\r
471\r
472Arguments:\r
473\r
474 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r
475\r
476 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r
477\r
478 ImageAddress - The base address of the relocated PE/COFF image\r
479\r
480 ImageSize - The size of the relocated PE/COFF image\r
481\r
482 EntryPoint - The entry point of the relocated PE/COFF image\r
483\r
484Returns:\r
485\r
486 EFI_SUCCESS - The file was loaded and relocated\r
487 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r
488\r
489--*/\r
490{\r
491 EFI_STATUS Status;\r
492 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
493 EFI_PHYSICAL_ADDRESS MemoryBuffer;\r
494\r
495 ZeroMem (&ImageContext, sizeof (ImageContext));\r
496 ImageContext.Handle = Pe32Data;\r
497 Status = GetImageReadFunction (&ImageContext);\r
498\r
499 ASSERT_EFI_ERROR (Status);\r
500\r
501 Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);\r
502 if (EFI_ERROR (Status)) {\r
503 return Status;\r
504 }\r
505 //\r
506 // Allocate Memory for the image\r
507 //\r
508 //\r
509 // Allocate Memory for the image\r
510 //\r
84a99d48 511 PeiServicesAllocatePages (MemoryType, EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize), &MemoryBuffer);\r
3005648d 512 ImageContext.ImageAddress = MemoryBuffer;\r
513 ASSERT (ImageContext.ImageAddress != 0);\r
514\r
515 //\r
516 // Load the image to our new buffer\r
517 //\r
518\r
519 Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r
520 if (EFI_ERROR (Status)) {\r
521 return Status;\r
522 }\r
523 \r
524 //\r
525 // Relocate the image in our new buffer\r
526 //\r
527 Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r
528 if (EFI_ERROR (Status)) {\r
529 return Status;\r
530 }\r
531\r
532 //\r
533 // Flush the instruction cache so the image data is written before we execute it\r
534 //\r
535 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
536\r
537 *ImageAddress = ImageContext.ImageAddress;\r
538 *ImageSize = ImageContext.ImageSize;\r
539 *EntryPoint = ImageContext.EntryPoint;\r
540\r
541 return EFI_SUCCESS;\r
542}\r
543\r
544EFI_STATUS\r
545ShadowDxeIpl (\r
546 IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,\r
547 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader\r
548 )\r
549/*++\r
550\r
551Routine Description:\r
552\r
553 Shadow the DXE IPL to a different memory location. This occurs after permanent\r
554 memory has been discovered.\r
555\r
556Arguments:\r
557\r
558 DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver\r
559\r
560 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r
561\r
562Returns:\r
563\r
564 EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.\r
565\r
566 EFI_ ERROR - The shadow was unsuccessful.\r
567\r
568\r
569--*/\r
570{\r
571 UINTN SectionLength;\r
572 UINTN OccupiedSectionLength;\r
573 EFI_PHYSICAL_ADDRESS DxeIplAddress;\r
574 UINT64 DxeIplSize;\r
575 EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;\r
576 EFI_STATUS Status;\r
577 EFI_COMMON_SECTION_HEADER *Section;\r
578\r
579 Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);\r
580\r
581 while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {\r
582 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r
583 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);\r
584 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r
585 }\r
586 \r
587 //\r
588 // Relocate DxeIpl into memory by using loadfile service\r
589 //\r
590 Status = PeiLoadx64File (\r
591 PeiEfiPeiPeCoffLoader,\r
592 (VOID *) (Section + 1),\r
593 EfiBootServicesData,\r
594 &DxeIplAddress,\r
595 &DxeIplSize,\r
596 &DxeIplEntryPoint\r
597 );\r
598 \r
599 if (Status == EFI_SUCCESS) {\r
600 //\r
601 // Install PeiInMemory to indicate the Dxeipl is shadowed\r
602 //\r
84a99d48 603 Status = PeiServicesInstallPpi (&mPpiPeiInMemory);\r
3005648d 604\r
605 if (EFI_ERROR (Status)) {\r
606 return Status;\r
607 }\r
608\r
609 Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer());\r
610 }\r
611\r
612 return Status;\r
613}\r
614\r
615EFI_STATUS\r
616EFIAPI\r
617DxeIplLoadFile (\r
618 IN EFI_PEI_FV_FILE_LOADER_PPI *This,\r
619 IN EFI_FFS_FILE_HEADER *FfsHeader,\r
620 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r
621 OUT UINT64 *ImageSize,\r
622 OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r
623 )\r
624/*++\r
625\r
626Routine Description:\r
627\r
628 Given a pointer to an FFS file containing a PE32 image, get the\r
629 information on the PE32 image, and then "load" it so that it\r
630 can be executed.\r
631\r
632Arguments:\r
633\r
634 This - pointer to our file loader protocol\r
635 FfsHeader - pointer to the FFS file header of the FFS file that\r
636 contains the PE32 image we want to load\r
637 ImageAddress - returned address where the PE32 image is loaded\r
638 ImageSize - returned size of the loaded PE32 image\r
639 EntryPoint - entry point to the loaded PE32 image\r
640\r
641Returns:\r
642 \r
643 EFI_SUCCESS - The FFS file was successfully loaded.\r
644 EFI_ERROR - Unable to load the FFS file.\r
645\r
646--*/\r
647{\r
648 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r
649 EFI_STATUS Status;\r
650 VOID *Pe32Data;\r
651\r
652 Pe32Data = NULL;\r
653 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r
654\r
655 //\r
656 // Preprocess the FFS file to get a pointer to the PE32 information\r
657 // in the enclosed PE32 image.\r
658 //\r
659 Status = PeiProcessFile (\r
660 EFI_SECTION_PE32,\r
6326ee4e 661 &FfsHeader,\r
3005648d 662 &Pe32Data\r
663 );\r
664\r
665 if (EFI_ERROR (Status)) {\r
666 return Status;\r
667 }\r
668 //\r
669 // Load the PE image from the FFS file\r
670 //\r
671 Status = PeiLoadx64File (\r
672 PeiEfiPeiPeCoffLoader,\r
673 Pe32Data,\r
674 EfiBootServicesData,\r
675 ImageAddress,\r
676 ImageSize,\r
677 EntryPoint\r
678 );\r
679\r
680 return Status;\r
681}\r
682\r
683EFI_STATUS\r
684PeiProcessFile (\r
6326ee4e
LG
685 IN UINT16 SectionType,\r
686 IN OUT EFI_FFS_FILE_HEADER **RealFfsFileHeader,\r
687 OUT VOID **Pe32Data\r
3005648d 688 )\r
689/*++\r
690\r
691Routine Description:\r
692\r
693Arguments:\r
694\r
695 SectionType - The type of section in the FFS file to process.\r
696\r
697 FfsFileHeader - Pointer to the FFS file to process, looking for the\r
698 specified SectionType\r
699\r
700 Pe32Data - returned pointer to the start of the PE32 image found\r
701 in the FFS file.\r
702\r
703Returns:\r
704\r
705 EFI_SUCCESS - found the PE32 section in the FFS file\r
706\r
707--*/\r
708{\r
709 EFI_STATUS Status;\r
710 VOID *SectionData;\r
711 DECOMPRESS_LIBRARY *DecompressLibrary;\r
712 UINT8 *DstBuffer;\r
713 UINT8 *ScratchBuffer;\r
714 UINT32 DstBufferSize;\r
715 UINT32 ScratchBufferSize;\r
716 EFI_COMMON_SECTION_HEADER *CmpSection;\r
717 UINTN CmpSectionLength;\r
718 UINTN OccupiedCmpSectionLength;\r
719 VOID *CmpFileData;\r
720 UINTN CmpFileSize;\r
721 EFI_COMMON_SECTION_HEADER *Section;\r
722 UINTN SectionLength;\r
723 UINTN OccupiedSectionLength;\r
724 UINT64 FileSize;\r
725 EFI_GUID_DEFINED_SECTION *GuidedSectionHeader;\r
726 UINT32 AuthenticationStatus;\r
727 EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract;\r
728 UINT32 BufferSize;\r
729 UINT8 *Buffer;\r
730 EFI_PEI_SECURITY_PPI *Security;\r
731 BOOLEAN StartCrisisRecovery;\r
732 EFI_GUID TempGuid;\r
733 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
734 EFI_COMPRESSION_SECTION *CompressionSection;\r
6326ee4e
LG
735 EFI_FFS_FILE_HEADER *FfsFileHeader;\r
736 \r
737 FfsFileHeader = *RealFfsFileHeader;\r
3005648d 738\r
84a99d48 739 Status = PeiServicesFfsFindSectionData (\r
3005648d 740 EFI_SECTION_COMPRESSION,\r
741 FfsFileHeader,\r
742 &SectionData\r
743 );\r
744\r
745 //\r
746 // Upon finding a DXE Core file, see if there is first a compression section\r
747 //\r
748 if (!EFI_ERROR (Status)) {\r
749 //\r
750 // Yes, there is a compression section, so extract the contents\r
751 // Decompress the image here\r
752 //\r
753 Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));\r
754\r
755 do {\r
756 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r
757 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);\r
758\r
759 //\r
760 // Was the DXE Core file encapsulated in a GUID'd section?\r
761 //\r
762 if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
763 //\r
764 // Locate the GUID'd Section Extractor\r
765 //\r
766 GuidedSectionHeader = (VOID *) (Section + 1);\r
767\r
768 //\r
769 // This following code constitutes the addition of the security model\r
770 // to the DXE IPL.\r
771 //\r
772 //\r
773 // Set a default authenticatino state\r
774 //\r
775 AuthenticationStatus = 0;\r
776\r
84a99d48 777 Status = PeiServicesLocatePpi (\r
3005648d 778 &gEfiPeiSectionExtractionPpiGuid,\r
779 0,\r
780 NULL,\r
781 (VOID **)&SectionExtract\r
782 );\r
783\r
784 if (EFI_ERROR (Status)) {\r
785 return Status;\r
786 }\r
787 //\r
788 // Verify Authentication State\r
789 //\r
790 CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));\r
791\r
792 Status = SectionExtract->PeiGetSection (\r
793 GetPeiServicesTablePointer(),\r
794 SectionExtract,\r
795 (EFI_SECTION_TYPE *) &SectionType,\r
796 &TempGuid,\r
797 0,\r
798 (VOID **) &Buffer,\r
799 &BufferSize,\r
800 &AuthenticationStatus\r
801 );\r
802\r
803 if (EFI_ERROR (Status)) {\r
804 return Status;\r
805 }\r
806 //\r
807 // If not ask the Security PPI, if exists, for disposition\r
808 //\r
809 //\r
84a99d48 810 Status = PeiServicesLocatePpi (\r
3005648d 811 &gEfiPeiSecurityPpiGuid,\r
812 0,\r
813 NULL,\r
814 (VOID **)&Security\r
815 );\r
816 if (EFI_ERROR (Status)) {\r
817 return Status;\r
818 }\r
819\r
820 Status = Security->AuthenticationState (\r
821 GetPeiServicesTablePointer(),\r
822 (struct _EFI_PEI_SECURITY_PPI *) Security,\r
823 AuthenticationStatus,\r
824 FfsFileHeader,\r
825 &StartCrisisRecovery\r
826 );\r
827\r
828 if (EFI_ERROR (Status)) {\r
829 return Status;\r
830 }\r
831 //\r
832 // If there is a security violation, report to caller and have\r
833 // the upper-level logic possible engender a crisis recovery\r
834 //\r
835 if (StartCrisisRecovery) {\r
836 return EFI_SECURITY_VIOLATION;\r
837 }\r
838 }\r
839\r
840 if (Section->Type == EFI_SECTION_PE32) {\r
841 //\r
842 // This is what we want\r
843 //\r
844 *Pe32Data = (VOID *) (Section + 1);\r
845 return EFI_SUCCESS;\r
846 } else if (Section->Type == EFI_SECTION_COMPRESSION) {\r
847 //\r
848 // This is a compression set, expand it\r
849 //\r
850 CompressionSection = (EFI_COMPRESSION_SECTION *) Section;\r
851\r
852 switch (CompressionSection->CompressionType) {\r
853 case EFI_STANDARD_COMPRESSION:\r
854 DecompressLibrary = &gTianoDecompress;\r
855 break;\r
856\r
857 case EFI_CUSTOMIZED_COMPRESSION:\r
858 //\r
859 // Load user customized compression protocol.\r
860 //\r
861 DecompressLibrary = &gCustomDecompress;\r
862 break;\r
863\r
864 case EFI_NOT_COMPRESSED:\r
865 default:\r
866 //\r
867 // Need to support not compressed file\r
868 //\r
869 ASSERT_EFI_ERROR (Status);\r
870 return EFI_NOT_FOUND;\r
871 }\r
872\r
873 Status = DecompressLibrary->GetInfo (\r
874 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r
875 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),\r
876 &DstBufferSize,\r
877 &ScratchBufferSize\r
878 );\r
879 if (EFI_ERROR (Status)) {\r
880 //\r
881 // GetInfo failed\r
882 //\r
883 return EFI_NOT_FOUND;\r
884 }\r
885\r
886 //\r
887 // Allocate scratch buffer\r
888 //\r
889 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r
890 if (ScratchBuffer == NULL) {\r
891 return EFI_OUT_OF_RESOURCES;\r
892 }\r
893\r
894 //\r
895 // Allocate destination buffer\r
896 //\r
897 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r
898 if (DstBuffer == NULL) {\r
899 return EFI_OUT_OF_RESOURCES;\r
900 }\r
901\r
902 //\r
903 // Call decompress function\r
904 //\r
905 Status = DecompressLibrary->Decompress (\r
906 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r
907 DstBuffer,\r
908 ScratchBuffer\r
909 );\r
910\r
911 CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;\r
912 if (CmpSection->Type == EFI_SECTION_RAW) {\r
913 //\r
914 // Skip the section header and\r
915 // adjust the pointer alignment to 16\r
916 //\r
917 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16);\r
918\r
919 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {\r
920 FfsFileHeader = NULL;\r
921 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);\r
84a99d48 922 Status = PeiServicesFfsFindNextFile (\r
3005648d 923 EFI_FV_FILETYPE_DXE_CORE,\r
924 FvHeader,\r
925 &FfsFileHeader\r
926 );\r
927\r
928 if (EFI_ERROR (Status)) {\r
929 return EFI_NOT_FOUND;\r
930 }\r
931\r
6326ee4e
LG
932 //\r
933 // Reture the FfsHeader that contain Pe32Data.\r
934 //\r
935 *RealFfsFileHeader = FfsFileHeader;\r
936 return PeiProcessFile (SectionType, RealFfsFileHeader, Pe32Data);\r
3005648d 937 }\r
938 }\r
939 //\r
940 // Decompress successfully.\r
941 // Loop the decompressed data searching for expected section.\r
942 //\r
943 CmpFileData = (VOID *) DstBuffer;\r
944 CmpFileSize = DstBufferSize;\r
945 do {\r
946 CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;\r
947 if (CmpSection->Type == EFI_SECTION_PE32) {\r
948 //\r
949 // This is what we want\r
950 //\r
951 *Pe32Data = (VOID *) (CmpSection + 1);\r
952 return EFI_SUCCESS;\r
953 }\r
954\r
955 OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4);\r
956 CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);\r
957 } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);\r
958 }\r
959\r
960 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r
961 FileSize = FfsFileHeader->Size[0] & 0xFF;\r
962 FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;\r
963 FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;\r
964 FileSize &= 0x00FFFFFF;\r
965 } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);\r
966\r
967 //\r
968 // End of the decompression activity\r
969 //\r
970 } else {\r
971\r
84a99d48 972 Status = PeiServicesFfsFindSectionData (\r
3005648d 973 EFI_SECTION_PE32,\r
974 FfsFileHeader,\r
975 &SectionData\r
976 );\r
977\r
978 if (EFI_ERROR (Status)) {\r
84a99d48 979 Status = PeiServicesFfsFindSectionData (\r
3005648d 980 EFI_SECTION_TE,\r
981 FfsFileHeader,\r
982 &SectionData\r
983 );\r
984 if (EFI_ERROR (Status)) {\r
985 return Status;\r
986 }\r
987 }\r
988 }\r
989\r
990 *Pe32Data = SectionData;\r
991\r
992 return EFI_SUCCESS;\r
878ddf1f 993}