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