]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Dispatcher/Dispatcher.c
Add some definitions which will be used for future PI enabling.
[mirror_edk2.git] / MdeModulePkg / 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 EFI_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 //
166 // BUGBUG: Before enable PI, we need cast EFI_FFS_FILE_HEADER* to EFI_PEI_FILE_HANDLE*
167 // Because we use new MdePkg's definition, but they are binary compatible in fact.
168 //
169 Status = TempPtr.PeimEntry (
170 (EFI_PEI_FILE_HANDLE*)DispatchData->CurrentPeimAddress,
171 &PrivateData->PS
172 );
173 }
174
175 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
176 EFI_PROGRESS_CODE,
177 EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT_END,
178 (VOID *)(&ExtendedData),
179 sizeof (ExtendedData)
180 );
181
182 PERF_END ((VOID *) (UINTN) (DispatchData->CurrentPeimAddress), "PEIM", NULL, 0);
183
184 //
185 // Mark the PEIM as dispatched so we don't attempt to run it again
186 //
187 SetDispatched (
188 &PrivateData->PS,
189 DispatchData->CurrentPeim,
190 &DispatchData->DispatchedPeimBitMap
191 );
192
193 //
194 // Process the Notify list and dispatch any notifies for
195 // newly installed PPIs.
196 //
197 ProcessNotifyList (&PrivateData->PS);
198
199 //
200 // If real system memory was discovered and installed by this
201 // PEIM, switch the stacks to the new memory. Since we are
202 // at dispatch level, only the Core's private data is preserved,
203 // nobody else should have any data on the stack.
204 //
205 if (PrivateData->SwitchStackSignal) {
206 TempPtr.PeiCore = (PEI_CORE_ENTRY_POINT)PeiCore;
207 PrivateDataInMem = (UINTN) TransferOldDataToNewDataRange (PrivateData);
208 ASSERT (PrivateDataInMem != 0);
209 //
210 // Adjust the top of stack to be aligned at CPU_STACK_ALIGNMENT
211 //
212 TopOfStack = (VOID *)((UINTN)PrivateData->StackBase + (UINTN)PrivateData->StackSize - CPU_STACK_ALIGNMENT);
213 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
214
215 PeiSwitchStacks (
216 (SWITCH_STACK_ENTRY_POINT)(UINTN)TempPtr.Raw,
217 PeiStartupDescriptor,
218 (VOID*)PrivateDataInMem,
219 TopOfStack,
220 (VOID*)(UINTN)PrivateData->StackBase
221 );
222 }
223 }
224 }
225 }
226 DispatchData->CurrentPeim++;
227 continue;
228
229 } else {
230
231 //
232 // If we could not find another PEIM in the current FV, go try
233 // the FindFv PPI to look in other FVs for more PEIMs. If we can
234 // not locate the FindFv PPI, or if the FindFv PPI can not find
235 // anymore FVs, then exit the PEIM search loop.
236 //
237 if (DispatchData->FindFv == NULL) {
238 Status = PeiServicesLocatePpi (
239 &gEfiFindFvPpiGuid,
240 0,
241 NULL,
242 (VOID **)&DispatchData->FindFv
243 );
244 if (Status != EFI_SUCCESS) {
245 break;
246 }
247 }
248 NextFvFound = FALSE;
249 while (!NextFvFound) {
250 Status = DispatchData->FindFv->FindFv (
251 DispatchData->FindFv,
252 &PrivateData->PS,
253 &DispatchData->CurrentFv,
254 &NextFvAddress
255 );
256 //
257 // if there is no next fv, get out of this loop of finding FVs
258 //
259 if (Status != EFI_SUCCESS) {
260 break;
261 }
262 //
263 // don't process the default Fv again. (we don't know the order in which the hobs were created)
264 //
265 if ((NextFvAddress != DefaultFvAddress) &&
266 (NextFvAddress != DispatchData->CurrentFvAddress)) {
267
268 //
269 // VerifyFv() is currently returns SUCCESS all the time, add code to it to
270 // actually verify the given FV
271 //
272 Status = VerifyFv (NextFvAddress);
273 if (Status == EFI_SUCCESS) {
274 NextFvFound = TRUE;
275 DispatchData->CurrentFvAddress = NextFvAddress;
276 DispatchData->CurrentPeimAddress = NULL;
277 //
278 // current PRIM number (CurrentPeim) must continue as is, don't reset it here
279 //
280 }
281 }
282 }
283 //
284 // if there is no next fv, get out of this loop of dispatching PEIMs
285 //
286 if (!NextFvFound) {
287 break;
288 }
289 //
290 // continue in the inner for(;;) loop with a new FV;
291 //
292 }
293 }
294
295 //
296 // If all the PEIMs that we have found have been dispatched, then
297 // there is nothing left to dispatch and we don't need to go search
298 // through all PEIMs again.
299 //
300 if ((~(DispatchData->DispatchedPeimBitMap) &
301 ((1 << DispatchData->CurrentPeim)-1)) == 0) {
302 break;
303 }
304
305 //
306 // Check if no more PEIMs that depex was satisfied
307 //
308 if (DispatchData->DispatchedPeimBitMap == DispatchData->PreviousPeimBitMap) {
309 break;
310 }
311
312 //
313 // Case when Depex is not satisfied and has to traverse the list again
314 //
315 DispatchData->CurrentPeim = 0;
316 DispatchData->CurrentPeimAddress = 0;
317 DispatchData->PreviousPeimBitMap = DispatchData->DispatchedPeimBitMap;
318
319 //
320 // don't go back to the loop without making sure that the CurrentFvAddress is the
321 // same as the 1st (or default) FV we started with. otherwise we will interpret the bimap wrongly and
322 // mess it up, always start processing the PEIMs from the default FV just like in the first time around.
323 //
324 DispatchData->CurrentFv = 0;
325 DispatchData->CurrentFvAddress = DefaultFvAddress;
326 }
327
328 DEBUG_CODE_BEGIN ();
329 //
330 // Debug data for uninstalled Peim list
331 //
332 UINT32 DebugNotDispatchedBitmap;
333 UINT8 DebugFoundPeimPoint;
334
335 DebugFoundPeimPoint = 0;
336 //
337 // Get bitmap of Peims that were not dispatched,
338 //
339
340 DebugNotDispatchedBitmap = ((DispatchData->DispatchedPeimBitMap) ^ ((1 << DispatchData->CurrentPeim)-1));
341 //
342 // Scan bitmap of Peims not installed and print GUIDS
343 //
344 while (DebugNotDispatchedBitmap != 0) {
345 if ((DebugNotDispatchedBitmap & 1) != 0) {
346 DEBUG ((EFI_D_INFO, "WARNING -> InstallPpi: Not Installed: %g\n",
347 &DebugFoundPeimList[DebugFoundPeimPoint]
348 ));
349 }
350 DebugFoundPeimPoint++;
351 DebugNotDispatchedBitmap >>= 1;
352 }
353
354 DEBUG_CODE_END ();
355
356 return EFI_NOT_FOUND;
357 }
358
359 VOID
360 InitializeDispatcherData (
361 IN EFI_PEI_SERVICES **PeiServices,
362 IN PEI_CORE_INSTANCE *OldCoreData,
363 IN EFI_PEI_STARTUP_DESCRIPTOR *PeiStartupDescriptor
364 )
365 /*++
366
367 Routine Description:
368
369 Initialize the Dispatcher's data members
370
371 Arguments:
372
373 PeiServices - The PEI core services table.
374 OldCoreData - Pointer to old core data (before switching stack).
375 NULL if being run in non-permament memory mode.
376 PeiStartupDescriptor - Information and services provided by SEC phase.
377
378 Returns:
379
380 None.
381
382 --*/
383 {
384 PEI_CORE_INSTANCE *PrivateData;
385
386 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
387
388 if (OldCoreData == NULL) {
389 PrivateData->DispatchData.CurrentFvAddress = (EFI_FIRMWARE_VOLUME_HEADER *) PeiStartupDescriptor->BootFirmwareVolume;
390 PrivateData->DispatchData.BootFvAddress = (EFI_FIRMWARE_VOLUME_HEADER *) PeiStartupDescriptor->BootFirmwareVolume;
391 } else {
392
393 //
394 // Current peim has been dispatched, but not count
395 //
396 PrivateData->DispatchData.CurrentPeim = (UINT8)(OldCoreData->DispatchData.CurrentPeim + 1);
397 }
398
399 return;
400 }
401
402
403 BOOLEAN
404 Dispatched (
405 IN UINT8 CurrentPeim,
406 IN UINT32 DispatchedPeimBitMap
407 )
408 /*++
409
410 Routine Description:
411
412 This routine checks to see if a particular PEIM has been dispatched during
413 the PEI core dispatch.
414
415 Arguments:
416 CurrentPeim - The PEIM/FV in the bit array to check.
417 DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV.
418
419 Returns:
420 TRUE - PEIM already dispatched
421 FALSE - Otherwise
422
423 --*/
424 {
425 return (BOOLEAN)((DispatchedPeimBitMap & (1 << CurrentPeim)) != 0);
426 }
427
428 VOID
429 SetDispatched (
430 IN EFI_PEI_SERVICES **PeiServices,
431 IN UINT8 CurrentPeim,
432 OUT UINT32 *DispatchedPeimBitMap
433 )
434 /*++
435
436 Routine Description:
437
438 This routine sets a PEIM as having been dispatched once its entry
439 point has been invoked.
440
441 Arguments:
442
443 PeiServices - The PEI core services table.
444 CurrentPeim - The PEIM/FV in the bit array to check.
445 DispatchedPeimBitMap - Bit array, each bit corresponds to a PEIM/FV.
446
447 Returns:
448 None
449
450 --*/
451 {
452 //
453 // Check if the total number of PEIMs exceed the bitmap.
454 // CurrentPeim is 0-based
455 //
456 ASSERT (CurrentPeim < (sizeof (*DispatchedPeimBitMap) * 8));
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 STATIC
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 //
534 //Build private HOB to PEI core to transfer old NEM-range data to new NEM-range
535 //
536 return BuildGuidDataHob (&gEfiPeiCorePrivateGuid, PrivateData, sizeof (PEI_CORE_INSTANCE));
537 }
538