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