]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Core/Pei/Dispatcher/Dispatcher.c
1. Rename PeiCoreLib to PeiServicesLib and rename all the interfaces from PeiCoreXXX...
[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 (
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 );
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 SwitchStack (
212 (SWITCH_STACK_ENTRY_POINT)(UINTN)TempPtr.Raw,
213 PeiStartupDescriptor,
214 (VOID*)PrivateDataInMem,
215 (VOID*)((UINTN)PrivateData->StackBase + (UINTN)PrivateData->StackSize)
216 );
217 }
218 }
219 }
220 }
221 DispatchData->CurrentPeim++;
222 continue;
223
224 } else {
225
226 //
227 // If we could not find another PEIM in the current FV, go try
228 // the FindFv PPI to look in other FVs for more PEIMs. If we can
229 // not locate the FindFv PPI, or if the FindFv PPI can not find
230 // anymore FVs, then exit the PEIM search loop.
231 //
232 if (DispatchData->FindFv == NULL) {
233 Status = PeiServicesLocatePpi (
234 &gEfiFindFvPpiGuid,
235 0,
236 NULL,
237 (VOID **)&DispatchData->FindFv
238 );
239 if (Status != EFI_SUCCESS) {
240 break;
241 }
242 }
243 NextFvFound = FALSE;
244 while (!NextFvFound) {
245 Status = DispatchData->FindFv->FindFv (
246 DispatchData->FindFv,
247 &PrivateData->PS,
248 &DispatchData->CurrentFv,
249 &NextFvAddress
250 );
251 //
252 // if there is no next fv, get out of this loop of finding FVs
253 //
254 if (Status != EFI_SUCCESS) {
255 break;
256 }
257 //
258 // don't process the default Fv again. (we don't know the order in which the hobs were created)
259 //
260 if ((NextFvAddress != DefaultFvAddress) &&
261 (NextFvAddress != DispatchData->CurrentFvAddress)) {
262
263 //
264 // VerifyFv() is currently returns SUCCESS all the time, add code to it to
265 // actually verify the given FV
266 //
267 Status = VerifyFv (NextFvAddress);
268 if (Status == EFI_SUCCESS) {
269 NextFvFound = TRUE;
270 DispatchData->CurrentFvAddress = NextFvAddress;
271 DispatchData->CurrentPeimAddress = NULL;
272 //
273 // current PRIM number (CurrentPeim) must continue as is, don't reset it here
274 //
275 }
276 }
277 }
278 //
279 // if there is no next fv, get out of this loop of dispatching PEIMs
280 //
281 if (!NextFvFound) {
282 break;
283 }
284 //
285 // continue in the inner for(;;) loop with a new FV;
286 //
287 }
288 }
289
290 //
291 // If all the PEIMs that we have found have been dispatched, then
292 // there is nothing left to dispatch and we don't need to go search
293 // through all PEIMs again.
294 //
295 if ((~(DispatchData->DispatchedPeimBitMap) &
296 ((1 << DispatchData->CurrentPeim)-1)) == 0) {
297 break;
298 }
299
300 //
301 // Check if no more PEIMs that depex was satisfied
302 //
303 if (DispatchData->DispatchedPeimBitMap == DispatchData->PreviousPeimBitMap) {
304 break;
305 }
306
307 //
308 // Case when Depex is not satisfied and has to traverse the list again
309 //
310 DispatchData->CurrentPeim = 0;
311 DispatchData->CurrentPeimAddress = 0;
312 DispatchData->PreviousPeimBitMap = DispatchData->DispatchedPeimBitMap;
313
314 //
315 // don't go back to the loop without making sure that the CurrentFvAddress is the
316 // same as the 1st (or default) FV we started with. otherwise we will interpret the bimap wrongly and
317 // mess it up, always start processing the PEIMs from the default FV just like in the first time around.
318 //
319 DispatchData->CurrentFv = 0;
320 DispatchData->CurrentFvAddress = DefaultFvAddress;
321 }
322
323 DEBUG_CODE (
324 //
325 // Debug data for uninstalled Peim list
326 //
327 UINT32 DebugNotDispatchedBitmap;
328 UINT8 DebugFoundPeimPoint;
329
330 DebugFoundPeimPoint = 0;
331 //
332 // Get bitmap of Peims that were not dispatched,
333 //
334
335 DebugNotDispatchedBitmap = ((DispatchData->DispatchedPeimBitMap) ^ ((1 << DispatchData->CurrentPeim)-1));
336 //
337 // Scan bitmap of Peims not installed and print GUIDS
338 //
339 while (DebugNotDispatchedBitmap != 0) {
340 if ((DebugNotDispatchedBitmap & 1) != 0) {
341 DEBUG ((EFI_D_INFO, "WARNING -> InstallPpi: Not Installed: %g\n",
342 &DebugFoundPeimList[DebugFoundPeimPoint]
343 ));
344 }
345 DebugFoundPeimPoint++;
346 DebugNotDispatchedBitmap >>= 1;
347 }
348
349 );
350
351 return EFI_NOT_FOUND;
352 }
353
354 VOID
355 InitializeDispatcherData (
356 IN EFI_PEI_SERVICES **PeiServices,
357 IN PEI_CORE_INSTANCE *OldCoreData,
358 IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor
359 )
360 /*++
361
362 Routine Description:
363
364 Initialize the Dispatcher's data members
365
366 Arguments:
367
368 PeiServices - The PEI core services table.
369 OldCoreData - Pointer to old core data (before switching stack).
370 NULL if being run in non-permament memory mode.
371 PeiStartupDescriptor - Information and services provided by SEC phase.
372
373 Returns:
374
375 None.
376
377 --*/
378 {
379 PEI_CORE_INSTANCE *PrivateData;
380
381 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
382
383 if (OldCoreData == NULL) {
384 PrivateData->DispatchData.CurrentFvAddress = (EFI_FIRMWARE_VOLUME_HEADER *) PeiStartupDescriptor->BootFirmwareVolume;
385 PrivateData->DispatchData.BootFvAddress = (EFI_FIRMWARE_VOLUME_HEADER *) PeiStartupDescriptor->BootFirmwareVolume;
386 } else {
387
388 //
389 // Current peim has been dispatched, but not count
390 //
391 PrivateData->DispatchData.CurrentPeim = (UINT8)(OldCoreData->DispatchData.CurrentPeim + 1);
392 }
393
394 return;
395 }
396
397
398 BOOLEAN
399 Dispatched (
400 IN UINT8 CurrentPeim,
401 IN UINT32 DispatchedPeimBitMap
402 )
403 /*++
404
405 Routine Description:
406
407 This routine checks to see if a particular PEIM has been dispatched during
408 the PEI core dispatch.
409
410 Arguments:
411 CurrentPeim - The PEIM/FV in the bit array to check.
412 DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV.
413
414 Returns:
415 TRUE - PEIM already dispatched
416 FALSE - Otherwise
417
418 --*/
419 {
420 return (BOOLEAN)((DispatchedPeimBitMap & (1 << CurrentPeim)) != 0);
421 }
422
423 VOID
424 SetDispatched (
425 IN EFI_PEI_SERVICES **PeiServices,
426 IN UINT8 CurrentPeim,
427 OUT UINT32 *DispatchedPeimBitMap
428 )
429 /*++
430
431 Routine Description:
432
433 This routine sets a PEIM as having been dispatched once its entry
434 point has been invoked.
435
436 Arguments:
437
438 PeiServices - The PEI core services table.
439 CurrentPeim - The PEIM/FV in the bit array to check.
440 DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV.
441
442 Returns:
443 None
444
445 --*/
446 {
447 //
448 // Check if the total number of PEIMs exceed the bitmap.
449 // CurrentPeim is 0-based
450 //
451 DEBUG_CODE (
452 if (CurrentPeim > (sizeof (*DispatchedPeimBitMap) * 8 - 1)) {
453 ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
454 }
455 );
456
457 *DispatchedPeimBitMap |= (1 << CurrentPeim);
458 return;
459 }
460
461 BOOLEAN
462 DepexSatisfied (
463 IN EFI_PEI_SERVICES **PeiServices,
464 IN VOID *CurrentPeimAddress
465 )
466 /*++
467
468 Routine Description:
469
470 This routine parses the Dependency Expression, if available, and
471 decides if the module can be executed.
472
473 Arguments:
474 PeiServices - The PEI Service Table
475 CurrentPeimAddress - Address of the PEIM Firmware File under investigation
476
477 Returns:
478 TRUE - Can be dispatched
479 FALSE - Cannot be dispatched
480
481 --*/
482 {
483 EFI_STATUS Status;
484 INT8 *DepexData;
485 BOOLEAN Runnable;
486
487 Status = PeiServicesFfsFindSectionData (
488 EFI_SECTION_PEI_DEPEX,
489 CurrentPeimAddress,
490 (VOID **)&DepexData
491 );
492 //
493 // If there is no DEPEX, assume the module can be executed
494 //
495 if (EFI_ERROR (Status)) {
496 return TRUE;
497 }
498
499 //
500 // Evaluate a given DEPEX
501 //
502 Status = PeimDispatchReadiness (
503 PeiServices,
504 DepexData,
505 &Runnable
506 );
507
508 return Runnable;
509 }
510
511
512 VOID *
513 TransferOldDataToNewDataRange (
514 IN PEI_CORE_INSTANCE *PrivateData
515 )
516 /*++
517
518 Routine Description:
519
520 This routine transfers the contents of the pre-permanent memory
521 PEI Core private data to a post-permanent memory data location.
522
523 Arguments:
524
525 PrivateData - Pointer to the current PEI Core private data pre-permanent memory
526
527 Returns:
528
529 Pointer to the PrivateData once the private data has been transferred to permanent memory
530
531 --*/
532 {
533 return BuildGuidDataHob (&gEfiPeiCorePrivateGuid, PrivateData, sizeof (PEI_CORE_INSTANCE));
534 }
535