]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/SecCore/SecMain.c
UefiCpuPkg: Move MigrateGdt from DiscoverMemory to TempRamDone. (CVE-2019-11098)
[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 PeiStackSize = PcdGet32 (PcdPeiTemporaryRamStackSize);
171 if (PeiStackSize == 0) {
172 PeiStackSize = (SizeOfRam >> 1);
173 }
174
175 ASSERT (PeiStackSize < SizeOfRam);
176
177 //
178 // Process all libraries constructor function linked to SecCore.
179 //
180 ProcessLibraryConstructorList ();
181
182 //
183 // Initialize floating point operating environment
184 // to be compliant with UEFI spec.
185 //
186 InitializeFloatingPointUnits ();
187
188 // |-------------------|---->
189 // |IDT Table |
190 // |-------------------|
191 // |PeiService Pointer | PeiStackSize
192 // |-------------------|
193 // | |
194 // | Stack |
195 // |-------------------|---->
196 // | |
197 // | |
198 // | Heap | PeiTemporayRamSize
199 // | |
200 // | |
201 // |-------------------|----> TempRamBase
202
203 IdtTableInStack.PeiService = 0;
204 for (Index = 0; Index < SEC_IDT_ENTRY_COUNT; Index ++) {
205 CopyMem ((VOID*)&IdtTableInStack.IdtTable[Index], (VOID*)&mIdtEntryTemplate, sizeof (UINT64));
206 }
207
208 IdtDescriptor.Base = (UINTN) &IdtTableInStack.IdtTable;
209 IdtDescriptor.Limit = (UINT16)(sizeof (IdtTableInStack.IdtTable) - 1);
210
211 AsmWriteIdtr (&IdtDescriptor);
212
213 //
214 // Setup the default exception handlers
215 //
216 Status = InitializeCpuExceptionHandlers (NULL);
217 ASSERT_EFI_ERROR (Status);
218
219 //
220 // Update the base address and length of Pei temporary memory
221 //
222 SecCoreData.DataSize = (UINT16) sizeof (EFI_SEC_PEI_HAND_OFF);
223 SecCoreData.BootFirmwareVolumeBase = BootFirmwareVolume;
224 SecCoreData.BootFirmwareVolumeSize = (UINTN)((EFI_FIRMWARE_VOLUME_HEADER *) BootFirmwareVolume)->FvLength;
225 SecCoreData.TemporaryRamBase = (VOID*)(UINTN) TempRamBase;
226 SecCoreData.TemporaryRamSize = SizeOfRam;
227 SecCoreData.PeiTemporaryRamBase = SecCoreData.TemporaryRamBase;
228 SecCoreData.PeiTemporaryRamSize = SizeOfRam - PeiStackSize;
229 SecCoreData.StackBase = (VOID*)(UINTN)(TempRamBase + SecCoreData.PeiTemporaryRamSize);
230 SecCoreData.StackSize = PeiStackSize;
231
232 //
233 // Initialize Debug Agent to support source level debug in SEC/PEI phases before memory ready.
234 //
235 InitializeDebugAgent (DEBUG_AGENT_INIT_PREMEM_SEC, &SecCoreData, SecStartupPhase2);
236
237 //
238 // Should not come here.
239 //
240 UNREACHABLE ();
241 }
242
243 /**
244 Caller provided function to be invoked at the end of InitializeDebugAgent().
245
246 Entry point to the C language phase of SEC. After the SEC assembly
247 code has initialized some temporary memory and set up the stack,
248 the control is transferred to this function.
249
250 @param[in] Context The first input parameter of InitializeDebugAgent().
251
252 **/
253 VOID
254 NORETURN
255 EFIAPI
256 SecStartupPhase2(
257 IN VOID *Context
258 )
259 {
260 EFI_SEC_PEI_HAND_OFF *SecCoreData;
261 EFI_PEI_PPI_DESCRIPTOR *PpiList;
262 UINT32 Index;
263 EFI_PEI_PPI_DESCRIPTOR *AllSecPpiList;
264 EFI_PEI_CORE_ENTRY_POINT PeiCoreEntryPoint;
265
266 PeiCoreEntryPoint = NULL;
267 SecCoreData = (EFI_SEC_PEI_HAND_OFF *) Context;
268
269 //
270 // Perform platform specific initialization before entering PeiCore.
271 //
272 PpiList = SecPlatformMain (SecCoreData);
273 //
274 // Find Pei Core entry point. It will report SEC and Pei Core debug information if remote debug
275 // is enabled.
276 //
277 if (PpiList != NULL) {
278 Index = 0;
279 do {
280 if (CompareGuid (PpiList[Index].Guid, &gEfiPeiCoreFvLocationPpiGuid) &&
281 (((EFI_PEI_CORE_FV_LOCATION_PPI *) PpiList[Index].Ppi)->PeiCoreFvLocation != 0)
282 ) {
283 //
284 // In this case, SecCore is in BFV but PeiCore is in another FV reported by PPI.
285 //
286 FindAndReportEntryPoints (
287 (EFI_FIRMWARE_VOLUME_HEADER *) SecCoreData->BootFirmwareVolumeBase,
288 (EFI_FIRMWARE_VOLUME_HEADER *) ((EFI_PEI_CORE_FV_LOCATION_PPI *) PpiList[Index].Ppi)->PeiCoreFvLocation,
289 &PeiCoreEntryPoint
290 );
291 if (PeiCoreEntryPoint != NULL) {
292 break;
293 } else {
294 //
295 // Invalid PeiCore FV provided by platform
296 //
297 CpuDeadLoop ();
298 }
299 }
300 } while ((PpiList[Index++].Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) != EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
301 }
302 //
303 // If EFI_PEI_CORE_FV_LOCATION_PPI not found, try to locate PeiCore from BFV.
304 //
305 if (PeiCoreEntryPoint == NULL) {
306 //
307 // Both SecCore and PeiCore are in BFV.
308 //
309 FindAndReportEntryPoints (
310 (EFI_FIRMWARE_VOLUME_HEADER *) SecCoreData->BootFirmwareVolumeBase,
311 (EFI_FIRMWARE_VOLUME_HEADER *) SecCoreData->BootFirmwareVolumeBase,
312 &PeiCoreEntryPoint
313 );
314 if (PeiCoreEntryPoint == NULL) {
315 CpuDeadLoop ();
316 }
317 }
318
319 if (PpiList != NULL) {
320 AllSecPpiList = (EFI_PEI_PPI_DESCRIPTOR *) SecCoreData->PeiTemporaryRamBase;
321
322 //
323 // Remove the terminal flag from the terminal PPI
324 //
325 CopyMem (AllSecPpiList, mPeiSecPlatformInformationPpi, sizeof (mPeiSecPlatformInformationPpi));
326 Index = sizeof (mPeiSecPlatformInformationPpi) / sizeof (EFI_PEI_PPI_DESCRIPTOR) - 1;
327 AllSecPpiList[Index].Flags = AllSecPpiList[Index].Flags & (~EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
328
329 //
330 // Append the platform additional PPI list
331 //
332 Index += 1;
333 while (((PpiList->Flags & EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST) != EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST)) {
334 CopyMem (&AllSecPpiList[Index], PpiList, sizeof (EFI_PEI_PPI_DESCRIPTOR));
335 Index++;
336 PpiList++;
337 }
338
339 //
340 // Add the terminal PPI
341 //
342 CopyMem (&AllSecPpiList[Index ++], PpiList, sizeof (EFI_PEI_PPI_DESCRIPTOR));
343
344 //
345 // Set PpiList to the total PPI
346 //
347 PpiList = AllSecPpiList;
348
349 //
350 // Adjust PEI TEMP RAM Range.
351 //
352 ASSERT (SecCoreData->PeiTemporaryRamSize > Index * sizeof (EFI_PEI_PPI_DESCRIPTOR));
353 SecCoreData->PeiTemporaryRamBase = (VOID *)((UINTN) SecCoreData->PeiTemporaryRamBase + Index * sizeof (EFI_PEI_PPI_DESCRIPTOR));
354 SecCoreData->PeiTemporaryRamSize = SecCoreData->PeiTemporaryRamSize - Index * sizeof (EFI_PEI_PPI_DESCRIPTOR);
355 //
356 // Adjust the Base and Size to be 8-byte aligned as HOB which has 8byte aligned requirement
357 // will be built based on them in PEI phase.
358 //
359 SecCoreData->PeiTemporaryRamBase = (VOID *)(((UINTN)SecCoreData->PeiTemporaryRamBase + 7) & ~0x07);
360 SecCoreData->PeiTemporaryRamSize &= ~(UINTN)0x07;
361 } else {
362 //
363 // No addition PPI, PpiList directly point to the common PPI list.
364 //
365 PpiList = &mPeiSecPlatformInformationPpi[0];
366 }
367
368 DEBUG ((
369 DEBUG_INFO,
370 "%a() Stack Base: 0x%p, Stack Size: 0x%x\n",
371 __FUNCTION__,
372 SecCoreData->StackBase,
373 (UINT32) SecCoreData->StackSize
374 ));
375
376 //
377 // Report Status Code to indicate transferring to PEI core
378 //
379 REPORT_STATUS_CODE (
380 EFI_PROGRESS_CODE,
381 EFI_SOFTWARE_SEC | EFI_SW_SEC_PC_HANDOFF_TO_NEXT
382 );
383
384 //
385 // Transfer the control to the PEI core
386 //
387 ASSERT (PeiCoreEntryPoint != NULL);
388 (*PeiCoreEntryPoint) (SecCoreData, PpiList);
389
390 //
391 // Should not come here.
392 //
393 UNREACHABLE ();
394 }
395
396 /**
397 TemporaryRamDone() disables the use of Temporary RAM. If present, this service is invoked
398 by the PEI Foundation after the EFI_PEI_PERMANANT_MEMORY_INSTALLED_PPI is installed.
399
400 @retval EFI_SUCCESS Use of Temporary RAM was disabled.
401 @retval EFI_INVALID_PARAMETER Temporary RAM could not be disabled.
402
403 **/
404 EFI_STATUS
405 EFIAPI
406 SecTemporaryRamDone (
407 VOID
408 )
409 {
410 EFI_STATUS Status;
411 EFI_STATUS Status2;
412 UINTN Index;
413 BOOLEAN State;
414 EFI_PEI_PPI_DESCRIPTOR *PeiPpiDescriptor;
415 REPUBLISH_SEC_PPI_PPI *RepublishSecPpiPpi;
416
417 //
418 // Republish Sec Platform Information(2) PPI
419 //
420 RepublishSecPlatformInformationPpi ();
421
422 //
423 // Re-install SEC PPIs using a PEIM produced service if published
424 //
425 for (Index = 0, Status = EFI_SUCCESS; Status == EFI_SUCCESS; Index++) {
426 Status = PeiServicesLocatePpi (
427 &gRepublishSecPpiPpiGuid,
428 Index,
429 &PeiPpiDescriptor,
430 (VOID **) &RepublishSecPpiPpi
431 );
432 if (!EFI_ERROR (Status)) {
433 DEBUG ((DEBUG_INFO, "Calling RepublishSecPpi instance %d.\n", Index));
434 Status2 = RepublishSecPpiPpi->RepublishSecPpis ();
435 ASSERT_EFI_ERROR (Status2);
436 }
437 }
438
439 //
440 // Migrate DebugAgentContext.
441 //
442 InitializeDebugAgent (DEBUG_AGENT_INIT_POSTMEM_SEC, NULL, NULL);
443
444 //
445 // Disable interrupts and save current interrupt state
446 //
447 State = SaveAndDisableInterrupts ();
448
449 //
450 // Migrate GDT before NEM near down
451 //
452 if (PcdGetBool (PcdMigrateTemporaryRamFirmwareVolumes)) {
453 Status = MigrateGdt ();
454 ASSERT_EFI_ERROR (Status);
455 }
456
457 //
458 // Disable Temporary RAM after Stack and Heap have been migrated at this point.
459 //
460 SecPlatformDisableTemporaryMemory ();
461
462 //
463 // Restore original interrupt state
464 //
465 SetInterruptState (State);
466
467 return EFI_SUCCESS;
468 }