]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
Correct more comments for PeiCore.
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Dispatcher / Dispatcher.c
1 /** @file
2 EFI PEI Core dispatch services
3
4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <PeiMain.h>
16
17 ///
18 /// CAR is filled with this initial value during SEC phase
19 ///
20 #define INIT_CAR_VALUE 0x5AA55AA5
21
22 typedef struct {
23 EFI_STATUS_CODE_DATA DataHeader;
24 EFI_HANDLE Handle;
25 } PEIM_FILE_HANDLE_EXTENDED_DATA;
26
27 /**
28
29 Discover all Peims and optional Apriori file in one FV. There is at most one
30 Apriori file in one FV.
31
32
33 @param Private - Pointer to the private data passed in from caller
34 @param VolumeHandle - Fv handle.
35
36 **/
37 VOID
38 DiscoverPeimsAndOrderWithApriori (
39 IN PEI_CORE_INSTANCE *Private,
40 IN EFI_PEI_FV_HANDLE VolumeHandle
41 )
42 {
43 EFI_STATUS Status;
44 EFI_PEI_FV_HANDLE FileHandle;
45 EFI_PEI_FILE_HANDLE AprioriFileHandle;
46 EFI_GUID *Apriori;
47 UINTN Index;
48 UINTN Index2;
49 UINTN PeimIndex;
50 UINTN PeimCount;
51 EFI_GUID *Guid;
52 EFI_PEI_FV_HANDLE TempFileHandles[FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)];
53 EFI_GUID FileGuid[FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)];
54
55 //
56 // Walk the FV and find all the PEIMs and the Apriori file.
57 //
58 AprioriFileHandle = NULL;
59 Private->CurrentFvFileHandles[0] = NULL;
60 Guid = NULL;
61 FileHandle = NULL;
62
63 //
64 // If the current Fv has been scanned, directly get its cachable record.
65 //
66 if (Private->Fv[Private->CurrentPeimFvCount].ScanFv) {
67 CopyMem (Private->CurrentFvFileHandles, Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, sizeof (Private->CurrentFvFileHandles));
68 return;
69 }
70
71 //
72 // Go ahead to scan this Fv, and cache FileHandles within it.
73 //
74 for (PeimCount = 0; PeimCount < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv); PeimCount++) {
75 Status = PeiFindFileEx (
76 VolumeHandle,
77 NULL,
78 PEI_CORE_INTERNAL_FFS_FILE_DISPATCH_TYPE,
79 &FileHandle,
80 &AprioriFileHandle
81 );
82 if (Status != EFI_SUCCESS) {
83 break;
84 }
85
86 Private->CurrentFvFileHandles[PeimCount] = FileHandle;
87 }
88
89 Private->AprioriCount = 0;
90 if (AprioriFileHandle != NULL) {
91 //
92 // Read the Apriori file
93 //
94 Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, AprioriFileHandle, (VOID **) &Apriori);
95 if (!EFI_ERROR (Status)) {
96 //
97 // Calculate the number of PEIMs in the A Priori list
98 //
99 Private->AprioriCount = *(UINT32 *)(((EFI_FFS_FILE_HEADER *)AprioriFileHandle)->Size) & 0x00FFFFFF;
100 Private->AprioriCount -= sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_COMMON_SECTION_HEADER);
101 Private->AprioriCount /= sizeof (EFI_GUID);
102
103 ZeroMem (FileGuid, sizeof (FileGuid));
104 for (Index = 0; Index < PeimCount; Index++) {
105 //
106 // Make an array of file name guids that matches the FileHandle array so we can convert
107 // quickly from file name to file handle
108 //
109 CopyMem (&FileGuid[Index], &((EFI_FFS_FILE_HEADER *)Private->CurrentFvFileHandles[Index])->Name,sizeof(EFI_GUID));
110 }
111
112 //
113 // Walk through FileGuid array to find out who is invalid PEIM guid in Apriori file.
114 // Add avalible PEIMs in Apriori file into TempFileHandles array at first.
115 //
116 Index2 = 0;
117 for (Index = 0; Index2 < Private->AprioriCount; Index++) {
118 while (Index2 < Private->AprioriCount) {
119 Guid = ScanGuid (FileGuid, PeimCount * sizeof (EFI_GUID), &Apriori[Index2++]);
120 if (Guid != NULL) {
121 break;
122 }
123 }
124 if (Guid == NULL) {
125 break;
126 }
127 PeimIndex = ((UINTN)Guid - (UINTN)&FileGuid[0])/sizeof (EFI_GUID);
128 TempFileHandles[Index] = Private->CurrentFvFileHandles[PeimIndex];
129
130 //
131 // Since we have copied the file handle we can remove it from this list.
132 //
133 Private->CurrentFvFileHandles[PeimIndex] = NULL;
134 }
135
136 //
137 // Update valid Aprioricount
138 //
139 Private->AprioriCount = Index;
140
141 //
142 // Add in any PEIMs not in the Apriori file
143 //
144 for (;Index < PeimCount; Index++) {
145 for (Index2 = 0; Index2 < PeimCount; Index2++) {
146 if (Private->CurrentFvFileHandles[Index2] != NULL) {
147 TempFileHandles[Index] = Private->CurrentFvFileHandles[Index2];
148 Private->CurrentFvFileHandles[Index2] = NULL;
149 break;
150 }
151 }
152 }
153 //
154 //Index the end of array contains re-range Pei moudle.
155 //
156 TempFileHandles[Index] = NULL;
157
158 //
159 // Private->CurrentFvFileHandles is currently in PEIM in the FV order.
160 // We need to update it to start with files in the A Priori list and
161 // then the remaining files in PEIM order.
162 //
163 CopyMem (Private->CurrentFvFileHandles, TempFileHandles, sizeof (Private->CurrentFvFileHandles));
164 }
165 }
166 //
167 // Cache the current Fv File Handle. So that we don't have to scan the Fv again.
168 // Instead, we can retrieve the file handles within this Fv from cachable data.
169 //
170 Private->Fv[Private->CurrentPeimFvCount].ScanFv = TRUE;
171 CopyMem (Private->Fv[Private->CurrentPeimFvCount].FvFileHandles, Private->CurrentFvFileHandles, sizeof (Private->CurrentFvFileHandles));
172
173 }
174
175 /**
176 Shadow PeiCore module from flash to installed memory.
177
178 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
179 @param PrivateInMem PeiCore's private data structure
180
181 @return PeiCore function address after shadowing.
182 **/
183 VOID*
184 ShadowPeiCore(
185 EFI_PEI_SERVICES **PeiServices,
186 PEI_CORE_INSTANCE *PrivateInMem
187 )
188 {
189 EFI_PEI_FILE_HANDLE PeiCoreFileHandle;
190 EFI_PHYSICAL_ADDRESS EntryPoint;
191 EFI_STATUS Status;
192 UINT32 AuthenticationState;
193
194 PeiCoreFileHandle = NULL;
195
196 //
197 // Find the PEI Core in the BFV
198 //
199 Status = PeiFindFileEx (
200 (EFI_PEI_FV_HANDLE)PrivateInMem->Fv[0].FvHeader,
201 NULL,
202 EFI_FV_FILETYPE_PEI_CORE,
203 &PeiCoreFileHandle,
204 NULL
205 );
206 ASSERT_EFI_ERROR (Status);
207
208 //
209 // Shadow PEI Core into memory so it will run faster
210 //
211 Status = PeiLoadImage (
212 PeiServices,
213 *((EFI_PEI_FILE_HANDLE*)&PeiCoreFileHandle),
214 &EntryPoint,
215 &AuthenticationState
216 );
217 ASSERT_EFI_ERROR (Status);
218
219 //
220 // Compute the PeiCore's function address after shaowed PeiCore.
221 // _ModuleEntryPoint is PeiCore main function entry
222 //
223 return (VOID*) ((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint);
224 }
225
226 /**
227 Conduct PEIM dispatch.
228
229 @param SecCoreData Points to a data structure containing information about the PEI core's operating
230 environment, such as the size and location of temporary RAM, the stack location and
231 the BFV location.
232 @param Private Pointer to the private data passed in from caller
233
234 @retval EFI_SUCCESS - Successfully dispatched PEIM.
235 @retval EFI_NOT_FOUND - The dispatch failed.
236
237 **/
238 VOID
239 PeiDispatcher (
240 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
241 IN PEI_CORE_INSTANCE *Private
242 )
243 {
244 EFI_STATUS Status;
245 UINT32 Index1;
246 UINT32 Index2;
247 EFI_PEI_SERVICES **PeiServices;
248 EFI_PEI_FV_HANDLE VolumeHandle;
249 EFI_PEI_FILE_HANDLE PeimFileHandle;
250 UINTN FvCount;
251 UINTN PeimCount;
252 UINT32 AuthenticationState;
253 EFI_PHYSICAL_ADDRESS EntryPoint;
254 EFI_PEIM_ENTRY_POINT2 PeimEntryPoint;
255 UINTN SaveCurrentPeimCount;
256 UINTN SaveCurrentFvCount;
257 EFI_PEI_FILE_HANDLE SaveCurrentFileHandle;
258 PEIM_FILE_HANDLE_EXTENDED_DATA ExtendedData;
259 EFI_PHYSICAL_ADDRESS NewPermenentMemoryBase;
260 TEMPORARY_RAM_SUPPORT_PPI *TemporaryRamSupportPpi;
261 EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffTable;
262 EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffTable;
263 INTN StackOffset;
264 INTN HeapOffset;
265 PEI_CORE_INSTANCE *PrivateInMem;
266 UINT64 NewPeiStackSize;
267 UINT64 OldPeiStackSize;
268 UINT64 StackGap;
269 EFI_FV_FILE_INFO FvFileInfo;
270 UINTN OldCheckingTop;
271 UINTN OldCheckingBottom;
272
273
274 PeiServices = &Private->PS;
275 PeimEntryPoint = NULL;
276 PeimFileHandle = NULL;
277 EntryPoint = 0;
278
279 if ((Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
280 //
281 // Once real memory is available, shadow the RegisterForShadow modules. And meanwhile
282 // update the modules' status from PEIM_STATE_REGISITER_FOR_SHADOW to PEIM_STATE_DONE.
283 //
284 SaveCurrentPeimCount = Private->CurrentPeimCount;
285 SaveCurrentFvCount = Private->CurrentPeimFvCount;
286 SaveCurrentFileHandle = Private->CurrentFileHandle;
287
288 for (Index1 = 0; Index1 <= SaveCurrentFvCount; Index1++) {
289 for (Index2 = 0; (Index2 < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->Fv[Index1].FvFileHandles[Index2] != NULL); Index2++) {
290 if (Private->Fv[Index1].PeimState[Index2] == PEIM_STATE_REGISITER_FOR_SHADOW) {
291 PeimFileHandle = Private->Fv[Index1].FvFileHandles[Index2];
292 Status = PeiLoadImage (
293 &Private->PS,
294 PeimFileHandle,
295 &EntryPoint,
296 &AuthenticationState
297 );
298 if (Status == EFI_SUCCESS) {
299 //
300 // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE
301 //
302 Private->Fv[Index1].PeimState[Index2]++;
303 Private->CurrentFileHandle = PeimFileHandle;
304 Private->CurrentPeimFvCount = Index1;
305 Private->CurrentPeimCount = Index2;
306 //
307 // Call the PEIM entry point
308 //
309 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
310
311 PERF_START (0, "PEIM", NULL, 0);
312 PeimEntryPoint(PeimFileHandle, (const EFI_PEI_SERVICES **) &Private->PS);
313 PERF_END (0, "PEIM", NULL, 0);
314 }
315
316 //
317 // Process the Notify list and dispatch any notifies for
318 // newly installed PPIs.
319 //
320 ProcessNotifyList (Private);
321 }
322 }
323 }
324 Private->CurrentFileHandle = SaveCurrentFileHandle;
325 Private->CurrentPeimFvCount = SaveCurrentFvCount;
326 Private->CurrentPeimCount = SaveCurrentPeimCount;
327 }
328
329 //
330 // This is the main dispatch loop. It will search known FVs for PEIMs and
331 // attempt to dispatch them. If any PEIM gets dispatched through a single
332 // pass of the dispatcher, it will start over from the Bfv again to see
333 // if any new PEIMs dependencies got satisfied. With a well ordered
334 // FV where PEIMs are found in the order their dependencies are also
335 // satisfied, this dipatcher should run only once.
336 //
337 do {
338
339 for (FvCount = Private->CurrentPeimFvCount; FvCount < Private->FvCount; FvCount++) {
340 Private->CurrentPeimFvCount = FvCount;
341 VolumeHandle = Private->Fv[FvCount].FvHeader;
342
343 if (Private->CurrentPeimCount == 0) {
344 //
345 // When going through each FV, at first, search Apriori file to
346 // reorder all PEIMs to ensure the PEIMs in Apriori file to get
347 // dispatch at first.
348 //
349 DiscoverPeimsAndOrderWithApriori (Private, VolumeHandle);
350 }
351
352 //
353 // Start to dispatch all modules within the current Fv.
354 //
355 for (PeimCount = Private->CurrentPeimCount;
356 (PeimCount < FixedPcdGet32 (PcdPeiCoreMaxPeimPerFv)) && (Private->CurrentFvFileHandles[PeimCount] != NULL);
357 PeimCount++) {
358 Private->CurrentPeimCount = PeimCount;
359 PeimFileHandle = Private->CurrentFileHandle = Private->CurrentFvFileHandles[PeimCount];
360
361 if (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_NOT_DISPATCHED) {
362 if (!DepexSatisfied (Private, PeimFileHandle, PeimCount)) {
363 Private->PeimNeedingDispatch = TRUE;
364 } else {
365 Status = PeiFfsGetFileInfo (PeimFileHandle, &FvFileInfo);
366 ASSERT_EFI_ERROR (Status);
367 if (FvFileInfo.FileType == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
368 //
369 // For Fv type file, Produce new FV PPI and FV hob
370 //
371 Status = ProcessFvFile (PeiServices, PeimFileHandle, &AuthenticationState);
372 } else {
373 //
374 // For PEIM driver, Load its entry point
375 //
376 Status = PeiLoadImage (
377 PeiServices,
378 PeimFileHandle,
379 &EntryPoint,
380 &AuthenticationState
381 );
382 }
383
384 if ((Status == EFI_SUCCESS)) {
385 //
386 // The PEIM has its dependencies satisfied, and its entry point
387 // has been found, so invoke it.
388 //
389 PERF_START (0, "PEIM", NULL, 0);
390
391 ExtendedData.Handle = (EFI_HANDLE)PeimFileHandle;
392
393 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
394 EFI_PROGRESS_CODE,
395 FixedPcdGet32(PcdStatusCodeValuePeimDispatch),
396 (VOID *)(&ExtendedData),
397 sizeof (ExtendedData)
398 );
399
400 Status = VerifyPeim (Private, VolumeHandle, PeimFileHandle);
401 if (Status != EFI_SECURITY_VIOLATION && (AuthenticationState == 0)) {
402 //
403 // PEIM_STATE_NOT_DISPATCHED move to PEIM_STATE_DISPATCHED
404 //
405 Private->Fv[FvCount].PeimState[PeimCount]++;
406
407 if (FvFileInfo.FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
408 //
409 // Call the PEIM entry point for PEIM driver
410 //
411 PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)EntryPoint;
412 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
413 }
414
415 Private->PeimDispatchOnThisPass = TRUE;
416 }
417
418 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
419 EFI_PROGRESS_CODE,
420 FixedPcdGet32(PcdStatusCodeValuePeimDispatch),
421 (VOID *)(&ExtendedData),
422 sizeof (ExtendedData)
423 );
424 PERF_END (0, "PEIM", NULL, 0);
425
426 }
427
428 if (Private->SwitchStackSignal) {
429 //
430 // Before switch stack from CAR to permenent memory, caculate the heap and stack
431 // usage in temporary memory for debuging.
432 //
433 DEBUG_CODE_BEGIN ();
434 UINT32 *StackPointer;
435
436 for (StackPointer = (UINT32*)SecCoreData->StackBase;
437 (StackPointer < (UINT32*)((UINTN)SecCoreData->StackBase + SecCoreData->StackSize)) \
438 && (*StackPointer == INIT_CAR_VALUE);
439 StackPointer ++);
440
441 DEBUG ((EFI_D_INFO, "Total Cache as RAM: %d bytes.\n", SecCoreData->TemporaryRamSize));
442 DEBUG ((EFI_D_INFO, " CAR stack ever used: %d bytes.\n",
443 (SecCoreData->StackSize - ((UINTN) StackPointer - (UINTN)SecCoreData->StackBase))
444 ));
445 DEBUG ((EFI_D_INFO, " CAR heap used: %d bytes.\n",
446 ((UINTN) Private->HobList.HandoffInformationTable->EfiFreeMemoryBottom -
447 (UINTN) Private->HobList.Raw)
448 ));
449 DEBUG_CODE_END ();
450
451 //
452 // Reserve the size of new stack at bottom of physical memory
453 //
454 OldPeiStackSize = Private->StackSize;
455 NewPeiStackSize = (RShiftU64 (Private->PhysicalMemoryLength, 1) + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
456 if (FixedPcdGet32(PcdPeiCoreMaxPeiStackSize) > (UINT32) NewPeiStackSize) {
457 Private->StackSize = NewPeiStackSize;
458 } else {
459 Private->StackSize = FixedPcdGet32(PcdPeiCoreMaxPeiStackSize);
460 }
461
462 //
463 // In theory, the size of new stack in permenent memory should large than
464 // size of old stack in temporary memory.
465 // But if new stack is smaller than the size of old stack, we also reserve
466 // the size of old stack at bottom of permenent memory.
467 //
468 StackGap = 0;
469 if (Private->StackSize > OldPeiStackSize) {
470 StackGap = Private->StackSize - OldPeiStackSize;
471 }
472
473 //
474 // Update HandOffHob for new installed permenent memory
475 //
476 OldHandOffTable = Private->HobList.HandoffInformationTable;
477 OldCheckingBottom = (UINTN)(SecCoreData->TemporaryRamBase);
478 OldCheckingTop = (UINTN)(OldCheckingBottom + SecCoreData->TemporaryRamSize);
479
480 //
481 // The whole temporary memory will be migrated to physical memory.
482 // CAUTION: The new base is computed accounding to gap of new stack.
483 //
484 NewPermenentMemoryBase = Private->PhysicalMemoryBegin + StackGap;
485
486 //
487 // Caculate stack offset and heap offset between CAR and new permement
488 // memory seperately.
489 //
490 StackOffset = (UINTN) NewPermenentMemoryBase - (UINTN) SecCoreData->StackBase;
491 HeapOffset = (INTN) ((UINTN) Private->PhysicalMemoryBegin + Private->StackSize - \
492 (UINTN) SecCoreData->PeiTemporaryRamBase);
493 DEBUG ((EFI_D_INFO, "Heap Offset = 0x%X Stack Offset = 0x%X\n", HeapOffset, StackOffset));
494
495 //
496 // Caculate new HandOffTable and PrivateData address in permenet memory's stack
497 //
498 NewHandOffTable = (EFI_HOB_HANDOFF_INFO_TABLE *)((UINTN)OldHandOffTable + HeapOffset);
499 PrivateInMem = (PEI_CORE_INSTANCE *)((UINTN) (VOID*) Private + StackOffset);
500
501 //
502 // TemporaryRamSupportPpi is produced by platform's SEC
503 //
504 Status = PeiLocatePpi (
505 (CONST EFI_PEI_SERVICES **) PeiServices,
506 &gEfiTemporaryRamSupportPpiGuid,
507 0,
508 NULL,
509 (VOID**)&TemporaryRamSupportPpi
510 );
511
512
513 if (!EFI_ERROR (Status)) {
514 //
515 // Temporary Ram support Ppi is provided by platform, it will copy
516 // temporary memory to permenent memory and do stack switching.
517 // After invoken temporary Ram support, following code's stack is in
518 // memory but not in CAR.
519 //
520 TemporaryRamSupportPpi->TemporaryRamMigration (
521 (CONST EFI_PEI_SERVICES **) PeiServices,
522 (EFI_PHYSICAL_ADDRESS)(UINTN) SecCoreData->TemporaryRamBase,
523 (EFI_PHYSICAL_ADDRESS)(UINTN) NewPermenentMemoryBase,
524 SecCoreData->TemporaryRamSize
525 );
526
527 } else {
528 //
529 // In IA32/x64/Itanium architecture, we need platform provide
530 // TEMPORAY_RAM_MIGRATION_PPI.
531 //
532 ASSERT (FALSE);
533 }
534
535
536 //
537 //
538 // Fixup the PeiCore's private data
539 //
540 PrivateInMem->PS = &PrivateInMem->ServiceTableShadow;
541 PrivateInMem->CpuIo = &PrivateInMem->ServiceTableShadow.CpuIo;
542 PrivateInMem->HobList.Raw = (VOID*) ((UINTN) PrivateInMem->HobList.Raw + HeapOffset);
543 PrivateInMem->StackBase = (EFI_PHYSICAL_ADDRESS)(((UINTN)PrivateInMem->PhysicalMemoryBegin + EFI_PAGE_MASK) & ~EFI_PAGE_MASK);
544
545 PeiServices = &PrivateInMem->PS;
546
547 //
548 // Fixup for PeiService's address
549 //
550 SetPeiServicesTablePointer(PeiServices);
551
552 //
553 // Update HandOffHob for new installed permenent memory
554 //
555 NewHandOffTable->EfiEndOfHobList =
556 (EFI_PHYSICAL_ADDRESS)((UINTN) NewHandOffTable->EfiEndOfHobList + HeapOffset);
557 NewHandOffTable->EfiMemoryTop = PrivateInMem->PhysicalMemoryBegin +
558 PrivateInMem->PhysicalMemoryLength;
559 NewHandOffTable->EfiMemoryBottom = PrivateInMem->PhysicalMemoryBegin;
560 NewHandOffTable->EfiFreeMemoryTop = PrivateInMem->FreePhysicalMemoryTop;
561 NewHandOffTable->EfiFreeMemoryBottom = NewHandOffTable->EfiEndOfHobList +
562 sizeof (EFI_HOB_GENERIC_HEADER);
563
564 //
565 // We need convert the PPI desciptor's pointer
566 //
567 ConvertPpiPointers (PrivateInMem,
568 OldCheckingBottom,
569 OldCheckingTop,
570 HeapOffset
571 );
572
573 DEBUG ((EFI_D_INFO, "Stack Hob: BaseAddress=0x%X Length=0x%X\n",
574 (UINTN)PrivateInMem->StackBase,
575 PrivateInMem->StackSize));
576 BuildStackHob (PrivateInMem->StackBase, PrivateInMem->StackSize);
577
578 //
579 // After the whole temporary memory is migrated, then we can allocate page in
580 // permenent memory.
581 //
582 PrivateInMem->PeiMemoryInstalled = TRUE;
583
584 //
585 // Shadow PEI Core. When permanent memory is avaiable, shadow
586 // PEI Core and PEIMs to get high performance.
587 //
588 PrivateInMem->ShadowedPeiCore = ShadowPeiCore (
589 PeiServices,
590 PrivateInMem
591 );
592 //
593 // Process the Notify list and dispatch any notifies for
594 // newly installed PPIs.
595 //
596 ProcessNotifyList (PrivateInMem);
597
598 //
599 // Entry PEI Phase 2
600 //
601 PeiCore (SecCoreData, NULL, PrivateInMem);
602
603 //
604 // Code should not come here
605 //
606 ASSERT_EFI_ERROR(FALSE);
607 }
608
609 //
610 // Process the Notify list and dispatch any notifies for
611 // newly installed PPIs.
612 //
613 ProcessNotifyList (Private);
614
615 if ((Private->PeiMemoryInstalled) && (Private->Fv[FvCount].PeimState[PeimCount] == PEIM_STATE_REGISITER_FOR_SHADOW) && \
616 (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
617 //
618 // If memory is availble we shadow images by default for performance reasons.
619 // We call the entry point a 2nd time so the module knows it's shadowed.
620 //
621 //PERF_START (PeiServices, L"PEIM", PeimFileHandle, 0);
622 PeimEntryPoint (PeimFileHandle, (const EFI_PEI_SERVICES **) PeiServices);
623 //PERF_END (PeiServices, L"PEIM", PeimFileHandle, 0);
624
625 //
626 // PEIM_STATE_REGISITER_FOR_SHADOW move to PEIM_STATE_DONE
627 //
628 Private->Fv[FvCount].PeimState[PeimCount]++;
629
630 //
631 // Process the Notify list and dispatch any notifies for
632 // newly installed PPIs.
633 //
634 ProcessNotifyList (Private);
635 }
636 }
637 }
638 }
639
640 //
641 // We set to NULL here to optimize the 2nd entry to this routine after
642 // memory is found. This reprevents rescanning of the FV. We set to
643 // NULL here so we start at the begining of the next FV
644 //
645 Private->CurrentFileHandle = NULL;
646 Private->CurrentPeimCount = 0;
647 //
648 // Before walking through the next FV,Private->CurrentFvFileHandles[]should set to NULL
649 //
650 SetMem (Private->CurrentFvFileHandles, sizeof (Private->CurrentFvFileHandles), 0);
651 }
652
653 //
654 // Before making another pass, we should set Private->CurrentPeimFvCount =0 to go
655 // through all the FV.
656 //
657 Private->CurrentPeimFvCount = 0;
658
659 //
660 // PeimNeedingDispatch being TRUE means we found a PEIM that did not get
661 // dispatched. So we need to make another pass
662 //
663 // PeimDispatchOnThisPass being TRUE means we dispatched a PEIM on this
664 // pass. If we did not dispatch a PEIM there is no point in trying again
665 // as it will fail the next time too (nothing has changed).
666 //
667 } while (Private->PeimNeedingDispatch && Private->PeimDispatchOnThisPass);
668
669 }
670
671 /**
672 Initialize the Dispatcher's data members
673
674 @param PrivateData PeiCore's private data structure
675 @param OldCoreData Old data from SecCore
676 NULL if being run in non-permament memory mode.
677 @param SecCoreData Points to a data structure containing information about the PEI core's operating
678 environment, such as the size and location of temporary RAM, the stack location and
679 the BFV location.
680
681 @return None.
682
683 **/
684 VOID
685 InitializeDispatcherData (
686 IN PEI_CORE_INSTANCE *PrivateData,
687 IN PEI_CORE_INSTANCE *OldCoreData,
688 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData
689 )
690 {
691 if (OldCoreData == NULL) {
692 PrivateData->PeimNeedingDispatch = FALSE;
693 PrivateData->PeimDispatchOnThisPass = FALSE;
694 PeiInitializeFv (PrivateData, SecCoreData);
695 }
696
697 return;
698 }
699
700 /**
701 This routine parses the Dependency Expression, if available, and
702 decides if the module can be executed.
703
704
705 @param Private PeiCore's private data structure
706 @param FileHandle PEIM's file handle
707 @param PeimCount Peim count in all dispatched PEIMs.
708
709 @retval TRUE Can be dispatched
710 @retval FALSE Cannot be dispatched
711
712 **/
713 BOOLEAN
714 DepexSatisfied (
715 IN PEI_CORE_INSTANCE *Private,
716 IN EFI_PEI_FILE_HANDLE FileHandle,
717 IN UINTN PeimCount
718 )
719 {
720 EFI_STATUS Status;
721 VOID *DepexData;
722
723 if (PeimCount < Private->AprioriCount) {
724 //
725 // If its in the A priori file then we set Depex to TRUE
726 //
727 return TRUE;
728 }
729
730 //
731 // Depex section not in the encapsulated section.
732 //
733 Status = PeiServicesFfsFindSectionData (
734 EFI_SECTION_PEI_DEPEX,
735 FileHandle,
736 (VOID **)&DepexData
737 );
738
739 if (EFI_ERROR (Status)) {
740 //
741 // If there is no DEPEX, assume the module can be executed
742 //
743 return TRUE;
744 }
745
746 //
747 // Evaluate a given DEPEX
748 //
749 return PeimDispatchReadiness (&Private->PS, DepexData);
750 }
751
752 /**
753 This routine enable a PEIM to register itself to shadow when PEI Foundation
754 discovery permanent memory.
755
756 @param FileHandle File handle of a PEIM.
757
758 @retval EFI_NOT_FOUND The file handle doesn't point to PEIM itself.
759 @retval EFI_ALREADY_STARTED Indicate that the PEIM has been registered itself.
760 @retval EFI_SUCCESS Successfully to register itself.
761
762 **/
763 EFI_STATUS
764 EFIAPI
765 PeiRegisterForShadow (
766 IN EFI_PEI_FILE_HANDLE FileHandle
767 )
768 {
769 PEI_CORE_INSTANCE *Private;
770 Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ());
771
772 if (Private->CurrentFileHandle != FileHandle) {
773 //
774 // The FileHandle must be for the current PEIM
775 //
776 return EFI_NOT_FOUND;
777 }
778
779 if (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] >= PEIM_STATE_REGISITER_FOR_SHADOW) {
780 //
781 // If the PEIM has already entered the PEIM_STATE_REGISTER_FOR_SHADOW or PEIM_STATE_DONE then it's already been started
782 //
783 return EFI_ALREADY_STARTED;
784 }
785
786 Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] = PEIM_STATE_REGISITER_FOR_SHADOW;
787
788 return EFI_SUCCESS;
789 }
790
791 /**
792 Get Fv image from the FV type file, then install FV INFO ppi, Build FV hob.
793
794 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
795 @param FvFileHandle File handle of a Fv type file.
796 @param AuthenticationState Pointer to attestation authentication state of image.
797
798
799 @retval EFI_NOT_FOUND FV image can't be found.
800 @retval EFI_SUCCESS Successfully to process it.
801 @retval EFI_OUT_OF_RESOURCES Can not allocate page when aligning FV image
802 @retval Others Can not find EFI_SECTION_FIRMWARE_VOLUME_IMAGE section
803
804 **/
805 EFI_STATUS
806 ProcessFvFile (
807 IN EFI_PEI_SERVICES **PeiServices,
808 IN EFI_PEI_FILE_HANDLE FvFileHandle,
809 OUT UINT32 *AuthenticationState
810 )
811 {
812 EFI_STATUS Status;
813 EFI_PEI_FV_HANDLE FvImageHandle;
814 EFI_FV_INFO FvImageInfo;
815 UINT32 FvAlignment;
816 VOID *FvBuffer;
817 EFI_PEI_HOB_POINTERS HobPtr;
818
819 FvBuffer = NULL;
820 *AuthenticationState = 0;
821
822 //
823 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
824 // been extracted.
825 //
826 HobPtr.Raw = GetHobList ();
827 while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobPtr.Raw)) != NULL) {
828 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobPtr.FirmwareVolume2->FileName)) {
829 //
830 // this FILE has been dispatched, it will not be dispatched again.
831 //
832 return EFI_SUCCESS;
833 }
834 HobPtr.Raw = GET_NEXT_HOB (HobPtr);
835 }
836
837 //
838 // Find FvImage in FvFile
839 //
840 Status = PeiFfsFindSectionData (
841 (CONST EFI_PEI_SERVICES **) PeiServices,
842 EFI_SECTION_FIRMWARE_VOLUME_IMAGE,
843 FvFileHandle,
844 (VOID **)&FvImageHandle
845 );
846
847 if (EFI_ERROR (Status)) {
848 return Status;
849 }
850
851 //
852 // Collect FvImage Info.
853 //
854 Status = PeiFfsGetVolumeInfo (FvImageHandle, &FvImageInfo);
855 ASSERT_EFI_ERROR (Status);
856
857 //
858 // FvAlignment must be more than 8 bytes required by FvHeader structure.
859 //
860 FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);
861 if (FvAlignment < 8) {
862 FvAlignment = 8;
863 }
864
865 //
866 // Check FvImage
867 //
868 if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) {
869 FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment);
870 if (FvBuffer == NULL) {
871 return EFI_OUT_OF_RESOURCES;
872 }
873 CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize);
874 //
875 // Update FvImageInfo after reload FvImage to new aligned memory
876 //
877 PeiFfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo);
878 }
879
880 //
881 // Install FvPpi and Build FvHob
882 //
883 PiLibInstallFvInfoPpi (
884 NULL,
885 FvImageInfo.FvStart,
886 (UINT32) FvImageInfo.FvSize,
887 &(FvImageInfo.FvName),
888 &(((EFI_FFS_FILE_HEADER*)FvFileHandle)->Name)
889 );
890
891 //
892 // Inform the extracted FvImage to Fv HOB consumer phase, i.e. DXE phase
893 // based on its parent Fvimage is informed or not.
894 // If FvHob of its parent fvimage is built, the extracted FvImage will be built also.
895 // Or, the extracted FvImage will not be built.
896 //
897 HobPtr.Raw = GetHobList ();
898 while ((HobPtr.Raw = GetNextHob (EFI_HOB_TYPE_FV, HobPtr.Raw)) != NULL) {
899 if (((EFI_PHYSICAL_ADDRESS) (UINTN)FvFileHandle > HobPtr.FirmwareVolume->BaseAddress) &&
900 ((EFI_PHYSICAL_ADDRESS) (UINTN)FvFileHandle < HobPtr.FirmwareVolume->BaseAddress + HobPtr.FirmwareVolume->Length)) {
901 BuildFvHob (
902 (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
903 FvImageInfo.FvSize
904 );
905 break;
906 }
907 HobPtr.Raw = GET_NEXT_HOB (HobPtr);
908 }
909
910 //
911 // Makes the encapsulated volume show up in DXE phase to skip processing of
912 // encapsulated file again.
913 //
914 BuildFv2Hob (
915 (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart,
916 FvImageInfo.FvSize,
917 &FvImageInfo.FvName,
918 &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name)
919 );
920
921 return EFI_SUCCESS;
922 }