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