]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Ppi/Ppi.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Ppi / Ppi.c
1 /** @file
2 EFI PEI Core PPI services
3
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PeiMain.h"
10
11 /**
12
13 Migrate Pointer from the temporary memory to PEI installed memory.
14
15 @param Pointer Pointer to the Pointer needs to be converted.
16 @param TempBottom Base of old temporary memory
17 @param TempTop Top of old temporary memory
18 @param Offset Offset of new memory to old temporary memory.
19 @param OffsetPositive Positive flag of Offset value.
20
21 **/
22 VOID
23 ConvertPointer (
24 IN OUT VOID **Pointer,
25 IN UINTN TempBottom,
26 IN UINTN TempTop,
27 IN UINTN Offset,
28 IN BOOLEAN OffsetPositive
29 )
30 {
31 if (((UINTN)*Pointer < TempTop) &&
32 ((UINTN)*Pointer >= TempBottom))
33 {
34 if (OffsetPositive) {
35 *Pointer = (VOID *)((UINTN)*Pointer + Offset);
36 } else {
37 *Pointer = (VOID *)((UINTN)*Pointer - Offset);
38 }
39 }
40 }
41
42 /**
43
44 Migrate Pointer in ranges of the temporary memory to PEI installed memory.
45
46 @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
47 and location of temporary RAM, the stack location and the BFV location.
48 @param PrivateData Pointer to PeiCore's private data structure.
49 @param Pointer Pointer to the Pointer needs to be converted.
50
51 **/
52 VOID
53 ConvertPointerInRanges (
54 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
55 IN PEI_CORE_INSTANCE *PrivateData,
56 IN OUT VOID **Pointer
57 )
58 {
59 UINT8 IndexHole;
60
61 if (PrivateData->MemoryPages.Size != 0) {
62 //
63 // Convert PPI pointer in old memory pages
64 // It needs to be done before Convert PPI pointer in old Heap
65 //
66 ConvertPointer (
67 Pointer,
68 (UINTN)PrivateData->MemoryPages.Base,
69 (UINTN)PrivateData->MemoryPages.Base + PrivateData->MemoryPages.Size,
70 PrivateData->MemoryPages.Offset,
71 PrivateData->MemoryPages.OffsetPositive
72 );
73 }
74
75 //
76 // Convert PPI pointer in old Heap
77 //
78 ConvertPointer (
79 Pointer,
80 (UINTN)SecCoreData->PeiTemporaryRamBase,
81 (UINTN)SecCoreData->PeiTemporaryRamBase + SecCoreData->PeiTemporaryRamSize,
82 PrivateData->HeapOffset,
83 PrivateData->HeapOffsetPositive
84 );
85
86 //
87 // Convert PPI pointer in old Stack
88 //
89 ConvertPointer (
90 Pointer,
91 (UINTN)SecCoreData->StackBase,
92 (UINTN)SecCoreData->StackBase + SecCoreData->StackSize,
93 PrivateData->StackOffset,
94 PrivateData->StackOffsetPositive
95 );
96
97 //
98 // Convert PPI pointer in old TempRam Hole
99 //
100 for (IndexHole = 0; IndexHole < HOLE_MAX_NUMBER; IndexHole++) {
101 if (PrivateData->HoleData[IndexHole].Size == 0) {
102 continue;
103 }
104
105 ConvertPointer (
106 Pointer,
107 (UINTN)PrivateData->HoleData[IndexHole].Base,
108 (UINTN)PrivateData->HoleData[IndexHole].Base + PrivateData->HoleData[IndexHole].Size,
109 PrivateData->HoleData[IndexHole].Offset,
110 PrivateData->HoleData[IndexHole].OffsetPositive
111 );
112 }
113 }
114
115 /**
116
117 Migrate Single PPI Pointer from the temporary memory to PEI installed memory.
118
119 @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
120 and location of temporary RAM, the stack location and the BFV location.
121 @param PrivateData Pointer to PeiCore's private data structure.
122 @param PpiPointer Pointer to Ppi
123
124 **/
125 VOID
126 ConvertSinglePpiPointer (
127 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
128 IN PEI_CORE_INSTANCE *PrivateData,
129 IN PEI_PPI_LIST_POINTERS *PpiPointer
130 )
131 {
132 //
133 // 1. Convert the pointer to the PPI descriptor from the old TempRam
134 // to the relocated physical memory.
135 // It (for the pointer to the PPI descriptor) needs to be done before 2 (for
136 // the pointer to the GUID) and 3 (for the pointer to the PPI interface structure).
137 //
138 ConvertPointerInRanges (SecCoreData, PrivateData, &PpiPointer->Raw);
139 //
140 // 2. Convert the pointer to the GUID in the PPI or NOTIFY descriptor
141 // from the old TempRam to the relocated physical memory.
142 //
143 ConvertPointerInRanges (SecCoreData, PrivateData, (VOID **)&PpiPointer->Ppi->Guid);
144 //
145 // 3. Convert the pointer to the PPI interface structure in the PPI descriptor
146 // from the old TempRam to the relocated physical memory.
147 //
148 ConvertPointerInRanges (SecCoreData, PrivateData, (VOID **)&PpiPointer->Ppi->Ppi);
149 }
150
151 /**
152
153 Migrate PPI Pointers from the temporary memory to PEI installed memory.
154
155 @param SecCoreData Points to a data structure containing SEC to PEI handoff data, such as the size
156 and location of temporary RAM, the stack location and the BFV location.
157 @param PrivateData Pointer to PeiCore's private data structure.
158
159 **/
160 VOID
161 ConvertPpiPointers (
162 IN CONST EFI_SEC_PEI_HAND_OFF *SecCoreData,
163 IN PEI_CORE_INSTANCE *PrivateData
164 )
165 {
166 UINT8 Index;
167
168 //
169 // Convert normal PPIs.
170 //
171 for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
172 ConvertSinglePpiPointer (
173 SecCoreData,
174 PrivateData,
175 &PrivateData->PpiData.PpiList.PpiPtrs[Index]
176 );
177 }
178
179 //
180 // Convert Callback Notification PPIs.
181 //
182 for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
183 ConvertSinglePpiPointer (
184 SecCoreData,
185 PrivateData,
186 &PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index]
187 );
188 }
189
190 //
191 // Convert Dispatch Notification PPIs.
192 //
193 for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
194 ConvertSinglePpiPointer (
195 SecCoreData,
196 PrivateData,
197 &PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index]
198 );
199 }
200 }
201
202 /**
203
204 Migrate Notify Pointers inside an FV from temporary memory to permanent memory.
205
206 @param PrivateData Pointer to PeiCore's private data structure.
207 @param OrgFvHandle Address of FV Handle in temporary memory.
208 @param FvHandle Address of FV Handle in permanent memory.
209 @param FvSize Size of the FV.
210
211 **/
212 VOID
213 ConvertPpiPointersFv (
214 IN PEI_CORE_INSTANCE *PrivateData,
215 IN UINTN OrgFvHandle,
216 IN UINTN FvHandle,
217 IN UINTN FvSize
218 )
219 {
220 UINT8 Index;
221 UINTN Offset;
222 BOOLEAN OffsetPositive;
223 EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *FvInfoPpi;
224 UINT8 GuidIndex;
225 EFI_GUID *Guid;
226 EFI_GUID *GuidCheckList[2];
227
228 GuidCheckList[0] = &gEfiPeiFirmwareVolumeInfoPpiGuid;
229 GuidCheckList[1] = &gEfiPeiFirmwareVolumeInfo2PpiGuid;
230
231 if (FvHandle > OrgFvHandle) {
232 OffsetPositive = TRUE;
233 Offset = FvHandle - OrgFvHandle;
234 } else {
235 OffsetPositive = FALSE;
236 Offset = OrgFvHandle - FvHandle;
237 }
238
239 DEBUG ((DEBUG_VERBOSE, "Converting PPI pointers in FV.\n"));
240 DEBUG ((
241 DEBUG_VERBOSE,
242 " OrgFvHandle at 0x%08x. FvHandle at 0x%08x. FvSize = 0x%x\n",
243 (UINTN)OrgFvHandle,
244 (UINTN)FvHandle,
245 FvSize
246 ));
247 DEBUG ((
248 DEBUG_VERBOSE,
249 " OrgFvHandle range: 0x%08x - 0x%08x\n",
250 OrgFvHandle,
251 OrgFvHandle + FvSize
252 ));
253
254 for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
255 ConvertPointer (
256 (VOID **)&PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw,
257 OrgFvHandle,
258 OrgFvHandle + FvSize,
259 Offset,
260 OffsetPositive
261 );
262 ConvertPointer (
263 (VOID **)&PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Guid,
264 OrgFvHandle,
265 OrgFvHandle + FvSize,
266 Offset,
267 OffsetPositive
268 );
269 ConvertPointer (
270 (VOID **)&PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Notify,
271 OrgFvHandle,
272 OrgFvHandle + FvSize,
273 Offset,
274 OffsetPositive
275 );
276 }
277
278 for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
279 ConvertPointer (
280 (VOID **)&PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw,
281 OrgFvHandle,
282 OrgFvHandle + FvSize,
283 Offset,
284 OffsetPositive
285 );
286 ConvertPointer (
287 (VOID **)&PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Guid,
288 OrgFvHandle,
289 OrgFvHandle + FvSize,
290 Offset,
291 OffsetPositive
292 );
293 ConvertPointer (
294 (VOID **)&PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Notify,
295 OrgFvHandle,
296 OrgFvHandle + FvSize,
297 Offset,
298 OffsetPositive
299 );
300 }
301
302 for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
303 ConvertPointer (
304 (VOID **)&PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw,
305 OrgFvHandle,
306 OrgFvHandle + FvSize,
307 Offset,
308 OffsetPositive
309 );
310 ConvertPointer (
311 (VOID **)&PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid,
312 OrgFvHandle,
313 OrgFvHandle + FvSize,
314 Offset,
315 OffsetPositive
316 );
317 ConvertPointer (
318 (VOID **)&PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Ppi,
319 OrgFvHandle,
320 OrgFvHandle + FvSize,
321 Offset,
322 OffsetPositive
323 );
324
325 Guid = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid;
326 for (GuidIndex = 0; GuidIndex < ARRAY_SIZE (GuidCheckList); ++GuidIndex) {
327 //
328 // Don't use CompareGuid function here for performance reasons.
329 // Instead we compare the GUID as INT32 at a time and branch
330 // on the first failed comparison.
331 //
332 if ((((INT32 *)Guid)[0] == ((INT32 *)GuidCheckList[GuidIndex])[0]) &&
333 (((INT32 *)Guid)[1] == ((INT32 *)GuidCheckList[GuidIndex])[1]) &&
334 (((INT32 *)Guid)[2] == ((INT32 *)GuidCheckList[GuidIndex])[2]) &&
335 (((INT32 *)Guid)[3] == ((INT32 *)GuidCheckList[GuidIndex])[3]))
336 {
337 FvInfoPpi = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Ppi;
338 DEBUG ((DEBUG_VERBOSE, " FvInfo: %p -> ", FvInfoPpi->FvInfo));
339 if ((UINTN)FvInfoPpi->FvInfo == OrgFvHandle) {
340 ConvertPointer (
341 (VOID **)&FvInfoPpi->FvInfo,
342 OrgFvHandle,
343 OrgFvHandle + FvSize,
344 Offset,
345 OffsetPositive
346 );
347 DEBUG ((DEBUG_VERBOSE, "%p", FvInfoPpi->FvInfo));
348 }
349
350 DEBUG ((DEBUG_VERBOSE, "\n"));
351 break;
352 }
353 }
354 }
355 }
356
357 /**
358
359 Dumps the PPI lists to debug output.
360
361 @param PrivateData Points to PeiCore's private instance data.
362
363 **/
364 VOID
365 DumpPpiList (
366 IN PEI_CORE_INSTANCE *PrivateData
367 )
368 {
369 DEBUG_CODE_BEGIN ();
370 UINTN Index;
371
372 if (PrivateData == NULL) {
373 return;
374 }
375
376 for (Index = 0; Index < PrivateData->PpiData.CallbackNotifyList.CurrentCount; Index++) {
377 DEBUG ((
378 DEBUG_VERBOSE,
379 "CallbackNotify[%2d] {%g} at 0x%x (%a)\n",
380 Index,
381 PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Notify->Guid,
382 (UINTN)PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw,
383 (
384 !(
385 ((EFI_PHYSICAL_ADDRESS)(UINTN)PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw >= PrivateData->PhysicalMemoryBegin) &&
386 (((EFI_PHYSICAL_ADDRESS)((UINTN)PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index].Raw) + sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
387 )
388 ? "CAR" : "Post-Memory"
389 )
390 ));
391 }
392
393 for (Index = 0; Index < PrivateData->PpiData.DispatchNotifyList.CurrentCount; Index++) {
394 DEBUG ((
395 DEBUG_VERBOSE,
396 "DispatchNotify[%2d] {%g} at 0x%x (%a)\n",
397 Index,
398 PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Notify->Guid,
399 (UINTN)PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw,
400 (
401 !(
402 ((EFI_PHYSICAL_ADDRESS)(UINTN)PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw >= PrivateData->PhysicalMemoryBegin) &&
403 (((EFI_PHYSICAL_ADDRESS)((UINTN)PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index].Raw) + sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
404 )
405 ? "CAR" : "Post-Memory"
406 )
407 ));
408 }
409
410 for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
411 DEBUG ((
412 DEBUG_VERBOSE,
413 "PPI[%2d] {%g} at 0x%x (%a)\n",
414 Index,
415 PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi->Guid,
416 (UINTN)PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw,
417 (
418 !(
419 ((EFI_PHYSICAL_ADDRESS)(UINTN)PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw >= PrivateData->PhysicalMemoryBegin) &&
420 (((EFI_PHYSICAL_ADDRESS)((UINTN)PrivateData->PpiData.PpiList.PpiPtrs[Index].Raw) + sizeof (EFI_PEI_PPI_DESCRIPTOR)) < PrivateData->FreePhysicalMemoryTop)
421 )
422 ? "CAR" : "Post-Memory"
423 )
424 ));
425 }
426
427 DEBUG_CODE_END ();
428 }
429
430 /**
431
432 This function installs an interface in the PEI PPI database by GUID.
433 The purpose of the service is to publish an interface that other parties
434 can use to call additional PEIMs.
435
436 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
437 @param PpiList Pointer to a list of PEI PPI Descriptors.
438 @param Single TRUE if only single entry in the PpiList.
439 FALSE if the PpiList is ended with an entry which has the
440 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
441
442 @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
443 @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
444 if any PPI in PpiList is not valid
445 @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
446
447 **/
448 EFI_STATUS
449 InternalPeiInstallPpi (
450 IN CONST EFI_PEI_SERVICES **PeiServices,
451 IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList,
452 IN BOOLEAN Single
453 )
454 {
455 PEI_CORE_INSTANCE *PrivateData;
456 PEI_PPI_LIST *PpiListPointer;
457 UINTN Index;
458 UINTN LastCount;
459 VOID *TempPtr;
460
461 if (PpiList == NULL) {
462 return EFI_INVALID_PARAMETER;
463 }
464
465 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
466
467 PpiListPointer = &PrivateData->PpiData.PpiList;
468 Index = PpiListPointer->CurrentCount;
469 LastCount = Index;
470
471 //
472 // This is loop installs all PPI descriptors in the PpiList. It is terminated
473 // by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
474 // EFI_PEI_PPI_DESCRIPTOR in the list.
475 //
476
477 for ( ; ;) {
478 //
479 // Check if it is a valid PPI.
480 // If not, rollback list to exclude all in this list.
481 // Try to indicate which item failed.
482 //
483 if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
484 PpiListPointer->CurrentCount = LastCount;
485 DEBUG ((DEBUG_ERROR, "ERROR -> InstallPpi: %g %p\n", PpiList->Guid, PpiList->Ppi));
486 return EFI_INVALID_PARAMETER;
487 }
488
489 if (Index >= PpiListPointer->MaxCount) {
490 //
491 // Run out of room, grow the buffer.
492 //
493 TempPtr = AllocateZeroPool (
494 sizeof (PEI_PPI_LIST_POINTERS) * (PpiListPointer->MaxCount + PPI_GROWTH_STEP)
495 );
496 ASSERT (TempPtr != NULL);
497 CopyMem (
498 TempPtr,
499 PpiListPointer->PpiPtrs,
500 sizeof (PEI_PPI_LIST_POINTERS) * PpiListPointer->MaxCount
501 );
502 PpiListPointer->PpiPtrs = TempPtr;
503 PpiListPointer->MaxCount = PpiListPointer->MaxCount + PPI_GROWTH_STEP;
504 }
505
506 DEBUG ((DEBUG_INFO, "Install PPI: %g\n", PpiList->Guid));
507 PpiListPointer->PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *)PpiList;
508 Index++;
509 PpiListPointer->CurrentCount++;
510
511 if (Single) {
512 //
513 // Only single entry in the PpiList.
514 //
515 break;
516 } else if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
517 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
518 {
519 //
520 // Continue until the end of the PPI List.
521 //
522 break;
523 }
524
525 //
526 // Go to the next descriptor.
527 //
528 PpiList++;
529 }
530
531 //
532 // Process any callback level notifies for newly installed PPIs.
533 //
534 ProcessNotify (
535 PrivateData,
536 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
537 LastCount,
538 PpiListPointer->CurrentCount,
539 0,
540 PrivateData->PpiData.CallbackNotifyList.CurrentCount
541 );
542
543 return EFI_SUCCESS;
544 }
545
546 /**
547
548 This function installs an interface in the PEI PPI database by GUID.
549 The purpose of the service is to publish an interface that other parties
550 can use to call additional PEIMs.
551
552 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
553 @param PpiList Pointer to a list of PEI PPI Descriptors.
554
555 @retval EFI_SUCCESS if all PPIs in PpiList are successfully installed.
556 @retval EFI_INVALID_PARAMETER if PpiList is NULL pointer
557 if any PPI in PpiList is not valid
558 @retval EFI_OUT_OF_RESOURCES if there is no more memory resource to install PPI
559
560 **/
561 EFI_STATUS
562 EFIAPI
563 PeiInstallPpi (
564 IN CONST EFI_PEI_SERVICES **PeiServices,
565 IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
566 )
567 {
568 return InternalPeiInstallPpi (PeiServices, PpiList, FALSE);
569 }
570
571 /**
572
573 This function reinstalls an interface in the PEI PPI database by GUID.
574 The purpose of the service is to publish an interface that other parties can
575 use to replace an interface of the same name in the protocol database with a
576 different interface.
577
578 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
579 @param OldPpi Pointer to the old PEI PPI Descriptors.
580 @param NewPpi Pointer to the new PEI PPI Descriptors.
581
582 @retval EFI_SUCCESS if the operation was successful
583 @retval EFI_INVALID_PARAMETER if OldPpi or NewPpi is NULL
584 @retval EFI_INVALID_PARAMETER if NewPpi is not valid
585 @retval EFI_NOT_FOUND if the PPI was not in the database
586
587 **/
588 EFI_STATUS
589 EFIAPI
590 PeiReInstallPpi (
591 IN CONST EFI_PEI_SERVICES **PeiServices,
592 IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi,
593 IN CONST EFI_PEI_PPI_DESCRIPTOR *NewPpi
594 )
595 {
596 PEI_CORE_INSTANCE *PrivateData;
597 UINTN Index;
598
599 if ((OldPpi == NULL) || (NewPpi == NULL)) {
600 return EFI_INVALID_PARAMETER;
601 }
602
603 if ((NewPpi->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
604 return EFI_INVALID_PARAMETER;
605 }
606
607 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
608
609 //
610 // Find the old PPI instance in the database. If we can not find it,
611 // return the EFI_NOT_FOUND error.
612 //
613 for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
614 if (OldPpi == PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi) {
615 break;
616 }
617 }
618
619 if (Index == PrivateData->PpiData.PpiList.CurrentCount) {
620 return EFI_NOT_FOUND;
621 }
622
623 //
624 // Replace the old PPI with the new one.
625 //
626 DEBUG ((DEBUG_INFO, "Reinstall PPI: %g\n", NewPpi->Guid));
627 PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *)NewPpi;
628
629 //
630 // Process any callback level notifies for the newly installed PPI.
631 //
632 ProcessNotify (
633 PrivateData,
634 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
635 Index,
636 Index+1,
637 0,
638 PrivateData->PpiData.CallbackNotifyList.CurrentCount
639 );
640
641 return EFI_SUCCESS;
642 }
643
644 /**
645
646 Locate a given named PPI.
647
648
649 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
650 @param Guid Pointer to GUID of the PPI.
651 @param Instance Instance Number to discover.
652 @param PpiDescriptor Pointer to reference the found descriptor. If not NULL,
653 returns a pointer to the descriptor (includes flags, etc)
654 @param Ppi Pointer to reference the found PPI
655
656 @retval EFI_SUCCESS if the PPI is in the database
657 @retval EFI_NOT_FOUND if the PPI is not in the database
658
659 **/
660 EFI_STATUS
661 EFIAPI
662 PeiLocatePpi (
663 IN CONST EFI_PEI_SERVICES **PeiServices,
664 IN CONST EFI_GUID *Guid,
665 IN UINTN Instance,
666 IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
667 IN OUT VOID **Ppi
668 )
669 {
670 PEI_CORE_INSTANCE *PrivateData;
671 UINTN Index;
672 EFI_GUID *CheckGuid;
673 EFI_PEI_PPI_DESCRIPTOR *TempPtr;
674
675 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
676
677 //
678 // Search the data base for the matching instance of the GUIDed PPI.
679 //
680 for (Index = 0; Index < PrivateData->PpiData.PpiList.CurrentCount; Index++) {
681 TempPtr = PrivateData->PpiData.PpiList.PpiPtrs[Index].Ppi;
682 CheckGuid = TempPtr->Guid;
683
684 //
685 // Don't use CompareGuid function here for performance reasons.
686 // Instead we compare the GUID as INT32 at a time and branch
687 // on the first failed comparison.
688 //
689 if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
690 (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
691 (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
692 (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3]))
693 {
694 if (Instance == 0) {
695 if (PpiDescriptor != NULL) {
696 *PpiDescriptor = TempPtr;
697 }
698
699 if (Ppi != NULL) {
700 *Ppi = TempPtr->Ppi;
701 }
702
703 return EFI_SUCCESS;
704 }
705
706 Instance--;
707 }
708 }
709
710 return EFI_NOT_FOUND;
711 }
712
713 /**
714
715 This function installs a notification service to be called back when a given
716 interface is installed or reinstalled. The purpose of the service is to publish
717 an interface that other parties can use to call additional PPIs that may materialize later.
718
719 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
720 @param NotifyList Pointer to list of Descriptors to notify upon.
721 @param Single TRUE if only single entry in the NotifyList.
722 FALSE if the NotifyList is ended with an entry which has the
723 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST flag set in its Flags field.
724
725 @retval EFI_SUCCESS if successful
726 @retval EFI_OUT_OF_RESOURCES if no space in the database
727 @retval EFI_INVALID_PARAMETER if not a good descriptor
728
729 **/
730 EFI_STATUS
731 InternalPeiNotifyPpi (
732 IN CONST EFI_PEI_SERVICES **PeiServices,
733 IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList,
734 IN BOOLEAN Single
735 )
736 {
737 PEI_CORE_INSTANCE *PrivateData;
738 PEI_CALLBACK_NOTIFY_LIST *CallbackNotifyListPointer;
739 UINTN CallbackNotifyIndex;
740 UINTN LastCallbackNotifyCount;
741 PEI_DISPATCH_NOTIFY_LIST *DispatchNotifyListPointer;
742 UINTN DispatchNotifyIndex;
743 UINTN LastDispatchNotifyCount;
744 VOID *TempPtr;
745
746 if (NotifyList == NULL) {
747 return EFI_INVALID_PARAMETER;
748 }
749
750 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS (PeiServices);
751
752 CallbackNotifyListPointer = &PrivateData->PpiData.CallbackNotifyList;
753 CallbackNotifyIndex = CallbackNotifyListPointer->CurrentCount;
754 LastCallbackNotifyCount = CallbackNotifyIndex;
755
756 DispatchNotifyListPointer = &PrivateData->PpiData.DispatchNotifyList;
757 DispatchNotifyIndex = DispatchNotifyListPointer->CurrentCount;
758 LastDispatchNotifyCount = DispatchNotifyIndex;
759
760 //
761 // This is loop installs all Notify descriptors in the NotifyList. It is
762 // terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
763 // EFI_PEI_NOTIFY_DESCRIPTOR in the list.
764 //
765
766 for ( ; ;) {
767 //
768 // If some of the PPI data is invalid restore original Notify PPI database value
769 //
770 if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
771 CallbackNotifyListPointer->CurrentCount = LastCallbackNotifyCount;
772 DispatchNotifyListPointer->CurrentCount = LastDispatchNotifyCount;
773 DEBUG ((DEBUG_ERROR, "ERROR -> NotifyPpi: %g %p\n", NotifyList->Guid, NotifyList->Notify));
774 return EFI_INVALID_PARAMETER;
775 }
776
777 if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) != 0) {
778 if (CallbackNotifyIndex >= CallbackNotifyListPointer->MaxCount) {
779 //
780 // Run out of room, grow the buffer.
781 //
782 TempPtr = AllocateZeroPool (
783 sizeof (PEI_PPI_LIST_POINTERS) * (CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP)
784 );
785 ASSERT (TempPtr != NULL);
786 CopyMem (
787 TempPtr,
788 CallbackNotifyListPointer->NotifyPtrs,
789 sizeof (PEI_PPI_LIST_POINTERS) * CallbackNotifyListPointer->MaxCount
790 );
791 CallbackNotifyListPointer->NotifyPtrs = TempPtr;
792 CallbackNotifyListPointer->MaxCount = CallbackNotifyListPointer->MaxCount + CALLBACK_NOTIFY_GROWTH_STEP;
793 }
794
795 CallbackNotifyListPointer->NotifyPtrs[CallbackNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *)NotifyList;
796 CallbackNotifyIndex++;
797 CallbackNotifyListPointer->CurrentCount++;
798 } else {
799 if (DispatchNotifyIndex >= DispatchNotifyListPointer->MaxCount) {
800 //
801 // Run out of room, grow the buffer.
802 //
803 TempPtr = AllocateZeroPool (
804 sizeof (PEI_PPI_LIST_POINTERS) * (DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP)
805 );
806 ASSERT (TempPtr != NULL);
807 CopyMem (
808 TempPtr,
809 DispatchNotifyListPointer->NotifyPtrs,
810 sizeof (PEI_PPI_LIST_POINTERS) * DispatchNotifyListPointer->MaxCount
811 );
812 DispatchNotifyListPointer->NotifyPtrs = TempPtr;
813 DispatchNotifyListPointer->MaxCount = DispatchNotifyListPointer->MaxCount + DISPATCH_NOTIFY_GROWTH_STEP;
814 }
815
816 DispatchNotifyListPointer->NotifyPtrs[DispatchNotifyIndex].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *)NotifyList;
817 DispatchNotifyIndex++;
818 DispatchNotifyListPointer->CurrentCount++;
819 }
820
821 DEBUG ((DEBUG_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
822
823 if (Single) {
824 //
825 // Only single entry in the NotifyList.
826 //
827 break;
828 } else if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
829 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)
830 {
831 //
832 // Continue until the end of the Notify List.
833 //
834 break;
835 }
836
837 //
838 // Go to the next descriptor.
839 //
840 NotifyList++;
841 }
842
843 //
844 // Process any callback level notifies for all previously installed PPIs.
845 //
846 ProcessNotify (
847 PrivateData,
848 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
849 0,
850 PrivateData->PpiData.PpiList.CurrentCount,
851 LastCallbackNotifyCount,
852 CallbackNotifyListPointer->CurrentCount
853 );
854
855 return EFI_SUCCESS;
856 }
857
858 /**
859
860 This function installs a notification service to be called back when a given
861 interface is installed or reinstalled. The purpose of the service is to publish
862 an interface that other parties can use to call additional PPIs that may materialize later.
863
864 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
865 @param NotifyList Pointer to list of Descriptors to notify upon.
866
867 @retval EFI_SUCCESS if successful
868 @retval EFI_OUT_OF_RESOURCES if no space in the database
869 @retval EFI_INVALID_PARAMETER if not a good descriptor
870
871 **/
872 EFI_STATUS
873 EFIAPI
874 PeiNotifyPpi (
875 IN CONST EFI_PEI_SERVICES **PeiServices,
876 IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
877 )
878 {
879 return InternalPeiNotifyPpi (PeiServices, NotifyList, FALSE);
880 }
881
882 /**
883
884 Process the Notify List at dispatch level.
885
886 @param PrivateData PeiCore's private data structure.
887
888 **/
889 VOID
890 ProcessDispatchNotifyList (
891 IN PEI_CORE_INSTANCE *PrivateData
892 )
893 {
894 UINTN TempValue;
895
896 while (TRUE) {
897 //
898 // Check if the PEIM that was just dispatched resulted in any
899 // Notifies getting installed. If so, go process any dispatch
900 // level Notifies that match the previously installed PPIs.
901 // Use "while" instead of "if" since ProcessNotify can modify
902 // DispatchNotifyList.CurrentCount (with NotifyPpi) so we have
903 // to iterate until the same.
904 //
905 while (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount != PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
906 TempValue = PrivateData->PpiData.DispatchNotifyList.CurrentCount;
907 ProcessNotify (
908 PrivateData,
909 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
910 0,
911 PrivateData->PpiData.PpiList.LastDispatchedCount,
912 PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount,
913 PrivateData->PpiData.DispatchNotifyList.CurrentCount
914 );
915 PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount = TempValue;
916 }
917
918 //
919 // Check if the PEIM that was just dispatched resulted in any
920 // PPIs getting installed. If so, go process any dispatch
921 // level Notifies that match the installed PPIs.
922 // Use "while" instead of "if" since ProcessNotify can modify
923 // PpiList.CurrentCount (with InstallPpi) so we have to iterate
924 // until the same.
925 //
926 while (PrivateData->PpiData.PpiList.LastDispatchedCount != PrivateData->PpiData.PpiList.CurrentCount) {
927 TempValue = PrivateData->PpiData.PpiList.CurrentCount;
928 ProcessNotify (
929 PrivateData,
930 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
931 PrivateData->PpiData.PpiList.LastDispatchedCount,
932 PrivateData->PpiData.PpiList.CurrentCount,
933 0,
934 PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount
935 );
936 PrivateData->PpiData.PpiList.LastDispatchedCount = TempValue;
937 }
938
939 if (PrivateData->PpiData.DispatchNotifyList.LastDispatchedCount == PrivateData->PpiData.DispatchNotifyList.CurrentCount) {
940 break;
941 }
942 }
943
944 return;
945 }
946
947 /**
948
949 Process notifications.
950
951 @param PrivateData PeiCore's private data structure
952 @param NotifyType Type of notify to fire.
953 @param InstallStartIndex Install Beginning index.
954 @param InstallStopIndex Install Ending index.
955 @param NotifyStartIndex Notify Beginning index.
956 @param NotifyStopIndex Notify Ending index.
957
958 **/
959 VOID
960 ProcessNotify (
961 IN PEI_CORE_INSTANCE *PrivateData,
962 IN UINTN NotifyType,
963 IN INTN InstallStartIndex,
964 IN INTN InstallStopIndex,
965 IN INTN NotifyStartIndex,
966 IN INTN NotifyStopIndex
967 )
968 {
969 INTN Index1;
970 INTN Index2;
971 EFI_GUID *SearchGuid;
972 EFI_GUID *CheckGuid;
973 EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
974
975 for (Index1 = NotifyStartIndex; Index1 < NotifyStopIndex; Index1++) {
976 if (NotifyType == EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK) {
977 NotifyDescriptor = PrivateData->PpiData.CallbackNotifyList.NotifyPtrs[Index1].Notify;
978 } else {
979 NotifyDescriptor = PrivateData->PpiData.DispatchNotifyList.NotifyPtrs[Index1].Notify;
980 }
981
982 CheckGuid = NotifyDescriptor->Guid;
983
984 for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
985 SearchGuid = PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi->Guid;
986 //
987 // Don't use CompareGuid function here for performance reasons.
988 // Instead we compare the GUID as INT32 at a time and branch
989 // on the first failed comparison.
990 //
991 if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
992 (((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
993 (((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
994 (((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3]))
995 {
996 DEBUG ((
997 DEBUG_INFO,
998 "Notify: PPI Guid: %g, Peim notify entry point: %p\n",
999 SearchGuid,
1000 NotifyDescriptor->Notify
1001 ));
1002 NotifyDescriptor->Notify (
1003 (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
1004 NotifyDescriptor,
1005 (PrivateData->PpiData.PpiList.PpiPtrs[Index2].Ppi)->Ppi
1006 );
1007 }
1008 }
1009 }
1010 }
1011
1012 /**
1013 Process PpiList from SEC phase.
1014
1015 @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
1016 @param PpiList Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
1017 These PPI's will be installed and/or immediately signaled if they are notification type.
1018
1019 **/
1020 VOID
1021 ProcessPpiListFromSec (
1022 IN CONST EFI_PEI_SERVICES **PeiServices,
1023 IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
1024 )
1025 {
1026 EFI_STATUS Status;
1027 EFI_SEC_HOB_DATA_PPI *SecHobDataPpi;
1028 EFI_HOB_GENERIC_HEADER *SecHobList;
1029
1030 for ( ; ;) {
1031 if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) != 0) {
1032 //
1033 // It is a notification PPI.
1034 //
1035 Status = InternalPeiNotifyPpi (PeiServices, (CONST EFI_PEI_NOTIFY_DESCRIPTOR *)PpiList, TRUE);
1036 ASSERT_EFI_ERROR (Status);
1037 } else {
1038 //
1039 // It is a normal PPI.
1040 //
1041 Status = InternalPeiInstallPpi (PeiServices, PpiList, TRUE);
1042 ASSERT_EFI_ERROR (Status);
1043 }
1044
1045 if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) == EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
1046 //
1047 // Continue until the end of the PPI List.
1048 //
1049 break;
1050 }
1051
1052 PpiList++;
1053 }
1054
1055 //
1056 // If the EFI_SEC_HOB_DATA_PPI is in the list of PPIs passed to the PEI entry point,
1057 // the PEI Foundation will call the GetHobs() member function and install all HOBs
1058 // returned into the HOB list. It does this after installing all PPIs passed from SEC
1059 // into the PPI database and before dispatching any PEIMs.
1060 //
1061 Status = PeiLocatePpi (PeiServices, &gEfiSecHobDataPpiGuid, 0, NULL, (VOID **)&SecHobDataPpi);
1062 if (!EFI_ERROR (Status)) {
1063 Status = SecHobDataPpi->GetHobs (SecHobDataPpi, &SecHobList);
1064 if (!EFI_ERROR (Status)) {
1065 Status = PeiInstallSecHobData (PeiServices, SecHobList);
1066 ASSERT_EFI_ERROR (Status);
1067 }
1068 }
1069 }
1070
1071 /**
1072
1073 Migrate PPI Pointers of PEI_CORE from temporary memory to permanent memory.
1074
1075 @param PrivateData Pointer to PeiCore's private data structure.
1076 @param CoreFvHandle Address of PEI_CORE FV Handle in temporary memory.
1077
1078 **/
1079 VOID
1080 ConvertPeiCorePpiPointers (
1081 IN PEI_CORE_INSTANCE *PrivateData,
1082 IN PEI_CORE_FV_HANDLE *CoreFvHandle
1083 )
1084 {
1085 EFI_FV_FILE_INFO FileInfo;
1086 EFI_PHYSICAL_ADDRESS OrgImageBase;
1087 EFI_PHYSICAL_ADDRESS MigratedImageBase;
1088 UINTN PeiCoreModuleSize;
1089 EFI_PEI_FILE_HANDLE PeiCoreFileHandle;
1090 VOID *PeiCoreImageBase;
1091 VOID *PeiCoreEntryPoint;
1092 EFI_STATUS Status;
1093
1094 PeiCoreFileHandle = NULL;
1095
1096 //
1097 // Find the PEI Core in the BFV in temporary memory.
1098 //
1099 Status = CoreFvHandle->FvPpi->FindFileByType (
1100 CoreFvHandle->FvPpi,
1101 EFI_FV_FILETYPE_PEI_CORE,
1102 CoreFvHandle->FvHandle,
1103 &PeiCoreFileHandle
1104 );
1105 ASSERT_EFI_ERROR (Status);
1106
1107 if (!EFI_ERROR (Status)) {
1108 Status = CoreFvHandle->FvPpi->GetFileInfo (CoreFvHandle->FvPpi, PeiCoreFileHandle, &FileInfo);
1109 ASSERT_EFI_ERROR (Status);
1110
1111 Status = PeiGetPe32Data (PeiCoreFileHandle, &PeiCoreImageBase);
1112 ASSERT_EFI_ERROR (Status);
1113
1114 //
1115 // Find PEI Core EntryPoint in the BFV in temporary memory.
1116 //
1117 Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)PeiCoreImageBase, &PeiCoreEntryPoint);
1118 ASSERT_EFI_ERROR (Status);
1119
1120 OrgImageBase = (UINTN)PeiCoreImageBase;
1121 MigratedImageBase = (UINTN)_ModuleEntryPoint - ((UINTN)PeiCoreEntryPoint - (UINTN)PeiCoreImageBase);
1122
1123 //
1124 // Size of loaded PEI_CORE in permanent memory.
1125 //
1126 PeiCoreModuleSize = (UINTN)FileInfo.BufferSize - ((UINTN)OrgImageBase - (UINTN)FileInfo.Buffer);
1127
1128 //
1129 // Migrate PEI_CORE PPI pointers from temporary memory to newly
1130 // installed PEI_CORE in permanent memory.
1131 //
1132 ConvertPpiPointersFv (PrivateData, (UINTN)OrgImageBase, (UINTN)MigratedImageBase, PeiCoreModuleSize);
1133 }
1134 }