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