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