TianoCore EDK2 master
Loading...
Searching...
No Matches
SmmFuncsArch.c
Go to the documentation of this file.
1
9#include "PiSmmCpuCommon.h"
10
11extern UINT64 gTaskGateDescriptor;
12
13EFI_PHYSICAL_ADDRESS mGdtBuffer;
14UINTN mGdtBufferSize;
15
16extern BOOLEAN mCetSupported;
17
18X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;
19X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;
20UINT32 mCetPl0Ssp;
21UINT32 mCetInterruptSsp;
22
27VOID
28EFIAPI
30 VOID
31 )
32{
33 IA32_IDT_GATE_DESCRIPTOR *IdtGate;
34
35 //
36 // If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
37 // is a Task Gate Descriptor so that when a Page Fault Exception occurs,
38 // the processors can use a known good stack in case stack is ran out.
39 //
40 IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;
41 IdtGate += EXCEPT_IA32_PAGE_FAULT;
42 IdtGate->Uint64 = gTaskGateDescriptor;
43}
44
54VOID *
56 IN UINTN Cr3,
57 OUT UINTN *GdtStepSize
58 )
59{
60 UINTN Index;
61 IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;
62 UINTN TssBase;
63 UINTN GdtTssTableSize;
64 UINT8 *GdtTssTables;
65 UINTN GdtTableStepSize;
66 UINTN InterruptShadowStack;
67
68 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
69 //
70 // For IA32 SMM, if SMM Stack Guard feature is enabled, we use 2 TSS.
71 // in this case, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
72 // on each SMI entry.
73 //
74
75 //
76 // Enlarge GDT to contain 2 TSS descriptors
77 //
78 gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
79
80 GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE + 7) & ~7; // 8 bytes aligned
81 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
82 //
83 // IA32 Stack Guard need use task switch to switch stack that need
84 // write GDT and TSS, so AllocateCodePages() could not be used here
85 // as code pages will be set to RO.
86 //
87 GdtTssTables = (UINT8 *)AllocatePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
88 ASSERT (GdtTssTables != NULL);
89 mGdtBuffer = (UINTN)GdtTssTables;
90 GdtTableStepSize = GdtTssTableSize;
91
92 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
93 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE);
94 //
95 // Fixup TSS descriptors
96 //
97 TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
98 GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
99 GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
100 GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
101 GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
102
103 TssBase += TSS_SIZE;
104 GdtDescriptor++;
105 GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
106 GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
107 GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
108 //
109 // Fixup TSS segments
110 //
111 // ESP as known good stack
112 //
113 *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
114 *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
115
116 //
117 // Setup ShadowStack for stack switch
118 //
119 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
120 InterruptShadowStack = (UINTN)(mSmmStackArrayBase + mSmmStackSize + EFI_PAGES_TO_SIZE (1) - sizeof (UINT64) + (mSmmStackSize + mSmmShadowStackSize) * Index);
121 *(UINT32 *)(TssBase + TSS_IA32_SSP_OFFSET) = (UINT32)InterruptShadowStack;
122 }
123 }
124 } else {
125 //
126 // Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.
127 //
128 GdtTssTableSize = gcSmiGdtr.Limit + 1;
129 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
130 GdtTssTables = (UINT8 *)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
131 ASSERT (GdtTssTables != NULL);
132 mGdtBuffer = (UINTN)GdtTssTables;
133 GdtTableStepSize = GdtTssTableSize;
134
135 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
136 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1);
137 }
138 }
139
140 *GdtStepSize = GdtTableStepSize;
141 return GdtTssTables;
142}
143
150VOID
152 IN UINTN CpuIndex,
153 IN VOID *ShadowStack
154 )
155{
156 UINTN SmmShadowStackSize;
157
158 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
159 SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));
160 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
161 SmmShadowStackSize += EFI_PAGES_TO_SIZE (2);
162 }
163
164 mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof (UINT64));
165 PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);
166 DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp));
167 DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));
168 DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));
169
170 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
171 mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE (1) - sizeof (UINT64));
172 PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);
173 DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));
174 }
175 }
176}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID EFIAPI InitializeIDTSmmStackGuard(VOID)
Definition: SmmFuncsArch.c:29
VOID InitShadowStack(IN UINTN CpuIndex, IN VOID *ShadowStack)
Definition: SmmFuncsArch.c:151
VOID * InitGdt(IN UINTN Cr3, OUT UINTN *GdtStepSize)
Definition: SmmFuncsArch.c:55
#define NULL
Definition: Base.h:319
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
STATIC VOID *EFIAPI AllocateCodePages(IN UINTN Pages)
Definition: PrePiLib.c:28
VOID *EFIAPI AllocatePages(IN UINTN Pages)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
VOID EFIAPI PatchInstructionX86(OUT X86_ASSEMBLY_PATCH_LABEL *InstructionEnd, IN UINT64 PatchValue, IN UINTN ValueSize)