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