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