]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/SecCore/SecMain.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / SecCore / SecMain.c
1 /** @file
2 C functions in SEC
3
4 Copyright (c) 2008 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "SecMain.h"
10
11 EFI_PEI_TEMPORARY_RAM_DONE_PPI gSecTemporaryRamDonePpi = {
12 SecTemporaryRamDone
13 };
14
15 EFI_SEC_PLATFORM_INFORMATION_PPI mSecPlatformInformationPpi = { SecPlatformInformation };
16
17 EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformationPpi[] = {
18 {
19 //
20 // SecPerformance PPI notify descriptor.
21 //
22 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
23 &gPeiSecPerformancePpiGuid,
24 (VOID *)(UINTN)SecPerformancePpiCallBack
25 },
26 {
27 EFI_PEI_PPI_DESCRIPTOR_PPI,
28 &gEfiTemporaryRamDonePpiGuid,
29 &gSecTemporaryRamDonePpi
30 },
31 {
32 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
33 &gEfiSecPlatformInformationPpiGuid,
34 &mSecPlatformInformationPpi
35 }
36 };
37
38 /**
39 Migrates the Global Descriptor Table (GDT) to permanent memory.
40
41 @retval EFI_SUCCESS The GDT was migrated successfully.
42 @retval EFI_OUT_OF_RESOURCES The GDT could not be migrated due to lack of available memory.
43
44 **/
45 EFI_STATUS
46 MigrateGdt (
47 VOID
48 )
49 {
50 EFI_STATUS Status;
51 UINTN GdtBufferSize;
52 IA32_DESCRIPTOR Gdtr;
53 VOID *GdtBuffer;
54
55 AsmReadGdtr ((IA32_DESCRIPTOR *)&Gdtr);
56 GdtBufferSize = sizeof (IA32_SEGMENT_DESCRIPTOR) -1 + Gdtr.Limit + 1;
57
58 Status = PeiServicesAllocatePool (
59 GdtBufferSize,
60 &GdtBuffer
61 );
62 ASSERT (GdtBuffer != NULL);
63 if (EFI_ERROR (Status)) {
64 return EFI_OUT_OF_RESOURCES;
65 }
66
67 GdtBuffer = ALIGN_POINTER (GdtBuffer, sizeof (IA32_SEGMENT_DESCRIPTOR));
68 CopyMem (GdtBuffer, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
69 Gdtr.Base = (UINTN)GdtBuffer;
70 AsmWriteGdtr (&Gdtr);
71
72 return EFI_SUCCESS;
73 }
74
75 //
76 // These are IDT entries pointing to 10:FFFFFFE4h.
77 //
78 UINT64 mIdtEntryTemplate = 0xffff8e000010ffe4ULL;
79
80 /**
81 Caller provided function to be invoked at the end of InitializeDebugAgent().
82
83 Entry point to the C language phase of SEC. After the SEC assembly
84 code has initialized some temporary memory and set up the stack,
85 the control is transferred to this function.
86
87 @param[in] Context The first input parameter of InitializeDebugAgent().
88
89 **/
90 VOID
91 NORETURN
92 EFIAPI
93 SecStartupPhase2 (
94 IN VOID *Context
95 );
96
97 /**
98 Entry point of the notification callback function itself within the PEIM.
99 It is to get SEC performance data and build HOB to convey the SEC performance
100 data to DXE phase.
101
102 @param PeiServices Indirect reference to the PEI Services Table.
103 @param NotifyDescriptor Address of the notification descriptor data structure.
104 @param Ppi Address of the PPI that was installed.
105
106 @return Status of the notification.
107 The status code returned from this function is ignored.
108 **/
109 EFI_STATUS
110 EFIAPI
111 SecPerformancePpiCallBack (
112 IN EFI_PEI_SERVICES **PeiServices,
113 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
114 IN VOID *Ppi
115 )
116 {
117 EFI_STATUS Status;
118 PEI_SEC_PERFORMANCE_PPI *SecPerf;
119 FIRMWARE_SEC_PERFORMANCE Performance;
120
121 SecPerf = (PEI_SEC_PERFORMANCE_PPI *)Ppi;
122 Status = SecPerf->GetPerformance ((CONST EFI_PEI_SERVICES **)PeiServices, SecPerf, &Performance);
123 if (!EFI_ERROR (Status)) {
124 BuildGuidDataHob (
125 &gEfiFirmwarePerformanceGuid,
126 &Performance,
127 sizeof (FIRMWARE_SEC_PERFORMANCE)
128 );
129 DEBUG ((DEBUG_INFO, "FPDT: SEC Performance Hob ResetEnd = %ld\n", Performance.ResetEnd));
130 }
131
132 return Status;
133 }
134
135 /**
136
137 Entry point to the C language phase of SEC. After the SEC assembly
138 code has initialized some temporary memory and set up the stack,
139 the control is transferred to this function.
140
141
142 @param SizeOfRam Size of the temporary memory available for use.
143 @param TempRamBase Base address of temporary ram
144 @param BootFirmwareVolume Base address of the Boot Firmware Volume.
145 **/
146 VOID
147 NORETURN
148 EFIAPI
149 SecStartup (
150 IN UINT32 SizeOfRam,
151 IN UINT32 TempRamBase,
152 IN VOID *BootFirmwareVolume
153 )
154 {
155 EFI_SEC_PEI_HAND_OFF SecCoreData;
156 IA32_DESCRIPTOR IdtDescriptor;
157 SEC_IDT_TABLE IdtTableInStack;
158 UINT32 Index;
159 UINT32 PeiStackSize;
160 EFI_STATUS Status;
161
162 //
163 // Report Status Code to indicate entering SEC core
164 //
165 REPORT_STATUS_CODE (
166 EFI_PROGRESS_CODE,
167 EFI_SOFTWARE_SEC | EFI_SW_SEC_PC_ENTRY_POINT
168 );
169
170 DEBUG ((
171 DEBUG_INFO,
172 "%a() TempRAM Base: 0x%x, TempRAM Size: 0x%x, BootFirmwareVolume 0x%x\n",
173 __FUNCTION__,
174 TempRamBase,
175 SizeOfRam,
176 BootFirmwareVolume
177 ));
178
179 PeiStackSize = PcdGet32 (PcdPeiTemporaryRamStackSize);
180 if (PeiStackSize == 0) {
181 PeiStackSize = (SizeOfRam >> 1);
182 }
183
184 ASSERT (PeiStackSize < SizeOfRam);
185
186 //
187 // Process all libraries constructor function linked to SecCore.
188 //
189 ProcessLibraryConstructorList ();
190
191 //
192 // Initialize floating point operating environment
193 // to be compliant with UEFI spec.
194 //
195 InitializeFloatingPointUnits ();
196
197 // |-------------------|---->
198 // |IDT Table |
199 // |-------------------|
200 // |PeiService Pointer | PeiStackSize
201 // |-------------------|
202 // | |
203 // | Stack |
204 // |-------------------|---->
205 // | |
206 // | |
207 // | Heap | PeiTemporayRamSize
208 // | |
209 // | |
210 // |-------------------|----> TempRamBase
211
212 IdtTableInStack.PeiService = 0;
213 for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index++) {
214 ZeroMem ((VOID *)&IdtTableInStack.IdtTable[Index], sizeof (IA32_IDT_GATE_DESCRIPTOR));
215 CopyMem ((VOID *)&IdtTableInStack.IdtTable[Index], (VOID *)&mIdtEntryTemplate, sizeof (UINT64));
216 }
217
218 IdtDescriptor.Base = (UINTN)&IdtTableInStack.IdtTable;
219 IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
220
221 AsmWriteIdtr (&IdtDescriptor);
222
223 //
224 // Setup the default exception handlers
225 //
226 Status = InitializeCpuExceptionHandlers (NULL);
227 ASSERT_EFI_ERROR (Status);
228
229 //
230 // Update the base address and length of Pei temporary memory
231 //
232 SecCoreData.DataSize = (UINT16)sizeof (EFI_SEC_PEI_HAND_OFF);
233 SecCoreData.BootFirmwareVolumeBase = BootFirmwareVolume;
234 SecCoreData.BootFirmwareVolumeSize = (UINTN)((EFI_FIRMWARE_VOLUME_HEADER *)BootFirmwareVolume)->FvLength;
235 SecCoreData.TemporaryRamBase = (VOID *)(UINTN)TempRamBase;
236 SecCoreData.TemporaryRamSize = SizeOfRam;
237 SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
238 SecCoreData.PeiTemporaryRamSize = SizeOfRam - PeiStackSize;
239 SecCoreData.StackBase = (VOID *)(UINTN)(TempRamBase + SecCoreData.PeiTemporaryRamSize);
240 SecCoreData.StackSize = PeiStackSize;
241
242 DEBUG ((
243 DEBUG_INFO,
244 "%a() BFV Base: 0x%x, BFV Size: 0x%x, TempRAM Base: 0x%x, TempRAM Size: 0x%x, PeiTempRamBase: 0x%x, PeiTempRamSize: 0x%x, StackBase: 0x%x, StackSize: 0x%x\n",
245 __FUNCTION__,
246 SecCoreData.BootFirmwareVolumeBase,
247 SecCoreData.BootFirmwareVolumeSize,
248 SecCoreData.TemporaryRamBase,
249 SecCoreData.TemporaryRamSize,
250 SecCoreData.PeiTemporaryRamBase,
251 SecCoreData.PeiTemporaryRamSize,
252 SecCoreData.StackBase,
253 SecCoreData.StackSize
254 ));
255
256 //
257 // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
258 //
259 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
260
261 //
262 // Should not come here.
263 //
264 UNREACHABLE ();
265 }
266
267 /**
268 Caller provided function to be invoked at the end of InitializeDebugAgent().
269
270 Entry point to the C language phase of SEC. After the SEC assembly
271 code has initialized some temporary memory and set up the stack,
272 the control is transferred to this function.
273
274 @param[in] Context The first input parameter of InitializeDebugAgent().
275
276 **/
277 VOID
278 NORETURN
279 EFIAPI
280 SecStartupPhase2 (
281 IN VOID *Context
282 )
283 {
284 EFI_SEC_PEI_HAND_OFF *SecCoreData;
285 EFI_PEI_PPI_DESCRIPTOR *PpiList;
286 UINT32 Index;
287 EFI_PEI_PPI_DESCRIPTOR *AllSecPpiList;
288 EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;
289
290 PeiCoreEntryPoint = NULL;
291 SecCoreData = (EFI_SEC_PEI_HAND_OFF *)Context;
292
293 //
294 // Perform platform specific initialization before entering PeiCore.
295 //
296 PpiList = SecPlatformMain (SecCoreData);
297 //
298 // Find Pei Core entry point. It will report SEC and Pei Core debug information if remote debug
299 // is enabled.
300 //
301 if (PpiList != NULL) {
302 Index = 0;
303 do {
304 if (CompareGuid (PpiList[Index].Guid, &gEfiPeiCoreFvLocationPpiGuid) &&
305 (((EFI_PEI_CORE_FV_LOCATION_PPI *)PpiList[Index].Ppi)->PeiCoreFvLocation != 0)
306 )
307 {
308 //
309 // In this case, SecCore is in BFV but PeiCore is in another FV reported by PPI.
310 //
311 FindAndReportEntryPoints (
312 (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase,
313 (EFI_FIRMWARE_VOLUME_HEADER *)((EFI_PEI_CORE_FV_LOCATION_PPI *)PpiList[Index].Ppi)->PeiCoreFvLocation,
314 &PeiCoreEntryPoint
315 );
316 if (PeiCoreEntryPoint != NULL) {
317 break;
318 } else {
319 //
320 // Invalid PeiCore FV provided by platform
321 //
322 CpuDeadLoop ();
323 }
324 }
325 } while ((PpiList[Index++].Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) != EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
326 }
327
328 //
329 // If EFI_PEI_CORE_FV_LOCATION_PPI not found, try to locate PeiCore from BFV.
330 //
331 if (PeiCoreEntryPoint == NULL) {
332 //
333 // Both SecCore and PeiCore are in BFV.
334 //
335 FindAndReportEntryPoints (
336 (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase,
337 (EFI_FIRMWARE_VOLUME_HEADER *)SecCoreData->BootFirmwareVolumeBase,
338 &PeiCoreEntryPoint
339 );
340 if (PeiCoreEntryPoint == NULL) {
341 CpuDeadLoop ();
342 }
343 }
344
345 DEBUG ((
346 DEBUG_INFO,
347 "%a() PeiCoreEntryPoint: 0x%x\n",
348 __FUNCTION__,
349 PeiCoreEntryPoint
350 ));
351
352 if (PpiList != NULL) {
353 AllSecPpiList = (EFI_PEI_PPI_DESCRIPTOR *)SecCoreData->PeiTemporaryRamBase;
354
355 //
356 // Remove the terminal flag from the terminal PPI
357 //
358 CopyMem (AllSecPpiList, mPeiSecPlatformInformationPpi, sizeof (mPeiSecPlatformInformationPpi));
359 Index = sizeof (mPeiSecPlatformInformationPpi) / sizeof (EFI_PEI_PPI_DESCRIPTOR) - 1;
360 AllSecPpiList[Index].Flags = AllSecPpiList[Index].Flags & (~EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
361
362 //
363 // Append the platform additional PPI list
364 //
365 Index += 1;
366 while (((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) != EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)) {
367 CopyMem (&AllSecPpiList[Index], PpiList, sizeof (EFI_PEI_PPI_DESCRIPTOR));
368 Index++;
369 PpiList++;
370 }
371
372 //
373 // Add the terminal PPI
374 //
375 CopyMem (&AllSecPpiList[Index++], PpiList, sizeof (EFI_PEI_PPI_DESCRIPTOR));
376
377 //
378 // Set PpiList to the total PPI
379 //
380 PpiList = AllSecPpiList;
381
382 //
383 // Adjust PEI TEMP RAM Range.
384 //
385 ASSERT (SecCoreData->PeiTemporaryRamSize > Index * sizeof (EFI_PEI_PPI_DESCRIPTOR));
386 SecCoreData->PeiTemporaryRamBase = (VOID *)((UINTN)SecCoreData->PeiTemporaryRamBase + Index * sizeof (EFI_PEI_PPI_DESCRIPTOR));
387 SecCoreData->PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize - Index * sizeof (EFI_PEI_PPI_DESCRIPTOR);
388 //
389 // Adjust the Base and Size to be 8-byte aligned as HOB which has 8byte aligned requirement
390 // will be built based on them in PEI phase.
391 //
392 SecCoreData->PeiTemporaryRamBase = (VOID *)(((UINTN)SecCoreData->PeiTemporaryRamBase + 7) & ~0x07);
393 SecCoreData->PeiTemporaryRamSize &= ~(UINTN)0x07;
394 DEBUG ((
395 DEBUG_INFO,
396 "%a() PeiTemporaryRamBase: 0x%x, PeiTemporaryRamSize: 0x%x\n",
397 __FUNCTION__,
398 SecCoreData->PeiTemporaryRamBase,
399 SecCoreData->PeiTemporaryRamSize
400 ));
401 } else {
402 //
403 // No addition PPI, PpiList directly point to the common PPI list.
404 //
405 PpiList = &mPeiSecPlatformInformationPpi[0];
406 }
407
408 DEBUG ((
409 DEBUG_INFO,
410 "%a() Stack Base: 0x%p, Stack Size: 0x%x\n",
411 __FUNCTION__,
412 SecCoreData->StackBase,
413 (UINT32)SecCoreData->StackSize
414 ));
415
416 //
417 // Report Status Code to indicate transferring to PEI core
418 //
419 REPORT_STATUS_CODE (
420 EFI_PROGRESS_CODE,
421 EFI_SOFTWARE_SEC | EFI_SW_SEC_PC_HANDOFF_TO_NEXT
422 );
423
424 //
425 // Transfer the control to the PEI core
426 //
427 ASSERT (PeiCoreEntryPoint != NULL);
428 (*PeiCoreEntryPoint)(SecCoreData, PpiList);
429
430 //
431 // Should not come here.
432 //
433 UNREACHABLE ();
434 }
435
436 /**
437 TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked
438 by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed.
439
440 @retval EFI_SUCCESS Use of Temporary RAM was disabled.
441 @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled.
442
443 **/
444 EFI_STATUS
445 EFIAPI
446 SecTemporaryRamDone (
447 VOID
448 )
449 {
450 EFI_STATUS Status;
451 EFI_STATUS Status2;
452 UINTN Index;
453 BOOLEAN State;
454 EFI_PEI_PPI_DESCRIPTOR *PeiPpiDescriptor;
455 REPUBLISH_SEC_PPI_PPI *RepublishSecPpiPpi;
456
457 //
458 // Republish Sec Platform Information(2) PPI
459 //
460 RepublishSecPlatformInformationPpi ();
461
462 //
463 // Re-install SEC PPIs using a PEIM produced service if published
464 //
465 for (Index = 0, Status = EFI_SUCCESS; Status == EFI_SUCCESS; Index++) {
466 Status = PeiServicesLocatePpi (
467 &gRepublishSecPpiPpiGuid,
468 Index,
469 &PeiPpiDescriptor,
470 (VOID **)&RepublishSecPpiPpi
471 );
472 if (!EFI_ERROR (Status)) {
473 DEBUG ((DEBUG_INFO, "Calling RepublishSecPpi instance %d.\n", Index));
474 Status2 = RepublishSecPpiPpi->RepublishSecPpis ();
475 ASSERT_EFI_ERROR (Status2);
476 }
477 }
478
479 //
480 // Migrate DebugAgentContext.
481 //
482 InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL);
483
484 //
485 // Disable interrupts and save current interrupt state
486 //
487 State = SaveAndDisableInterrupts ();
488
489 //
490 // Migrate GDT before NEM near down
491 //
492 if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
493 Status = MigrateGdt ();
494 ASSERT_EFI_ERROR (Status);
495 }
496
497 //
498 // Disable Temporary RAM after Stack and Heap have been migrated at this point.
499 //
500 SecPlatformDisableTemporaryMemory ();
501
502 //
503 // Restore original interrupt state
504 //
505 SetInterruptState (State);
506
507 return EFI_SUCCESS;
508 }