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