]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Pei/Ppi/Ppi.c
Merge branch of PI tree to main trunk
[mirror_edk2.git] / MdeModulePkg / Core / Pei / Ppi / Ppi.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Ppi.c
15
16 Abstract:
17
18 EFI PEI Core PPI services
19
20 Revision History
21
22 --*/
23
24 #include <PeiMain.h>
25
26 VOID
27 InitializePpiServices (
28 IN PEI_CORE_INSTANCE *PrivateData,
29 IN PEI_CORE_INSTANCE *OldCoreData
30 )
31 /*++
32
33 Routine Description:
34
35 Initialize PPI services.
36
37 Arguments:
38
39 PeiServices - The PEI core services table.
40 OldCoreData - Pointer to the PEI Core data.
41 NULL if being run in non-permament memory mode.
42
43 Returns:
44 Nothing
45
46 --*/
47 {
48 if (OldCoreData == NULL) {
49 PrivateData->PpiData.NotifyListEnd = MAX_PPI_DESCRIPTORS-1;
50 PrivateData->PpiData.DispatchListEnd = MAX_PPI_DESCRIPTORS-1;
51 PrivateData->PpiData.LastDispatchedNotify = MAX_PPI_DESCRIPTORS-1;
52 }
53
54 return;
55 }
56
57 VOID
58 ConvertPpiPointers (
59 IN CONST EFI_PEI_SERVICES **PeiServices,
60 IN EFI_HOB_HANDOFF_INFO_TABLE *OldHandOffHob,
61 IN EFI_HOB_HANDOFF_INFO_TABLE *NewHandOffHob
62 )
63 /*++
64
65 Routine Description:
66
67 Migrate the Hob list from the CAR stack to PEI installed memory.
68
69 Arguments:
70
71 PeiServices - The PEI core services table.
72 OldHandOffHob - The old handoff HOB list.
73 NewHandOffHob - The new handoff HOB list.
74
75 Returns:
76
77 --*/
78 {
79 PEI_CORE_INSTANCE *PrivateData;
80 UINT8 Index;
81 PEI_PPI_LIST_POINTERS *PpiPointer;
82 UINTN Fixup;
83
84 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
85
86 Fixup = (UINTN)NewHandOffHob - (UINTN)OldHandOffHob;
87
88 for (Index = 0; Index < MAX_PPI_DESCRIPTORS; Index++) {
89 if (Index < PrivateData->PpiData.PpiListEnd ||
90 Index > PrivateData->PpiData.NotifyListEnd) {
91 PpiPointer = &PrivateData->PpiData.PpiListPtrs[Index];
92
93 if (((UINTN)PpiPointer->Raw < (UINTN)OldHandOffHob->EfiFreeMemoryBottom) &&
94 ((UINTN)PpiPointer->Raw >= (UINTN)OldHandOffHob)) {
95 //
96 // Convert the pointer to the PEIM descriptor from the old HOB heap
97 // to the relocated HOB heap.
98 //
99 PpiPointer->Raw = (VOID *) ((UINTN)PpiPointer->Raw + Fixup);
100
101 //
102 // Only when the PEIM descriptor is in the old HOB should it be necessary
103 // to try to convert the pointers in the PEIM descriptor
104 //
105
106 if (((UINTN)PpiPointer->Ppi->Guid < (UINTN)OldHandOffHob->EfiFreeMemoryBottom) &&
107 ((UINTN)PpiPointer->Ppi->Guid >= (UINTN)OldHandOffHob)) {
108 //
109 // Convert the pointer to the GUID in the PPI or NOTIFY descriptor
110 // from the old HOB heap to the relocated HOB heap.
111 //
112 PpiPointer->Ppi->Guid = (VOID *) ((UINTN)PpiPointer->Ppi->Guid + Fixup);
113 }
114
115 //
116 // Assume that no code is located in the temporary memory, so the pointer to
117 // the notification function in the NOTIFY descriptor needs not be converted.
118 //
119 if (Index < PrivateData->PpiData.PpiListEnd &&
120 (UINTN)PpiPointer->Ppi->Ppi < (UINTN)OldHandOffHob->EfiFreeMemoryBottom &&
121 (UINTN)PpiPointer->Ppi->Ppi >= (UINTN)OldHandOffHob) {
122 //
123 // Convert the pointer to the PPI interface structure in the PPI descriptor
124 // from the old HOB heap to the relocated HOB heap.
125 //
126 PpiPointer->Ppi->Ppi = (VOID *) ((UINTN)PpiPointer->Ppi->Ppi+ Fixup);
127 }
128 }
129 }
130 }
131 }
132
133
134
135 EFI_STATUS
136 EFIAPI
137 PeiInstallPpi (
138 IN CONST EFI_PEI_SERVICES **PeiServices,
139 IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList
140 )
141 /*++
142
143 Routine Description:
144
145 Install PPI services.
146
147 Arguments:
148
149 PeiServices - Pointer to the PEI Service Table
150 PpiList - Pointer to a list of PEI PPI Descriptors.
151
152 Returns:
153
154 EFI_SUCCESS - if all PPIs in PpiList are successfully installed.
155 EFI_INVALID_PARAMETER - if PpiList is NULL pointer
156 EFI_INVALID_PARAMETER - if any PPI in PpiList is not valid
157 EFI_OUT_OF_RESOURCES - if there is no more memory resource to install PPI
158
159 --*/
160 {
161 PEI_CORE_INSTANCE *PrivateData;
162 INTN Index;
163 INTN LastCallbackInstall;
164
165
166 if (PpiList == NULL) {
167 return EFI_INVALID_PARAMETER;
168 }
169
170 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
171
172 Index = PrivateData->PpiData.PpiListEnd;
173 LastCallbackInstall = Index;
174
175 //
176 // This is loop installs all PPI descriptors in the PpiList. It is terminated
177 // by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
178 // EFI_PEI_PPI_DESCRIPTOR in the list.
179 //
180
181 for (;;) {
182 //
183 // Since PpiData is used for NotifyList and InstallList, max resource
184 // is reached if the Install reaches the NotifyList
185 //
186 if (Index == PrivateData->PpiData.NotifyListEnd + 1) {
187 return EFI_OUT_OF_RESOURCES;
188 }
189 //
190 // Check if it is a valid PPI.
191 // If not, rollback list to exclude all in this list.
192 // Try to indicate which item failed.
193 //
194 if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
195 PrivateData->PpiData.PpiListEnd = LastCallbackInstall;
196 DEBUG((EFI_D_ERROR, "ERROR -> InstallPpi: %g %x\n", PpiList->Guid, PpiList->Ppi));
197 return EFI_INVALID_PARAMETER;
198 }
199
200 DEBUG((EFI_D_INFO, "Install PPI: %g\n", PpiList->Guid));
201 PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR*) PpiList;
202 PrivateData->PpiData.PpiListEnd++;
203
204 //
205 // Continue until the end of the PPI List.
206 //
207 if ((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
208 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
209 break;
210 }
211 PpiList++;
212 Index++;
213 }
214
215 //
216 // Dispatch any callback level notifies for newly installed PPIs.
217 //
218 DispatchNotify (
219 PrivateData,
220 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
221 LastCallbackInstall,
222 PrivateData->PpiData.PpiListEnd,
223 PrivateData->PpiData.DispatchListEnd,
224 PrivateData->PpiData.NotifyListEnd
225 );
226
227
228 return EFI_SUCCESS;
229 }
230
231
232 EFI_STATUS
233 EFIAPI
234 PeiReInstallPpi (
235 IN CONST EFI_PEI_SERVICES **PeiServices,
236 IN CONST EFI_PEI_PPI_DESCRIPTOR *OldPpi,
237 IN CONST EFI_PEI_PPI_DESCRIPTOR *NewPpi
238 )
239 /*++
240
241 Routine Description:
242
243 Re-Install PPI services.
244
245 Arguments:
246
247 PeiServices - Pointer to the PEI Service Table
248 OldPpi - Pointer to the old PEI PPI Descriptors.
249 NewPpi - Pointer to the new PEI PPI Descriptors.
250
251 Returns:
252
253 EFI_SUCCESS - if the operation was successful
254 EFI_INVALID_PARAMETER - if OldPpi or NewPpi is NULL
255 EFI_INVALID_PARAMETER - if NewPpi is not valid
256 EFI_NOT_FOUND - if the PPI was not in the database
257
258 --*/
259 {
260 PEI_CORE_INSTANCE *PrivateData;
261 INTN Index;
262
263
264 if ((OldPpi == NULL) || (NewPpi == NULL)) {
265 return EFI_INVALID_PARAMETER;
266 }
267
268 if ((NewPpi->Flags & EFI_PEI_PPI_DESCRIPTOR_PPI) == 0) {
269 return EFI_INVALID_PARAMETER;
270 }
271
272 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
273
274 //
275 // Find the old PPI instance in the database. If we can not find it,
276 // return the EFI_NOT_FOUND error.
277 //
278 for (Index = 0; Index < PrivateData->PpiData.PpiListEnd; Index++) {
279 if (OldPpi == PrivateData->PpiData.PpiListPtrs[Index].Ppi) {
280 break;
281 }
282 }
283 if (Index == PrivateData->PpiData.PpiListEnd) {
284 return EFI_NOT_FOUND;
285 }
286
287 //
288 // Remove the old PPI from the database, add the new one.
289 //
290 DEBUG((EFI_D_INFO, "Reinstall PPI: %g\n", NewPpi->Guid));
291 PrivateData->PpiData.PpiListPtrs[Index].Ppi = (EFI_PEI_PPI_DESCRIPTOR *) NewPpi;
292
293 //
294 // Dispatch any callback level notifies for the newly installed PPI.
295 //
296 DispatchNotify (
297 PrivateData,
298 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
299 Index,
300 Index+1,
301 PrivateData->PpiData.DispatchListEnd,
302 PrivateData->PpiData.NotifyListEnd
303 );
304
305
306 return EFI_SUCCESS;
307 }
308
309
310 EFI_STATUS
311 EFIAPI
312 PeiLocatePpi (
313 IN CONST EFI_PEI_SERVICES **PeiServices,
314 IN CONST EFI_GUID *Guid,
315 IN UINTN Instance,
316 IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
317 IN OUT VOID **Ppi
318 )
319 /*++
320
321 Routine Description:
322
323 Locate a given named PPI.
324
325 Arguments:
326
327 PeiServices - Pointer to the PEI Service Table
328 Guid - Pointer to GUID of the PPI.
329 Instance - Instance Number to discover.
330 PpiDescriptor - Pointer to reference the found descriptor. If not NULL,
331 returns a pointer to the descriptor (includes flags, etc)
332 Ppi - Pointer to reference the found PPI
333
334 Returns:
335
336 Status - EFI_SUCCESS if the PPI is in the database
337 EFI_NOT_FOUND if the PPI is not in the database
338 --*/
339 {
340 PEI_CORE_INSTANCE *PrivateData;
341 INTN Index;
342 EFI_GUID *CheckGuid;
343 EFI_PEI_PPI_DESCRIPTOR *TempPtr;
344
345
346 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
347
348 //
349 // Search the data base for the matching instance of the GUIDed PPI.
350 //
351 for (Index = 0; Index < PrivateData->PpiData.PpiListEnd; Index++) {
352 TempPtr = PrivateData->PpiData.PpiListPtrs[Index].Ppi;
353 CheckGuid = TempPtr->Guid;
354
355 //
356 // Don't use CompareGuid function here for performance reasons.
357 // Instead we compare the GUID as INT32 at a time and branch
358 // on the first failed comparison.
359 //
360 if ((((INT32 *)Guid)[0] == ((INT32 *)CheckGuid)[0]) &&
361 (((INT32 *)Guid)[1] == ((INT32 *)CheckGuid)[1]) &&
362 (((INT32 *)Guid)[2] == ((INT32 *)CheckGuid)[2]) &&
363 (((INT32 *)Guid)[3] == ((INT32 *)CheckGuid)[3])) {
364 if (Instance == 0) {
365
366 if (PpiDescriptor != NULL) {
367 *PpiDescriptor = TempPtr;
368 }
369
370 if (Ppi != NULL) {
371 *Ppi = TempPtr->Ppi;
372 }
373
374
375 return EFI_SUCCESS;
376 }
377 Instance--;
378 }
379 }
380
381 return EFI_NOT_FOUND;
382 }
383
384
385 EFI_STATUS
386 EFIAPI
387 PeiNotifyPpi (
388 IN CONST EFI_PEI_SERVICES **PeiServices,
389 IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList
390 )
391 /*++
392
393 Routine Description:
394
395 Install a notification for a given PPI.
396
397 Arguments:
398
399 PeiServices - Pointer to the PEI Service Table
400 NotifyList - Pointer to list of Descriptors to notify upon.
401
402 Returns:
403
404 Status - EFI_SUCCESS if successful
405 EFI_OUT_OF_RESOURCES if no space in the database
406 EFI_INVALID_PARAMETER if not a good decriptor
407
408 --*/
409 {
410 PEI_CORE_INSTANCE *PrivateData;
411 INTN Index;
412 INTN NotifyIndex;
413 INTN LastCallbackNotify;
414 EFI_PEI_NOTIFY_DESCRIPTOR *NotifyPtr;
415 UINTN NotifyDispatchCount;
416
417
418 NotifyDispatchCount = 0;
419
420 if (NotifyList == NULL) {
421 return EFI_INVALID_PARAMETER;
422 }
423
424 PrivateData = PEI_CORE_INSTANCE_FROM_PS_THIS(PeiServices);
425
426 Index = PrivateData->PpiData.NotifyListEnd;
427 LastCallbackNotify = Index;
428
429 //
430 // This is loop installs all Notify descriptors in the NotifyList. It is
431 // terminated by the EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST being set in the last
432 // EFI_PEI_NOTIFY_DESCRIPTOR in the list.
433 //
434
435 for (;;) {
436 //
437 // Since PpiData is used for NotifyList and InstallList, max resource
438 // is reached if the Install reaches the PpiList
439 //
440 if (Index == PrivateData->PpiData.PpiListEnd - 1) {
441 return EFI_OUT_OF_RESOURCES;
442 }
443
444 //
445 // If some of the PPI data is invalid restore original Notify PPI database value
446 //
447 if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_TYPES) == 0) {
448 PrivateData->PpiData.NotifyListEnd = LastCallbackNotify;
449 DEBUG((EFI_D_ERROR, "ERROR -> InstallNotify: %g %x\n", NotifyList->Guid, NotifyList->Notify));
450 return EFI_INVALID_PARAMETER;
451 }
452
453 if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
454 NotifyDispatchCount ++;
455 }
456
457 PrivateData->PpiData.PpiListPtrs[Index].Notify = (EFI_PEI_NOTIFY_DESCRIPTOR *) NotifyList;
458
459 PrivateData->PpiData.NotifyListEnd--;
460 DEBUG((EFI_D_INFO, "Register PPI Notify: %g\n", NotifyList->Guid));
461 if ((NotifyList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) ==
462 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) {
463 break;
464 }
465 //
466 // Go the next descriptor. Remember the NotifyList moves down.
467 //
468 NotifyList++;
469 Index--;
470 }
471
472 //
473 // If there is Dispatch Notify PPI installed put them on the bottom
474 //
475 if (NotifyDispatchCount > 0) {
476 for (NotifyIndex = LastCallbackNotify; NotifyIndex > PrivateData->PpiData.NotifyListEnd; NotifyIndex--) {
477 if ((PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify->Flags & EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH) != 0) {
478 NotifyPtr = PrivateData->PpiData.PpiListPtrs[NotifyIndex].Notify;
479
480 for (Index = NotifyIndex; Index < PrivateData->PpiData.DispatchListEnd; Index++){
481 PrivateData->PpiData.PpiListPtrs[Index].Notify = PrivateData->PpiData.PpiListPtrs[Index + 1].Notify;
482 }
483 PrivateData->PpiData.PpiListPtrs[Index].Notify = NotifyPtr;
484 PrivateData->PpiData.DispatchListEnd--;
485 }
486 }
487
488 LastCallbackNotify -= NotifyDispatchCount;
489 }
490
491 //
492 // Dispatch any callback level notifies for all previously installed PPIs.
493 //
494 DispatchNotify (
495 PrivateData,
496 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
497 0,
498 PrivateData->PpiData.PpiListEnd,
499 LastCallbackNotify,
500 PrivateData->PpiData.NotifyListEnd
501 );
502
503
504 return EFI_SUCCESS;
505 }
506
507
508 VOID
509 ProcessNotifyList (
510 IN PEI_CORE_INSTANCE *PrivateData
511 )
512 /*++
513
514 Routine Description:
515
516 Process the Notify List at dispatch level.
517
518 Arguments:
519
520 PeiServices - Pointer to the PEI Service Table
521
522 Returns:
523
524 --*/
525
526 {
527 INTN TempValue;
528
529 while (TRUE) {
530 //
531 // Check if the PEIM that was just dispatched resulted in any
532 // Notifies getting installed. If so, go process any dispatch
533 // level Notifies that match the previouly installed PPIs.
534 // Use "while" instead of "if" since DispatchNotify can modify
535 // DispatchListEnd (with NotifyPpi) so we have to iterate until the same.
536 //
537 while (PrivateData->PpiData.LastDispatchedNotify != PrivateData->PpiData.DispatchListEnd) {
538 TempValue = PrivateData->PpiData.DispatchListEnd;
539 DispatchNotify (
540 PrivateData,
541 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
542 0,
543 PrivateData->PpiData.LastDispatchedInstall,
544 PrivateData->PpiData.LastDispatchedNotify,
545 PrivateData->PpiData.DispatchListEnd
546 );
547 PrivateData->PpiData.LastDispatchedNotify = TempValue;
548 }
549
550
551 //
552 // Check if the PEIM that was just dispatched resulted in any
553 // PPIs getting installed. If so, go process any dispatch
554 // level Notifies that match the installed PPIs.
555 // Use "while" instead of "if" since DispatchNotify can modify
556 // PpiListEnd (with InstallPpi) so we have to iterate until the same.
557 //
558 while (PrivateData->PpiData.LastDispatchedInstall != PrivateData->PpiData.PpiListEnd) {
559 TempValue = PrivateData->PpiData.PpiListEnd;
560 DispatchNotify (
561 PrivateData,
562 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH,
563 PrivateData->PpiData.LastDispatchedInstall,
564 PrivateData->PpiData.PpiListEnd,
565 MAX_PPI_DESCRIPTORS-1,
566 PrivateData->PpiData.DispatchListEnd
567 );
568 PrivateData->PpiData.LastDispatchedInstall = TempValue;
569 }
570
571 if (PrivateData->PpiData.LastDispatchedNotify == PrivateData->PpiData.DispatchListEnd) {
572 break;
573 }
574 }
575 return;
576 }
577
578 VOID
579 DispatchNotify (
580 IN PEI_CORE_INSTANCE *PrivateData,
581 IN UINTN NotifyType,
582 IN INTN InstallStartIndex,
583 IN INTN InstallStopIndex,
584 IN INTN NotifyStartIndex,
585 IN INTN NotifyStopIndex
586 )
587 /*++
588
589 Routine Description:
590
591 Dispatch notifications.
592
593 Arguments:
594
595 PeiServices - Pointer to the PEI Service Table
596 NotifyType - Type of notify to fire.
597 InstallStartIndex - Install Beginning index.
598 InstallStopIndex - Install Ending index.
599 NotifyStartIndex - Notify Beginning index.
600 NotifyStopIndex - Notify Ending index.
601
602 Returns: None
603
604 --*/
605
606 {
607 INTN Index1;
608 INTN Index2;
609 EFI_GUID *SearchGuid;
610 EFI_GUID *CheckGuid;
611 EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor;
612
613 //
614 // Remember that Installs moves up and Notifies moves down.
615 //
616 for (Index1 = NotifyStartIndex; Index1 > NotifyStopIndex; Index1--) {
617 NotifyDescriptor = PrivateData->PpiData.PpiListPtrs[Index1].Notify;
618
619 CheckGuid = NotifyDescriptor->Guid;
620
621 for (Index2 = InstallStartIndex; Index2 < InstallStopIndex; Index2++) {
622 SearchGuid = PrivateData->PpiData.PpiListPtrs[Index2].Ppi->Guid;
623 //
624 // Don't use CompareGuid function here for performance reasons.
625 // Instead we compare the GUID as INT32 at a time and branch
626 // on the first failed comparison.
627 //
628 if ((((INT32 *)SearchGuid)[0] == ((INT32 *)CheckGuid)[0]) &&
629 (((INT32 *)SearchGuid)[1] == ((INT32 *)CheckGuid)[1]) &&
630 (((INT32 *)SearchGuid)[2] == ((INT32 *)CheckGuid)[2]) &&
631 (((INT32 *)SearchGuid)[3] == ((INT32 *)CheckGuid)[3])) {
632 DEBUG ((EFI_D_INFO, "Notify: PPI Guid: %g, Peim notify entry point: %x\n",
633 SearchGuid,
634 NotifyDescriptor->Notify
635 ));
636 NotifyDescriptor->Notify (
637 GetPeiServicesTablePointer (),
638 NotifyDescriptor,
639 (PrivateData->PpiData.PpiListPtrs[Index2].Ppi)->Ppi
640 );
641 }
642 }
643 }
644
645 return;
646 }
647