1 /** @file
2   This driver will register two callbacks to call fsp's notifies.
3 
4   Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.<BR>
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <PiDxe.h>
10 
11 #include <Protocol/PciEnumerationComplete.h>
12 
13 #include <Library/UefiDriverEntryPoint.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/UefiLib.h>
18 #include <Library/FspWrapperApiLib.h>
19 #include <Library/FspWrapperPlatformLib.h>
20 #include <Library/PerformanceLib.h>
21 #include <Library/HobLib.h>
22 #include <FspStatusCode.h>
23 
24 #define   FSP_API_NOTIFY_PHASE_AFTER_PCI_ENUMERATION     BIT16
25 
26 typedef
27 EFI_STATUS
28 (EFIAPI * ADD_PERFORMANCE_RECORDS)(
29   IN CONST VOID *HobStart
30   );
31 
32 struct _ADD_PERFORMANCE_RECORD_PROTOCOL {
33   ADD_PERFORMANCE_RECORDS          AddPerformanceRecords;
34 };
35 
36 typedef struct _ADD_PERFORMANCE_RECORD_PROTOCOL ADD_PERFORMANCE_RECORD_PROTOCOL;
37 
38 extern EFI_GUID gAddPerfRecordProtocolGuid;
39 extern EFI_GUID gFspHobGuid;
40 extern EFI_GUID gFspApiPerformanceGuid;
41 
42 static EFI_EVENT mExitBootServicesEvent     = NULL;
43 
44 /**
45   Relocate this image under 4G memory.
46 
47   @param  ImageHandle  Handle of driver image.
48   @param  SystemTable  Pointer to system table.
49 
50   @retval EFI_SUCCESS  Image successfully relocated.
51   @retval EFI_ABORTED  Failed to relocate image.
52 
53 **/
54 EFI_STATUS
55 RelocateImageUnder4GIfNeeded (
56   IN EFI_HANDLE           ImageHandle,
57   IN EFI_SYSTEM_TABLE     *SystemTable
58   );
59 
60 /**
61   PciEnumerationComplete Protocol notification event handler.
62 
63   @param[in] Event    Event whose notification function is being invoked.
64   @param[in] Context  Pointer to the notification function's context.
65 **/
66 VOID
67 EFIAPI
OnPciEnumerationComplete(IN EFI_EVENT Event,IN VOID * Context)68 OnPciEnumerationComplete (
69   IN EFI_EVENT  Event,
70   IN VOID       *Context
71   )
72 {
73   NOTIFY_PHASE_PARAMS NotifyPhaseParams;
74   EFI_STATUS          Status;
75   VOID                *Interface;
76 
77   //
78   // Try to locate it because gEfiPciEnumerationCompleteProtocolGuid will trigger it once when registration.
79   // Just return if it is not found.
80   //
81   Status = gBS->LocateProtocol (
82                   &gEfiPciEnumerationCompleteProtocolGuid,
83                   NULL,
84                   &Interface
85                   );
86   if (EFI_ERROR (Status)) {
87     return ;
88   }
89 
90   NotifyPhaseParams.Phase = EnumInitPhaseAfterPciEnumeration;
91   PERF_START_EX(&gFspApiPerformanceGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_POST_PCIE_ENUM_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
92   Status = CallFspNotifyPhase (&NotifyPhaseParams);
93   PERF_END_EX(&gFspApiPerformanceGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_POST_PCIE_ENUM_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
94 
95   //
96   // Reset the system if FSP API returned FSP_STATUS_RESET_REQUIRED status
97   //
98   if ((Status >= FSP_STATUS_RESET_REQUIRED_COLD) && (Status <= FSP_STATUS_RESET_REQUIRED_8)) {
99     DEBUG((DEBUG_INFO, "FSP NotifyPhase AfterPciEnumeration requested reset 0x%x\n", Status));
100     CallFspWrapperResetSystem ((UINT32)Status);
101   }
102 
103   if (Status != EFI_SUCCESS) {
104     DEBUG((DEBUG_ERROR, "FSP NotifyPhase AfterPciEnumeration failed, status: 0x%x\n", Status));
105   } else {
106     DEBUG((DEBUG_INFO, "FSP NotifyPhase AfterPciEnumeration Success.\n"));
107   }
108 }
109 
110 /**
111   Notification function of EVT_GROUP_READY_TO_BOOT event group.
112 
113   This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
114   When the Boot Manager is about to load and execute a boot option, it reclaims variable
115   storage if free size is below the threshold.
116 
117   @param[in] Event        Event whose notification function is being invoked.
118   @param[in] Context      Pointer to the notification function's context.
119 
120 **/
121 VOID
122 EFIAPI
OnReadyToBoot(IN EFI_EVENT Event,IN VOID * Context)123 OnReadyToBoot (
124   IN EFI_EVENT  Event,
125   IN VOID       *Context
126   )
127 {
128   NOTIFY_PHASE_PARAMS               NotifyPhaseParams;
129   EFI_STATUS                        Status;
130 
131   gBS->CloseEvent (Event);
132 
133   NotifyPhaseParams.Phase = EnumInitPhaseReadyToBoot;
134   PERF_START_EX(&gFspApiPerformanceGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_READY_TO_BOOT_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
135   Status = CallFspNotifyPhase (&NotifyPhaseParams);
136   PERF_END_EX(&gFspApiPerformanceGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_READY_TO_BOOT_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
137 
138   //
139   // Reset the system if FSP API returned FSP_STATUS_RESET_REQUIRED status
140   //
141   if ((Status >= FSP_STATUS_RESET_REQUIRED_COLD) && (Status <= FSP_STATUS_RESET_REQUIRED_8)) {
142     DEBUG((DEBUG_INFO, "FSP NotifyPhase ReadyToBoot requested reset 0x%x\n", Status));
143     CallFspWrapperResetSystem ((UINT32)Status);
144   }
145 
146   if (Status != EFI_SUCCESS) {
147     DEBUG((DEBUG_ERROR, "FSP NotifyPhase ReadyToBoot failed, status: 0x%x\n", Status));
148   } else {
149     DEBUG((DEBUG_INFO, "FSP NotifyPhase ReadyToBoot Success.\n"));
150   }
151 }
152 
153 /**
154   This stage is notified just before the firmware/Preboot environment transfers
155   management of all system resources to the OS or next level execution environment.
156 
157   @param  Event         Event whose notification function is being invoked.
158   @param  Context       Pointer to the notification function's context, which is
159                         always zero in current implementation.
160 
161 **/
162 VOID
163 EFIAPI
OnEndOfFirmware(IN EFI_EVENT Event,IN VOID * Context)164 OnEndOfFirmware (
165   IN EFI_EVENT  Event,
166   IN VOID       *Context
167   )
168 {
169   NOTIFY_PHASE_PARAMS               NotifyPhaseParams;
170   EFI_STATUS                        Status;
171   ADD_PERFORMANCE_RECORD_PROTOCOL   *AddPerfRecordInterface;
172   EFI_PEI_HOB_POINTERS              Hob;
173   VOID                              **FspHobListPtr;
174 
175   gBS->CloseEvent (Event);
176 
177   NotifyPhaseParams.Phase = EnumInitPhaseEndOfFirmware;
178   PERF_START_EX(&gFspApiPerformanceGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_END_OF_FIRMWARE_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
179   Status = CallFspNotifyPhase (&NotifyPhaseParams);
180   PERF_END_EX(&gFspApiPerformanceGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_END_OF_FIRMWARE_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
181 
182   //
183   // Reset the system if FSP API returned FSP_STATUS_RESET_REQUIRED status
184   //
185   if ((Status >= FSP_STATUS_RESET_REQUIRED_COLD) && (Status <= FSP_STATUS_RESET_REQUIRED_8)) {
186     DEBUG((DEBUG_INFO, "FSP NotifyPhase EndOfFirmware requested reset 0x%x\n", Status));
187     CallFspWrapperResetSystem ((UINT32)Status);
188   }
189 
190   if (Status != EFI_SUCCESS) {
191     DEBUG((DEBUG_ERROR, "FSP NotifyPhase EndOfFirmware failed, status: 0x%x\n", Status));
192   } else {
193     DEBUG((DEBUG_INFO, "FSP NotifyPhase EndOfFirmware Success.\n"));
194   }
195   Status = gBS->LocateProtocol (
196                   &gAddPerfRecordProtocolGuid,
197                   NULL,
198                   (VOID**) &AddPerfRecordInterface
199                   );
200   if (EFI_ERROR (Status)) {
201     DEBUG((DEBUG_INFO, "gAddPerfRecordProtocolGuid - Locate protocol failed\n"));
202     return;
203   } else {
204     Hob.Raw = GetFirstGuidHob (&gFspHobGuid);
205     if (Hob.Raw != NULL) {
206       FspHobListPtr = GET_GUID_HOB_DATA (Hob.Raw);
207       AddPerfRecordInterface->AddPerformanceRecords ((VOID *)(UINTN)(((UINT32)(UINTN)*FspHobListPtr) & 0xFFFFFFFF));
208     }
209   }
210 }
211 
212 /**
213   Main entry for the FSP DXE module.
214 
215   This routine registers two callbacks to call fsp's notifies.
216 
217   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
218   @param[in] SystemTable    A pointer to the EFI System Table.
219 
220   @retval EFI_SUCCESS       The entry point is executed successfully.
221   @retval other             Some error occurs when executing this entry point.
222 
223 **/
224 EFI_STATUS
225 EFIAPI
FspWrapperNotifyDxeEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)226 FspWrapperNotifyDxeEntryPoint (
227   IN EFI_HANDLE         ImageHandle,
228   IN EFI_SYSTEM_TABLE   *SystemTable
229   )
230 {
231   EFI_STATUS Status;
232   EFI_EVENT  ReadyToBootEvent;
233   VOID       *Registration;
234   EFI_EVENT  ProtocolNotifyEvent;
235   UINT32     FspApiMask;
236 
237   //
238   // Load this driver's image to memory
239   //
240   Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);
241   if (EFI_ERROR (Status)) {
242     return EFI_SUCCESS;
243   }
244 
245   FspApiMask = PcdGet32 (PcdSkipFspApi);
246   if ((FspApiMask & FSP_API_NOTIFY_PHASE_AFTER_PCI_ENUMERATION) == 0) {
247     ProtocolNotifyEvent = EfiCreateProtocolNotifyEvent (
248                             &gEfiPciEnumerationCompleteProtocolGuid,
249                             TPL_CALLBACK,
250                             OnPciEnumerationComplete,
251                             NULL,
252                             &Registration
253                             );
254     ASSERT (ProtocolNotifyEvent != NULL);
255   }
256 
257   Status = EfiCreateEventReadyToBootEx (
258              TPL_CALLBACK,
259              OnReadyToBoot,
260              NULL,
261              &ReadyToBootEvent
262              );
263   ASSERT_EFI_ERROR (Status);
264 
265   Status = gBS->CreateEventEx (
266                   EVT_NOTIFY_SIGNAL,
267                   TPL_NOTIFY,
268                   OnEndOfFirmware,
269                   NULL,
270                   &gEfiEventExitBootServicesGuid,
271                   &mExitBootServicesEvent
272                   );
273   ASSERT_EFI_ERROR (Status);
274 
275   return EFI_SUCCESS;
276 }
277 
278