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