c764b3907eaae43d5fa7aab382666b7baaaded9d
[mirror_edk2.git] / EdkModulePkg / Core / Pei / Dispatcher / Dispatcher.c
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 Dispatcher.c
15
16 Abstract:
17
18 EFI PEI Core dispatch services
19
20 Revision History
21
22 --*/
23
24 #include <PeiMain.h>
25
26 STATIC
27 VOID *
28 TransferOldDataToNewDataRange (
29 IN PEI_CORE_INSTANCE *PrivateData
30 );
31
32 EFI_GUID gEfiPeiCorePrivateGuid = EFI_PEI_CORE_PRIVATE_GUID;
33
34
35 EFI_STATUS
36 PeiDispatcher (
37 IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor,
38 IN PEI_CORE_INSTANCE *PrivateData,
39 IN PEI_CORE_DISPATCH_DATA *DispatchData
40 )
41
42 /*++
43
44 Routine Description:
45
46 Conduct PEIM dispatch.
47
48 Arguments:
49
50 PeiStartupDescriptor - Pointer to IN EFI_PEI_STARTUP_DESCRIPTOR
51 PrivateData - Pointer to the private data passed in from caller
52 DispatchData - Pointer to PEI_CORE_DISPATCH_DATA data.
53
54 Returns:
55
56 EFI_SUCCESS - Successfully dispatched PEIM.
57 EFI_NOT_FOUND - The dispatch failed.
58
59 --*/
60 {
61 EFI_STATUS Status;
62 PEI_CORE_TEMP_POINTERS TempPtr;
63 UINTN PrivateDataInMem;
64 BOOLEAN NextFvFound;
65 EFI_FIRMWARE_VOLUME_HEADER *NextFvAddress;
66 EFI_FIRMWARE_VOLUME_HEADER *DefaultFvAddress;
67 VOID *TopOfStack;
68 //
69 // Debug data for uninstalled Peim list
70 //
71 EFI_GUID DebugFoundPeimList[32];
72 REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA ExtendedData;
73
74 //
75 // save the Current FV Address so that we will not process it again if FindFv returns it later
76 //
77 DefaultFvAddress = DispatchData->BootFvAddress;
78
79 //
80 // This is the main dispatch loop. It will search known FVs for PEIMs and
81 // attempt to dispatch them. If any PEIM gets dispatched through a single
82 // pass of the dispatcher, it will start over from the Bfv again to see
83 // if any new PEIMs dependencies got satisfied. With a well ordered
84 // FV where PEIMs are found in the order their dependencies are also
85 // satisfied, this dipatcher should run only once.
86 //
87 for (;;) {
88 //
89 // This is the PEIM search loop. It will scan through all PEIMs it can find
90 // looking for PEIMs to dispatch, and will dipatch them if they have not
91 // already been dispatched and all of their dependencies are met.
92 // If no more PEIMs can be found in this pass through all known FVs,
93 // then it will break out of this loop.
94 //
95 for (;;) {
96
97 Status = FindNextPeim (
98 &PrivateData->PS,
99 DispatchData->CurrentFvAddress,
100 &DispatchData->CurrentPeimAddress
101 );
102
103 //
104 // If we found a PEIM, check if it is dispatched. If so, go to the
105 // next PEIM. If not, dispatch it if its dependencies are satisfied.
106 // If its dependencies are not satisfied, go to the next PEIM.
107 //
108 if (Status == EFI_SUCCESS) {
109
110 DEBUG_CODE_BEGIN ();
111
112 //
113 // Fill list of found Peims for later list of those not installed
114 //
115 CopyMem (
116 &DebugFoundPeimList[DispatchData->CurrentPeim],
117 &DispatchData->CurrentPeimAddress->Name,
118 sizeof (EFI_GUID)
119 );
120
121 DEBUG_CODE_END ();
122
123 if (!Dispatched (
124 DispatchData->CurrentPeim,
125 DispatchData->DispatchedPeimBitMap
126 )) {
127 if (DepexSatisfied (&PrivateData->PS, DispatchData->CurrentPeimAddress)) {
128 Status = PeiLoadImage (
129 &PrivateData->PS,
130 DispatchData->CurrentPeimAddress,
131 &TempPtr.Raw
132 );
133 if (Status == EFI_SUCCESS) {
134
135 //
136 // The PEIM has its dependencies satisfied, and its entry point
137 // has been found, so invoke it.
138 //
139 PERF_START (
140 (VOID *) (UINTN) (DispatchData->CurrentPeimAddress),
141 "PEIM",
142 NULL,
143 0
144 );
145
146 //
147 // BUGBUG: Used to be EFI_PEI_REPORT_STATUS_CODE_CODE
148 //
149 ExtendedData.Handle = (EFI_HANDLE)DispatchData->CurrentPeimAddress;
150
151 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
152 EFI_PROGRESS_CODE,
153 EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN,
154 (VOID *)(&ExtendedData),
155 sizeof (ExtendedData)
156 );
157
158 //
159 // Is this a authentic image
160 //
161 Status = VerifyPeim (
162 &PrivateData->PS,
163 DispatchData->CurrentPeimAddress
164 );
165
166 if (Status != EFI_SECURITY_VIOLATION) {
167
168 Status = TempPtr.PeimEntry (
169 DispatchData->CurrentPeimAddress,
170 &PrivateData->PS
171 );
172 }
173
174 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
175 EFI_PROGRESS_CODE,
176 EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END,
177 (VOID *)(&ExtendedData),
178 sizeof (ExtendedData)
179 );
180
181 PERF_END ((VOID *) (UINTN) (DispatchData->CurrentPeimAddress), "PEIM", NULL, 0);
182
183 //
184 // Mark the PEIM as dispatched so we don't attempt to run it again
185 //
186 SetDispatched (
187 &PrivateData->PS,
188 DispatchData->CurrentPeim,
189 &DispatchData->DispatchedPeimBitMap
190 );
191
192 //
193 // Process the Notify list and dispatch any notifies for
194 // newly installed PPIs.
195 //
196 ProcessNotifyList (&PrivateData->PS);
197
198 //
199 // If real system memory was discovered and installed by this
200 // PEIM, switch the stacks to the new memory. Since we are
201 // at dispatch level, only the Core's private data is preserved,
202 // nobody else should have any data on the stack.
203 //
204 if (PrivateData->SwitchStackSignal) {
205 TempPtr.PeiCore = (PEI_CORE_ENTRY_POINT)PeiCore;
206 PrivateDataInMem = (UINTN) TransferOldDataToNewDataRange (PrivateData);
207 ASSERT (PrivateDataInMem != 0);
208 //
209 // Adjust the top of stack to be aligned at CPU_STACK_ALIGNMENT
210 //
211 TopOfStack = (VOID *)((UINTN)PrivateData->StackBase + (UINTN)PrivateData->StackSize - CPU_STACK_ALIGNMENT);
212 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
213
214 PeiSwitchStacks (
215 (SWITCH_STACK_ENTRY_POINT)(UINTN)TempPtr.Raw,
216 PeiStartupDescriptor,
217 (VOID*)PrivateDataInMem,
218 TopOfStack,
219 (VOID*)(UINTN)PrivateData->StackBase
220 );
221 }
222 }
223 }
224 }
225 DispatchData->CurrentPeim++;
226 continue;
227
228 } else {
229
230 //
231 // If we could not find another PEIM in the current FV, go try
232 // the FindFv PPI to look in other FVs for more PEIMs. If we can
233 // not locate the FindFv PPI, or if the FindFv PPI can not find
234 // anymore FVs, then exit the PEIM search loop.
235 //
236 if (DispatchData->FindFv == NULL) {
237 Status = PeiServicesLocatePpi (
238 &gEfiFindFvPpiGuid,
239 0,
240 NULL,
241 (VOID **)&DispatchData->FindFv
242 );
243 if (Status != EFI_SUCCESS) {
244 break;
245 }
246 }
247 NextFvFound = FALSE;
248 while (!NextFvFound) {
249 Status = DispatchData->FindFv->FindFv (
250 DispatchData->FindFv,
251 &PrivateData->PS,
252 &DispatchData->CurrentFv,
253 &NextFvAddress
254 );
255 //
256 // if there is no next fv, get out of this loop of finding FVs
257 //
258 if (Status != EFI_SUCCESS) {
259 break;
260 }
261 //
262 // don't process the default Fv again. (we don't know the order in which the hobs were created)
263 //
264 if ((NextFvAddress != DefaultFvAddress) &&
265 (NextFvAddress != DispatchData->CurrentFvAddress)) {
266
267 //
268 // VerifyFv() is currently returns SUCCESS all the time, add code to it to
269 // actually verify the given FV
270 //
271 Status = VerifyFv (NextFvAddress);
272 if (Status == EFI_SUCCESS) {
273 NextFvFound = TRUE;
274 DispatchData->CurrentFvAddress = NextFvAddress;
275 DispatchData->CurrentPeimAddress = NULL;
276 //
277 // current PRIM number (CurrentPeim) must continue as is, don't reset it here
278 //
279 }
280 }
281 }
282 //
283 // if there is no next fv, get out of this loop of dispatching PEIMs
284 //
285 if (!NextFvFound) {
286 break;
287 }
288 //
289 // continue in the inner for(;;) loop with a new FV;
290 //
291 }
292 }
293
294 //
295 // If all the PEIMs that we have found have been dispatched, then
296 // there is nothing left to dispatch and we don't need to go search
297 // through all PEIMs again.
298 //
299 if ((~(DispatchData->DispatchedPeimBitMap) &
300 ((1 << DispatchData->CurrentPeim)-1)) == 0) {
301 break;
302 }
303
304 //
305 // Check if no more PEIMs that depex was satisfied
306 //
307 if (DispatchData->DispatchedPeimBitMap == DispatchData->PreviousPeimBitMap) {
308 break;
309 }
310
311 //
312 // Case when Depex is not satisfied and has to traverse the list again
313 //
314 DispatchData->CurrentPeim = 0;
315 DispatchData->CurrentPeimAddress = 0;
316 DispatchData->PreviousPeimBitMap = DispatchData->DispatchedPeimBitMap;
317
318 //
319 // don't go back to the loop without making sure that the CurrentFvAddress is the
320 // same as the 1st (or default) FV we started with. otherwise we will interpret the bimap wrongly and
321 // mess it up, always start processing the PEIMs from the default FV just like in the first time around.
322 //
323 DispatchData->CurrentFv = 0;
324 DispatchData->CurrentFvAddress = DefaultFvAddress;
325 }
326
327 DEBUG_CODE_BEGIN ();
328 //
329 // Debug data for uninstalled Peim list
330 //
331 UINT32 DebugNotDispatchedBitmap;
332 UINT8 DebugFoundPeimPoint;
333
334 DebugFoundPeimPoint = 0;
335 //
336 // Get bitmap of Peims that were not dispatched,
337 //
338
339 DebugNotDispatchedBitmap = ((DispatchData->DispatchedPeimBitMap) ^ ((1 << DispatchData->CurrentPeim)-1));
340 //
341 // Scan bitmap of Peims not installed and print GUIDS
342 //
343 while (DebugNotDispatchedBitmap != 0) {
344 if ((DebugNotDispatchedBitmap & 1) != 0) {
345 DEBUG ((EFI_D_INFO, "WARNING -> InstallPpi: Not Installed: %g\n",
346 &DebugFoundPeimList[DebugFoundPeimPoint]
347 ));
348 }
349 DebugFoundPeimPoint++;
350 DebugNotDispatchedBitmap >>= 1;
351 }
352
353 DEBUG_CODE_END ();
354
355 return EFI_NOT_FOUND;
356 }
357
358 VOID
359 InitializeDispatcherData (
360 IN EFI_PEI_SERVICES **PeiServices,
361 IN PEI_CORE_INSTANCE *OldCoreData,
362 IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor
363 )
364 /*++
365
366 Routine Description:
367
368 Initialize the Dispatcher's data members
369
370 Arguments:
371
372 PeiServices - The PEI core services table.
373 OldCoreData - Pointer to old core data (before switching stack).
374 NULL if being run in non-permament memory mode.
375 PeiStartupDescriptor - Information and services provided by SEC phase.
376
377 Returns:
378
379 None.
380
381 --*/
382 {
383 PEI_CORE_INSTANCE *PrivateData;
384
385 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
386
387 if (OldCoreData == NULL) {
388 PrivateData->DispatchData.CurrentFvAddress = (EFI_FIRMWARE_VOLUME_HEADER *) PeiStartupDescriptor->BootFirmwareVolume;
389 PrivateData->DispatchData.BootFvAddress = (EFI_FIRMWARE_VOLUME_HEADER *) PeiStartupDescriptor->BootFirmwareVolume;
390 } else {
391
392 //
393 // Current peim has been dispatched, but not count
394 //
395 PrivateData->DispatchData.CurrentPeim = (UINT8)(OldCoreData->DispatchData.CurrentPeim + 1);
396 }
397
398 return;
399 }
400
401
402 BOOLEAN
403 Dispatched (
404 IN UINT8 CurrentPeim,
405 IN UINT32 DispatchedPeimBitMap
406 )
407 /*++
408
409 Routine Description:
410
411 This routine checks to see if a particular PEIM has been dispatched during
412 the PEI core dispatch.
413
414 Arguments:
415 CurrentPeim - The PEIM/FV in the bit array to check.
416 DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV.
417
418 Returns:
419 TRUE - PEIM already dispatched
420 FALSE - Otherwise
421
422 --*/
423 {
424 return (BOOLEAN)((DispatchedPeimBitMap & (1 << CurrentPeim)) != 0);
425 }
426
427 VOID
428 SetDispatched (
429 IN EFI_PEI_SERVICES **PeiServices,
430 IN UINT8 CurrentPeim,
431 OUT UINT32 *DispatchedPeimBitMap
432 )
433 /*++
434
435 Routine Description:
436
437 This routine sets a PEIM as having been dispatched once its entry
438 point has been invoked.
439
440 Arguments:
441
442 PeiServices - The PEI core services table.
443 CurrentPeim - The PEIM/FV in the bit array to check.
444 DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV.
445
446 Returns:
447 None
448
449 --*/
450 {
451 //
452 // Check if the total number of PEIMs exceed the bitmap.
453 // CurrentPeim is 0-based
454 //
455 ASSERT (CurrentPeim < (sizeof (*DispatchedPeimBitMap) * 8));
456 *DispatchedPeimBitMap |= (1 << CurrentPeim);
457 return;
458 }
459
460 BOOLEAN
461 DepexSatisfied (
462 IN EFI_PEI_SERVICES **PeiServices,
463 IN VOID *CurrentPeimAddress
464 )
465 /*++
466
467 Routine Description:
468
469 This routine parses the Dependency Expression, if available, and
470 decides if the module can be executed.
471
472 Arguments:
473 PeiServices - The PEI Service Table
474 CurrentPeimAddress - Address of the PEIM Firmware File under investigation
475
476 Returns:
477 TRUE - Can be dispatched
478 FALSE - Cannot be dispatched
479
480 --*/
481 {
482 EFI_STATUS Status;
483 INT8 *DepexData;
484 BOOLEAN Runnable;
485
486 Status = PeiServicesFfsFindSectionData (
487 EFI_SECTION_PEI_DEPEX,
488 CurrentPeimAddress,
489 (VOID **)&DepexData
490 );
491 //
492 // If there is no DEPEX, assume the module can be executed
493 //
494 if (EFI_ERROR (Status)) {
495 return TRUE;
496 }
497
498 //
499 // Evaluate a given DEPEX
500 //
501 Status = PeimDispatchReadiness (
502 PeiServices,
503 DepexData,
504 &Runnable
505 );
506
507 return Runnable;
508 }
509
510 STATIC
511 VOID *
512 TransferOldDataToNewDataRange (
513 IN PEI_CORE_INSTANCE *PrivateData
514 )
515 /*++
516
517 Routine Description:
518
519 This routine transfers the contents of the pre-permanent memory
520 PEI Core private data to a post-permanent memory data location.
521
522 Arguments:
523
524 PrivateData - Pointer to the current PEI Core private data pre-permanent memory
525
526 Returns:
527
528 Pointer to the PrivateData once the private data has been transferred to permanent memory
529
530 --*/
531 {
532 return BuildGuidDataHob (&gEfiPeiCorePrivateGuid, PrivateData, sizeof (PEI_CORE_INSTANCE));
533 }
534