Clean up MSA file of the checked in modules which include:
[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_STATUS
33 PeiDispatcher (
34 IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor,
35 IN PEI_CORE_INSTANCE *PrivateData,
36 IN PEI_CORE_DISPATCH_DATA *DispatchData
37 )
38
39 /*++
40
41 Routine Description:
42
43 Conduct PEIM dispatch.
44
45 Arguments:
46
47 PeiStartupDescriptor - Pointer to IN EFI_PEI_STARTUP_DESCRIPTOR
48 PrivateData - Pointer to the private data passed in from caller
49 DispatchData - Pointer to PEI_CORE_DISPATCH_DATA data.
50
51 Returns:
52
53 EFI_SUCCESS - Successfully dispatched PEIM.
54 EFI_NOT_FOUND - The dispatch failed.
55
56 --*/
57 {
58 EFI_STATUS Status;
59 PEI_CORE_TEMP_POINTERS TempPtr;
60 UINTN PrivateDataInMem;
61 BOOLEAN NextFvFound;
62 EFI_FIRMWARE_VOLUME_HEADER *NextFvAddress;
63 EFI_FIRMWARE_VOLUME_HEADER *DefaultFvAddress;
64 VOID *TopOfStack;
65 //
66 // Debug data for uninstalled Peim list
67 //
68 EFI_GUID DebugFoundPeimList[32];
69 REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA ExtendedData;
70
71 //
72 // save the Current FV Address so that we will not process it again if FindFv returns it later
73 //
74 DefaultFvAddress = DispatchData->BootFvAddress;
75
76 //
77 // This is the main dispatch loop. It will search known FVs for PEIMs and
78 // attempt to dispatch them. If any PEIM gets dispatched through a single
79 // pass of the dispatcher, it will start over from the Bfv again to see
80 // if any new PEIMs dependencies got satisfied. With a well ordered
81 // FV where PEIMs are found in the order their dependencies are also
82 // satisfied, this dipatcher should run only once.
83 //
84 for (;;) {
85 //
86 // This is the PEIM search loop. It will scan through all PEIMs it can find
87 // looking for PEIMs to dispatch, and will dipatch them if they have not
88 // already been dispatched and all of their dependencies are met.
89 // If no more PEIMs can be found in this pass through all known FVs,
90 // then it will break out of this loop.
91 //
92 for (;;) {
93
94 Status = FindNextPeim (
95 &PrivateData->PS,
96 DispatchData->CurrentFvAddress,
97 &DispatchData->CurrentPeimAddress
98 );
99
100 //
101 // If we found a PEIM, check if it is dispatched. If so, go to the
102 // next PEIM. If not, dispatch it if its dependencies are satisfied.
103 // If its dependencies are not satisfied, go to the next PEIM.
104 //
105 if (Status == EFI_SUCCESS) {
106
107 DEBUG_CODE_BEGIN ();
108
109 //
110 // Fill list of found Peims for later list of those not installed
111 //
112 CopyMem (
113 &DebugFoundPeimList[DispatchData->CurrentPeim],
114 &DispatchData->CurrentPeimAddress->Name,
115 sizeof (EFI_GUID)
116 );
117
118 DEBUG_CODE_END ();
119
120 if (!Dispatched (
121 DispatchData->CurrentPeim,
122 DispatchData->DispatchedPeimBitMap
123 )) {
124 if (DepexSatisfied (&PrivateData->PS, DispatchData->CurrentPeimAddress)) {
125 Status = PeiLoadImage (
126 &PrivateData->PS,
127 DispatchData->CurrentPeimAddress,
128 &TempPtr.Raw
129 );
130 if (Status == EFI_SUCCESS) {
131
132 //
133 // The PEIM has its dependencies satisfied, and its entry point
134 // has been found, so invoke it.
135 //
136 PERF_START (
137 (VOID *) (UINTN) (DispatchData->CurrentPeimAddress),
138 "PEIM",
139 NULL,
140 0
141 );
142
143 //
144 // BUGBUG: Used to be EFI_PEI_REPORT_STATUS_CODE_CODE
145 //
146 ExtendedData.Handle = (EFI_HANDLE)DispatchData->CurrentPeimAddress;
147
148 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
149 EFI_PROGRESS_CODE,
150 EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_BEGIN,
151 (VOID *)(&ExtendedData),
152 sizeof (ExtendedData)
153 );
154
155 //
156 // Is this a authentic image
157 //
158 Status = VerifyPeim (
159 &PrivateData->PS,
160 DispatchData->CurrentPeimAddress
161 );
162
163 if (Status != EFI_SECURITY_VIOLATION) {
164
165 Status = TempPtr.PeimEntry (
166 DispatchData->CurrentPeimAddress,
167 &PrivateData->PS
168 );
169 }
170
171 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
172 EFI_PROGRESS_CODE,
173 EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END,
174 (VOID *)(&ExtendedData),
175 sizeof (ExtendedData)
176 );
177
178 PERF_END ((VOID *) (UINTN) (DispatchData->CurrentPeimAddress), "PEIM", NULL, 0);
179
180 //
181 // Mark the PEIM as dispatched so we don't attempt to run it again
182 //
183 SetDispatched (
184 &PrivateData->PS,
185 DispatchData->CurrentPeim,
186 &DispatchData->DispatchedPeimBitMap
187 );
188
189 //
190 // Process the Notify list and dispatch any notifies for
191 // newly installed PPIs.
192 //
193 ProcessNotifyList (&PrivateData->PS);
194
195 //
196 // If real system memory was discovered and installed by this
197 // PEIM, switch the stacks to the new memory. Since we are
198 // at dispatch level, only the Core's private data is preserved,
199 // nobody else should have any data on the stack.
200 //
201 if (PrivateData->SwitchStackSignal) {
202 TempPtr.PeiCore = (PEI_CORE_ENTRY_POINT)PeiCore;
203 PrivateDataInMem = (UINTN) TransferOldDataToNewDataRange (PrivateData);
204 ASSERT (PrivateDataInMem != 0);
205 //
206 // Adjust the top of stack to be aligned at CPU_STACK_ALIGNMENT
207 //
208 TopOfStack = (VOID *)((UINTN)PrivateData->StackBase + (UINTN)PrivateData->StackSize - CPU_STACK_ALIGNMENT);
209 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
210
211 PeiSwitchStacks (
212 (SWITCH_STACK_ENTRY_POINT)(UINTN)TempPtr.Raw,
213 PeiStartupDescriptor,
214 (VOID*)PrivateDataInMem,
215 TopOfStack,
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 STATIC
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 //
530 //Build private HOB to PEI core to transfer old NEM-range data to new NEM-range
531 //
532 return BuildGuidDataHob (&gEfiPeiCorePrivateGuid, PrivateData, sizeof (PEI_CORE_INSTANCE));
533 }
534