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