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