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