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