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