3005648d |
1 | /*++\r |
2 | \r |
3 | Copyright (c) 2006, Intel Corporation \r |
4 | All rights reserved. This program and the accompanying materials \r |
5 | are licensed and made available under the terms and conditions of the BSD License \r |
6 | which accompanies this distribution. The full text of the license may be found at \r |
7 | http://opensource.org/licenses/bsd-license.php \r |
8 | \r |
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r |
11 | \r |
12 | Module Name:\r |
13 | \r |
14 | DxeLoad.c\r |
15 | \r |
16 | Abstract:\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 |
27 | BOOLEAN gInMemory = FALSE;\r |
28 | \r |
29 | //\r |
30 | // GUID for EM64T\r |
31 | //\r |
32 | #define EFI_PPI_NEEDED_BY_DXE \\r |
33 | { \\r |
34 | 0x4d37da42, 0x3a0c, 0x4eda, 0xb9, 0xeb, 0xbc, 0x0e, 0x1d, 0xb4, 0x71, 0x3b \\r |
35 | }\r |
36 | EFI_GUID mPpiNeededByDxeGuid = EFI_PPI_NEEDED_BY_DXE;\r |
37 | \r |
38 | //\r |
39 | // Module Globals used in the DXE to PEI handoff\r |
40 | // These must be module globals, so the stack can be switched\r |
41 | //\r |
42 | static EFI_DXE_IPL_PPI mDxeIplPpi = {\r |
43 | DxeLoadCore\r |
44 | };\r |
45 | \r |
46 | static EFI_PEI_FV_FILE_LOADER_PPI mLoadFilePpi = {\r |
47 | DxeIplLoadFile\r |
48 | };\r |
49 | \r |
50 | static EFI_PEI_PPI_DESCRIPTOR mPpiLoadFile = {\r |
51 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
52 | &gEfiPeiFvFileLoaderPpiGuid,\r |
53 | &mLoadFilePpi\r |
54 | };\r |
55 | \r |
56 | static EFI_PEI_PPI_DESCRIPTOR mPpiList = {\r |
57 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
58 | &gEfiDxeIplPpiGuid,\r |
59 | &mDxeIplPpi\r |
60 | };\r |
61 | \r |
62 | static EFI_PEI_PPI_DESCRIPTOR mPpiPeiInMemory = {\r |
63 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
64 | &gPeiInMemoryGuid,\r |
65 | NULL\r |
66 | };\r |
67 | \r |
68 | static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = {\r |
69 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
70 | &gEfiEndOfPeiSignalPpiGuid,\r |
71 | NULL\r |
72 | };\r |
73 | \r |
74 | DECOMPRESS_LIBRARY gEfiDecompress = {\r |
75 | UefiDecompressGetInfo,\r |
76 | UefiDecompress\r |
77 | };\r |
78 | \r |
79 | DECOMPRESS_LIBRARY gTianoDecompress = {\r |
80 | TianoDecompressGetInfo,\r |
81 | TianoDecompress\r |
82 | };\r |
83 | \r |
84 | DECOMPRESS_LIBRARY gCustomDecompress = {\r |
85 | CustomDecompressGetInfo,\r |
86 | CustomDecompress\r |
87 | };\r |
88 | \r |
89 | STATIC\r |
90 | UINTN\r |
91 | GetOccupiedSize (\r |
92 | IN UINTN ActualSize,\r |
93 | IN UINTN Alignment\r |
94 | )\r |
95 | {\r |
96 | UINTN OccupiedSize;\r |
97 | \r |
98 | OccupiedSize = ActualSize;\r |
99 | while ((OccupiedSize & (Alignment - 1)) != 0) {\r |
100 | OccupiedSize++;\r |
101 | }\r |
102 | \r |
103 | return OccupiedSize;\r |
104 | }\r |
105 | \r |
106 | EFI_STATUS\r |
107 | EFIAPI\r |
108 | PeimInitializeDxeIpl (\r |
109 | IN EFI_FFS_FILE_HEADER *FfsHeader,\r |
110 | IN EFI_PEI_SERVICES **PeiServices\r |
111 | )\r |
112 | /*++\r |
113 | \r |
114 | Routine Description:\r |
115 | \r |
116 | Initializes the Dxe Ipl PPI\r |
117 | \r |
118 | Arguments:\r |
119 | \r |
120 | FfsHeader - Pointer to FFS file header\r |
121 | PeiServices - General purpose services available to every PEIM.\r |
122 | \r |
123 | Returns:\r |
124 | \r |
125 | EFI_SUCCESS\r |
126 | \r |
127 | --*/\r |
128 | {\r |
129 | EFI_STATUS Status;\r |
130 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
131 | EFI_BOOT_MODE BootMode;\r |
132 | \r |
133 | Status = PeiCoreGetBootMode (&BootMode);\r |
134 | \r |
135 | ASSERT_EFI_ERROR (Status);\r |
136 | \r |
137 | Status = PeiCoreLocatePpi (\r |
138 | &gPeiInMemoryGuid,\r |
139 | 0,\r |
140 | NULL,\r |
141 | NULL\r |
142 | );\r |
143 | \r |
144 | if (EFI_ERROR (Status) && (BootMode != BOOT_ON_S3_RESUME)) { \r |
145 | //\r |
146 | // The DxeIpl has not yet been shadowed\r |
147 | //\r |
148 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
149 | \r |
150 | //\r |
151 | // Shadow DxeIpl and then re-run its entry point\r |
152 | //\r |
153 | Status = ShadowDxeIpl (FfsHeader, PeiEfiPeiPeCoffLoader);\r |
154 | if (EFI_ERROR (Status)) {\r |
155 | return Status;\r |
156 | }\r |
157 | \r |
158 | } else {\r |
159 | if (BootMode != BOOT_ON_S3_RESUME) {\r |
160 | //\r |
161 | // The DxeIpl has been shadowed\r |
162 | //\r |
163 | gInMemory = TRUE;\r |
164 | \r |
165 | //\r |
166 | // Install LoadFile PPI\r |
167 | //\r |
168 | Status = PeiCoreInstallPpi (&mPpiLoadFile);\r |
169 | \r |
170 | if (EFI_ERROR (Status)) {\r |
171 | return Status;\r |
172 | }\r |
173 | }\r |
174 | //\r |
175 | // Install DxeIpl PPI\r |
176 | //\r |
177 | PeiCoreInstallPpi (&mPpiList);\r |
178 | \r |
179 | if (EFI_ERROR (Status)) {\r |
180 | return Status;\r |
181 | }\r |
182 | \r |
183 | }\r |
184 | \r |
185 | return EFI_SUCCESS;\r |
186 | }\r |
187 | \r |
188 | EFI_STATUS\r |
189 | EFIAPI\r |
190 | DxeLoadCore (\r |
191 | IN EFI_DXE_IPL_PPI *This,\r |
192 | IN EFI_PEI_SERVICES **PeiServices,\r |
193 | IN EFI_PEI_HOB_POINTERS HobList\r |
194 | )\r |
195 | /*++\r |
196 | \r |
197 | Routine Description:\r |
198 | \r |
199 | Main entry point to last PEIM\r |
200 | \r |
201 | Arguments:\r |
202 | \r |
203 | This - Entry point for DXE IPL PPI\r |
204 | PeiServices - General purpose services available to every PEIM.\r |
205 | HobList - Address to the Pei HOB list\r |
206 | \r |
207 | Returns:\r |
208 | \r |
209 | EFI_SUCCESS - DEX core was successfully loaded.\r |
210 | EFI_OUT_OF_RESOURCES - There are not enough resources to load DXE core.\r |
211 | \r |
212 | --*/\r |
213 | {\r |
214 | EFI_STATUS Status;\r |
215 | EFI_PHYSICAL_ADDRESS TopOfStack;\r |
216 | EFI_PHYSICAL_ADDRESS BaseOfStack;\r |
217 | EFI_PHYSICAL_ADDRESS BspStore;\r |
218 | EFI_GUID DxeCoreFileName;\r |
219 | VOID *DxeCorePe32Data;\r |
220 | EFI_PHYSICAL_ADDRESS DxeCoreAddress;\r |
221 | UINT64 DxeCoreSize;\r |
222 | EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;\r |
223 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
224 | EFI_BOOT_MODE BootMode;\r |
225 | EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;\r |
226 | EFI_PEI_S3_RESUME_PPI *S3Resume;\r |
227 | EFI_PHYSICAL_ADDRESS PageTables;\r |
228 | \r |
229 | TopOfStack = 0;\r |
230 | BaseOfStack = 0;\r |
231 | BspStore = 0;\r |
232 | Status = EFI_SUCCESS;\r |
233 | \r |
234 | //\r |
235 | // if in S3 Resume, restore configure\r |
236 | //\r |
237 | Status = PeiCoreGetBootMode (&BootMode);\r |
238 | \r |
239 | if (!EFI_ERROR (Status) && (BootMode == BOOT_ON_S3_RESUME)) {\r |
240 | Status = PeiCoreLocatePpi (\r |
241 | &gEfiPeiS3ResumePpiGuid,\r |
242 | 0,\r |
243 | NULL,\r |
244 | (VOID **)&S3Resume\r |
245 | );\r |
246 | \r |
247 | ASSERT_EFI_ERROR (Status);\r |
248 | \r |
249 | Status = S3Resume->S3RestoreConfig (PeiServices);\r |
250 | \r |
251 | ASSERT_EFI_ERROR (Status);\r |
252 | }\r |
253 | \r |
254 | Status = EFI_SUCCESS;\r |
255 | \r |
256 | //\r |
257 | // Install the PEI Protocols that are shared between PEI and DXE\r |
258 | //\r |
259 | #ifdef EFI_NT_EMULATOR\r |
260 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
261 | ASSERT (PeiEfiPeiPeCoffLoader != NULL);\r |
262 | #else\r |
263 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderX64Protocol ();\r |
264 | #endif \r |
265 | \r |
266 | #if 0\r |
267 | Status = InstallEfiPeiPeCoffLoader64 (PeiServices, &PeiEfiPeiPeCoffLoader, NULL);\r |
268 | ASSERT_EFI_ERROR (Status);\r |
269 | #endif\r |
270 | //\r |
271 | // Allocate 128KB for the Stack\r |
272 | //\r |
273 | PeiCoreAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r |
274 | ASSERT (BaseOfStack != 0);\r |
275 | \r |
276 | //\r |
277 | // Compute the top of the stack we were allocated. Pre-allocate a 32 bytes\r |
278 | // for safety (PpisNeededByDxe and DxeCore).\r |
279 | //\r |
280 | TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;\r |
281 | \r |
282 | //\r |
283 | // Add architecture-specifc HOBs (including the BspStore HOB)\r |
284 | //\r |
285 | Status = CreateArchSpecificHobs (&BspStore);\r |
286 | ASSERT_EFI_ERROR (Status);\r |
287 | \r |
288 | //\r |
289 | // See if we are in crisis recovery\r |
290 | //\r |
291 | Status = PeiCoreGetBootMode (&BootMode);\r |
292 | if (!EFI_ERROR (Status) && (BootMode == BOOT_IN_RECOVERY_MODE)) {\r |
293 | Status = PeiCoreLocatePpi (\r |
294 | &gEfiPeiRecoveryModulePpiGuid,\r |
295 | 0,\r |
296 | NULL,\r |
297 | (VOID **)&PeiRecovery\r |
298 | );\r |
299 | \r |
300 | ASSERT_EFI_ERROR (Status);\r |
301 | Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);\r |
302 | ASSERT_EFI_ERROR (Status);\r |
303 | }\r |
304 | \r |
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 |
316 | //\r |
317 | // Transfer control to the DXE Core\r |
318 | // The handoff state is simply a pointer to the HOB list\r |
319 | //\r |
320 | // PEI_PERF_END (PeiServices, L"DxeIpl", NULL, 0);\r |
321 | \r |
322 | Status = PeiCoreInstallPpi (&mPpiSignal);\r |
323 | ASSERT_EFI_ERROR (Status);\r |
324 | \r |
325 | //\r |
326 | // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA \\r |
327 | // memory, it may be corrupted when copying FV to high-end memory \r |
328 | LoadGo64Gdt();\r |
329 | \r |
330 | //\r |
331 | // Limit to 36 bits of addressing for debug. Should get it from CPU\r |
332 | //\r |
333 | PageTables = CreateIdentityMappingPageTables (36);\r |
334 | \r |
335 | \r |
336 | //\r |
337 | // Load the DXE Core from a Firmware Volume\r |
338 | //\r |
339 | Status = PeiLoadx64File (\r |
340 | PeiEfiPeiPeCoffLoader,\r |
341 | DxeCorePe32Data,\r |
342 | EfiBootServicesData,\r |
343 | &DxeCoreAddress,\r |
344 | &DxeCoreSize,\r |
345 | &DxeCoreEntryPoint\r |
346 | );\r |
347 | ASSERT_EFI_ERROR (Status);\r |
348 | \r |
349 | //\r |
350 | //\r |
351 | // Add HOB for the DXE Core\r |
352 | //\r |
353 | BuildModuleHob (\r |
354 | &DxeCoreFileName,\r |
355 | DxeCoreAddress,\r |
356 | DxeCoreSize,\r |
357 | DxeCoreEntryPoint\r |
358 | );\r |
359 | \r |
360 | //\r |
361 | // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT\r |
362 | //\r |
363 | REPORT_STATUS_CODE (\r |
364 | EFI_PROGRESS_CODE,\r |
365 | EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT\r |
366 | );\r |
367 | \r |
368 | DEBUG ((EFI_D_INFO, "DXE Core Entry\n"));\r |
369 | //\r |
370 | // Go to Long Mode. Interrupts will not get turned on until the CPU AP is loaded.\r |
371 | // Call x64 drivers passing in single argument, a pointer to the HOBs.\r |
372 | //\r |
373 | ActivateLongMode (\r |
374 | PageTables, \r |
375 | (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw), \r |
376 | TopOfStack,\r |
377 | 0x00000000,\r |
378 | DxeCoreEntryPoint\r |
379 | );\r |
380 | \r |
381 | //\r |
382 | // If we get here, then the DXE Core returned. This is an error\r |
383 | //\r |
384 | ASSERT_EFI_ERROR (Status);\r |
385 | \r |
386 | return EFI_OUT_OF_RESOURCES;\r |
387 | }\r |
388 | \r |
389 | EFI_STATUS\r |
390 | PeiFindFile (\r |
391 | IN UINT8 Type,\r |
392 | IN UINT16 SectionType,\r |
393 | OUT EFI_GUID *FileName,\r |
394 | OUT VOID **Pe32Data\r |
395 | )\r |
396 | /*++\r |
397 | \r |
398 | Routine Description:\r |
399 | \r |
400 | Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes\r |
401 | described in the HOB list. Able to search in a compression set in a FFS file.\r |
402 | But only one level of compression is supported, that is, not able to search\r |
403 | in a compression set that is within another compression set.\r |
404 | \r |
405 | Arguments:\r |
406 | \r |
407 | Type - The Type of file to retrieve\r |
408 | \r |
409 | SectionType - The type of section to retrieve from a file\r |
410 | \r |
411 | FileName - The name of the file found in the Firmware Volume\r |
412 | \r |
413 | Pe32Data - Pointer to the beginning of the PE/COFF file found in the Firmware Volume\r |
414 | \r |
415 | Returns:\r |
416 | \r |
417 | EFI_SUCCESS - The file was found, and the name is returned in FileName, and a pointer to\r |
418 | the PE/COFF image is returned in Pe32Data\r |
419 | \r |
420 | EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List\r |
421 | \r |
422 | --*/\r |
423 | {\r |
424 | EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r |
425 | EFI_FFS_FILE_HEADER *FfsFileHeader;\r |
426 | VOID *SectionData;\r |
427 | EFI_STATUS Status;\r |
428 | EFI_PEI_HOB_POINTERS Hob;\r |
429 | \r |
430 | \r |
431 | FwVolHeader = NULL;\r |
432 | FfsFileHeader = NULL;\r |
433 | SectionData = NULL;\r |
434 | \r |
435 | //\r |
436 | // Foreach Firmware Volume, look for a specified type\r |
437 | // of file and break out when one is found\r |
438 | //\r |
439 | Hob.Raw = GetHobList ();\r |
440 | while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw)) != NULL) {\r |
441 | FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress);\r |
442 | Status = PeiCoreFfsFindNextFile (\r |
443 | Type,\r |
444 | FwVolHeader,\r |
445 | &FfsFileHeader\r |
446 | );\r |
447 | if (!EFI_ERROR (Status)) {\r |
448 | CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));\r |
449 | Status = PeiProcessFile (\r |
450 | SectionType,\r |
451 | FfsFileHeader,\r |
452 | Pe32Data\r |
453 | );\r |
454 | return Status;\r |
455 | }\r |
456 | Hob.Raw = GET_NEXT_HOB (Hob);\r |
457 | }\r |
458 | return EFI_NOT_FOUND;\r |
459 | }\r |
460 | \r |
461 | EFI_STATUS\r |
462 | PeiLoadx64File (\r |
463 | IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,\r |
464 | IN VOID *Pe32Data,\r |
465 | IN EFI_MEMORY_TYPE MemoryType,\r |
466 | OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r |
467 | OUT UINT64 *ImageSize,\r |
468 | OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r |
469 | )\r |
470 | /*++\r |
471 | \r |
472 | Routine Description:\r |
473 | \r |
474 | Loads and relocates a PE/COFF image into memory.\r |
475 | \r |
476 | Arguments:\r |
477 | \r |
478 | PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r |
479 | \r |
480 | Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r |
481 | \r |
482 | ImageAddress - The base address of the relocated PE/COFF image\r |
483 | \r |
484 | ImageSize - The size of the relocated PE/COFF image\r |
485 | \r |
486 | EntryPoint - The entry point of the relocated PE/COFF image\r |
487 | \r |
488 | Returns:\r |
489 | \r |
490 | EFI_SUCCESS - The file was loaded and relocated\r |
491 | EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r |
492 | \r |
493 | --*/\r |
494 | {\r |
495 | EFI_STATUS Status;\r |
496 | PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r |
497 | EFI_PHYSICAL_ADDRESS MemoryBuffer;\r |
498 | \r |
499 | ZeroMem (&ImageContext, sizeof (ImageContext));\r |
500 | ImageContext.Handle = Pe32Data;\r |
501 | Status = GetImageReadFunction (&ImageContext);\r |
502 | \r |
503 | ASSERT_EFI_ERROR (Status);\r |
504 | \r |
505 | Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);\r |
506 | if (EFI_ERROR (Status)) {\r |
507 | return Status;\r |
508 | }\r |
509 | //\r |
510 | // Allocate Memory for the image\r |
511 | //\r |
512 | //\r |
513 | // Allocate Memory for the image\r |
514 | //\r |
515 | PeiCoreAllocatePages (MemoryType, EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize), &MemoryBuffer);\r |
516 | ImageContext.ImageAddress = MemoryBuffer;\r |
517 | ASSERT (ImageContext.ImageAddress != 0);\r |
518 | \r |
519 | //\r |
520 | // Load the image to our new buffer\r |
521 | //\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 | //\r |
529 | // Relocate the image in our new buffer\r |
530 | //\r |
531 | Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r |
532 | if (EFI_ERROR (Status)) {\r |
533 | return Status;\r |
534 | }\r |
535 | \r |
536 | //\r |
537 | // Flush the instruction cache so the image data is written before we execute it\r |
538 | //\r |
539 | InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r |
540 | \r |
541 | *ImageAddress = ImageContext.ImageAddress;\r |
542 | *ImageSize = ImageContext.ImageSize;\r |
543 | *EntryPoint = ImageContext.EntryPoint;\r |
544 | \r |
545 | return EFI_SUCCESS;\r |
546 | }\r |
547 | \r |
548 | EFI_STATUS\r |
549 | ShadowDxeIpl (\r |
550 | IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,\r |
551 | IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader\r |
552 | )\r |
553 | /*++\r |
554 | \r |
555 | Routine Description:\r |
556 | \r |
557 | Shadow the DXE IPL to a different memory location. This occurs after permanent\r |
558 | memory has been discovered.\r |
559 | \r |
560 | Arguments:\r |
561 | \r |
562 | DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver\r |
563 | \r |
564 | PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r |
565 | \r |
566 | Returns:\r |
567 | \r |
568 | EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.\r |
569 | \r |
570 | EFI_ ERROR - The shadow was unsuccessful.\r |
571 | \r |
572 | \r |
573 | --*/\r |
574 | {\r |
575 | UINTN SectionLength;\r |
576 | UINTN OccupiedSectionLength;\r |
577 | EFI_PHYSICAL_ADDRESS DxeIplAddress;\r |
578 | UINT64 DxeIplSize;\r |
579 | EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;\r |
580 | EFI_STATUS Status;\r |
581 | EFI_COMMON_SECTION_HEADER *Section;\r |
582 | \r |
583 | Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);\r |
584 | \r |
585 | while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {\r |
586 | SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r |
587 | OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);\r |
588 | Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r |
589 | }\r |
590 | \r |
591 | //\r |
592 | // Relocate DxeIpl into memory by using loadfile service\r |
593 | //\r |
594 | Status = PeiLoadx64File (\r |
595 | PeiEfiPeiPeCoffLoader,\r |
596 | (VOID *) (Section + 1),\r |
597 | EfiBootServicesData,\r |
598 | &DxeIplAddress,\r |
599 | &DxeIplSize,\r |
600 | &DxeIplEntryPoint\r |
601 | );\r |
602 | \r |
603 | if (Status == EFI_SUCCESS) {\r |
604 | //\r |
605 | // Install PeiInMemory to indicate the Dxeipl is shadowed\r |
606 | //\r |
607 | Status = PeiCoreInstallPpi (&mPpiPeiInMemory);\r |
608 | \r |
609 | if (EFI_ERROR (Status)) {\r |
610 | return Status;\r |
611 | }\r |
612 | \r |
613 | Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer());\r |
614 | }\r |
615 | \r |
616 | return Status;\r |
617 | }\r |
618 | \r |
619 | EFI_STATUS\r |
620 | EFIAPI\r |
621 | DxeIplLoadFile (\r |
622 | IN EFI_PEI_FV_FILE_LOADER_PPI *This,\r |
623 | IN EFI_FFS_FILE_HEADER *FfsHeader,\r |
624 | OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r |
625 | OUT UINT64 *ImageSize,\r |
626 | OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r |
627 | )\r |
628 | /*++\r |
629 | \r |
630 | Routine Description:\r |
631 | \r |
632 | Given a pointer to an FFS file containing a PE32 image, get the\r |
633 | information on the PE32 image, and then "load" it so that it\r |
634 | can be executed.\r |
635 | \r |
636 | Arguments:\r |
637 | \r |
638 | This - pointer to our file loader protocol\r |
639 | FfsHeader - pointer to the FFS file header of the FFS file that\r |
640 | contains the PE32 image we want to load\r |
641 | ImageAddress - returned address where the PE32 image is loaded\r |
642 | ImageSize - returned size of the loaded PE32 image\r |
643 | EntryPoint - entry point to the loaded PE32 image\r |
644 | \r |
645 | Returns:\r |
646 | \r |
647 | EFI_SUCCESS - The FFS file was successfully loaded.\r |
648 | EFI_ERROR - Unable to load the FFS file.\r |
649 | \r |
650 | --*/\r |
651 | {\r |
652 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
653 | EFI_STATUS Status;\r |
654 | VOID *Pe32Data;\r |
655 | \r |
656 | Pe32Data = NULL;\r |
657 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
658 | \r |
659 | //\r |
660 | // Preprocess the FFS file to get a pointer to the PE32 information\r |
661 | // in the enclosed PE32 image.\r |
662 | //\r |
663 | Status = PeiProcessFile (\r |
664 | EFI_SECTION_PE32,\r |
665 | FfsHeader,\r |
666 | &Pe32Data\r |
667 | );\r |
668 | \r |
669 | if (EFI_ERROR (Status)) {\r |
670 | return Status;\r |
671 | }\r |
672 | //\r |
673 | // Load the PE image from the FFS file\r |
674 | //\r |
675 | Status = PeiLoadx64File (\r |
676 | PeiEfiPeiPeCoffLoader,\r |
677 | Pe32Data,\r |
678 | EfiBootServicesData,\r |
679 | ImageAddress,\r |
680 | ImageSize,\r |
681 | EntryPoint\r |
682 | );\r |
683 | \r |
684 | return Status;\r |
685 | }\r |
686 | \r |
687 | EFI_STATUS\r |
688 | PeiProcessFile (\r |
689 | IN UINT16 SectionType,\r |
690 | IN EFI_FFS_FILE_HEADER *FfsFileHeader,\r |
691 | OUT VOID **Pe32Data\r |
692 | )\r |
693 | /*++\r |
694 | \r |
695 | Routine Description:\r |
696 | \r |
697 | Arguments:\r |
698 | \r |
699 | SectionType - The type of section in the FFS file to process.\r |
700 | \r |
701 | FfsFileHeader - Pointer to the FFS file to process, looking for the\r |
702 | specified SectionType\r |
703 | \r |
704 | Pe32Data - returned pointer to the start of the PE32 image found\r |
705 | in the FFS file.\r |
706 | \r |
707 | Returns:\r |
708 | \r |
709 | EFI_SUCCESS - found the PE32 section in the FFS file\r |
710 | \r |
711 | --*/\r |
712 | {\r |
713 | EFI_STATUS Status;\r |
714 | VOID *SectionData;\r |
715 | DECOMPRESS_LIBRARY *DecompressLibrary;\r |
716 | UINT8 *DstBuffer;\r |
717 | UINT8 *ScratchBuffer;\r |
718 | UINT32 DstBufferSize;\r |
719 | UINT32 ScratchBufferSize;\r |
720 | EFI_COMMON_SECTION_HEADER *CmpSection;\r |
721 | UINTN CmpSectionLength;\r |
722 | UINTN OccupiedCmpSectionLength;\r |
723 | VOID *CmpFileData;\r |
724 | UINTN CmpFileSize;\r |
725 | EFI_COMMON_SECTION_HEADER *Section;\r |
726 | UINTN SectionLength;\r |
727 | UINTN OccupiedSectionLength;\r |
728 | UINT64 FileSize;\r |
729 | EFI_GUID_DEFINED_SECTION *GuidedSectionHeader;\r |
730 | UINT32 AuthenticationStatus;\r |
731 | EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract;\r |
732 | UINT32 BufferSize;\r |
733 | UINT8 *Buffer;\r |
734 | EFI_PEI_SECURITY_PPI *Security;\r |
735 | BOOLEAN StartCrisisRecovery;\r |
736 | EFI_GUID TempGuid;\r |
737 | EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r |
738 | EFI_COMPRESSION_SECTION *CompressionSection;\r |
739 | \r |
740 | Status = PeiCoreFfsFindSectionData (\r |
741 | EFI_SECTION_COMPRESSION,\r |
742 | FfsFileHeader,\r |
743 | &SectionData\r |
744 | );\r |
745 | \r |
746 | //\r |
747 | // Upon finding a DXE Core file, see if there is first a compression section\r |
748 | //\r |
749 | if (!EFI_ERROR (Status)) {\r |
750 | //\r |
751 | // Yes, there is a compression section, so extract the contents\r |
752 | // Decompress the image here\r |
753 | //\r |
754 | Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));\r |
755 | \r |
756 | do {\r |
757 | SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r |
758 | OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);\r |
759 | \r |
760 | //\r |
761 | // Was the DXE Core file encapsulated in a GUID'd section?\r |
762 | //\r |
763 | if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r |
764 | //\r |
765 | // Locate the GUID'd Section Extractor\r |
766 | //\r |
767 | GuidedSectionHeader = (VOID *) (Section + 1);\r |
768 | \r |
769 | //\r |
770 | // This following code constitutes the addition of the security model\r |
771 | // to the DXE IPL.\r |
772 | //\r |
773 | //\r |
774 | // Set a default authenticatino state\r |
775 | //\r |
776 | AuthenticationStatus = 0;\r |
777 | \r |
778 | Status = PeiCoreLocatePpi (\r |
779 | &gEfiPeiSectionExtractionPpiGuid,\r |
780 | 0,\r |
781 | NULL,\r |
782 | (VOID **)&SectionExtract\r |
783 | );\r |
784 | \r |
785 | if (EFI_ERROR (Status)) {\r |
786 | return Status;\r |
787 | }\r |
788 | //\r |
789 | // Verify Authentication State\r |
790 | //\r |
791 | CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));\r |
792 | \r |
793 | Status = SectionExtract->PeiGetSection (\r |
794 | GetPeiServicesTablePointer(),\r |
795 | SectionExtract,\r |
796 | (EFI_SECTION_TYPE *) &SectionType,\r |
797 | &TempGuid,\r |
798 | 0,\r |
799 | (VOID **) &Buffer,\r |
800 | &BufferSize,\r |
801 | &AuthenticationStatus\r |
802 | );\r |
803 | \r |
804 | if (EFI_ERROR (Status)) {\r |
805 | return Status;\r |
806 | }\r |
807 | //\r |
808 | // If not ask the Security PPI, if exists, for disposition\r |
809 | //\r |
810 | //\r |
811 | Status = PeiCoreLocatePpi (\r |
812 | &gEfiPeiSecurityPpiGuid,\r |
813 | 0,\r |
814 | NULL,\r |
815 | (VOID **)&Security\r |
816 | );\r |
817 | if (EFI_ERROR (Status)) {\r |
818 | return Status;\r |
819 | }\r |
820 | \r |
821 | Status = Security->AuthenticationState (\r |
822 | GetPeiServicesTablePointer(),\r |
823 | (struct _EFI_PEI_SECURITY_PPI *) Security,\r |
824 | AuthenticationStatus,\r |
825 | FfsFileHeader,\r |
826 | &StartCrisisRecovery\r |
827 | );\r |
828 | \r |
829 | if (EFI_ERROR (Status)) {\r |
830 | return Status;\r |
831 | }\r |
832 | //\r |
833 | // If there is a security violation, report to caller and have\r |
834 | // the upper-level logic possible engender a crisis recovery\r |
835 | //\r |
836 | if (StartCrisisRecovery) {\r |
837 | return EFI_SECURITY_VIOLATION;\r |
838 | }\r |
839 | }\r |
840 | \r |
841 | if (Section->Type == EFI_SECTION_PE32) {\r |
842 | //\r |
843 | // This is what we want\r |
844 | //\r |
845 | *Pe32Data = (VOID *) (Section + 1);\r |
846 | return EFI_SUCCESS;\r |
847 | } else if (Section->Type == EFI_SECTION_COMPRESSION) {\r |
848 | //\r |
849 | // This is a compression set, expand it\r |
850 | //\r |
851 | CompressionSection = (EFI_COMPRESSION_SECTION *) Section;\r |
852 | \r |
853 | switch (CompressionSection->CompressionType) {\r |
854 | case EFI_STANDARD_COMPRESSION:\r |
855 | DecompressLibrary = &gTianoDecompress;\r |
856 | break;\r |
857 | \r |
858 | case EFI_CUSTOMIZED_COMPRESSION:\r |
859 | //\r |
860 | // Load user customized compression protocol.\r |
861 | //\r |
862 | DecompressLibrary = &gCustomDecompress;\r |
863 | break;\r |
864 | \r |
865 | case EFI_NOT_COMPRESSED:\r |
866 | default:\r |
867 | //\r |
868 | // Need to support not compressed file\r |
869 | //\r |
870 | ASSERT_EFI_ERROR (Status);\r |
871 | return EFI_NOT_FOUND;\r |
872 | }\r |
873 | \r |
874 | Status = DecompressLibrary->GetInfo (\r |
875 | (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r |
876 | (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),\r |
877 | &DstBufferSize,\r |
878 | &ScratchBufferSize\r |
879 | );\r |
880 | if (EFI_ERROR (Status)) {\r |
881 | //\r |
882 | // GetInfo failed\r |
883 | //\r |
884 | return EFI_NOT_FOUND;\r |
885 | }\r |
886 | \r |
887 | //\r |
888 | // Allocate scratch buffer\r |
889 | //\r |
890 | ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r |
891 | if (ScratchBuffer == NULL) {\r |
892 | return EFI_OUT_OF_RESOURCES;\r |
893 | }\r |
894 | \r |
895 | //\r |
896 | // Allocate destination buffer\r |
897 | //\r |
898 | DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r |
899 | if (DstBuffer == NULL) {\r |
900 | return EFI_OUT_OF_RESOURCES;\r |
901 | }\r |
902 | \r |
903 | //\r |
904 | // Call decompress function\r |
905 | //\r |
906 | Status = DecompressLibrary->Decompress (\r |
907 | (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r |
908 | DstBuffer,\r |
909 | ScratchBuffer\r |
910 | );\r |
911 | \r |
912 | CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;\r |
913 | if (CmpSection->Type == EFI_SECTION_RAW) {\r |
914 | //\r |
915 | // Skip the section header and\r |
916 | // adjust the pointer alignment to 16\r |
917 | //\r |
918 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16);\r |
919 | \r |
920 | if (FvHeader->Signature == EFI_FVH_SIGNATURE) {\r |
921 | FfsFileHeader = NULL;\r |
922 | BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);\r |
923 | Status = PeiCoreFfsFindNextFile (\r |
924 | EFI_FV_FILETYPE_DXE_CORE,\r |
925 | FvHeader,\r |
926 | &FfsFileHeader\r |
927 | );\r |
928 | \r |
929 | if (EFI_ERROR (Status)) {\r |
930 | return EFI_NOT_FOUND;\r |
931 | }\r |
932 | \r |
933 | return PeiProcessFile (SectionType, FfsFileHeader, Pe32Data);\r |
934 | }\r |
935 | }\r |
936 | //\r |
937 | // Decompress successfully.\r |
938 | // Loop the decompressed data searching for expected section.\r |
939 | //\r |
940 | CmpFileData = (VOID *) DstBuffer;\r |
941 | CmpFileSize = DstBufferSize;\r |
942 | do {\r |
943 | CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;\r |
944 | if (CmpSection->Type == EFI_SECTION_PE32) {\r |
945 | //\r |
946 | // This is what we want\r |
947 | //\r |
948 | *Pe32Data = (VOID *) (CmpSection + 1);\r |
949 | return EFI_SUCCESS;\r |
950 | }\r |
951 | \r |
952 | OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4);\r |
953 | CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);\r |
954 | } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);\r |
955 | }\r |
956 | \r |
957 | Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r |
958 | FileSize = FfsFileHeader->Size[0] & 0xFF;\r |
959 | FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;\r |
960 | FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;\r |
961 | FileSize &= 0x00FFFFFF;\r |
962 | } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);\r |
963 | \r |
964 | //\r |
965 | // End of the decompression activity\r |
966 | //\r |
967 | } else {\r |
968 | \r |
969 | Status = PeiCoreFfsFindSectionData (\r |
970 | EFI_SECTION_PE32,\r |
971 | FfsFileHeader,\r |
972 | &SectionData\r |
973 | );\r |
974 | \r |
975 | if (EFI_ERROR (Status)) {\r |
976 | Status = PeiCoreFfsFindSectionData (\r |
977 | EFI_SECTION_TE,\r |
978 | FfsFileHeader,\r |
979 | &SectionData\r |
980 | );\r |
981 | if (EFI_ERROR (Status)) {\r |
982 | return Status;\r |
983 | }\r |
984 | }\r |
985 | }\r |
986 | \r |
987 | *Pe32Data = SectionData;\r |
988 | \r |
989 | return EFI_SUCCESS;\r |
878ddf1f |
990 | } |