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