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