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
32typedef
33EFI_STATUS
34(EFIAPI * ADD_PERFORMANCE_RECORDS)(
35  IN CONST VOID *HobStart
36  );
37
38struct _ADD_PERFORMANCE_RECORD_PROTOCOL {
39  ADD_PERFORMANCE_RECORDS          AddPerformanceRecords;
40};
41
42typedef struct _ADD_PERFORMANCE_RECORD_PROTOCOL ADD_PERFORMANCE_RECORD_PROTOCOL;
43
44extern EFI_GUID gAddPerfRecordProtocolGuid;
45extern EFI_GUID gFspHobGuid;
46extern EFI_GUID gFspApiPerformanceGuid;
47
48EFI_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**/
60EFI_STATUS
61RelocateImageUnder4GIfNeeded (
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**/
72VOID
73EFIAPI
74OnPciEnumerationComplete (
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**/
127VOID
128EFIAPI
129OnReadyToBoot (
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**/
168VOID
169EFIAPI
170OnEndOfFirmware (
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**/
230EFI_STATUS
231EFIAPI
232FspWrapperNotifyDxeEntryPoint (
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
284