]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerAsm.nasm
UefiCpuPkg/CpuExceptionHandlerLib: Clear CET shadow stack token busy bit
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / Xcode5ExceptionHandlerAsm.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
3 ; SPDX-License-Identifier: BSD-2-Clause-Patent
4 ;
5 ; Module Name:
6 ;
7 ; ExceptionHandlerAsm.Asm
8 ;
9 ; Abstract:
10 ;
11 ; x64 CPU Exception Handler
12 ;
13 ; Notes:
14 ;
15 ;------------------------------------------------------------------------------
16 %include "Nasm.inc"
17
18 ;
19 ; CommonExceptionHandler()
20 ;
21
22 %define VC_EXCEPTION 29
23
24 extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions
25 extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag
26 extern ASM_PFX(CommonExceptionHandler)
27 extern ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
28
29 SECTION .data
30
31 DEFAULT REL
32 SECTION .text
33
34 ALIGN 8
35
36 AsmIdtVectorBegin:
37 %rep 32
38 db 0x6a ; push #VectorNum
39 db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
40 push rax
41 mov rax, strict qword 0 ; mov rax, ASM_PFX(CommonInterruptEntry)
42 jmp rax
43 %endrep
44 AsmIdtVectorEnd:
45
46 HookAfterStubHeaderBegin:
47 db 0x6a ; push
48 @VectorNum:
49 db 0 ; 0 will be fixed
50 push rax
51 mov rax, strict qword 0 ; mov rax, HookAfterStubHeaderEnd
52 JmpAbsoluteAddress:
53 jmp rax
54 HookAfterStubHeaderEnd:
55 mov rax, rsp
56 and sp, 0xfff0 ; make sure 16-byte aligned for exception context
57 sub rsp, 0x18 ; reserve room for filling exception data later
58 push rcx
59 mov rcx, [rax + 8]
60 bt [ASM_PFX(mErrorCodeFlag)], ecx
61 jnc .0
62 push qword [rsp] ; push additional rcx to make stack alignment
63 .0:
64 xchg rcx, [rsp] ; restore rcx, save Exception Number in stack
65 push qword [rax] ; push rax into stack to keep code consistence
66
67 ;---------------------------------------;
68 ; CommonInterruptEntry ;
69 ;---------------------------------------;
70 ; The follow algorithm is used for the common interrupt routine.
71 ; Entry from each interrupt with a push eax and eax=interrupt number
72 ; Stack frame would be as follows as specified in IA32 manuals:
73 ;
74 ; +---------------------+ <-- 16-byte aligned ensured by processor
75 ; + Old SS +
76 ; +---------------------+
77 ; + Old RSP +
78 ; +---------------------+
79 ; + RFlags +
80 ; +---------------------+
81 ; + CS +
82 ; +---------------------+
83 ; + RIP +
84 ; +---------------------+
85 ; + Error Code +
86 ; +---------------------+
87 ; + Vector Number +
88 ; +---------------------+
89 ; + RBP +
90 ; +---------------------+ <-- RBP, 16-byte aligned
91 ; The follow algorithm is used for the common interrupt routine.
92 global ASM_PFX(CommonInterruptEntry)
93 ASM_PFX(CommonInterruptEntry):
94 cli
95 pop rax
96 ;
97 ; All interrupt handlers are invoked through interrupt gates, so
98 ; IF flag automatically cleared at the entry point
99 ;
100 xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx
101 and rcx, 0xFF
102 cmp ecx, 32 ; Intel reserved vector for exceptions?
103 jae NoErrorCode
104 bt [ASM_PFX(mErrorCodeFlag)], ecx
105 jc HasErrorCode
106
107 NoErrorCode:
108
109 ;
110 ; Push a dummy error code on the stack
111 ; to maintain coherent stack map
112 ;
113 push qword [rsp]
114 mov qword [rsp + 8], 0
115 HasErrorCode:
116 push rbp
117 mov rbp, rsp
118 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
119 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
120
121 ;
122 ; Stack:
123 ; +---------------------+ <-- 16-byte aligned ensured by processor
124 ; + Old SS +
125 ; +---------------------+
126 ; + Old RSP +
127 ; +---------------------+
128 ; + RFlags +
129 ; +---------------------+
130 ; + CS +
131 ; +---------------------+
132 ; + RIP +
133 ; +---------------------+
134 ; + Error Code +
135 ; +---------------------+
136 ; + RCX / Vector Number +
137 ; +---------------------+
138 ; + RBP +
139 ; +---------------------+ <-- RBP, 16-byte aligned
140 ;
141
142 ;
143 ; Since here the stack pointer is 16-byte aligned, so
144 ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
145 ; is 16-byte aligned
146 ;
147
148 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
149 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
150 push r15
151 push r14
152 push r13
153 push r12
154 push r11
155 push r10
156 push r9
157 push r8
158 push rax
159 push qword [rbp + 8] ; RCX
160 push rdx
161 push rbx
162 push qword [rbp + 48] ; RSP
163 push qword [rbp] ; RBP
164 push rsi
165 push rdi
166
167 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
168 movzx rax, word [rbp + 56]
169 push rax ; for ss
170 movzx rax, word [rbp + 32]
171 push rax ; for cs
172 mov rax, ds
173 push rax
174 mov rax, es
175 push rax
176 mov rax, fs
177 push rax
178 mov rax, gs
179 push rax
180
181 mov [rbp + 8], rcx ; save vector number
182
183 ;; UINT64 Rip;
184 push qword [rbp + 24]
185
186 ;; UINT64 Gdtr[2], Idtr[2];
187 xor rax, rax
188 push rax
189 push rax
190 sidt [rsp]
191 mov bx, word [rsp]
192 mov rax, qword [rsp + 2]
193 mov qword [rsp], rax
194 mov word [rsp + 8], bx
195
196 xor rax, rax
197 push rax
198 push rax
199 sgdt [rsp]
200 mov bx, word [rsp]
201 mov rax, qword [rsp + 2]
202 mov qword [rsp], rax
203 mov word [rsp + 8], bx
204
205 ;; UINT64 Ldtr, Tr;
206 xor rax, rax
207 str ax
208 push rax
209 sldt ax
210 push rax
211
212 ;; UINT64 RFlags;
213 push qword [rbp + 40]
214
215 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
216 mov rax, cr8
217 push rax
218 mov rax, cr4
219 or rax, 0x208
220 mov cr4, rax
221 push rax
222 mov rax, cr3
223 push rax
224 mov rax, cr2
225 push rax
226 xor rax, rax
227 push rax
228 mov rax, cr0
229 push rax
230
231 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
232 cmp qword [rbp + 8], VC_EXCEPTION
233 je VcDebugRegs ; For SEV-ES (#VC) Debug registers ignored
234
235 mov rax, dr7
236 push rax
237 mov rax, dr6
238 push rax
239 mov rax, dr3
240 push rax
241 mov rax, dr2
242 push rax
243 mov rax, dr1
244 push rax
245 mov rax, dr0
246 push rax
247 jmp DrFinish
248
249 VcDebugRegs:
250 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 are skipped for #VC to avoid exception recursion
251 xor rax, rax
252 push rax
253 push rax
254 push rax
255 push rax
256 push rax
257 push rax
258
259 DrFinish:
260 ;; FX_SAVE_STATE_X64 FxSaveState;
261 sub rsp, 512
262 mov rdi, rsp
263 db 0xf, 0xae, 0x7 ;fxsave [rdi]
264
265 ;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
266 cld
267
268 ;; UINT32 ExceptionData;
269 push qword [rbp + 16]
270
271 ;; Prepare parameter and call
272 mov rcx, [rbp + 8]
273 mov rdx, rsp
274 ;
275 ; Per X64 calling convention, allocate maximum parameter stack space
276 ; and make sure RSP is 16-byte aligned
277 ;
278 sub rsp, 4 * 8 + 8
279 call ASM_PFX(CommonExceptionHandler)
280 add rsp, 4 * 8 + 8
281
282 cli
283 ;; UINT64 ExceptionData;
284 add rsp, 8
285
286 ;; FX_SAVE_STATE_X64 FxSaveState;
287
288 mov rsi, rsp
289 db 0xf, 0xae, 0xE ; fxrstor [rsi]
290 add rsp, 512
291
292 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
293 ;; Skip restoration of DRx registers to support in-circuit emualators
294 ;; or debuggers set breakpoint in interrupt/exception context
295 add rsp, 8 * 6
296
297 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
298 pop rax
299 mov cr0, rax
300 add rsp, 8 ; not for Cr1
301 pop rax
302 mov cr2, rax
303 pop rax
304 mov cr3, rax
305 pop rax
306 mov cr4, rax
307 pop rax
308 mov cr8, rax
309
310 ;; UINT64 RFlags;
311 pop qword [rbp + 40]
312
313 ;; UINT64 Ldtr, Tr;
314 ;; UINT64 Gdtr[2], Idtr[2];
315 ;; Best not let anyone mess with these particular registers...
316 add rsp, 48
317
318 ;; UINT64 Rip;
319 pop qword [rbp + 24]
320
321 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
322 pop rax
323 ; mov gs, rax ; not for gs
324 pop rax
325 ; mov fs, rax ; not for fs
326 ; (X64 will not use fs and gs, so we do not restore it)
327 pop rax
328 mov es, rax
329 pop rax
330 mov ds, rax
331 pop qword [rbp + 32] ; for cs
332 pop qword [rbp + 56] ; for ss
333
334 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
335 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
336 pop rdi
337 pop rsi
338 add rsp, 8 ; not for rbp
339 pop qword [rbp + 48] ; for rsp
340 pop rbx
341 pop rdx
342 pop rcx
343 pop rax
344 pop r8
345 pop r9
346 pop r10
347 pop r11
348 pop r12
349 pop r13
350 pop r14
351 pop r15
352
353 mov rsp, rbp
354 pop rbp
355 add rsp, 16
356 cmp qword [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
357 jz DoReturn
358 cmp qword [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
359 jz ErrorCode
360 jmp qword [rsp - 32]
361 ErrorCode:
362 sub rsp, 8
363 jmp qword [rsp - 24]
364
365 DoReturn:
366 cmp qword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
367 jz DoIret
368 push rax
369 mov rax, rsp ; save old RSP to rax
370 mov rsp, [rsp + 0x20]
371 push qword [rax + 0x10] ; save CS in new location
372 push qword [rax + 0x8] ; save EIP in new location
373 push qword [rax + 0x18] ; save EFLAGS in new location
374 mov rax, [rax] ; restore rax
375 popfq ; restore EFLAGS
376
377 ; The follow algorithm is used for clear shadow stack token busy bit.
378 ; The comment is based on the sample shadow stack.
379 ; The sample shadow stack layout :
380 ; Address | Context
381 ; +-------------------------+
382 ; 0xFD0 | FREE | it is 0xFD8|0x02|(LMA & CS.L), after SAVEPREVSSP.
383 ; +-------------------------+
384 ; 0xFD8 | Prev SSP |
385 ; +-------------------------+
386 ; 0xFE0 | RIP |
387 ; +-------------------------+
388 ; 0xFE8 | CS |
389 ; +-------------------------+
390 ; 0xFF0 | 0xFF0 | BUSY | BUSY flag cleared after CLRSSBSY
391 ; +-------------------------+
392 ; 0xFF8 | 0xFD8|0x02|(LMA & CS.L) |
393 ; +-------------------------+
394 ; Instructions for Intel Control Flow Enforcement Technology (CET) are supported since NASM version 2.15.01.
395 push rax ; SSP should be 0xFD8 at this point
396 cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))], 0
397 jz CetDone
398 mov rax, cr4
399 and rax, 0x800000 ; check if CET is enabled
400 jz CetDone
401 mov rax, 0x04 ; advance past cs:lip:prevssp;supervisor shadow stack token
402 INCSSP_RAX ; After this SSP should be 0xFF8
403 SAVEPREVSSP ; now the shadow stack restore token will be created at 0xFD0
404 READSSP_RAX ; Read new SSP, SSP should be 0x1000
405 push rax
406 sub rax, 0x10
407 CLRSSBSY_RAX ; Clear token at 0xFF0, SSP should be 0 after this
408 sub rax, 0x20
409 RSTORSSP_RAX ; Restore to token at 0xFD0, new SSP will be 0xFD0
410 pop rax
411 mov rax, 0x01 ; Pop off the new save token created
412 INCSSP_RAX ; SSP should be 0xFD8 now
413 CetDone:
414 pop rax ; restore rax
415
416 DB 0x48 ; prefix to composite "retq" with next "retf"
417 retf ; far return
418 DoIret:
419 iretq
420
421 ;-------------------------------------------------------------------------------------
422 ; GetTemplateAddressMap (&AddressMap);
423 ;-------------------------------------------------------------------------------------
424 ; comments here for definition of address map
425 global ASM_PFX(AsmGetTemplateAddressMap)
426 ASM_PFX(AsmGetTemplateAddressMap):
427 lea rax, [AsmIdtVectorBegin]
428 mov qword [rcx], rax
429 mov qword [rcx + 0x8], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
430 lea rax, [HookAfterStubHeaderBegin]
431 mov qword [rcx + 0x10], rax
432
433 ; Fix up CommonInterruptEntry address
434 lea rax, [ASM_PFX(CommonInterruptEntry)]
435 lea rcx, [AsmIdtVectorBegin]
436 %rep 32
437 mov qword [rcx + (JmpAbsoluteAddress - 8 - HookAfterStubHeaderBegin)], rax
438 add rcx, (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
439 %endrep
440 ; Fix up HookAfterStubHeaderEnd
441 lea rax, [HookAfterStubHeaderEnd]
442 lea rcx, [JmpAbsoluteAddress]
443 mov qword [rcx - 8], rax
444
445 ret
446
447 ;-------------------------------------------------------------------------------------
448 ; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
449 ;-------------------------------------------------------------------------------------
450 global ASM_PFX(AsmVectorNumFixup)
451 ASM_PFX(AsmVectorNumFixup):
452 mov rax, rdx
453 mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
454 ret
455