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