1 /** @file
2   Pei Core Main Entry Point
3 
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "PeiMain.h"
10 
11 EFI_PEI_PPI_DESCRIPTOR mMemoryDiscoveredPpi = {
12   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
13   &gEfiPeiMemoryDiscoveredPpiGuid,
14   NULL
15 };
16 
17 ///
18 /// Pei service instance
19 ///
20 EFI_PEI_SERVICES  gPs = {
21   {
22     PEI_SERVICES_SIGNATURE,
23     PEI_SERVICES_REVISION,
24     sizeof (EFI_PEI_SERVICES),
25     0,
26     0
27   },
28   PeiInstallPpi,
29   PeiReInstallPpi,
30   PeiLocatePpi,
31   PeiNotifyPpi,
32 
33   PeiGetBootMode,
34   PeiSetBootMode,
35 
36   PeiGetHobList,
37   PeiCreateHob,
38 
39   PeiFfsFindNextVolume,
40   PeiFfsFindNextFile,
41   PeiFfsFindSectionData,
42 
43   PeiInstallPeiMemory,
44   PeiAllocatePages,
45   PeiAllocatePool,
46   (EFI_PEI_COPY_MEM)CopyMem,
47   (EFI_PEI_SET_MEM)SetMem,
48 
49   PeiReportStatusCode,
50   PeiResetSystem,
51 
52   &gPeiDefaultCpuIoPpi,
53   &gPeiDefaultPciCfg2Ppi,
54 
55   PeiFfsFindFileByName,
56   PeiFfsGetFileInfo,
57   PeiFfsGetVolumeInfo,
58   PeiRegisterForShadow,
59   PeiFfsFindSectionData3,
60   PeiFfsGetFileInfo2,
61   PeiResetSystem2,
62   PeiFreePages,
63 };
64 
65 /**
66   Shadow PeiCore module from flash to installed memory.
67 
68   @param PrivateData    PeiCore's private data structure
69 
70   @return PeiCore function address after shadowing.
71 **/
72 PEICORE_FUNCTION_POINTER
ShadowPeiCore(IN PEI_CORE_INSTANCE * PrivateData)73 ShadowPeiCore (
74   IN PEI_CORE_INSTANCE  *PrivateData
75   )
76 {
77   EFI_PEI_FILE_HANDLE          PeiCoreFileHandle;
78   EFI_PHYSICAL_ADDRESS         EntryPoint;
79   EFI_STATUS                   Status;
80   UINT32                       AuthenticationState;
81   UINTN                        Index;
82   EFI_PEI_CORE_FV_LOCATION_PPI *PeiCoreFvLocationPpi;
83   UINTN                        PeiCoreFvIndex;
84 
85   PeiCoreFileHandle = NULL;
86   //
87   // Default PeiCore is in BFV
88   //
89   PeiCoreFvIndex = 0;
90   //
91   // Find the PEI Core either from EFI_PEI_CORE_FV_LOCATION_PPI indicated FV or BFV
92   //
93   Status = PeiServicesLocatePpi (
94              &gEfiPeiCoreFvLocationPpiGuid,
95              0,
96              NULL,
97              (VOID **) &PeiCoreFvLocationPpi
98              );
99   if (!EFI_ERROR (Status) && (PeiCoreFvLocationPpi->PeiCoreFvLocation != NULL)) {
100     //
101     // If PeiCoreFvLocation present, the PEI Core should be found from indicated FV
102     //
103     for (Index = 0; Index < PrivateData->FvCount; Index ++) {
104       if (PrivateData->Fv[Index].FvHandle == PeiCoreFvLocationPpi->PeiCoreFvLocation) {
105         PeiCoreFvIndex = Index;
106         break;
107       }
108     }
109     ASSERT (Index < PrivateData->FvCount);
110   }
111   //
112   // Find PEI Core from the given FV index
113   //
114   Status = PrivateData->Fv[PeiCoreFvIndex].FvPpi->FindFileByType (
115                                                     PrivateData->Fv[PeiCoreFvIndex].FvPpi,
116                                                     EFI_FV_FILETYPE_PEI_CORE,
117                                                     PrivateData->Fv[PeiCoreFvIndex].FvHandle,
118                                                     &PeiCoreFileHandle
119                                                     );
120   ASSERT_EFI_ERROR (Status);
121 
122   //
123   // Shadow PEI Core into memory so it will run faster
124   //
125   Status = PeiLoadImage (
126               GetPeiServicesTablePointer (),
127               *((EFI_PEI_FILE_HANDLE*)&PeiCoreFileHandle),
128               PEIM_STATE_REGISTER_FOR_SHADOW,
129               &EntryPoint,
130               &AuthenticationState
131               );
132   ASSERT_EFI_ERROR (Status);
133 
134   //
135   // Compute the PeiCore's function address after shadowed PeiCore.
136   // _ModuleEntryPoint is PeiCore main function entry
137   //
138   return (PEICORE_FUNCTION_POINTER)((UINTN) EntryPoint + (UINTN) PeiCore - (UINTN) _ModuleEntryPoint);
139 }
140 
141 /**
142   This routine is invoked by main entry of PeiMain module during transition
143   from SEC to PEI. After switching stack in the PEI core, it will restart
144   with the old core data.
145 
146   @param SecCoreDataPtr  Points to a data structure containing information about the PEI core's operating
147                          environment, such as the size and location of temporary RAM, the stack location and
148                          the BFV location.
149   @param PpiList         Points to a list of one or more PPI descriptors to be installed initially by the PEI core.
150                          An empty PPI list consists of a single descriptor with the end-tag
151                          EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST. As part of its initialization
152                          phase, the PEI Foundation will add these SEC-hosted PPIs to its PPI database such
153                          that both the PEI Foundation and any modules can leverage the associated service
154                          calls and/or code in these early PPIs
155   @param Data            Pointer to old core data that is used to initialize the
156                          core's data areas.
157                          If NULL, it is first PeiCore entering.
158 
159 **/
160 VOID
161 EFIAPI
PeiCore(IN CONST EFI_SEC_PEI_HAND_OFF * SecCoreDataPtr,IN CONST EFI_PEI_PPI_DESCRIPTOR * PpiList,IN VOID * Data)162 PeiCore (
163   IN CONST EFI_SEC_PEI_HAND_OFF        *SecCoreDataPtr,
164   IN CONST EFI_PEI_PPI_DESCRIPTOR      *PpiList,
165   IN VOID                              *Data
166   )
167 {
168   PEI_CORE_INSTANCE           PrivateData;
169   EFI_SEC_PEI_HAND_OFF        *SecCoreData;
170   EFI_SEC_PEI_HAND_OFF        NewSecCoreData;
171   EFI_STATUS                  Status;
172   PEI_CORE_TEMP_POINTERS      TempPtr;
173   PEI_CORE_INSTANCE           *OldCoreData;
174   EFI_PEI_CPU_IO_PPI          *CpuIo;
175   EFI_PEI_PCI_CFG2_PPI        *PciCfg;
176   EFI_HOB_HANDOFF_INFO_TABLE  *HandoffInformationTable;
177   EFI_PEI_TEMPORARY_RAM_DONE_PPI *TemporaryRamDonePpi;
178   UINTN                       Index;
179 
180   //
181   // Retrieve context passed into PEI Core
182   //
183   OldCoreData = (PEI_CORE_INSTANCE *) Data;
184   SecCoreData = (EFI_SEC_PEI_HAND_OFF *) SecCoreDataPtr;
185 
186   //
187   // Perform PEI Core phase specific actions.
188   //
189   if (OldCoreData == NULL) {
190     //
191     // If OldCoreData is NULL, means current is the first entry into the PEI Core before memory is available.
192     //
193     ZeroMem (&PrivateData, sizeof (PEI_CORE_INSTANCE));
194     PrivateData.Signature = PEI_CORE_HANDLE_SIGNATURE;
195     CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
196   } else {
197     //
198     // Memory is available to the PEI Core.  See if the PEI Core has been shadowed to memory yet.
199     //
200     if (OldCoreData->ShadowedPeiCore == NULL) {
201       //
202       // Fixup the PeiCore's private data
203       //
204       OldCoreData->Ps    = &OldCoreData->ServiceTableShadow;
205       OldCoreData->CpuIo = &OldCoreData->ServiceTableShadow.CpuIo;
206       if (OldCoreData->HeapOffsetPositive) {
207         OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw + OldCoreData->HeapOffset);
208         if (OldCoreData->UnknownFvInfo != NULL) {
209           OldCoreData->UnknownFvInfo      = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *) ((UINT8 *) OldCoreData->UnknownFvInfo + OldCoreData->HeapOffset);
210         }
211         if (OldCoreData->CurrentFvFileHandles != NULL) {
212           OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->CurrentFvFileHandles + OldCoreData->HeapOffset);
213         }
214         if (OldCoreData->PpiData.PpiList.PpiPtrs != NULL) {
215           OldCoreData->PpiData.PpiList.PpiPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.PpiList.PpiPtrs + OldCoreData->HeapOffset);
216         }
217         if (OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs != NULL) {
218           OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs + OldCoreData->HeapOffset);
219         }
220         if (OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs != NULL) {
221           OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs + OldCoreData->HeapOffset);
222         }
223         OldCoreData->Fv                   = (PEI_CORE_FV_HANDLE *) ((UINT8 *) OldCoreData->Fv + OldCoreData->HeapOffset);
224         for (Index = 0; Index < OldCoreData->FvCount; Index ++) {
225           if (OldCoreData->Fv[Index].PeimState != NULL) {
226             OldCoreData->Fv[Index].PeimState     = (UINT8 *) OldCoreData->Fv[Index].PeimState + OldCoreData->HeapOffset;
227           }
228           if (OldCoreData->Fv[Index].FvFileHandles != NULL) {
229             OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->Fv[Index].FvFileHandles + OldCoreData->HeapOffset);
230           }
231         }
232         OldCoreData->TempFileGuid         = (EFI_GUID *) ((UINT8 *) OldCoreData->TempFileGuid + OldCoreData->HeapOffset);
233         OldCoreData->TempFileHandles      = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->TempFileHandles + OldCoreData->HeapOffset);
234       } else {
235         OldCoreData->HobList.Raw = (VOID *)(OldCoreData->HobList.Raw - OldCoreData->HeapOffset);
236         if (OldCoreData->UnknownFvInfo != NULL) {
237           OldCoreData->UnknownFvInfo      = (PEI_CORE_UNKNOW_FORMAT_FV_INFO *) ((UINT8 *) OldCoreData->UnknownFvInfo - OldCoreData->HeapOffset);
238         }
239         if (OldCoreData->CurrentFvFileHandles != NULL) {
240           OldCoreData->CurrentFvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->CurrentFvFileHandles - OldCoreData->HeapOffset);
241         }
242         if (OldCoreData->PpiData.PpiList.PpiPtrs != NULL) {
243           OldCoreData->PpiData.PpiList.PpiPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.PpiList.PpiPtrs - OldCoreData->HeapOffset);
244         }
245         if (OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs != NULL) {
246           OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.CallbackNotifyList.NotifyPtrs - OldCoreData->HeapOffset);
247         }
248         if (OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs != NULL) {
249           OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs = (PEI_PPI_LIST_POINTERS *) ((UINT8 *) OldCoreData->PpiData.DispatchNotifyList.NotifyPtrs - OldCoreData->HeapOffset);
250         }
251         OldCoreData->Fv                   = (PEI_CORE_FV_HANDLE *) ((UINT8 *) OldCoreData->Fv - OldCoreData->HeapOffset);
252         for (Index = 0; Index < OldCoreData->FvCount; Index ++) {
253           if (OldCoreData->Fv[Index].PeimState != NULL) {
254             OldCoreData->Fv[Index].PeimState     = (UINT8 *) OldCoreData->Fv[Index].PeimState - OldCoreData->HeapOffset;
255           }
256           if (OldCoreData->Fv[Index].FvFileHandles != NULL) {
257             OldCoreData->Fv[Index].FvFileHandles = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->Fv[Index].FvFileHandles - OldCoreData->HeapOffset);
258           }
259         }
260         OldCoreData->TempFileGuid         = (EFI_GUID *) ((UINT8 *) OldCoreData->TempFileGuid - OldCoreData->HeapOffset);
261         OldCoreData->TempFileHandles      = (EFI_PEI_FILE_HANDLE *) ((UINT8 *) OldCoreData->TempFileHandles - OldCoreData->HeapOffset);
262       }
263 
264       //
265       // Fixup for PeiService's address
266       //
267       SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
268 
269       //
270       // Initialize libraries that the PEI Core is linked against
271       //
272       ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&OldCoreData->Ps);
273 
274       //
275       // Update HandOffHob for new installed permanent memory
276       //
277       HandoffInformationTable = OldCoreData->HobList.HandoffInformationTable;
278       if (OldCoreData->HeapOffsetPositive) {
279         HandoffInformationTable->EfiEndOfHobList   = HandoffInformationTable->EfiEndOfHobList + OldCoreData->HeapOffset;
280       } else {
281         HandoffInformationTable->EfiEndOfHobList   = HandoffInformationTable->EfiEndOfHobList - OldCoreData->HeapOffset;
282       }
283       HandoffInformationTable->EfiMemoryTop        = OldCoreData->PhysicalMemoryBegin + OldCoreData->PhysicalMemoryLength;
284       HandoffInformationTable->EfiMemoryBottom     = OldCoreData->PhysicalMemoryBegin;
285       HandoffInformationTable->EfiFreeMemoryTop    = OldCoreData->FreePhysicalMemoryTop;
286       HandoffInformationTable->EfiFreeMemoryBottom = HandoffInformationTable->EfiEndOfHobList + sizeof (EFI_HOB_GENERIC_HEADER);
287 
288       //
289       // We need convert MemoryBaseAddress in memory allocation HOBs
290       //
291       ConvertMemoryAllocationHobs (OldCoreData);
292 
293       //
294       // We need convert the PPI descriptor's pointer
295       //
296       ConvertPpiPointers (SecCoreData, OldCoreData);
297 
298       //
299       // After the whole temporary memory is migrated, then we can allocate page in
300       // permanent memory.
301       //
302       OldCoreData->PeiMemoryInstalled = TRUE;
303 
304       //
305       // Indicate that PeiCore reenter
306       //
307       OldCoreData->PeimDispatcherReenter = TRUE;
308 
309       if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (OldCoreData->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) {
310         //
311         // if Loading Module at Fixed Address is enabled, allocate the PEI code memory range usage bit map array.
312         // Every bit in the array indicate the status of the corresponding memory page available or not
313         //
314         OldCoreData->PeiCodeMemoryRangeUsageBitMap = AllocateZeroPool (((PcdGet32(PcdLoadFixAddressPeiCodePageNumber)>>6) + 1)*sizeof(UINT64));
315       }
316 
317       //
318       // Shadow PEI Core. When permanent memory is available, shadow
319       // PEI Core and PEIMs to get high performance.
320       //
321       OldCoreData->ShadowedPeiCore = (PEICORE_FUNCTION_POINTER) (UINTN) PeiCore;
322       if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes) ||
323           (HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnS3Boot)) ||
324           (HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME && PcdGetBool (PcdShadowPeimOnBoot))) {
325         OldCoreData->ShadowedPeiCore = ShadowPeiCore (OldCoreData);
326       }
327 
328       //
329       // PEI Core has now been shadowed to memory.  Restart PEI Core in memory.
330       //
331       OldCoreData->ShadowedPeiCore (SecCoreData, PpiList, OldCoreData);
332 
333       //
334       // Should never reach here.
335       //
336       ASSERT (FALSE);
337       CpuDeadLoop();
338 
339       UNREACHABLE ();
340     }
341 
342     //
343     // Memory is available to the PEI Core and the PEI Core has been shadowed to memory.
344     //
345     CopyMem (&NewSecCoreData, SecCoreDataPtr, sizeof (NewSecCoreData));
346     SecCoreData = &NewSecCoreData;
347 
348     CopyMem (&PrivateData, OldCoreData, sizeof (PrivateData));
349 
350     CpuIo = (VOID*)PrivateData.ServiceTableShadow.CpuIo;
351     PciCfg = (VOID*)PrivateData.ServiceTableShadow.PciCfg;
352 
353     CopyMem (&PrivateData.ServiceTableShadow, &gPs, sizeof (gPs));
354 
355     PrivateData.ServiceTableShadow.CpuIo  = CpuIo;
356     PrivateData.ServiceTableShadow.PciCfg = PciCfg;
357   }
358 
359   //
360   // Cache a pointer to the PEI Services Table that is either in temporary memory or permanent memory
361   //
362   PrivateData.Ps = &PrivateData.ServiceTableShadow;
363 
364   //
365   // Save PeiServicePointer so that it can be retrieved anywhere.
366   //
367   SetPeiServicesTablePointer ((CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
368 
369   //
370   // Initialize libraries that the PEI Core is linked against
371   //
372   ProcessLibraryConstructorList (NULL, (CONST EFI_PEI_SERVICES **)&PrivateData.Ps);
373 
374   //
375   // Initialize PEI Core Services
376   //
377   InitializeMemoryServices   (&PrivateData, SecCoreData, OldCoreData);
378 
379   //
380   // Update performance measurements
381   //
382   if (OldCoreData == NULL) {
383     PERF_EVENT ("SEC"); // Means the end of SEC phase.
384 
385     //
386     // If first pass, start performance measurement.
387     //
388     PERF_CROSSMODULE_BEGIN ("PEI");
389     PERF_INMODULE_BEGIN ("PreMem");
390 
391   } else {
392     PERF_INMODULE_END ("PreMem");
393     PERF_INMODULE_BEGIN ("PostMem");
394   }
395 
396   //
397   // Complete PEI Core Service initialization
398   //
399   InitializeSecurityServices (&PrivateData.Ps, OldCoreData);
400   InitializeDispatcherData   (&PrivateData,    OldCoreData, SecCoreData);
401   InitializeImageServices    (&PrivateData,    OldCoreData);
402 
403   //
404   // Perform PEI Core Phase specific actions
405   //
406   if (OldCoreData == NULL) {
407     //
408     // Report Status Code EFI_SW_PC_INIT
409     //
410     REPORT_STATUS_CODE (
411       EFI_PROGRESS_CODE,
412       (EFI_SOFTWARE_PEI_CORE | EFI_SW_PC_INIT)
413       );
414 
415     //
416     // If SEC provided the PpiList, process it.
417     //
418     if (PpiList != NULL) {
419       ProcessPpiListFromSec ((CONST EFI_PEI_SERVICES **) &PrivateData.Ps, PpiList);
420     }
421   } else {
422     if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
423       //
424       // When PcdMigrateTemporaryRamFirmwareVolumes is TRUE, alway shadow all
425       // PEIMs no matter the condition of PcdShadowPeimOnBoot and PcdShadowPeimOnS3Boot
426       //
427       DEBUG ((DEBUG_VERBOSE, "PPI lists before temporary RAM evacuation:\n"));
428       DumpPpiList (&PrivateData);
429 
430       //
431       // Migrate installed content from Temporary RAM to Permanent RAM
432       //
433       EvacuateTempRam (&PrivateData, SecCoreData);
434 
435       DEBUG ((DEBUG_VERBOSE, "PPI lists after temporary RAM evacuation:\n"));
436       DumpPpiList (&PrivateData);
437     }
438 
439     //
440     // Try to locate Temporary RAM Done Ppi.
441     //
442     Status = PeiServicesLocatePpi (
443                &gEfiTemporaryRamDonePpiGuid,
444                0,
445                NULL,
446                (VOID**)&TemporaryRamDonePpi
447                );
448     if (!EFI_ERROR (Status)) {
449       //
450       // Disable the use of Temporary RAM after the transition from Temporary RAM to Permanent RAM is complete.
451       //
452       TemporaryRamDonePpi->TemporaryRamDone ();
453     }
454 
455     //
456     // Alert any listeners that there is permanent memory available
457     //
458     PERF_INMODULE_BEGIN ("DisMem");
459     Status = PeiServicesInstallPpi (&mMemoryDiscoveredPpi);
460 
461     //
462     // Process the Notify list and dispatch any notifies for the Memory Discovered PPI
463     //
464     ProcessDispatchNotifyList (&PrivateData);
465 
466     PERF_INMODULE_END ("DisMem");
467   }
468 
469   //
470   // Call PEIM dispatcher
471   //
472   PeiDispatcher (SecCoreData, &PrivateData);
473 
474   if (PrivateData.HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME) {
475     //
476     // Check if InstallPeiMemory service was called on non-S3 resume boot path.
477     //
478     ASSERT(PrivateData.PeiMemoryInstalled == TRUE);
479   }
480 
481   //
482   // Measure PEI Core execution time.
483   //
484   PERF_INMODULE_END ("PostMem");
485 
486   //
487   // Lookup DXE IPL PPI
488   //
489   Status = PeiServicesLocatePpi (
490              &gEfiDxeIplPpiGuid,
491              0,
492              NULL,
493              (VOID **)&TempPtr.DxeIpl
494              );
495   ASSERT_EFI_ERROR (Status);
496 
497   if (EFI_ERROR (Status)) {
498     //
499     // Report status code to indicate DXE IPL PPI could not be found.
500     //
501     REPORT_STATUS_CODE (
502       EFI_ERROR_CODE | EFI_ERROR_MAJOR,
503       (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_EC_DXEIPL_NOT_FOUND)
504       );
505     CpuDeadLoop ();
506   }
507 
508   //
509   // Enter DxeIpl to load Dxe core.
510   //
511   DEBUG ((EFI_D_INFO, "DXE IPL Entry\n"));
512   Status = TempPtr.DxeIpl->Entry (
513                              TempPtr.DxeIpl,
514                              &PrivateData.Ps,
515                              PrivateData.HobList
516                              );
517   //
518   // Should never reach here.
519   //
520   ASSERT_EFI_ERROR (Status);
521   CpuDeadLoop();
522 
523   UNREACHABLE ();
524 }
525