]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmmFuncsArch.c
e44eb5c6d9bcd7ca5381beda6186aad3396b7f21
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / Ia32 / SmmFuncsArch.c
1 /** @file
2 SMM CPU misc functions for Ia32 arch specific.
3
4 Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "PiSmmCpuDxeSmm.h"
16
17 extern UINT64 gTaskGateDescriptor;
18
19 EFI_PHYSICAL_ADDRESS mGdtBuffer;
20 UINTN mGdtBufferSize;
21
22 extern BOOLEAN mCetSupported;
23 extern UINTN mSmmShadowStackSize;
24
25 X86_ASSEMBLY_PATCH_LABEL mPatchCetPl0Ssp;
26 X86_ASSEMBLY_PATCH_LABEL mPatchCetInterruptSsp;
27 UINT32 mCetPl0Ssp;
28 UINT32 mCetInterruptSsp;
29
30 /**
31 Initialize IDT for SMM Stack Guard.
32
33 **/
34 VOID
35 EFIAPI
36 InitializeIDTSmmStackGuard (
37 VOID
38 )
39 {
40 IA32_IDT_GATE_DESCRIPTOR *IdtGate;
41
42 //
43 // If SMM Stack Guard feature is enabled, the Page Fault Exception entry in IDT
44 // is a Task Gate Descriptor so that when a Page Fault Exception occurs,
45 // the processors can use a known good stack in case stack is ran out.
46 //
47 IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)gcSmiIdtr.Base;
48 IdtGate += EXCEPT_IA32_PAGE_FAULT;
49 IdtGate->Uint64 = gTaskGateDescriptor;
50 }
51
52 /**
53 Initialize Gdt for all processors.
54
55 @param[in] Cr3 CR3 value.
56 @param[out] GdtStepSize The step size for GDT table.
57
58 @return GdtBase for processor 0.
59 GdtBase for processor X is: GdtBase + (GdtStepSize * X)
60 **/
61 VOID *
62 InitGdt (
63 IN UINTN Cr3,
64 OUT UINTN *GdtStepSize
65 )
66 {
67 UINTN Index;
68 IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;
69 UINTN TssBase;
70 UINTN GdtTssTableSize;
71 UINT8 *GdtTssTables;
72 UINTN GdtTableStepSize;
73 UINTN InterruptShadowStack;
74
75 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
76 //
77 // For IA32 SMM, if SMM Stack Guard feature is enabled, we use 2 TSS.
78 // in this case, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
79 // on each SMI entry.
80 //
81
82 //
83 // Enlarge GDT to contain 2 TSS descriptors
84 //
85 gcSmiGdtr.Limit += (UINT16)(2 * sizeof (IA32_SEGMENT_DESCRIPTOR));
86
87 GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE + 7) & ~7; // 8 bytes aligned
88 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
89 //
90 // IA32 Stack Guard need use task switch to switch stack that need
91 // write GDT and TSS, so AllocateCodePages() could not be used here
92 // as code pages will be set to RO.
93 //
94 GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
95 ASSERT (GdtTssTables != NULL);
96 mGdtBuffer = (UINTN)GdtTssTables;
97 GdtTableStepSize = GdtTssTableSize;
98
99 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
100 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE + EXCEPTION_TSS_SIZE);
101 //
102 // Fixup TSS descriptors
103 //
104 TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
105 GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
106 GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
107 GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
108 GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
109
110 TssBase += TSS_SIZE;
111 GdtDescriptor++;
112 GdtDescriptor->Bits.BaseLow = (UINT16)TssBase;
113 GdtDescriptor->Bits.BaseMid = (UINT8)(TssBase >> 16);
114 GdtDescriptor->Bits.BaseHigh = (UINT8)(TssBase >> 24);
115 //
116 // Fixup TSS segments
117 //
118 // ESP as known good stack
119 //
120 *(UINTN *)(TssBase + TSS_IA32_ESP_OFFSET) = mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize;
121 *(UINT32 *)(TssBase + TSS_IA32_CR3_OFFSET) = Cr3;
122
123 //
124 // Setup ShadowStack for stack switch
125 //
126 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
127 InterruptShadowStack = (UINTN)(mSmmStackArrayBase + mSmmStackSize + EFI_PAGES_TO_SIZE (1) - sizeof(UINT64) + (mSmmStackSize + mSmmShadowStackSize) * Index);
128 *(UINT32 *)(TssBase + TSS_IA32_SSP_OFFSET) = (UINT32)InterruptShadowStack;
129 }
130 }
131 } else {
132 //
133 // Just use original table, AllocatePage and copy them here to make sure GDTs are covered in page memory.
134 //
135 GdtTssTableSize = gcSmiGdtr.Limit + 1;
136 mGdtBufferSize = GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus;
137 GdtTssTables = (UINT8*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize));
138 ASSERT (GdtTssTables != NULL);
139 mGdtBuffer = (UINTN)GdtTssTables;
140 GdtTableStepSize = GdtTssTableSize;
141
142 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
143 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1);
144 }
145 }
146
147 *GdtStepSize = GdtTableStepSize;
148 return GdtTssTables;
149 }
150
151 /**
152 Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.
153
154 @param[in] ApHltLoopCode The address of the safe hlt-loop function.
155 @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.
156 @param[in] NumberToFinishAddress Address of Semaphore of APs finish count.
157
158 **/
159 VOID
160 TransferApToSafeState (
161 IN UINTN ApHltLoopCode,
162 IN UINTN TopOfStack,
163 IN UINTN NumberToFinishAddress
164 )
165 {
166 SwitchStack (
167 (SWITCH_STACK_ENTRY_POINT)ApHltLoopCode,
168 (VOID *)NumberToFinishAddress,
169 NULL,
170 (VOID *)TopOfStack
171 );
172 //
173 // It should never reach here
174 //
175 ASSERT (FALSE);
176 }
177
178 /**
179 Initialize the shadow stack related data structure.
180
181 @param CpuIndex The index of CPU.
182 @param ShadowStack The bottom of the shadow stack for this CPU.
183 **/
184 VOID
185 InitShadowStack (
186 IN UINTN CpuIndex,
187 IN VOID *ShadowStack
188 )
189 {
190 UINTN SmmShadowStackSize;
191
192 if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {
193 SmmShadowStackSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmShadowStackSize)));
194 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
195 SmmShadowStackSize += EFI_PAGES_TO_SIZE (2);
196 }
197 mCetPl0Ssp = (UINT32)((UINTN)ShadowStack + SmmShadowStackSize - sizeof(UINT64));
198 PatchInstructionX86 (mPatchCetPl0Ssp, mCetPl0Ssp, 4);
199 DEBUG ((DEBUG_INFO, "mCetPl0Ssp - 0x%x\n", mCetPl0Ssp));
200 DEBUG ((DEBUG_INFO, "ShadowStack - 0x%x\n", ShadowStack));
201 DEBUG ((DEBUG_INFO, " SmmShadowStackSize - 0x%x\n", SmmShadowStackSize));
202
203 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
204 mCetInterruptSsp = (UINT32)((UINTN)ShadowStack + EFI_PAGES_TO_SIZE(1) - sizeof(UINT64));
205 PatchInstructionX86 (mPatchCetInterruptSsp, mCetInterruptSsp, 4);
206 DEBUG ((DEBUG_INFO, "mCetInterruptSsp - 0x%x\n", mCetInterruptSsp));
207 }
208 }
209 }
210