TianoCore EDK2 master
Loading...
Searching...
No Matches
SmmFuncsArch.c
Go to the documentation of this file.
1
9#include "PiSmmCpuCommon.h"
10
11EFI_PHYSICAL_ADDRESS mGdtBuffer;
12UINTN mGdtBufferSize;
13
14extern BOOLEAN mCetSupported;
15
16X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;
17X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;
18X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSspTable;
19UINT32 mCetPl0Ssp;
20UINT32 mCetInterruptSsp;
21UINT32 mCetInterruptSspTable;
22
23UINTN mSmmInterruptSspTables;
24
32VOID
33EFIAPI
35 IN EFI_EXCEPTION_TYPE ExceptionType,
36 IN UINT8 Ist
37 )
38{
39 IA32_IDT_GATE_DESCRIPTOR *IdtGate;
40
41 IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;
42 IdtGate += ExceptionType;
43 IdtGate->Bits.Reserved_0 = Ist;
44}
45
55VOID *
57 IN UINTN Cr3,
58 OUT UINTN *GdtStepSize
59 )
60{
61 UINTN Index;
62 IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;
63 UINTN TssBase;
64 UINTN GdtTssTableSize;
65 UINT8 *GdtTssTables;
66 UINTN GdtTableStepSize;
67
68 //
69 // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
70 // on each SMI entry.
71 //
72 GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned
73 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
74 GdtTssTables = (UINT8 *)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
75 ASSERT (GdtTssTables != NULL);
76 mGdtBuffer = (UINTN)GdtTssTables;
77 GdtTableStepSize = GdtTssTableSize;
78
79 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
80 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID *)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);
81
82 //
83 // Fixup TSS descriptors
84 //
85 TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
86 GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
87 GdtDescriptor->Bits.BaseLow = (UINT16)(UINTN)TssBase;
88 GdtDescriptor->Bits.BaseMid = (UINT8)((UINTN)TssBase >> 16);
89 GdtDescriptor->Bits.BaseHigh = (UINT8)((UINTN)TssBase >> 24);
90
91 if ((FeaturePcdGet (PcdCpuSmmStackGuard)) || ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported)) {
92 //
93 // Setup top of known good stack as IST1 for each processor.
94 //
95 *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * (mSmmStackSize + mSmmShadowStackSize));
96 }
97 }
98
99 *GdtStepSize = GdtTableStepSize;
100 return GdtTssTables;
101}
102
108UINT16
110 VOID
111 )
112{
113 IA32_DESCRIPTOR GdtrDesc;
114 IA32_SEGMENT_DESCRIPTOR *GdtEntry;
115 UINTN GdtEntryCount;
116 UINT16 Index;
117
118 AsmReadGdtr (&GdtrDesc);
119 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
120 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *)GdtrDesc.Base;
121 for (Index = 0; (UINTN)Index < GdtEntryCount; Index++) {
122 if (GdtEntry->Bits.L == 0) {
123 if ((GdtEntry->Bits.Type > 8) && (GdtEntry->Bits.DB == 1)) {
124 break;
125 }
126 }
127
128 GdtEntry++;
129 }
130
131 ASSERT (Index != GdtEntryCount);
132 return Index * 8;
133}
134
141VOID
143 IN UINTN CpuIndex,
144 IN VOID *ShadowStack
145 )
146{
147 UINTN SmmShadowStackSize;
148 UINT64 *InterruptSspTable;
149 UINT32 InterruptSsp;
150
151 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
152 SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));
153 //
154 // Add 1 page as known good shadow stack
155 //
156 SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);
157
158 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
159 //
160 // Add one guard page between Known Good Shadow Stack and SMM Shadow Stack.
161 //
162 SmmShadowStackSize += EFI_PAGES_TO_SIZE (1);
163 }
164
165 mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof (UINT64));
166 PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);
167 DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp));
168 DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));
169 DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));
170
171 if (mSmmInterruptSspTables == 0) {
172 mSmmInterruptSspTables = (UINTN)AllocateZeroPool (sizeof (UINT64) * 8 * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus);
173 ASSERT (mSmmInterruptSspTables != 0);
174 DEBUG ((DEBUG_INFO, "mSmmInterruptSspTables - 0x%x\n", mSmmInterruptSspTables));
175 }
176
177 //
178 // The highest address on the stack (0xFE0) is a save-previous-ssp token pointing to a location that is 40 bytes away - 0xFB8.
179 // The supervisor shadow stack token is just above it at address 0xFD8. This is where the interrupt SSP table points.
180 // So when an interrupt of exception occurs, we can use SAVESSP/RESTORESSP/CLEARSSBUSY for the supervisor shadow stack,
181 // due to the reason the RETF in SMM exception handler cannot clear the BUSY flag with same CPL.
182 // (only IRET or RETF with different CPL can clear BUSY flag)
183 // Please refer to UefiCpuPkg/Library/CpuExceptionHandlerLib/X64 for the full stack frame at runtime.
184 // According to SDM (ver. 075 June 2021), shadow stack should be 32 bytes aligned.
185 //
186 InterruptSsp = (UINT32)(((UINTN)ShadowStack + EFI_PAGES_TO_SIZE (1) - (sizeof (UINT64) * 4)) & ~0x1f);
187 *(UINT64 *)(UINTN)InterruptSsp = (InterruptSsp - sizeof (UINT64) * 4) | 0x2;
188 mCetInterruptSsp = InterruptSsp - sizeof (UINT64);
189
190 mCetInterruptSspTable = (UINT32)(UINTN)(mSmmInterruptSspTables + sizeof (UINT64) * 8 * CpuIndex);
191 InterruptSspTable = (UINT64 *)(UINTN)mCetInterruptSspTable;
192 InterruptSspTable[1] = mCetInterruptSsp;
193 PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);
194 PatchInstructionX86 (mPatchCetInterruptSspTable, mCetInterruptSspTable, 4);
195 DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));
196 DEBUG ((DEBUG_INFO, "mCetInterruptSspTable - 0x%x\n", mCetInterruptSspTable));
197 }
198}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
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
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
#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
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 InitializeIdtIst(IN EFI_EXCEPTION_TYPE ExceptionType, IN UINT8 Ist)
Definition: SmmFuncsArch.c:34
UINT16 GetProtectedModeCS(VOID)
Definition: SmmFuncsArch.c:109
VOID EFIAPI PatchInstructionX86(OUT X86_ASSEMBLY_PATCH_LABEL *InstructionEnd, IN UINT64 PatchValue, IN UINTN ValueSize)
VOID EFIAPI AsmReadGdtr(OUT IA32_DESCRIPTOR *Gdtr)
Definition: X86ReadGdtr.c:24