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