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