]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.asm
Fix bug when reserve stack space to fill exception context.
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ExceptionHandlerAsm.asm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
3 ; This program and the accompanying materials
4 ; are licensed and made available under the terms and conditions of the BSD License
5 ; which accompanies this distribution. The full text of the license may be found at
6 ; http://opensource.org/licenses/bsd-license.php.
7 ;
8 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10 ;
11 ; Module Name:
12 ;
13 ; ExceptionHandlerAsm.Asm
14 ;
15 ; Abstract:
16 ;
17 ; x64 CPU Exception Handler
18 ;
19 ; Notes:
20 ;
21 ;------------------------------------------------------------------------------
22
23 ;
24 ; CommonExceptionHandler()
25 ;
26 externdef CommonExceptionHandler:near
27
28 EXTRN mErrorCodeFlag:DWORD ; Error code flags for exceptions
29 EXTRN mDoFarReturnFlag:QWORD ; Do far return flag
30
31 data SEGMENT
32
33 .code
34
35 ALIGN 8
36
37 AsmIdtVectorBegin:
38 REPEAT 32
39 db 6ah ; push #VectorNum
40 db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
41 push rax
42 mov rax, CommonInterruptEntry
43 jmp rax
44 ENDM
45 AsmIdtVectorEnd:
46
47 HookAfterStubHeaderBegin:
48 db 6ah ; push
49 @VectorNum:
50 db 0 ; 0 will be fixed
51 push rax
52 mov rax, HookAfterStubHeaderEnd
53 jmp rax
54 HookAfterStubHeaderEnd:
55 mov rax, rsp
56 and sp, 0fff0h ; make sure 16-byte aligned for exception context
57 sub rsp, 18h ; reserve room for filling exception data later
58 push rcx
59 mov rcx, [rax + 8]
60 bt mErrorCodeFlag, ecx
61 jnc @F
62 push [rsp] ; push additional rcx to make stack alignment
63 @@:
64 xchg rcx, [rsp] ; restore rcx, save Exception Number in stack
65 push [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 CommonInterruptEntry PROC PUBLIC
93 cli
94 pop rax
95 ;
96 ; All interrupt handlers are invoked through interrupt gates, so
97 ; IF flag automatically cleared at the entry point
98 ;
99 xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx
100 and rcx, 0FFh
101 cmp ecx, 32 ; Intel reserved vector for exceptions?
102 jae NoErrorCode
103 bt mErrorCodeFlag, ecx
104 jc @F
105
106 NoErrorCode:
107
108 ;
109 ; Push a dummy error code on the stack
110 ; to maintain coherent stack map
111 ;
112 push [rsp]
113 mov qword ptr [rsp + 8], 0
114 @@:
115 push rbp
116 mov rbp, rsp
117 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
118 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
119
120 ;
121 ; Stack:
122 ; +---------------------+ <-- 16-byte aligned ensured by processor
123 ; + Old SS +
124 ; +---------------------+
125 ; + Old RSP +
126 ; +---------------------+
127 ; + RFlags +
128 ; +---------------------+
129 ; + CS +
130 ; +---------------------+
131 ; + RIP +
132 ; +---------------------+
133 ; + Error Code +
134 ; +---------------------+
135 ; + RCX / Vector Number +
136 ; +---------------------+
137 ; + RBP +
138 ; +---------------------+ <-- RBP, 16-byte aligned
139 ;
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 ptr [rbp + 8] ; RCX
160 push rdx
161 push rbx
162 push qword ptr [rbp + 48] ; RSP
163 push qword ptr [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 ptr [rbp + 56]
169 push rax ; for ss
170 movzx rax, word ptr [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 ptr [rbp + 24]
185
186 ;; UINT64 Gdtr[2], Idtr[2];
187 xor rax, rax
188 push rax
189 push rax
190 sidt [rsp]
191 xchg rax, [rsp + 2]
192 xchg rax, [rsp]
193 xchg rax, [rsp + 8]
194
195 xor rax, rax
196 push rax
197 push rax
198 sgdt [rsp]
199 xchg rax, [rsp + 2]
200 xchg rax, [rsp]
201 xchg rax, [rsp + 8]
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 ptr [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, 208h
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 mov rax, dr7
231 push rax
232 mov rax, dr6
233 push rax
234 mov rax, dr3
235 push rax
236 mov rax, dr2
237 push rax
238 mov rax, dr1
239 push rax
240 mov rax, dr0
241 push rax
242
243 ;; FX_SAVE_STATE_X64 FxSaveState;
244 sub rsp, 512
245 mov rdi, rsp
246 db 0fh, 0aeh, 07h ;fxsave [rdi]
247
248 ;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
249 cld
250
251 ;; UINT32 ExceptionData;
252 push qword ptr [rbp + 16]
253
254 ;; Prepare parameter and call
255 mov rcx, [rbp + 8]
256 mov rdx, rsp
257 ;
258 ; Per X64 calling convention, allocate maximum parameter stack space
259 ; and make sure RSP is 16-byte aligned
260 ;
261 sub rsp, 4 * 8 + 8
262 mov rax, CommonExceptionHandler
263 call rax
264 add rsp, 4 * 8 + 8
265
266 cli
267 ;; UINT64 ExceptionData;
268 add rsp, 8
269
270 ;; FX_SAVE_STATE_X64 FxSaveState;
271
272 mov rsi, rsp
273 db 0fh, 0aeh, 0Eh ; fxrstor [rsi]
274 add rsp, 512
275
276 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
277 ;; Skip restoration of DRx registers to support in-circuit emualators
278 ;; or debuggers set breakpoint in interrupt/exception context
279 add rsp, 8 * 6
280
281 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
282 pop rax
283 mov cr0, rax
284 add rsp, 8 ; not for Cr1
285 pop rax
286 mov cr2, rax
287 pop rax
288 mov cr3, rax
289 pop rax
290 mov cr4, rax
291 pop rax
292 mov cr8, rax
293
294 ;; UINT64 RFlags;
295 pop qword ptr [rbp + 40]
296
297 ;; UINT64 Ldtr, Tr;
298 ;; UINT64 Gdtr[2], Idtr[2];
299 ;; Best not let anyone mess with these particular registers...
300 add rsp, 48
301
302 ;; UINT64 Rip;
303 pop qword ptr [rbp + 24]
304
305 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
306 pop rax
307 ; mov gs, rax ; not for gs
308 pop rax
309 ; mov fs, rax ; not for fs
310 ; (X64 will not use fs and gs, so we do not restore it)
311 pop rax
312 mov es, rax
313 pop rax
314 mov ds, rax
315 pop qword ptr [rbp + 32] ; for cs
316 pop qword ptr [rbp + 56] ; for ss
317
318 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
319 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
320 pop rdi
321 pop rsi
322 add rsp, 8 ; not for rbp
323 pop qword ptr [rbp + 48] ; for rsp
324 pop rbx
325 pop rdx
326 pop rcx
327 pop rax
328 pop r8
329 pop r9
330 pop r10
331 pop r11
332 pop r12
333 pop r13
334 pop r14
335 pop r15
336
337 mov rsp, rbp
338 pop rbp
339 add rsp, 16
340 cmp qword ptr [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
341 jz DoReturn
342 cmp qword ptr [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
343 jz ErrorCode
344 jmp qword ptr [rsp - 32]
345 ErrorCode:
346 sub rsp, 8
347 jmp qword ptr [rsp - 24]
348
349 DoReturn:
350 cmp mDoFarReturnFlag, 0 ; Check if need to do far return instead of IRET
351 jz DoIret
352 push rax
353 mov rax, rsp ; save old RSP to rax
354 mov rsp, [rsp + 20h]
355 push [rax + 10h] ; save CS in new location
356 push [rax + 8h] ; save EIP in new location
357 push [rax + 18h] ; save EFLAGS in new location
358 mov rax, [rax] ; restore rax
359 popfq ; restore EFLAGS
360 DB 48h ; prefix to composite "retq" with next "retf"
361 retf ; far return
362 DoIret:
363 iretq
364
365 CommonInterruptEntry ENDP
366
367 ;-------------------------------------------------------------------------------------
368 ; GetTemplateAddressMap (&AddressMap);
369 ;-------------------------------------------------------------------------------------
370 ; comments here for definition of address map
371 AsmGetTemplateAddressMap PROC
372 mov rax, offset AsmIdtVectorBegin
373 mov qword ptr [rcx], rax
374 mov qword ptr [rcx + 8h], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
375 mov rax, offset HookAfterStubHeaderBegin
376 mov qword ptr [rcx + 10h], rax
377 ret
378 AsmGetTemplateAddressMap ENDP
379
380 ;-------------------------------------------------------------------------------------
381 ; AsmVectorNumFixup (*VectorBase, VectorNum);
382 ;-------------------------------------------------------------------------------------
383 AsmVectorNumFixup PROC
384 mov rax, rdx
385 mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
386 ret
387 AsmVectorNumFixup ENDP
388
389 END