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