TianoCore EDK2 master
Loading...
Searching...
No Matches
SmmCpuFeaturesLib.c
Go to the documentation of this file.
1
10#include <Library/BaseLib.h>
12#include <Library/DebugLib.h>
15#include <Library/PcdLib.h>
16#include <Library/SafeIntLib.h>
20#include <Library/HobLib.h>
21#include <Pcd/CpuHotEjectData.h>
22#include <PiSmm.h>
25#include <Guid/SmmBaseHob.h>
26
27//
28// EFER register LMA bit
29//
30#define LMA BIT10
31
42EFIAPI
44 IN EFI_HANDLE ImageHandle,
45 IN EFI_SYSTEM_TABLE *SystemTable
46 )
47{
48 //
49 // If gSmmBaseHobGuid found, means SmBase info has been relocated and recorded
50 // in the SmBase array. ASSERT it's not supported in OVMF.
51 //
52 ASSERT (GetFirstGuidHob (&gSmmBaseHobGuid) == NULL);
53
54 //
55 // No need to program SMRRs on our virtual platform.
56 //
57 return EFI_SUCCESS;
58}
59
84VOID
85EFIAPI
87 IN UINTN CpuIndex,
88 IN BOOLEAN IsMonarch,
89 IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,
90 IN CPU_HOT_PLUG_DATA *CpuHotPlugData
91 )
92{
94
95 //
96 // Configure SMBASE.
97 //
98 CpuState = (QEMU_SMRAM_SAVE_STATE_MAP *)(UINTN)(
101 );
102 if ((CpuState->x86.SMMRevId & 0xFFFF) == 0) {
103 CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];
104 } else {
105 CpuState->x64.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];
106 }
107
108 //
109 // No need to program SMRRs on our virtual platform.
110 //
111}
112
144UINT64
145EFIAPI
147 IN UINTN CpuIndex,
148 IN SMRAM_SAVE_STATE_MAP *CpuState,
149 IN UINT64 NewInstructionPointer32,
150 IN UINT64 NewInstructionPointer
151 )
152{
153 UINT64 OriginalInstructionPointer;
154 QEMU_SMRAM_SAVE_STATE_MAP *CpuSaveState;
155
156 CpuSaveState = (QEMU_SMRAM_SAVE_STATE_MAP *)CpuState;
157 if ((CpuSaveState->x86.SMMRevId & 0xFFFF) == 0) {
158 OriginalInstructionPointer = (UINT64)CpuSaveState->x86._EIP;
159 CpuSaveState->x86._EIP = (UINT32)NewInstructionPointer;
160 //
161 // Clear the auto HALT restart flag so the RSM instruction returns
162 // program control to the instruction following the HLT instruction.
163 //
164 if ((CpuSaveState->x86.AutoHALTRestart & BIT0) != 0) {
165 CpuSaveState->x86.AutoHALTRestart &= ~BIT0;
166 }
167 } else {
168 OriginalInstructionPointer = CpuSaveState->x64._RIP;
169 if ((CpuSaveState->x64.IA32_EFER & LMA) == 0) {
170 CpuSaveState->x64._RIP = (UINT32)NewInstructionPointer32;
171 } else {
172 CpuSaveState->x64._RIP = (UINT32)NewInstructionPointer;
173 }
174
175 //
176 // Clear the auto HALT restart flag so the RSM instruction returns
177 // program control to the instruction following the HLT instruction.
178 //
179 if ((CpuSaveState->x64.AutoHALTRestart & BIT0) != 0) {
180 CpuSaveState->x64.AutoHALTRestart &= ~BIT0;
181 }
182 }
183
184 return OriginalInstructionPointer;
185}
186
187STATIC CPU_HOT_EJECT_DATA *mCpuHotEjectData = NULL;
188
194STATIC
195VOID
197 VOID
198 )
199{
200 UINTN Size;
201 UINT32 Idx;
202 UINT32 MaxNumberOfCpus;
203 RETURN_STATUS PcdStatus;
204
205 MaxNumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
206 if (MaxNumberOfCpus == 1) {
207 return;
208 }
209
210 //
211 // We allocate CPU_HOT_EJECT_DATA and CPU_HOT_EJECT_DATA->QemuSelectorMap[]
212 // in a single allocation, and explicitly align the QemuSelectorMap[] (which
213 // is a UINT64 array) at its natural boundary.
214 // Accordingly, allocate:
215 // sizeof(*mCpuHotEjectData) + (MaxNumberOfCpus * sizeof(UINT64))
216 // and, add sizeof(UINT64) - 1 to use as padding if needed.
217 //
218
219 if (RETURN_ERROR (SafeUintnMult (MaxNumberOfCpus, sizeof (UINT64), &Size)) ||
220 RETURN_ERROR (SafeUintnAdd (Size, sizeof (*mCpuHotEjectData), &Size)) ||
221 RETURN_ERROR (SafeUintnAdd (Size, sizeof (UINT64) - 1, &Size)))
222 {
223 DEBUG ((DEBUG_ERROR, "%a: invalid CPU_HOT_EJECT_DATA\n", __func__));
224 goto Fatal;
225 }
226
227 mCpuHotEjectData = AllocatePool (Size);
228 if (mCpuHotEjectData == NULL) {
229 ASSERT (mCpuHotEjectData != NULL);
230 goto Fatal;
231 }
232
233 mCpuHotEjectData->Handler = NULL;
234 mCpuHotEjectData->ArrayLength = MaxNumberOfCpus;
235
236 mCpuHotEjectData->QemuSelectorMap = ALIGN_POINTER (
237 mCpuHotEjectData + 1,
238 sizeof (UINT64)
239 );
240 //
241 // We use mCpuHotEjectData->QemuSelectorMap to map
242 // ProcessorNum -> QemuSelector. Initialize to invalid values.
243 //
244 for (Idx = 0; Idx < mCpuHotEjectData->ArrayLength; Idx++) {
245 mCpuHotEjectData->QemuSelectorMap[Idx] = CPU_EJECT_QEMU_SELECTOR_INVALID;
246 }
247
248 //
249 // Expose address of CPU Hot eject Data structure
250 //
251 PcdStatus = PcdSet64S (
252 PcdCpuHotEjectDataAddress,
253 (UINTN)(VOID *)mCpuHotEjectData
254 );
255 ASSERT_RETURN_ERROR (PcdStatus);
256
257 return;
258
259Fatal:
260 CpuDeadLoop ();
261}
262
270VOID
271EFIAPI
273 VOID
274 )
275{
276 EFI_STATUS Status;
277 UINTN MapPagesBase;
278 UINTN MapPagesCount;
279
281
282 if (!MemEncryptSevIsEnabled ()) {
283 return;
284 }
285
286 //
287 // Now that SMBASE relocation is complete, re-encrypt the original SMRAM save
288 // state map's container pages, and release the pages to DXE. (The pages were
289 // allocated in PlatformPei.)
290 //
292 &MapPagesBase,
293 &MapPagesCount
294 );
295 ASSERT_EFI_ERROR (Status);
296
298 0, // Cr3BaseAddress -- use current CR3
299 MapPagesBase, // BaseAddress
300 MapPagesCount // NumPages
301 );
302 if (EFI_ERROR (Status)) {
303 DEBUG ((
304 DEBUG_ERROR,
305 "%a: MemEncryptSevSetPageEncMask(): %r\n",
306 __func__,
307 Status
308 ));
309 ASSERT (FALSE);
310 CpuDeadLoop ();
311 }
312
313 ZeroMem ((VOID *)MapPagesBase, EFI_PAGES_TO_SIZE (MapPagesCount));
314
315 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
316 //
317 // The initial SMRAM Save State Map has been covered as part of a larger
318 // reserved memory allocation in PlatformPei's InitializeRamRegions(). That
319 // allocation is supposed to survive into OS runtime; we must not release
320 // any part of it. Only re-assert the containment here.
321 //
322 ASSERT (SMM_DEFAULT_SMBASE <= MapPagesBase);
323 ASSERT (
324 (MapPagesBase + EFI_PAGES_TO_SIZE (MapPagesCount) <=
325 SMM_DEFAULT_SMBASE + MCH_DEFAULT_SMBASE_SIZE)
326 );
327 } else {
328 Status = gBS->FreePages (MapPagesBase, MapPagesCount);
329 ASSERT_EFI_ERROR (Status);
330 }
331}
332
344UINTN
345EFIAPI
347 VOID
348 )
349{
350 return 0;
351}
352
378VOID
379EFIAPI
381 IN UINTN CpuIndex,
382 IN UINT32 SmBase,
383 IN VOID *SmiStack,
384 IN UINTN StackSize,
385 IN UINTN GdtBase,
386 IN UINTN GdtSize,
387 IN UINTN IdtBase,
388 IN UINTN IdtSize,
389 IN UINT32 Cr3
390 )
391{
392}
393
402BOOLEAN
403EFIAPI
405 VOID
406 )
407{
408 return FALSE;
409}
410
415VOID
416EFIAPI
418 VOID
419 )
420{
421 //
422 // No SMRR support, nothing to do
423 //
424}
425
430VOID
431EFIAPI
433 VOID
434 )
435{
436 //
437 // No SMRR support, nothing to do
438 //
439}
440
448VOID
449EFIAPI
451 IN UINTN CpuIndex
452 )
453{
454 //
455 // No SMRR support, nothing to do
456 //
457}
458
466VOID
467EFIAPI
469 IN UINTN CpuIndex
470 )
471{
472 //
473 // We only call the Handler if CPU hot-eject is enabled
474 // (PcdCpuMaxLogicalProcessorNumber > 1), and hot-eject is needed
475 // in this SMI exit (otherwise mCpuHotEjectData->Handler is not armed.)
476 //
477
478 if (mCpuHotEjectData != NULL) {
479 CPU_HOT_EJECT_HANDLER Handler;
480
481 //
482 // As the comment above mentions, mCpuHotEjectData->Handler might be
483 // written to on the BSP as part of handling of the CPU-ejection.
484 //
485 // We know that any initial assignment to mCpuHotEjectData->Handler
486 // (on the BSP, in the CpuHotplugMmi() context) is ordered-before the
487 // load below, since it is guaranteed to happen before the
488 // control-dependency of the BSP's SMI exit signal -- by way of a store
489 // to AllCpusInSync (on the BSP, in BspHandler()) and the corresponding
490 // AllCpusInSync loop (on the APs, in SmiRendezvous()) which depends on
491 // that store.
492 //
493 // This guarantees that these pieces of code can never execute
494 // simultaneously. In addition, we ensure that the following load is
495 // ordered-after the AllCpusInSync loop by using a MemoryFence() with
496 // acquire semantics.
497 //
498 MemoryFence ();
499
500 Handler = mCpuHotEjectData->Handler;
501
502 if (Handler != NULL) {
503 Handler (CpuIndex);
504 }
505 }
506}
507
521BOOLEAN
522EFIAPI
524 IN UINTN CpuIndex,
525 IN SMM_REG_NAME RegName
526 )
527{
528 ASSERT (RegName == SmmRegFeatureControl);
529 return FALSE;
530}
531
544UINT64
545EFIAPI
547 IN UINTN CpuIndex,
548 IN SMM_REG_NAME RegName
549 )
550{
551 //
552 // This is called for SmmRegSmmDelayed, SmmRegSmmBlocked, SmmRegSmmEnable.
553 // The last of these should actually be SmmRegSmmDisable, so we can just
554 // return FALSE.
555 //
556 return 0;
557}
558
570VOID
571EFIAPI
573 IN UINTN CpuIndex,
574 IN SMM_REG_NAME RegName,
575 IN UINT64 Value
576 )
577{
578 ASSERT (FALSE);
579}
580
585VOID
586EFIAPI
588 VOID
589 )
590{
591}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define RETURN_ERROR(StatusCode)
Definition: Base.h:1061
#define ALIGN_POINTER(Pointer, Alignment)
Definition: Base.h:963
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:23
VOID EFIAPI MemoryFence(VOID)
Definition: CpuBreakpoint.c:42
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID(EFIAPI * CPU_HOT_EJECT_HANDLER)(IN UINTN ProcessorNum)
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:445
#define ASSERT_RETURN_ERROR(StatusParameter)
Definition: DebugLib.h:471
#define DEBUG(Expression)
Definition: DebugLib.h:422
#define SMM_DEFAULT_SMBASE
#define SMRAM_SAVE_STATE_MAP_OFFSET
BOOLEAN EFIAPI MemEncryptSevIsEnabled(VOID)
RETURN_STATUS EFIAPI MemEncryptSevLocateInitialSmramSaveStateMapPages(OUT UINTN *BaseAddress, OUT UINTN *NumberOfPages)
RETURN_STATUS EFIAPI MemEncryptSevSetPageEncMask(IN PHYSICAL_ADDRESS Cr3BaseAddress, IN PHYSICAL_ADDRESS BaseAddress, IN UINTN NumPages)
UINT64 EFIAPI SmmCpuFeaturesGetSmmRegister(IN UINTN CpuIndex, IN SMM_REG_NAME RegName)
VOID EFIAPI SmmCpuFeaturesCompleteSmmReadyToLock(VOID)
UINT64 EFIAPI SmmCpuFeaturesHookReturnFromSmm(IN UINTN CpuIndex, IN SMRAM_SAVE_STATE_MAP *CpuState, IN UINT64 NewInstructionPointer32, IN UINT64 NewInstructionPointer)
VOID EFIAPI SmmCpuFeaturesSmmRelocationComplete(VOID)
VOID EFIAPI SmmCpuFeaturesInitializeProcessor(IN UINTN CpuIndex, IN BOOLEAN IsMonarch, IN EFI_PROCESSOR_INFORMATION *ProcessorInfo, IN CPU_HOT_PLUG_DATA *CpuHotPlugData)
VOID EFIAPI SmmCpuFeaturesRendezvousEntry(IN UINTN CpuIndex)
VOID EFIAPI SmmCpuFeaturesReenableSmrr(VOID)
BOOLEAN EFIAPI SmmCpuFeaturesIsSmmRegisterSupported(IN UINTN CpuIndex, IN SMM_REG_NAME RegName)
STATIC VOID InitCpuHotEjectData(VOID)
VOID EFIAPI SmmCpuFeaturesSetSmmRegister(IN UINTN CpuIndex, IN SMM_REG_NAME RegName, IN UINT64 Value)
EFI_STATUS EFIAPI SmmCpuFeaturesLibConstructor(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
BOOLEAN EFIAPI SmmCpuFeaturesNeedConfigureMtrrs(VOID)
VOID EFIAPI SmmCpuFeaturesInstallSmiHandler(IN UINTN CpuIndex, IN UINT32 SmBase, IN VOID *SmiStack, IN UINTN StackSize, IN UINTN GdtBase, IN UINTN GdtSize, IN UINTN IdtBase, IN UINTN IdtSize, IN UINT32 Cr3)
VOID EFIAPI SmmCpuFeaturesDisableSmrr(VOID)
VOID EFIAPI SmmCpuFeaturesRendezvousExit(IN UINTN CpuIndex)
UINTN EFIAPI SmmCpuFeaturesGetSmiHandlerSize(VOID)
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
#define PcdSet64S(TokenName, Value)
Definition: PcdLib.h:511
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFIAPI SafeUintnAdd(IN UINTN Augend, IN UINTN Addend, OUT UINTN *Result)
Definition: SafeIntLib32.c:338
RETURN_STATUS EFIAPI SafeUintnMult(IN UINTN Multiplicand, IN UINTN Multiplier, OUT UINTN *Result)
Definition: SafeIntLib32.c:430
SMM_REG_NAME
@ SmmRegFeatureControl
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS