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