]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmiEntry.nasm
UefiCpuPkg/PiSmmCpu: Add Shadow Stack Support for X86 SMM.
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / X64 / SmiEntry.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
3 ; This program and the accompanying materials
4 ; are licensed and made available under the terms and conditions of the BSD License
5 ; which accompanies this distribution. The full text of the license may be found at
6 ; http://opensource.org/licenses/bsd-license.php.
7 ;
8 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10 ;
11 ; Module Name:
12 ;
13 ; SmiEntry.nasm
14 ;
15 ; Abstract:
16 ;
17 ; Code template of the SMI handler for a particular processor
18 ;
19 ;-------------------------------------------------------------------------------
20
21 %include "StuffRsbNasm.inc"
22 %include "Nasm.inc"
23
24 ;
25 ; Variables referrenced by C code
26 ;
27
28 %define MSR_IA32_S_CET 0x6A2
29 %define MSR_IA32_CET_SH_STK_EN 0x1
30 %define MSR_IA32_CET_WR_SHSTK_EN 0x2
31 %define MSR_IA32_CET_ENDBR_EN 0x4
32 %define MSR_IA32_CET_LEG_IW_EN 0x8
33 %define MSR_IA32_CET_NO_TRACK_EN 0x10
34 %define MSR_IA32_CET_SUPPRESS_DIS 0x20
35 %define MSR_IA32_CET_SUPPRESS 0x400
36 %define MSR_IA32_CET_TRACKER 0x800
37 %define MSR_IA32_PL0_SSP 0x6A4
38 %define MSR_IA32_INTERRUPT_SSP_TABLE_ADDR 0x6A8
39
40 %define CR4_CET 0x800000
41
42 %define MSR_IA32_MISC_ENABLE 0x1A0
43 %define MSR_EFER 0xc0000080
44 %define MSR_EFER_XD 0x800
45
46 ;
47 ; Constants relating to PROCESSOR_SMM_DESCRIPTOR
48 ;
49 %define DSC_OFFSET 0xfb00
50 %define DSC_GDTPTR 0x30
51 %define DSC_GDTSIZ 0x38
52 %define DSC_CS 14
53 %define DSC_DS 16
54 %define DSC_SS 18
55 %define DSC_OTHERSEG 20
56 ;
57 ; Constants relating to CPU State Save Area
58 ;
59 %define SSM_DR6 0xffd0
60 %define SSM_DR7 0xffc8
61
62 %define PROTECT_MODE_CS 0x8
63 %define PROTECT_MODE_DS 0x20
64 %define LONG_MODE_CS 0x38
65 %define TSS_SEGMENT 0x40
66 %define GDT_SIZE 0x50
67
68 extern ASM_PFX(SmiRendezvous)
69 extern ASM_PFX(gSmiHandlerIdtr)
70 extern ASM_PFX(CpuSmmDebugEntry)
71 extern ASM_PFX(CpuSmmDebugExit)
72
73 global ASM_PFX(gPatchSmbase)
74 extern ASM_PFX(mXdSupported)
75 global ASM_PFX(gPatchXdSupported)
76 global ASM_PFX(gPatchSmiStack)
77 global ASM_PFX(gPatchSmiCr3)
78 global ASM_PFX(gcSmiHandlerTemplate)
79 global ASM_PFX(gcSmiHandlerSize)
80
81 extern ASM_PFX(mCetSupported)
82 global ASM_PFX(mPatchCetSupported)
83 global ASM_PFX(mPatchCetPl0Ssp)
84 global ASM_PFX(mPatchCetInterruptSsp)
85 global ASM_PFX(mPatchCetInterruptSspTable)
86
87 DEFAULT REL
88 SECTION .text
89
90 BITS 16
91 ASM_PFX(gcSmiHandlerTemplate):
92 _SmiEntryPoint:
93 mov bx, _GdtDesc - _SmiEntryPoint + 0x8000
94 mov ax,[cs:DSC_OFFSET + DSC_GDTSIZ]
95 dec ax
96 mov [cs:bx], ax
97 mov eax, [cs:DSC_OFFSET + DSC_GDTPTR]
98 mov [cs:bx + 2], eax
99 o32 lgdt [cs:bx] ; lgdt fword ptr cs:[bx]
100 mov ax, PROTECT_MODE_CS
101 mov [cs:bx-0x2],ax
102 mov edi, strict dword 0 ; source operand will be patched
103 ASM_PFX(gPatchSmbase):
104 lea eax, [edi + (@ProtectedMode - _SmiEntryPoint) + 0x8000]
105 mov [cs:bx-0x6],eax
106 mov ebx, cr0
107 and ebx, 0x9ffafff3
108 or ebx, 0x23
109 mov cr0, ebx
110 jmp dword 0x0:0x0
111 _GdtDesc:
112 DW 0
113 DD 0
114
115 BITS 32
116 @ProtectedMode:
117 mov ax, PROTECT_MODE_DS
118 o16 mov ds, ax
119 o16 mov es, ax
120 o16 mov fs, ax
121 o16 mov gs, ax
122 o16 mov ss, ax
123 mov esp, strict dword 0 ; source operand will be patched
124 ASM_PFX(gPatchSmiStack):
125 jmp ProtFlatMode
126
127 BITS 64
128 ProtFlatMode:
129 mov eax, strict dword 0 ; source operand will be patched
130 ASM_PFX(gPatchSmiCr3):
131 mov cr3, rax
132 mov eax, 0x668 ; as cr4.PGE is not set here, refresh cr3
133 mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
134 ; Load TSS
135 sub esp, 8 ; reserve room in stack
136 sgdt [rsp]
137 mov eax, [rsp + 2] ; eax = GDT base
138 add esp, 8
139 mov dl, 0x89
140 mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag
141 mov eax, TSS_SEGMENT
142 ltr ax
143
144 ; enable NXE if supported
145 mov al, strict byte 1 ; source operand may be patched
146 ASM_PFX(gPatchXdSupported):
147 cmp al, 0
148 jz @SkipXd
149 ;
150 ; Check XD disable bit
151 ;
152 mov ecx, MSR_IA32_MISC_ENABLE
153 rdmsr
154 sub esp, 4
155 push rdx ; save MSR_IA32_MISC_ENABLE[63-32]
156 test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
157 jz .0
158 and dx, 0xFFFB ; clear XD Disable bit if it is set
159 wrmsr
160 .0:
161 mov ecx, MSR_EFER
162 rdmsr
163 or ax, MSR_EFER_XD ; enable NXE
164 wrmsr
165 jmp @XdDone
166 @SkipXd:
167 sub esp, 8
168 @XdDone:
169
170 ; Switch into @LongMode
171 push LONG_MODE_CS ; push cs hardcore here
172 call Base ; push return address for retf later
173 Base:
174 add dword [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
175
176 mov ecx, MSR_EFER
177 rdmsr
178 or ah, 1 ; enable LME
179 wrmsr
180 mov rbx, cr0
181 or ebx, 0x80010023 ; enable paging + WP + NE + MP + PE
182 mov cr0, rbx
183 retf
184 @LongMode: ; long mode (64-bit code) starts here
185 mov rax, strict qword 0 ; mov rax, ASM_PFX(gSmiHandlerIdtr)
186 SmiHandlerIdtrAbsAddr:
187 lidt [rax]
188 lea ebx, [rdi + DSC_OFFSET]
189 mov ax, [rbx + DSC_DS]
190 mov ds, eax
191 mov ax, [rbx + DSC_OTHERSEG]
192 mov es, eax
193 mov fs, eax
194 mov gs, eax
195 mov ax, [rbx + DSC_SS]
196 mov ss, eax
197
198 mov rbx, [rsp + 0x8] ; rbx <- CpuIndex
199
200 ; enable CET if supported
201 mov al, strict byte 1 ; source operand may be patched
202 ASM_PFX(mPatchCetSupported):
203 cmp al, 0
204 jz CetDone
205
206 mov ecx, MSR_IA32_S_CET
207 rdmsr
208 push rdx
209 push rax
210
211 mov ecx, MSR_IA32_PL0_SSP
212 rdmsr
213 push rdx
214 push rax
215
216 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
217 rdmsr
218 push rdx
219 push rax
220
221 mov ecx, MSR_IA32_S_CET
222 mov eax, MSR_IA32_CET_SH_STK_EN
223 xor edx, edx
224 wrmsr
225
226 mov ecx, MSR_IA32_PL0_SSP
227 mov eax, strict dword 0 ; source operand will be patched
228 ASM_PFX(mPatchCetPl0Ssp):
229 xor edx, edx
230 wrmsr
231 mov rcx, cr0
232 btr ecx, 16 ; clear WP
233 mov cr0, rcx
234 mov [eax], eax ; reload SSP, and clear busyflag.
235 xor ecx, ecx
236 mov [eax + 4], ecx
237
238 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
239 mov eax, strict dword 0 ; source operand will be patched
240 ASM_PFX(mPatchCetInterruptSspTable):
241 xor edx, edx
242 wrmsr
243
244 mov eax, strict dword 0 ; source operand will be patched
245 ASM_PFX(mPatchCetInterruptSsp):
246 cmp eax, 0
247 jz CetInterruptDone
248 mov [eax], eax ; reload SSP, and clear busyflag.
249 xor ecx, ecx
250 mov [eax + 4], ecx
251 CetInterruptDone:
252
253 mov rcx, cr0
254 bts ecx, 16 ; set WP
255 mov cr0, rcx
256
257 mov eax, 0x668 | CR4_CET
258 mov cr4, rax
259
260 SETSSBSY
261
262 CetDone:
263
264 ;
265 ; Save FP registers
266 ;
267 sub rsp, 0x200
268 fxsave64 [rsp]
269
270 add rsp, -0x20
271
272 mov rcx, rbx
273 mov rax, strict qword 0 ; call ASM_PFX(CpuSmmDebugEntry)
274 CpuSmmDebugEntryAbsAddr:
275 call rax
276
277 mov rcx, rbx
278 mov rax, strict qword 0 ; call ASM_PFX(SmiRendezvous)
279 SmiRendezvousAbsAddr:
280 call rax
281
282 mov rcx, rbx
283 mov rax, strict qword 0 ; call ASM_PFX(CpuSmmDebugExit)
284 CpuSmmDebugExitAbsAddr:
285 call rax
286
287 add rsp, 0x20
288
289 ;
290 ; Restore FP registers
291 ;
292 fxrstor64 [rsp]
293
294 add rsp, 0x200
295
296 mov rax, strict qword 0 ; mov rax, ASM_PFX(mCetSupported)
297 mCetSupportedAbsAddr:
298 mov al, [rax]
299 cmp al, 0
300 jz CetDone2
301
302 mov eax, 0x668
303 mov cr4, rax ; disable CET
304
305 mov ecx, MSR_IA32_INTERRUPT_SSP_TABLE_ADDR
306 pop rax
307 pop rdx
308 wrmsr
309
310 mov ecx, MSR_IA32_PL0_SSP
311 pop rax
312 pop rdx
313 wrmsr
314
315 mov ecx, MSR_IA32_S_CET
316 pop rax
317 pop rdx
318 wrmsr
319 CetDone2:
320
321 mov rax, strict qword 0 ; lea rax, [ASM_PFX(mXdSupported)]
322 mXdSupportedAbsAddr:
323 mov al, [rax]
324 cmp al, 0
325 jz .1
326 pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
327 test edx, BIT2
328 jz .1
329 mov ecx, MSR_IA32_MISC_ENABLE
330 rdmsr
331 or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
332 wrmsr
333
334 .1:
335
336 StuffRsb64
337 rsm
338
339 ASM_PFX(gcSmiHandlerSize) DW $ - _SmiEntryPoint
340
341 ;
342 ; Retrieve the address and fill it into mov opcode.
343 ;
344 ; It is called in the driver entry point first.
345 ; It is used to fix up the real address in mov opcode.
346 ; Then, after the code logic is copied to the different location,
347 ; the code can also run.
348 ;
349 global ASM_PFX(PiSmmCpuSmiEntryFixupAddress)
350 ASM_PFX(PiSmmCpuSmiEntryFixupAddress):
351 lea rax, [ASM_PFX(gSmiHandlerIdtr)]
352 lea rcx, [SmiHandlerIdtrAbsAddr]
353 mov qword [rcx - 8], rax
354
355 lea rax, [ASM_PFX(CpuSmmDebugEntry)]
356 lea rcx, [CpuSmmDebugEntryAbsAddr]
357 mov qword [rcx - 8], rax
358
359 lea rax, [ASM_PFX(SmiRendezvous)]
360 lea rcx, [SmiRendezvousAbsAddr]
361 mov qword [rcx - 8], rax
362
363 lea rax, [ASM_PFX(CpuSmmDebugExit)]
364 lea rcx, [CpuSmmDebugExitAbsAddr]
365 mov qword [rcx - 8], rax
366
367 lea rax, [ASM_PFX(mXdSupported)]
368 lea rcx, [mXdSupportedAbsAddr]
369 mov qword [rcx - 8], rax
370
371 lea rax, [ASM_PFX(mCetSupported)]
372 lea rcx, [mCetSupportedAbsAddr]
373 mov qword [rcx - 8], rax
374 ret