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