1 /** @file
2 
3   Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.<BR>
4   This program and the accompanying materials
5   are licensed and made available under the terms and conditions of the BSD License
6   which accompanies this distribution.  The full text of the license may be found at
7   http://opensource.org/licenses/bsd-license.php.
8 
9   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 **/
13 
14 #include <PiPei.h>
15 #include <Library/PeiServicesLib.h>
16 #include <Library/PeiServicesTablePointerLib.h>
17 #include <Library/BaseLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/PcdLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/HobLib.h>
22 #include <Library/FspSwitchStackLib.h>
23 #include <Library/FspCommonLib.h>
24 #include <Guid/EventGroup.h>
25 #include <FspEas.h>
26 #include <FspStatusCode.h>
27 #include <Protocol/PciEnumerationComplete.h>
28 #include <Library/ReportStatusCodeLib.h>
29 #include <Library/PerformanceLib.h>
30 extern EFI_GUID gFspPerformanceDataGuid;
31 
32 EFI_PEI_PPI_DESCRIPTOR      mPeiPostPciEnumerationPpi = {
33   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
34   &gEfiPciEnumerationCompleteProtocolGuid,
35   NULL
36 };
37 
38 EFI_PEI_PPI_DESCRIPTOR      mPeiReadyToBootPpi = {
39   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
40   &gEfiEventReadyToBootGuid,
41   NULL
42 };
43 
44 EFI_PEI_PPI_DESCRIPTOR      mPeiEndOfFirmwarePpi = {
45   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
46   &gFspEventEndOfFirmwareGuid,
47   NULL
48 };
49 
50 UINT32  mFspNotifySequence[] = {
51   EnumInitPhaseAfterPciEnumeration,
52   EnumInitPhaseReadyToBoot,
53   EnumInitPhaseEndOfFirmware
54 };
55 
56 /**
57   Install FSP notification.
58 
59   @param[in] NotificationCode  FSP notification code
60 
61   @retval EFI_SUCCESS            Notify FSP successfully
62   @retval EFI_INVALID_PARAMETER  NotificationCode is invalid
63 
64 **/
65 EFI_STATUS
66 EFIAPI
FspNotificationHandler(IN UINT32 NotificationCode)67 FspNotificationHandler (
68   IN  UINT32     NotificationCode
69   )
70 {
71   EFI_STATUS                Status;
72 
73   Status   = EFI_SUCCESS;
74 
75   switch (NotificationCode) {
76   case EnumInitPhaseAfterPciEnumeration:
77     //
78     // Do POST PCI initialization if needed
79     //
80     DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP Post PCI Enumeration ...\n"));
81     PeiServicesInstallPpi (&mPeiPostPciEnumerationPpi);
82     break;
83 
84   case EnumInitPhaseReadyToBoot:
85     //
86     // Ready To Boot
87     //
88     DEBUG ((DEBUG_INFO| DEBUG_INIT, "FSP Ready To Boot ...\n"));
89     PeiServicesInstallPpi (&mPeiReadyToBootPpi);
90     break;
91 
92   case EnumInitPhaseEndOfFirmware:
93     //
94     // End of Firmware
95     //
96     DEBUG ((DEBUG_INFO| DEBUG_INIT, "FSP End of Firmware ...\n"));
97     PeiServicesInstallPpi (&mPeiEndOfFirmwarePpi);
98     break;
99 
100   default:
101     Status = EFI_INVALID_PARAMETER;
102     break;
103   }
104 
105   return Status;
106 }
107 
108 /**
109   This function transfer control back to BootLoader after FspSiliconInit.
110 
111   @param[in] Status return status for the FspSiliconInit.
112 
113 **/
114 VOID
115 EFIAPI
FspSiliconInitDone2(IN EFI_STATUS Status)116 FspSiliconInitDone2 (
117   IN EFI_STATUS Status
118   )
119 {
120   //
121   // Convert to FSP EAS defined API return codes
122   //
123   switch (Status) {
124     case EFI_SUCCESS:
125     case EFI_INVALID_PARAMETER:
126     case EFI_UNSUPPORTED:
127     case EFI_DEVICE_ERROR:
128       break;
129     default:
130       DEBUG ((DEBUG_INFO | DEBUG_INIT, "FspSiliconInitApi() Invalid Error - [Status: 0x%08X]\n", Status));
131       Status = EFI_DEVICE_ERROR;  // Force to known error.
132       break;
133   }
134   //
135   // This is the end of the FspSiliconInit API
136   // Give control back to the boot loader
137   //
138   SetFspMeasurePoint (FSP_PERF_ID_API_FSP_SILICON_INIT_EXIT);
139   DEBUG ((DEBUG_INFO | DEBUG_INIT, "FspSiliconInitApi() - [Status: 0x%08X] - End\n", Status));
140   PERF_END_EX (&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_SILICON_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
141   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
142   do {
143     SetFspApiReturnStatus (Status);
144     Pei2LoaderSwitchStack ();
145     if (Status != EFI_SUCCESS) {
146       DEBUG ((DEBUG_ERROR, "!!!ERROR: FspSiliconInitApi() - [Status: 0x%08X] - Error encountered during previous API and cannot proceed further\n", Status));
147     }
148   } while (Status != EFI_SUCCESS);
149 }
150 
151 /**
152   This function returns control to BootLoader after MemoryInitApi.
153 
154   @param[in] Status return status for the MemoryInitApi.
155   @param[in,out] HobListPtr The address of HobList pointer, if NULL, will get value from GetFspApiParameter2 ()
156 **/
157 VOID
158 EFIAPI
FspMemoryInitDone2(IN EFI_STATUS Status,IN OUT VOID ** HobListPtr)159 FspMemoryInitDone2 (
160   IN EFI_STATUS Status,
161   IN OUT VOID   **HobListPtr
162   )
163 {
164   FSP_GLOBAL_DATA   *FspData;
165   //
166   // Calling use FspMemoryInit API
167   // Update HOB and return the control directly
168   //
169   if (HobListPtr == NULL) {
170     HobListPtr = (VOID **)GetFspApiParameter2 ();
171   }
172   if (HobListPtr != NULL) {
173     *HobListPtr = (VOID *) GetHobList ();
174   }
175   //
176   // Convert to FSP EAS defined API return codes
177   //
178   switch (Status) {
179     case EFI_SUCCESS:
180     case EFI_INVALID_PARAMETER:
181     case EFI_UNSUPPORTED:
182     case EFI_DEVICE_ERROR:
183     case EFI_OUT_OF_RESOURCES:
184       break;
185     default:
186       DEBUG ((DEBUG_INFO | DEBUG_INIT, "FspMemoryInitApi() Invalid Error [Status: 0x%08X]\n", Status));
187       Status = EFI_DEVICE_ERROR;  // Force to known error.
188       break;
189   }
190   //
191   // This is the end of the FspMemoryInit API
192   // Give control back to the boot loader
193   //
194   DEBUG ((DEBUG_INFO | DEBUG_INIT, "FspMemoryInitApi() - [Status: 0x%08X] - End\n", Status));
195   SetFspMeasurePoint (FSP_PERF_ID_API_FSP_MEMORY_INIT_EXIT);
196   FspData = GetFspGlobalDataPointer ();
197   PERF_START_EX(&gFspPerformanceDataGuid, "EventRec", NULL, (FspData->PerfData[0] & FSP_PERFORMANCE_DATA_TIMER_MASK), FSP_STATUS_CODE_TEMP_RAM_INIT | FSP_STATUS_CODE_COMMON_CODE| FSP_STATUS_CODE_API_ENTRY);
198   PERF_END_EX(&gFspPerformanceDataGuid, "EventRec", NULL, (FspData->PerfData[1] & FSP_PERFORMANCE_DATA_TIMER_MASK), FSP_STATUS_CODE_TEMP_RAM_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
199   PERF_START_EX(&gFspPerformanceDataGuid, "EventRec", NULL, (FspData->PerfData[2] & FSP_PERFORMANCE_DATA_TIMER_MASK), FSP_STATUS_CODE_MEMORY_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
200   PERF_END_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_MEMORY_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
201   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_MEMORY_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
202   do {
203     SetFspApiReturnStatus (Status);
204     Pei2LoaderSwitchStack ();
205     if (Status != EFI_SUCCESS) {
206       DEBUG ((DEBUG_ERROR, "!!!ERROR: FspMemoryInitApi() - [Status: 0x%08X] - Error encountered during previous API and cannot proceed further\n", Status));
207     }
208   } while (Status != EFI_SUCCESS);
209 
210   //
211   // The TempRamExitApi is called
212   //
213   if (GetFspApiCallingIndex () == TempRamExitApiIndex) {
214     SetPhaseStatusCode (FSP_STATUS_CODE_TEMP_RAM_EXIT);
215     SetFspMeasurePoint (FSP_PERF_ID_API_TEMP_RAM_EXIT_ENTRY);
216     PERF_START_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_TEMP_RAM_EXIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
217     REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_TEMP_RAM_EXIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
218     DEBUG ((DEBUG_INFO | DEBUG_INIT, "TempRamExitApi() - Begin\n"));
219   } else {
220     SetPhaseStatusCode (FSP_STATUS_CODE_SILICON_INIT);
221     SetFspMeasurePoint (FSP_PERF_ID_API_FSP_SILICON_INIT_ENTRY);
222     PERF_START_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_SILICON_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
223     REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_SILICON_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
224     DEBUG ((DEBUG_INFO | DEBUG_INIT, "FspSiliconInitApi() - Begin\n"));
225   }
226 }
227 
228 /**
229   This function returns control to BootLoader after TempRamExitApi.
230 
231   @param[in] Status return status for the TempRamExitApi.
232 
233 **/
234 VOID
235 EFIAPI
FspTempRamExitDone2(IN EFI_STATUS Status)236 FspTempRamExitDone2 (
237   IN EFI_STATUS Status
238   )
239 {
240   //
241   // Convert to FSP EAS defined API return codes
242   //
243   switch (Status) {
244     case EFI_SUCCESS:
245     case EFI_INVALID_PARAMETER:
246     case EFI_UNSUPPORTED:
247     case EFI_DEVICE_ERROR:
248       break;
249     default:
250       DEBUG ((DEBUG_INFO | DEBUG_INIT, "TempRamExitApi() Invalid Error - [Status: 0x%08X]\n", Status));
251       Status = EFI_DEVICE_ERROR;  // Force to known error.
252       break;
253   }
254   //
255   // This is the end of the TempRamExit API
256   // Give control back to the boot loader
257   //
258   DEBUG ((DEBUG_INFO | DEBUG_INIT, "TempRamExitApi() - [Status: 0x%08X] - End\n", Status));
259   SetFspMeasurePoint (FSP_PERF_ID_API_TEMP_RAM_EXIT_EXIT);
260   PERF_END_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_TEMP_RAM_EXIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
261   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_TEMP_RAM_EXIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
262   do {
263     SetFspApiReturnStatus (Status);
264     Pei2LoaderSwitchStack ();
265     if (Status != EFI_SUCCESS) {
266       DEBUG ((DEBUG_ERROR, "!!!ERROR: TempRamExitApi() - [Status: 0x%08X] - Error encountered during previous API and cannot proceed further\n", Status));
267     }
268   } while (Status != EFI_SUCCESS);
269   SetPhaseStatusCode (FSP_STATUS_CODE_SILICON_INIT);
270   SetFspMeasurePoint (FSP_PERF_ID_API_FSP_SILICON_INIT_ENTRY);
271   PERF_START_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_SILICON_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
272   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_SILICON_INIT | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
273   DEBUG ((DEBUG_INFO | DEBUG_INIT, "SiliconInitApi() - Begin\n"));
274 }
275 
276 /**
277   This function handle NotifyPhase API call from the BootLoader.
278   It gives control back to the BootLoader after it is handled. If the
279   Notification code is a ReadyToBoot event, this function will return
280   and FSP continues the remaining execution until it reaches the DxeIpl.
281 
282 **/
283 VOID
FspWaitForNotify(VOID)284 FspWaitForNotify (
285   VOID
286   )
287 {
288   EFI_STATUS                 Status;
289   UINT32                     NotificationValue;
290   UINT32                     NotificationCount;
291   UINT8                      Count;
292 
293   NotificationCount = 0;
294   while (NotificationCount < sizeof(mFspNotifySequence) / sizeof(UINT32)) {
295 
296     Count = (UINT8)((NotificationCount << 1) & 0x07);
297     SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_POST_PCI_ENTRY + Count);
298 
299     if (NotificationCount == 0) {
300       SetPhaseStatusCode (FSP_STATUS_CODE_POST_PCIE_ENUM_NOTIFICATION);
301       PERF_START_EX (&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_POST_PCIE_ENUM_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
302       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_POST_PCIE_ENUM_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
303     } else if (NotificationCount == 1) {
304       SetPhaseStatusCode (FSP_STATUS_CODE_READY_TO_BOOT_NOTIFICATION);
305       PERF_START_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_READY_TO_BOOT_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
306       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_READY_TO_BOOT_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
307     } else if (NotificationCount == 2) {
308       SetPhaseStatusCode (FSP_STATUS_CODE_END_OF_FIRMWARE_NOTIFICATION);
309       PERF_START_EX (&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_END_OF_FIRMWARE_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
310       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_END_OF_FIRMWARE_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_ENTRY);
311     }
312 
313     NotificationValue = ((NOTIFY_PHASE_PARAMS *)(UINTN)GetFspApiParameter ())->Phase;
314     DEBUG ((DEBUG_INFO | DEBUG_INIT, "NotifyPhaseApi() - Begin  [Phase: %08X]\n", NotificationValue));
315     if (mFspNotifySequence[NotificationCount] != NotificationValue) {
316       //
317       // Notify code does not follow the predefined order
318       //
319       DEBUG ((DEBUG_INFO, "Unsupported FSP Notification Value\n"));
320       Status = EFI_UNSUPPORTED;
321     } else {
322       //
323       // Process Notification and Give control back to the boot loader framework caller
324       //
325       Status = FspNotificationHandler (NotificationValue);
326       if (!EFI_ERROR(Status)) {
327         NotificationCount++;
328       }
329     }
330 
331     DEBUG ((DEBUG_INFO | DEBUG_INIT, "NotifyPhaseApi() - End  [Status: 0x%08X]\n", Status));
332     SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_POST_PCI_EXIT + Count);
333 
334     if ((NotificationCount - 1) == 0) {
335       PERF_END_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_POST_PCIE_ENUM_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
336       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_POST_PCIE_ENUM_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
337     } else if ((NotificationCount - 1) == 1) {
338       PERF_END_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_READY_TO_BOOT_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
339       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_READY_TO_BOOT_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
340     } else if ((NotificationCount - 1) == 2) {
341       PERF_END_EX(&gFspPerformanceDataGuid, "EventRec", NULL, 0, FSP_STATUS_CODE_END_OF_FIRMWARE_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
342       REPORT_STATUS_CODE (EFI_PROGRESS_CODE, FSP_STATUS_CODE_END_OF_FIRMWARE_NOTIFICATION | FSP_STATUS_CODE_COMMON_CODE | FSP_STATUS_CODE_API_EXIT);
343     }
344     do {
345       SetFspApiReturnStatus(Status);
346       Pei2LoaderSwitchStack();
347       if (Status != EFI_SUCCESS) {
348         DEBUG ((DEBUG_ERROR, "!!!ERROR: NotifyPhaseApi() [Phase: %08X] - Failed - [Status: 0x%08X]\n", NotificationValue, Status));
349       }
350     } while (Status != EFI_SUCCESS);
351   }
352 
353   //
354   // Control goes back to the PEI Core and it dispatches further PEIMs.
355   // DXEIPL is the final one to transfer control back to the boot loader.
356   //
357 }
358 
359 /**
360   This function transfer control back to BootLoader after FspSiliconInit.
361 
362 **/
363 VOID
364 EFIAPI
FspSiliconInitDone(VOID)365 FspSiliconInitDone (
366   VOID
367   )
368 {
369   FspSiliconInitDone2 (EFI_SUCCESS);
370 }
371 
372 /**
373   This function returns control to BootLoader after MemoryInitApi.
374 
375   @param[in,out] HobListPtr The address of HobList pointer.
376 **/
377 VOID
378 EFIAPI
FspMemoryInitDone(IN OUT VOID ** HobListPtr)379 FspMemoryInitDone (
380   IN OUT VOID   **HobListPtr
381   )
382 {
383   FspMemoryInitDone2 (EFI_SUCCESS, HobListPtr);
384 }
385 
386 /**
387   This function returns control to BootLoader after TempRamExitApi.
388 
389 **/
390 VOID
391 EFIAPI
FspTempRamExitDone(VOID)392 FspTempRamExitDone (
393   VOID
394   )
395 {
396   FspTempRamExitDone2 (EFI_SUCCESS);
397 }
398