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