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