Move ConPlatform module from EdkNT32 package to EdkModulePkg, and remove EdkPeCoffLoa...
[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
fc198a79 250 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\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
f78797d5
LG
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
3005648d 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
3005648d 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
fc198a79 316 Status = PeiLoadPeImage (\r
3005648d 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
a61513d6
LG
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
3005648d 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
f78797d5 368 // Dxe Core should not return.\r
3005648d 369 //\r
f78797d5
LG
370 ASSERT (FALSE);\r
371 CpuDeadLoop ();\r
3005648d 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
84a99d48 429 Status = PeiServicesFfsFindNextFile (\r
3005648d 430 Type,\r
431 FwVolHeader,\r
432 &FfsFileHeader\r
433 );\r
434 if (!EFI_ERROR (Status)) {\r
3005648d 435 Status = PeiProcessFile (\r
436 SectionType,\r
6326ee4e 437 &FfsFileHeader,\r
3005648d 438 Pe32Data\r
439 );\r
6326ee4e 440 CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));\r
3005648d 441 return Status;\r
442 }\r
443 Hob.Raw = GET_NEXT_HOB (Hob);\r
444 }\r
445 return EFI_NOT_FOUND;\r
446}\r
447\r
448EFI_STATUS\r
fc198a79 449PeiLoadPeImage (\r
3005648d 450 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,\r
451 IN VOID *Pe32Data,\r
452 IN EFI_MEMORY_TYPE MemoryType,\r
453 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r
454 OUT UINT64 *ImageSize,\r
455 OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r
456 )\r
457/*++\r
458\r
459Routine Description:\r
460\r
461 Loads and relocates a PE/COFF image into memory.\r
462\r
463Arguments:\r
464\r
465 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r
466\r
467 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r
468\r
469 ImageAddress - The base address of the relocated PE/COFF image\r
470\r
471 ImageSize - The size of the relocated PE/COFF image\r
472\r
473 EntryPoint - The entry point of the relocated PE/COFF image\r
474\r
475Returns:\r
476\r
477 EFI_SUCCESS - The file was loaded and relocated\r
478 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r
479\r
480--*/\r
481{\r
482 EFI_STATUS Status;\r
483 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
484 EFI_PHYSICAL_ADDRESS MemoryBuffer;\r
485\r
486 ZeroMem (&ImageContext, sizeof (ImageContext));\r
487 ImageContext.Handle = Pe32Data;\r
488 Status = GetImageReadFunction (&ImageContext);\r
489\r
490 ASSERT_EFI_ERROR (Status);\r
491\r
492 Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);\r
493 if (EFI_ERROR (Status)) {\r
494 return Status;\r
495 }\r
496 //\r
497 // Allocate Memory for the image\r
498 //\r
499 //\r
500 // Allocate Memory for the image\r
501 //\r
84a99d48 502 PeiServicesAllocatePages (MemoryType, EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize), &MemoryBuffer);\r
3005648d 503 ImageContext.ImageAddress = MemoryBuffer;\r
504 ASSERT (ImageContext.ImageAddress != 0);\r
505\r
506 //\r
507 // Load the image to our new buffer\r
508 //\r
509\r
510 Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r
511 if (EFI_ERROR (Status)) {\r
512 return Status;\r
513 }\r
514 \r
515 //\r
516 // Relocate the image in our new buffer\r
517 //\r
518 Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r
519 if (EFI_ERROR (Status)) {\r
520 return Status;\r
521 }\r
522\r
523 //\r
524 // Flush the instruction cache so the image data is written before we execute it\r
525 //\r
526 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r
527\r
528 *ImageAddress = ImageContext.ImageAddress;\r
529 *ImageSize = ImageContext.ImageSize;\r
530 *EntryPoint = ImageContext.EntryPoint;\r
531\r
532 return EFI_SUCCESS;\r
533}\r
534\r
535EFI_STATUS\r
536ShadowDxeIpl (\r
537 IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,\r
538 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader\r
539 )\r
540/*++\r
541\r
542Routine Description:\r
543\r
544 Shadow the DXE IPL to a different memory location. This occurs after permanent\r
545 memory has been discovered.\r
546\r
547Arguments:\r
548\r
549 DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver\r
550\r
551 PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r
552\r
553Returns:\r
554\r
555 EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.\r
556\r
557 EFI_ ERROR - The shadow was unsuccessful.\r
558\r
559\r
560--*/\r
561{\r
562 UINTN SectionLength;\r
563 UINTN OccupiedSectionLength;\r
564 EFI_PHYSICAL_ADDRESS DxeIplAddress;\r
565 UINT64 DxeIplSize;\r
566 EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;\r
567 EFI_STATUS Status;\r
568 EFI_COMMON_SECTION_HEADER *Section;\r
569\r
570 Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);\r
571\r
572 while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {\r
573 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r
574 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);\r
575 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r
576 }\r
577 \r
578 //\r
579 // Relocate DxeIpl into memory by using loadfile service\r
580 //\r
fc198a79 581 Status = PeiLoadPeImage (\r
3005648d 582 PeiEfiPeiPeCoffLoader,\r
583 (VOID *) (Section + 1),\r
584 EfiBootServicesData,\r
585 &DxeIplAddress,\r
586 &DxeIplSize,\r
587 &DxeIplEntryPoint\r
588 );\r
589 \r
590 if (Status == EFI_SUCCESS) {\r
591 //\r
592 // Install PeiInMemory to indicate the Dxeipl is shadowed\r
593 //\r
84a99d48 594 Status = PeiServicesInstallPpi (&mPpiPeiInMemory);\r
3005648d 595\r
596 if (EFI_ERROR (Status)) {\r
597 return Status;\r
598 }\r
599\r
600 Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer());\r
601 }\r
602\r
603 return Status;\r
604}\r
605\r
606EFI_STATUS\r
607EFIAPI\r
608DxeIplLoadFile (\r
609 IN EFI_PEI_FV_FILE_LOADER_PPI *This,\r
610 IN EFI_FFS_FILE_HEADER *FfsHeader,\r
611 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r
612 OUT UINT64 *ImageSize,\r
613 OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r
614 )\r
615/*++\r
616\r
617Routine Description:\r
618\r
619 Given a pointer to an FFS file containing a PE32 image, get the\r
620 information on the PE32 image, and then "load" it so that it\r
621 can be executed.\r
622\r
623Arguments:\r
624\r
625 This - pointer to our file loader protocol\r
626 FfsHeader - pointer to the FFS file header of the FFS file that\r
627 contains the PE32 image we want to load\r
628 ImageAddress - returned address where the PE32 image is loaded\r
629 ImageSize - returned size of the loaded PE32 image\r
630 EntryPoint - entry point to the loaded PE32 image\r
631\r
632Returns:\r
633 \r
634 EFI_SUCCESS - The FFS file was successfully loaded.\r
635 EFI_ERROR - Unable to load the FFS file.\r
636\r
637--*/\r
638{\r
639 EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r
640 EFI_STATUS Status;\r
641 VOID *Pe32Data;\r
642\r
643 Pe32Data = NULL;\r
644 PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r
645\r
646 //\r
647 // Preprocess the FFS file to get a pointer to the PE32 information\r
648 // in the enclosed PE32 image.\r
649 //\r
650 Status = PeiProcessFile (\r
651 EFI_SECTION_PE32,\r
6326ee4e 652 &FfsHeader,\r
3005648d 653 &Pe32Data\r
654 );\r
655\r
656 if (EFI_ERROR (Status)) {\r
657 return Status;\r
658 }\r
659 //\r
660 // Load the PE image from the FFS file\r
661 //\r
fc198a79 662 Status = PeiLoadPeImage (\r
3005648d 663 PeiEfiPeiPeCoffLoader,\r
664 Pe32Data,\r
665 EfiBootServicesData,\r
666 ImageAddress,\r
667 ImageSize,\r
668 EntryPoint\r
669 );\r
670\r
671 return Status;\r
672}\r
673\r
674EFI_STATUS\r
675PeiProcessFile (\r
6326ee4e
LG
676 IN UINT16 SectionType,\r
677 IN OUT EFI_FFS_FILE_HEADER **RealFfsFileHeader,\r
678 OUT VOID **Pe32Data\r
3005648d 679 )\r
680/*++\r
681\r
682Routine Description:\r
683\r
684Arguments:\r
685\r
686 SectionType - The type of section in the FFS file to process.\r
687\r
688 FfsFileHeader - Pointer to the FFS file to process, looking for the\r
689 specified SectionType\r
690\r
691 Pe32Data - returned pointer to the start of the PE32 image found\r
692 in the FFS file.\r
693\r
694Returns:\r
695\r
696 EFI_SUCCESS - found the PE32 section in the FFS file\r
697\r
698--*/\r
699{\r
700 EFI_STATUS Status;\r
701 VOID *SectionData;\r
702 DECOMPRESS_LIBRARY *DecompressLibrary;\r
703 UINT8 *DstBuffer;\r
704 UINT8 *ScratchBuffer;\r
705 UINT32 DstBufferSize;\r
706 UINT32 ScratchBufferSize;\r
707 EFI_COMMON_SECTION_HEADER *CmpSection;\r
708 UINTN CmpSectionLength;\r
709 UINTN OccupiedCmpSectionLength;\r
710 VOID *CmpFileData;\r
711 UINTN CmpFileSize;\r
712 EFI_COMMON_SECTION_HEADER *Section;\r
713 UINTN SectionLength;\r
714 UINTN OccupiedSectionLength;\r
715 UINT64 FileSize;\r
716 EFI_GUID_DEFINED_SECTION *GuidedSectionHeader;\r
717 UINT32 AuthenticationStatus;\r
718 EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract;\r
719 UINT32 BufferSize;\r
720 UINT8 *Buffer;\r
721 EFI_PEI_SECURITY_PPI *Security;\r
722 BOOLEAN StartCrisisRecovery;\r
723 EFI_GUID TempGuid;\r
724 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
725 EFI_COMPRESSION_SECTION *CompressionSection;\r
6326ee4e
LG
726 EFI_FFS_FILE_HEADER *FfsFileHeader;\r
727 \r
728 FfsFileHeader = *RealFfsFileHeader;\r
3005648d 729\r
84a99d48 730 Status = PeiServicesFfsFindSectionData (\r
3005648d 731 EFI_SECTION_COMPRESSION,\r
732 FfsFileHeader,\r
733 &SectionData\r
734 );\r
735\r
736 //\r
737 // Upon finding a DXE Core file, see if there is first a compression section\r
738 //\r
739 if (!EFI_ERROR (Status)) {\r
740 //\r
741 // Yes, there is a compression section, so extract the contents\r
742 // Decompress the image here\r
743 //\r
744 Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));\r
745\r
746 do {\r
747 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r
748 OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);\r
749\r
750 //\r
751 // Was the DXE Core file encapsulated in a GUID'd section?\r
752 //\r
753 if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r
754 //\r
755 // Locate the GUID'd Section Extractor\r
756 //\r
757 GuidedSectionHeader = (VOID *) (Section + 1);\r
758\r
759 //\r
760 // This following code constitutes the addition of the security model\r
761 // to the DXE IPL.\r
762 //\r
763 //\r
764 // Set a default authenticatino state\r
765 //\r
766 AuthenticationStatus = 0;\r
767\r
84a99d48 768 Status = PeiServicesLocatePpi (\r
3005648d 769 &gEfiPeiSectionExtractionPpiGuid,\r
770 0,\r
771 NULL,\r
772 (VOID **)&SectionExtract\r
773 );\r
774\r
775 if (EFI_ERROR (Status)) {\r
776 return Status;\r
777 }\r
778 //\r
779 // Verify Authentication State\r
780 //\r
781 CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));\r
782\r
783 Status = SectionExtract->PeiGetSection (\r
784 GetPeiServicesTablePointer(),\r
785 SectionExtract,\r
786 (EFI_SECTION_TYPE *) &SectionType,\r
787 &TempGuid,\r
788 0,\r
789 (VOID **) &Buffer,\r
790 &BufferSize,\r
791 &AuthenticationStatus\r
792 );\r
793\r
794 if (EFI_ERROR (Status)) {\r
795 return Status;\r
796 }\r
797 //\r
798 // If not ask the Security PPI, if exists, for disposition\r
799 //\r
800 //\r
84a99d48 801 Status = PeiServicesLocatePpi (\r
3005648d 802 &gEfiPeiSecurityPpiGuid,\r
803 0,\r
804 NULL,\r
805 (VOID **)&Security\r
806 );\r
807 if (EFI_ERROR (Status)) {\r
808 return Status;\r
809 }\r
810\r
811 Status = Security->AuthenticationState (\r
812 GetPeiServicesTablePointer(),\r
813 (struct _EFI_PEI_SECURITY_PPI *) Security,\r
814 AuthenticationStatus,\r
815 FfsFileHeader,\r
816 &StartCrisisRecovery\r
817 );\r
818\r
819 if (EFI_ERROR (Status)) {\r
820 return Status;\r
821 }\r
822 //\r
823 // If there is a security violation, report to caller and have\r
824 // the upper-level logic possible engender a crisis recovery\r
825 //\r
826 if (StartCrisisRecovery) {\r
827 return EFI_SECURITY_VIOLATION;\r
828 }\r
829 }\r
830\r
831 if (Section->Type == EFI_SECTION_PE32) {\r
832 //\r
833 // This is what we want\r
834 //\r
835 *Pe32Data = (VOID *) (Section + 1);\r
836 return EFI_SUCCESS;\r
837 } else if (Section->Type == EFI_SECTION_COMPRESSION) {\r
838 //\r
839 // This is a compression set, expand it\r
840 //\r
841 CompressionSection = (EFI_COMPRESSION_SECTION *) Section;\r
842\r
843 switch (CompressionSection->CompressionType) {\r
844 case EFI_STANDARD_COMPRESSION:\r
845 DecompressLibrary = &gTianoDecompress;\r
846 break;\r
847\r
848 case EFI_CUSTOMIZED_COMPRESSION:\r
849 //\r
850 // Load user customized compression protocol.\r
851 //\r
852 DecompressLibrary = &gCustomDecompress;\r
853 break;\r
854\r
855 case EFI_NOT_COMPRESSED:\r
856 default:\r
857 //\r
858 // Need to support not compressed file\r
859 //\r
860 ASSERT_EFI_ERROR (Status);\r
861 return EFI_NOT_FOUND;\r
862 }\r
863\r
864 Status = DecompressLibrary->GetInfo (\r
865 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r
866 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),\r
867 &DstBufferSize,\r
868 &ScratchBufferSize\r
869 );\r
870 if (EFI_ERROR (Status)) {\r
871 //\r
872 // GetInfo failed\r
873 //\r
874 return EFI_NOT_FOUND;\r
875 }\r
876\r
877 //\r
878 // Allocate scratch buffer\r
879 //\r
880 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r
881 if (ScratchBuffer == NULL) {\r
882 return EFI_OUT_OF_RESOURCES;\r
883 }\r
884\r
885 //\r
886 // Allocate destination buffer\r
887 //\r
888 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r
889 if (DstBuffer == NULL) {\r
890 return EFI_OUT_OF_RESOURCES;\r
891 }\r
892\r
893 //\r
894 // Call decompress function\r
895 //\r
896 Status = DecompressLibrary->Decompress (\r
897 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r
898 DstBuffer,\r
899 ScratchBuffer\r
900 );\r
901\r
902 CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;\r
903 if (CmpSection->Type == EFI_SECTION_RAW) {\r
904 //\r
905 // Skip the section header and\r
906 // adjust the pointer alignment to 16\r
907 //\r
908 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16);\r
909\r
910 if (FvHeader->Signature == EFI_FVH_SIGNATURE) {\r
911 FfsFileHeader = NULL;\r
912 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);\r
84a99d48 913 Status = PeiServicesFfsFindNextFile (\r
3005648d 914 EFI_FV_FILETYPE_DXE_CORE,\r
915 FvHeader,\r
916 &FfsFileHeader\r
917 );\r
918\r
919 if (EFI_ERROR (Status)) {\r
920 return EFI_NOT_FOUND;\r
921 }\r
922\r
6326ee4e
LG
923 //\r
924 // Reture the FfsHeader that contain Pe32Data.\r
925 //\r
926 *RealFfsFileHeader = FfsFileHeader;\r
927 return PeiProcessFile (SectionType, RealFfsFileHeader, Pe32Data);\r
3005648d 928 }\r
929 }\r
930 //\r
931 // Decompress successfully.\r
932 // Loop the decompressed data searching for expected section.\r
933 //\r
934 CmpFileData = (VOID *) DstBuffer;\r
935 CmpFileSize = DstBufferSize;\r
936 do {\r
937 CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;\r
938 if (CmpSection->Type == EFI_SECTION_PE32) {\r
939 //\r
940 // This is what we want\r
941 //\r
942 *Pe32Data = (VOID *) (CmpSection + 1);\r
943 return EFI_SUCCESS;\r
944 }\r
945\r
946 OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4);\r
947 CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);\r
948 } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);\r
949 }\r
950\r
951 Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r
952 FileSize = FfsFileHeader->Size[0] & 0xFF;\r
953 FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;\r
954 FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;\r
955 FileSize &= 0x00FFFFFF;\r
956 } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);\r
957\r
958 //\r
959 // End of the decompression activity\r
960 //\r
961 } else {\r
962\r
84a99d48 963 Status = PeiServicesFfsFindSectionData (\r
3005648d 964 EFI_SECTION_PE32,\r
965 FfsFileHeader,\r
966 &SectionData\r
967 );\r
968\r
969 if (EFI_ERROR (Status)) {\r
84a99d48 970 Status = PeiServicesFfsFindSectionData (\r
3005648d 971 EFI_SECTION_TE,\r
972 FfsFileHeader,\r
973 &SectionData\r
974 );\r
975 if (EFI_ERROR (Status)) {\r
976 return Status;\r
977 }\r
978 }\r
979 }\r
980\r
981 *Pe32Data = SectionData;\r
982\r
983 return EFI_SUCCESS;\r
878ddf1f 984}