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