]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
UefiCpuPkg: Replace Opcode with the corresponding instructions.
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ExceptionHandlerAsm.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
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 %assign Vector 0
36 %rep 32
37 push byte %[Vector]
38 push rax
39 mov rax, ASM_PFX(CommonInterruptEntry)
40 jmp rax
41 %assign Vector Vector+1
42 %endrep
43 AsmIdtVectorEnd:
44
45 HookAfterStubHeaderBegin:
46 db 0x6a ; push
47 @VectorNum:
48 db 0 ; 0 will be fixed
49 push rax
50 mov rax, HookAfterStubHeaderEnd
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 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 mov rax, ASM_PFX(CommonExceptionHandler)
278 call rax
279 add rsp, 4 * 8 + 8
280
281 cli
282 ;; UINT64 ExceptionData;
283 add rsp, 8
284
285 ;; FX_SAVE_STATE_X64 FxSaveState;
286
287 mov rsi, rsp
288 fxrstor [rsi]
289 add rsp, 512
290
291 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
292 ;; Skip restoration of DRx registers to support in-circuit emualators
293 ;; or debuggers set breakpoint in interrupt/exception context
294 add rsp, 8 * 6
295
296 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
297 pop rax
298 mov cr0, rax
299 add rsp, 8 ; not for Cr1
300 pop rax
301 mov cr2, rax
302 pop rax
303 mov cr3, rax
304 pop rax
305 mov cr4, rax
306 pop rax
307 mov cr8, rax
308
309 ;; UINT64 RFlags;
310 pop qword [rbp + 40]
311
312 ;; UINT64 Ldtr, Tr;
313 ;; UINT64 Gdtr[2], Idtr[2];
314 ;; Best not let anyone mess with these particular registers...
315 add rsp, 48
316
317 ;; UINT64 Rip;
318 pop qword [rbp + 24]
319
320 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
321 pop rax
322 ; mov gs, rax ; not for gs
323 pop rax
324 ; mov fs, rax ; not for fs
325 ; (X64 will not use fs and gs, so we do not restore it)
326 pop rax
327 mov es, rax
328 pop rax
329 mov ds, rax
330 pop qword [rbp + 32] ; for cs
331 pop qword [rbp + 56] ; for ss
332
333 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
334 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
335 pop rdi
336 pop rsi
337 add rsp, 8 ; not for rbp
338 pop qword [rbp + 48] ; for rsp
339 pop rbx
340 pop rdx
341 pop rcx
342 pop rax
343 pop r8
344 pop r9
345 pop r10
346 pop r11
347 pop r12
348 pop r13
349 pop r14
350 pop r15
351
352 mov rsp, rbp
353 pop rbp
354 add rsp, 16
355 cmp qword [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
356 jz DoReturn
357 cmp qword [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
358 jz ErrorCode
359 jmp qword [rsp - 32]
360 ErrorCode:
361 sub rsp, 8
362 jmp qword [rsp - 24]
363
364 DoReturn:
365 cmp qword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
366 jz DoIret
367 push rax
368 mov rax, rsp ; save old RSP to rax
369 mov rsp, [rsp + 0x20]
370 push qword [rax + 0x10] ; save CS in new location
371 push qword [rax + 0x8] ; save EIP in new location
372 push qword [rax + 0x18] ; save EFLAGS in new location
373 mov rax, [rax] ; restore rax
374 popfq ; restore EFLAGS
375 retfq
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 mov rax, AsmIdtVectorBegin
386 mov qword [rcx], rax
387 mov qword [rcx + 0x8], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
388 mov rax, HookAfterStubHeaderBegin
389 mov qword [rcx + 0x10], rax
390 ret
391
392 ;-------------------------------------------------------------------------------------
393 ; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
394 ;-------------------------------------------------------------------------------------
395 global ASM_PFX(AsmVectorNumFixup)
396 ASM_PFX(AsmVectorNumFixup):
397 mov rax, rdx
398 mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
399 ret
400