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