]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Ppi/Ppi.c
36b8c235b2358bc28fb450cb877c668048c48d55
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Ppi / Ppi.c
1 /** @file
2 EFI PEI Core PPI services
3
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PeiMain.h"
16
17 /**
18
19 Initialize PPI services.
20
21 @param PrivateData Pointer to the PEI Core data.
22 @param OldCoreData Pointer to old PEI Core data.
23 NULL if being run in non-permament memory mode.
24
25 **/
26 VOID
27 InitializePpiServices (
28 IN PEI_CORE_INSTANCE *PrivateData,
29 IN PEI_CORE_INSTANCE *OldCoreData
30 )
31 {
32 if (OldCoreData == NULL) {
33 PrivateData->PpiData.NotifyListEnd = PcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
34 PrivateData->PpiData.DispatchListEnd = PcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
35 PrivateData->PpiData.LastDispatchedNotify = PcdGet32 (PcdPeiCoreMaxPpiSupported)-1;
36 }
37 }
38
39 /**
40
41 Migrate Single PPI Pointer from the temporary memory to PEI installed memory.
42
43 @param PpiPointer Pointer to Ppi
44 @param TempBottom Base of old temporary memory
45 @param TempTop Top of old temporary memory
46 @param Offset Offset of new memory to old temporary memory.
47 @param OffsetPositive Positive flag of Offset value.
48
49 **/
50 VOID
51 ConvertSinglePpiPointer (
52 IN PEI_PPI_LIST_POINTERS *PpiPointer,
53 IN UINTN TempBottom,
54 IN UINTN TempTop,
55 IN UINTN Offset,
56 IN BOOLEAN OffsetPositive
57 )
58 {
59 if (((UINTN)PpiPointer->Raw < TempTop) &&
60 ((UINTN)PpiPointer->Raw >= TempBottom)) {
61 //
62 // Convert the pointer to the PPI descriptor from the old TempRam
63 // to the relocated physical memory.
64 //
65 if (OffsetPositive) {
66 PpiPointer->Raw = (VOID *) ((UINTN)PpiPointer->Raw + Offset);
67 } else {
68 PpiPointer->Raw = (VOID *) ((UINTN)PpiPointer->Raw - Offset);
69 }
70
71 //
72 // Only when the PEIM descriptor is in the old TempRam should it be necessary
73 // to try to convert the pointers in the PEIM descriptor
74 //
75
76 if (((UINTN)PpiPointer->Ppi->Guid < TempTop) &&
77 ((UINTN)PpiPointer->Ppi->Guid >= TempBottom)) {
78 //
79 // Convert the pointer to the GUID in the PPI or NOTIFY descriptor
80 // from the old TempRam to the relocated physical memory.
81 //
82 if (OffsetPositive) {
83 PpiPointer->Ppi->Guid = (VOID *) ((UINTN)PpiPointer->Ppi->Guid + Offset);
84 } else {
85 PpiPointer->Ppi->Guid = (VOID *) ((UINTN)PpiPointer->Ppi->Guid - Offset);
86 }
87 }
88
89 //
90 // Convert the pointer to the PPI interface structure in the PPI descriptor
91 // from the old TempRam to the relocated physical memory.
92 //
93 if ((UINTN)PpiPointer->Ppi->Ppi < TempTop &&
94 (UINTN)PpiPointer->Ppi->Ppi >= TempBottom) {
95 if (OffsetPositive) {
96 PpiPointer->Ppi->Ppi = (VOID *) ((UINTN)PpiPointer->Ppi->Ppi + Offset);
97 } else {
98 PpiPointer->Ppi->Ppi = (VOID *) ((UINTN)PpiPointer->Ppi->Ppi - Offset);
99 }
100 }
101 }
102 }
103
104 /**
105
106 Migrate PPI Pointers from the temporary memory stack to PEI installed memory.
107
108 @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
109 and location of temporary RAM, the stack location and the BFV location.
110 @param PrivateData Pointer to PeiCore's private data structure.
111
112 **/
113 VOID
114 ConvertPpiPointers (
115 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
116 IN PEI_CORE_INSTANCE *PrivateData
117 )
118 {
119 UINT8 Index;
120 UINT8 IndexHole;
121
122 for (Index = 0; Index < PcdGet32 (PcdPeiCoreMaxPpiSupported); Index++) {
123 if (Index < PrivateData->PpiData.PpiListEnd || Index > PrivateData->PpiData.NotifyListEnd) {
124 //
125 // Convert PPI pointer in old Heap
126 //
127 ConvertSinglePpiPointer (
128 &PrivateData->PpiData.PpiListPtrs[Index],
129 (UINTN)SecCoreData->PeiTemporaryRamBase,
130 (UINTN)SecCoreData->PeiTemporaryRamBase + SecCoreData->PeiTemporaryRamSize,
131 PrivateData->HeapOffset,
132 PrivateData->HeapOffsetPositive
133 );
134
135 //
136 // Convert PPI pointer in old Stack
137 //
138 ConvertSinglePpiPointer (
139 &PrivateData->PpiData.PpiListPtrs[Index],
140 (UINTN)SecCoreData->StackBase,
141 (UINTN)SecCoreData->StackBase + SecCoreData->StackSize,
142 PrivateData->StackOffset,
143 PrivateData->StackOffsetPositive
144 );
145
146 //
147 // Convert PPI pointer in old TempRam Hole
148 //
149 for (IndexHole = 0; IndexHole < HOLE_MAX_NUMBER; IndexHole ++) {
150 if (PrivateData->HoleData[IndexHole].Size == 0) {
151 continue;
152 }
153
154 ConvertSinglePpiPointer (
155 &PrivateData->PpiData.PpiListPtrs[Index],
156 (UINTN)PrivateData->HoleData[IndexHole].Base,
157 (UINTN)PrivateData->HoleData[IndexHole].Base + PrivateData->HoleData[IndexHole].Size,
158 PrivateData->HoleData[IndexHole].Offset,
159 PrivateData->HoleData[IndexHole].OffsetPositive
160 );
161 }
162 }
163 }
164 }
165
166 /**
167
168 This function installs an interface in the PEI PPI database by GUID.
169 The purpose of the service is to publish an interface that other parties
170 can use to call additional PEIMs.
171
172 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
173 @param PpiList Pointer to a list of PEI PPI Descriptors.
174 @param Single TRUE if only single entry in the PpiList.
175 FALSE if the PpiList is ended with an entry which has the
176 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
177
178 @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
179 @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
180 if any PPI in PpiList is not valid
181 @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
182
183 **/
184 EFI_STATUS
185 InternalPeiInstallPpi (
186 IN CONST EFI_PEI_SERVICES **PeiServices,
187 IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
188 IN BOOLEAN Single
189 )
190 {
191 PEI_CORE_INSTANCE *PrivateData;
192 INTN Index;
193 INTN LastCallbackInstall;
194
195
196 if (PpiList == NULL) {
197 return EFI_INVALID_PARAMETER;
198 }
199
200 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
201
202 Index = PrivateData->PpiData.PpiListEnd;
203 LastCallbackInstall = Index;
204
205 //
206 // This is loop installs all PPI descriptors in the PpiList. It is terminated
207 // by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
208 // EFI_PEI_PPI_DESCRIPTOR in the list.
209 //
210
211 for (;;) {
212 //
213 // Since PpiData is used for NotifyList and PpiList, max resource
214 // is reached if the Install reaches the NotifyList
215 // PcdPeiCoreMaxPpiSupported can be set to a larger value in DSC to satisfy more PPI requirement.
216 //
217 if (Index == PrivateData->PpiData.NotifyListEnd + 1) {
218 return EFI_OUT_OF_RESOURCES;
219 }
220 //
221 // Check if it is a valid PPI.
222 // If not, rollback list to exclude all in this list.
223 // Try to indicate which item failed.
224 //
225 if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
226 PrivateData->PpiData.PpiListEnd = LastCallbackInstall;
227 DEBUG((EFI_D_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
228 return EFI_INVALID_PARAMETER;
229 }
230
231 DEBUG((EFI_D_INFO, "Install PPI: %g\n", PpiList->Guid));
232 PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR*) PpiList;
233 PrivateData->PpiData.PpiListEnd++;
234
235 if (Single) {
236 //
237 // Only single entry in the PpiList.
238 //
239 break;
240 } else if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
241 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
242 //
243 // Continue until the end of the PPI List.
244 //
245 break;
246 }
247 PpiList++;
248 Index++;
249 }
250
251 //
252 // Dispatch any callback level notifies for newly installed PPIs.
253 //
254 DispatchNotify (
255 PrivateData,
256 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
257 LastCallbackInstall,
258 PrivateData->PpiData.PpiListEnd,
259 PrivateData->PpiData.DispatchListEnd,
260 PrivateData->PpiData.NotifyListEnd
261 );
262
263
264 return EFI_SUCCESS;
265 }
266
267 /**
268
269 This function installs an interface in the PEI PPI database by GUID.
270 The purpose of the service is to publish an interface that other parties
271 can use to call additional PEIMs.
272
273 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
274 @param PpiList Pointer to a list of PEI PPI Descriptors.
275
276 @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
277 @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
278 if any PPI in PpiList is not valid
279 @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
280
281 **/
282 EFI_STATUS
283 EFIAPI
284 PeiInstallPpi (
285 IN CONST EFI_PEI_SERVICES **PeiServices,
286 IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
287 )
288 {
289 return InternalPeiInstallPpi (PeiServices, PpiList, FALSE);
290 }
291
292 /**
293
294 This function reinstalls an interface in the PEI PPI database by GUID.
295 The purpose of the service is to publish an interface that other parties can
296 use to replace an interface of the same name in the protocol database with a
297 different interface.
298
299 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
300 @param OldPpi Pointer to the old PEI PPI Descriptors.
301 @param NewPpi Pointer to the new PEI PPI Descriptors.
302
303 @retval EFI_SUCCESS if the operation was successful
304 @retval EFI_INVALID_PARAMETER if OldPpi or NewPpi is NULL
305 @retval EFI_INVALID_PARAMETER if NewPpi is not valid
306 @retval EFI_NOT_FOUND if the PPI was not in the database
307
308 **/
309 EFI_STATUS
310 EFIAPI
311 PeiReInstallPpi (
312 IN CONST EFI_PEI_SERVICES **PeiServices,
313 IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi,
314 IN CONST EFI_PEI_PPI_DESCRIPTOR *NewPpi
315 )
316 {
317 PEI_CORE_INSTANCE *PrivateData;
318 INTN Index;
319
320
321 if ((OldPpi == NULL) || (NewPpi == NULL)) {
322 return EFI_INVALID_PARAMETER;
323 }
324
325 if ((NewPpi->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
326 return EFI_INVALID_PARAMETER;
327 }
328
329 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
330
331 //
332 // Find the old PPI instance in the database. If we can not find it,
333 // return the EFI_NOT_FOUND error.
334 //
335 for (Index = 0; Index < PrivateData->PpiData.PpiListEnd; Index++) {
336 if (OldPpi == PrivateData->PpiData.PpiListPtrs[Index].Ppi) {
337 break;
338 }
339 }
340 if (Index == PrivateData->PpiData.PpiListEnd) {
341 return EFI_NOT_FOUND;
342 }
343
344 //
345 // Remove the old PPI from the database, add the new one.
346 //
347 DEBUG((EFI_D_INFO, "Reinstall PPI: %g\n", NewPpi->Guid));
348 ASSERT (Index < (INTN)(PcdGet32 (PcdPeiCoreMaxPpiSupported)));
349 PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *) NewPpi;
350
351 //
352 // Dispatch any callback level notifies for the newly installed PPI.
353 //
354 DispatchNotify (
355 PrivateData,
356 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
357 Index,
358 Index+1,
359 PrivateData->PpiData.DispatchListEnd,
360 PrivateData->PpiData.NotifyListEnd
361 );
362
363
364 return EFI_SUCCESS;
365 }
366
367 /**
368
369 Locate a given named PPI.
370
371
372 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
373 @param Guid Pointer to GUID of the PPI.
374 @param Instance Instance Number to discover.
375 @param PpiDescriptor Pointer to reference the found descriptor. If not NULL,
376 returns a pointer to the descriptor (includes flags, etc)
377 @param Ppi Pointer to reference the found PPI
378
379 @retval EFI_SUCCESS if the PPI is in the database
380 @retval EFI_NOT_FOUND if the PPI is not in the database
381
382 **/
383 EFI_STATUS
384 EFIAPI
385 PeiLocatePpi (
386 IN CONST EFI_PEI_SERVICES **PeiServices,
387 IN CONST EFI_GUID *Guid,
388 IN UINTN Instance,
389 IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
390 IN OUT VOID **Ppi
391 )
392 {
393 PEI_CORE_INSTANCE *PrivateData;
394 INTN Index;
395 EFI_GUID *CheckGuid;
396 EFI_PEI_PPI_DESCRIPTOR *TempPtr;
397
398
399 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
400
401 //
402 // Search the data base for the matching instance of the GUIDed PPI.
403 //
404 for (Index = 0; Index < PrivateData->PpiData.PpiListEnd; Index++) {
405 TempPtr = PrivateData->PpiData.PpiListPtrs[Index].Ppi;
406 CheckGuid = TempPtr->Guid;
407
408 //
409 // Don't use CompareGuid function here for performance reasons.
410 // Instead we compare the GUID as INT32 at a time and branch
411 // on the first failed comparison.
412 //
413 if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
414 (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
415 (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
416 (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3])) {
417 if (Instance == 0) {
418
419 if (PpiDescriptor != NULL) {
420 *PpiDescriptor = TempPtr;
421 }
422
423 if (Ppi != NULL) {
424 *Ppi = TempPtr->Ppi;
425 }
426
427
428 return EFI_SUCCESS;
429 }
430 Instance--;
431 }
432 }
433
434 return EFI_NOT_FOUND;
435 }
436
437 /**
438
439 This function installs a notification service to be called back when a given
440 interface is installed or reinstalled. The purpose of the service is to publish
441 an interface that other parties can use to call additional PPIs that may materialize later.
442
443 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
444 @param NotifyList Pointer to list of Descriptors to notify upon.
445 @param Single TRUE if only single entry in the NotifyList.
446 FALSE if the NotifyList is ended with an entry which has the
447 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
448
449 @retval EFI_SUCCESS if successful
450 @retval EFI_OUT_OF_RESOURCES if no space in the database
451 @retval EFI_INVALID_PARAMETER if not a good descriptor
452
453 **/
454 EFI_STATUS
455 InternalPeiNotifyPpi (
456 IN CONST EFI_PEI_SERVICES **PeiServices,
457 IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList,
458 IN BOOLEAN Single
459 )
460 {
461 PEI_CORE_INSTANCE *PrivateData;
462 INTN Index;
463 INTN NotifyIndex;
464 INTN LastCallbackNotify;
465 EFI_PEI_NOTIFY_DESCRIPTOR *NotifyPtr;
466 UINTN NotifyDispatchCount;
467
468
469 NotifyDispatchCount = 0;
470
471 if (NotifyList == NULL) {
472 return EFI_INVALID_PARAMETER;
473 }
474
475 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
476
477 Index = PrivateData->PpiData.NotifyListEnd;
478 LastCallbackNotify = Index;
479
480 //
481 // This is loop installs all Notify descriptors in the NotifyList. It is
482 // terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
483 // EFI_PEI_NOTIFY_DESCRIPTOR in the list.
484 //
485
486 for (;;) {
487 //
488 // Since PpiData is used for NotifyList and InstallList, max resource
489 // is reached if the Install reaches the PpiList
490 // PcdPeiCoreMaxPpiSupported can be set to a larger value in DSC to satisfy more Notify PPIs requirement.
491 //
492 if (Index == PrivateData->PpiData.PpiListEnd - 1) {
493 return EFI_OUT_OF_RESOURCES;
494 }
495
496 //
497 // If some of the PPI data is invalid restore original Notify PPI database value
498 //
499 if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
500 PrivateData->PpiData.NotifyListEnd = LastCallbackNotify;
501 DEBUG((EFI_D_ERROR, "ERROR -> InstallNotify: %g %p\n", NotifyList->Guid, NotifyList->Notify));
502 return EFI_INVALID_PARAMETER;
503 }
504
505 if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
506 NotifyDispatchCount ++;
507 }
508
509 PrivateData->PpiData.PpiListPtrs[Index].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList;
510
511 PrivateData->PpiData.NotifyListEnd--;
512 DEBUG((EFI_D_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
513 if (Single) {
514 //
515 // Only single entry in the NotifyList.
516 //
517 break;
518 } else if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
519 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
520 //
521 // Continue until the end of the Notify List.
522 //
523 break;
524 }
525 //
526 // Go the next descriptor. Remember the NotifyList moves down.
527 //
528 NotifyList++;
529 Index--;
530 }
531
532 //
533 // If there is Dispatch Notify PPI installed put them on the bottom
534 //
535 if (NotifyDispatchCount > 0) {
536 for (NotifyIndex = LastCallbackNotify; NotifyIndex > PrivateData->PpiData.NotifyListEnd; NotifyIndex--) {
537 if ((PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
538 NotifyPtr = PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify;
539
540 for (Index = NotifyIndex; Index < PrivateData->PpiData.DispatchListEnd; Index++){
541 PrivateData->PpiData.PpiListPtrs[Index].Notify = PrivateData->PpiData.PpiListPtrs[Index + 1].Notify;
542 }
543 PrivateData->PpiData.PpiListPtrs[Index].Notify = NotifyPtr;
544 PrivateData->PpiData.DispatchListEnd--;
545 }
546 }
547
548 LastCallbackNotify -= NotifyDispatchCount;
549 }
550
551 //
552 // Dispatch any callback level notifies for all previously installed PPIs.
553 //
554 DispatchNotify (
555 PrivateData,
556 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
557 0,
558 PrivateData->PpiData.PpiListEnd,
559 LastCallbackNotify,
560 PrivateData->PpiData.NotifyListEnd
561 );
562
563 return EFI_SUCCESS;
564 }
565
566 /**
567
568 This function installs a notification service to be called back when a given
569 interface is installed or reinstalled. The purpose of the service is to publish
570 an interface that other parties can use to call additional PPIs that may materialize later.
571
572 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
573 @param NotifyList Pointer to list of Descriptors to notify upon.
574
575 @retval EFI_SUCCESS if successful
576 @retval EFI_OUT_OF_RESOURCES if no space in the database
577 @retval EFI_INVALID_PARAMETER if not a good descriptor
578
579 **/
580 EFI_STATUS
581 EFIAPI
582 PeiNotifyPpi (
583 IN CONST EFI_PEI_SERVICES **PeiServices,
584 IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
585 )
586 {
587 return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
588 }
589
590
591 /**
592
593 Process the Notify List at dispatch level.
594
595 @param PrivateData PeiCore's private data structure.
596
597 **/
598 VOID
599 ProcessNotifyList (
600 IN PEI_CORE_INSTANCE *PrivateData
601 )
602 {
603 INTN TempValue;
604
605 while (TRUE) {
606 //
607 // Check if the PEIM that was just dispatched resulted in any
608 // Notifies getting installed. If so, go process any dispatch
609 // level Notifies that match the previouly installed PPIs.
610 // Use "while" instead of "if" since DispatchNotify can modify
611 // DispatchListEnd (with NotifyPpi) so we have to iterate until the same.
612 //
613 while (PrivateData->PpiData.LastDispatchedNotify != PrivateData->PpiData.DispatchListEnd) {
614 TempValue = PrivateData->PpiData.DispatchListEnd;
615 DispatchNotify (
616 PrivateData,
617 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
618 0,
619 PrivateData->PpiData.LastDispatchedInstall,
620 PrivateData->PpiData.LastDispatchedNotify,
621 PrivateData->PpiData.DispatchListEnd
622 );
623 PrivateData->PpiData.LastDispatchedNotify = TempValue;
624 }
625
626
627 //
628 // Check if the PEIM that was just dispatched resulted in any
629 // PPIs getting installed. If so, go process any dispatch
630 // level Notifies that match the installed PPIs.
631 // Use "while" instead of "if" since DispatchNotify can modify
632 // PpiListEnd (with InstallPpi) so we have to iterate until the same.
633 //
634 while (PrivateData->PpiData.LastDispatchedInstall != PrivateData->PpiData.PpiListEnd) {
635 TempValue = PrivateData->PpiData.PpiListEnd;
636 DispatchNotify (
637 PrivateData,
638 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
639 PrivateData->PpiData.LastDispatchedInstall,
640 PrivateData->PpiData.PpiListEnd,
641 PcdGet32 (PcdPeiCoreMaxPpiSupported)-1,
642 PrivateData->PpiData.DispatchListEnd
643 );
644 PrivateData->PpiData.LastDispatchedInstall = TempValue;
645 }
646
647 if (PrivateData->PpiData.LastDispatchedNotify == PrivateData->PpiData.DispatchListEnd) {
648 break;
649 }
650 }
651 return;
652 }
653
654 /**
655
656 Dispatch notifications.
657
658 @param PrivateData PeiCore's private data structure
659 @param NotifyType Type of notify to fire.
660 @param InstallStartIndex Install Beginning index.
661 @param InstallStopIndex Install Ending index.
662 @param NotifyStartIndex Notify Beginning index.
663 @param NotifyStopIndex Notify Ending index.
664
665 **/
666 VOID
667 DispatchNotify (
668 IN PEI_CORE_INSTANCE *PrivateData,
669 IN UINTN NotifyType,
670 IN INTN InstallStartIndex,
671 IN INTN InstallStopIndex,
672 IN INTN NotifyStartIndex,
673 IN INTN NotifyStopIndex
674 )
675 {
676 INTN Index1;
677 INTN Index2;
678 EFI_GUID *SearchGuid;
679 EFI_GUID *CheckGuid;
680 EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
681
682 //
683 // Remember that Installs moves up and Notifies moves down.
684 //
685 for (Index1 = NotifyStartIndex; Index1 > NotifyStopIndex; Index1--) {
686 NotifyDescriptor = PrivateData->PpiData.PpiListPtrs[Index1].Notify;
687
688 CheckGuid = NotifyDescriptor->Guid;
689
690 for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
691 SearchGuid = PrivateData->PpiData.PpiListPtrs[Index2].Ppi->Guid;
692 //
693 // Don't use CompareGuid function here for performance reasons.
694 // Instead we compare the GUID as INT32 at a time and branch
695 // on the first failed comparison.
696 //
697 if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
698 (((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
699 (((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
700 (((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3])) {
701 DEBUG ((EFI_D_INFO, "Notify: PPI Guid: %g, Peim notify entry point: %p\n",
702 SearchGuid,
703 NotifyDescriptor->Notify
704 ));
705 NotifyDescriptor->Notify (
706 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
707 NotifyDescriptor,
708 (PrivateData->PpiData.PpiListPtrs[Index2].Ppi)->Ppi
709 );
710 }
711 }
712 }
713 }
714
715 /**
716 Process PpiList from SEC phase.
717
718 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
719 @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
720 These PPI's will be installed and/or immediately signaled if they are notification type.
721
722 **/
723 VOID
724 ProcessPpiListFromSec (
725 IN CONST EFI_PEI_SERVICES **PeiServices,
726 IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
727 )
728 {
729 EFI_STATUS Status;
730 EFI_SEC_HOB_DATA_PPI *SecHobDataPpi;
731 EFI_HOB_GENERIC_HEADER *SecHobList;
732
733 for (;;) {
734 if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
735 //
736 // It is a notification PPI.
737 //
738 Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *) PpiList, TRUE);
739 ASSERT_EFI_ERROR (Status);
740 } else {
741 //
742 // It is a normal PPI.
743 //
744 Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
745 ASSERT_EFI_ERROR (Status);
746 }
747
748 if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
749 //
750 // Continue until the end of the PPI List.
751 //
752 break;
753 }
754
755 PpiList++;
756 }
757
758 //
759 // If the EFI_SEC_HOB_DATA_PPI is in the list of PPIs passed to the PEI entry point,
760 // the PEI Foundation will call the GetHobs() member function and install all HOBs
761 // returned into the HOB list. It does this after installing all PPIs passed from SEC
762 // into the PPI database and before dispatching any PEIMs.
763 //
764 Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **) &SecHobDataPpi);
765 if (!EFI_ERROR (Status)) {
766 Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
767 if (!EFI_ERROR (Status)) {
768 Status = PeiInstallSecHobData (PeiServices, SecHobList);
769 ASSERT_EFI_ERROR (Status);
770 }
771 }
772 }
773