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
ConvertPointer(IN OUT VOID ** Pointer,IN UINTN TempBottom,IN UINTN TempTop,IN UINTN Offset,IN BOOLEAN OffsetPositive)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
ConvertPointerInRanges(IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreData,IN PEI_CORE_INSTANCE * PrivateData,IN OUT VOID ** Pointer)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
ConvertSinglePpiPointer(IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreData,IN PEI_CORE_INSTANCE * PrivateData,IN PEI_PPI_LIST_POINTERS * PpiPointer)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
ConvertPpiPointers(IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreData,IN PEI_CORE_INSTANCE * PrivateData)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
InternalPeiInstallPpi(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_PPI_DESCRIPTOR * PpiList,IN BOOLEAN Single)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
PeiInstallPpi(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_PPI_DESCRIPTOR * PpiList)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
PeiReInstallPpi(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_PPI_DESCRIPTOR * OldPpi,IN CONST EFI_PEI_PPI_DESCRIPTOR * NewPpi)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
PeiLocatePpi(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_GUID * Guid,IN UINTN Instance,IN OUT EFI_PEI_PPI_DESCRIPTOR ** PpiDescriptor,IN OUT VOID ** Ppi)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
InternalPeiNotifyPpi(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_NOTIFY_DESCRIPTOR * NotifyList,IN BOOLEAN Single)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
PeiNotifyPpi(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_NOTIFY_DESCRIPTOR * NotifyList)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
ProcessDispatchNotifyList(IN PEI_CORE_INSTANCE * PrivateData)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
ProcessNotify(IN PEI_CORE_INSTANCE * PrivateData,IN UINTN NotifyType,IN INTN InstallStartIndex,IN INTN InstallStopIndex,IN INTN NotifyStartIndex,IN INTN NotifyStopIndex)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
ProcessPpiListFromSec(IN CONST EFI_PEI_SERVICES ** PeiServices,IN CONST EFI_PEI_PPI_DESCRIPTOR * PpiList)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 
833