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