]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
7b97810d10976a164688804a81519111a899e7f7
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ExceptionHandlerAsm.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2012 - 2018, 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, strict qword 0 ; 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, strict qword 0 ; mov rax, HookAfterStubHeaderEnd
54 JmpAbsoluteAddress:
55 jmp rax
56 HookAfterStubHeaderEnd:
57 mov rax, rsp
58 and sp, 0xfff0 ; make sure 16-byte aligned for exception context
59 sub rsp, 0x18 ; reserve room for filling exception data later
60 push rcx
61 mov rcx, [rax + 8]
62 bt [ASM_PFX(mErrorCodeFlag)], ecx
63 jnc .0
64 push qword [rsp] ; push additional rcx to make stack alignment
65 .0:
66 xchg rcx, [rsp] ; restore rcx, save Exception Number in stack
67 push qword [rax] ; push rax into stack to keep code consistence
68
69 ;---------------------------------------;
70 ; CommonInterruptEntry ;
71 ;---------------------------------------;
72 ; The follow algorithm is used for the common interrupt routine.
73 ; Entry from each interrupt with a push eax and eax=interrupt number
74 ; Stack frame would be as follows as specified in IA32 manuals:
75 ;
76 ; +---------------------+ <-- 16-byte aligned ensured by processor
77 ; + Old SS +
78 ; +---------------------+
79 ; + Old RSP +
80 ; +---------------------+
81 ; + RFlags +
82 ; +---------------------+
83 ; + CS +
84 ; +---------------------+
85 ; + RIP +
86 ; +---------------------+
87 ; + Error Code +
88 ; +---------------------+
89 ; + Vector Number +
90 ; +---------------------+
91 ; + RBP +
92 ; +---------------------+ <-- RBP, 16-byte aligned
93 ; The follow algorithm is used for the common interrupt routine.
94 global ASM_PFX(CommonInterruptEntry)
95 ASM_PFX(CommonInterruptEntry):
96 cli
97 pop rax
98 ;
99 ; All interrupt handlers are invoked through interrupt gates, so
100 ; IF flag automatically cleared at the entry point
101 ;
102 xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx
103 and rcx, 0xFF
104 cmp ecx, 32 ; Intel reserved vector for exceptions?
105 jae NoErrorCode
106 bt [ASM_PFX(mErrorCodeFlag)], ecx
107 jc HasErrorCode
108
109 NoErrorCode:
110
111 ;
112 ; Push a dummy error code on the stack
113 ; to maintain coherent stack map
114 ;
115 push qword [rsp]
116 mov qword [rsp + 8], 0
117 HasErrorCode:
118 push rbp
119 mov rbp, rsp
120 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
121 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
122
123 ;
124 ; Stack:
125 ; +---------------------+ <-- 16-byte aligned ensured by processor
126 ; + Old SS +
127 ; +---------------------+
128 ; + Old RSP +
129 ; +---------------------+
130 ; + RFlags +
131 ; +---------------------+
132 ; + CS +
133 ; +---------------------+
134 ; + RIP +
135 ; +---------------------+
136 ; + Error Code +
137 ; +---------------------+
138 ; + RCX / Vector Number +
139 ; +---------------------+
140 ; + RBP +
141 ; +---------------------+ <-- RBP, 16-byte aligned
142 ;
143
144 ;
145 ; Since here the stack pointer is 16-byte aligned, so
146 ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
147 ; is 16-byte aligned
148 ;
149
150 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
151 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
152 push r15
153 push r14
154 push r13
155 push r12
156 push r11
157 push r10
158 push r9
159 push r8
160 push rax
161 push qword [rbp + 8] ; RCX
162 push rdx
163 push rbx
164 push qword [rbp + 48] ; RSP
165 push qword [rbp] ; RBP
166 push rsi
167 push rdi
168
169 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
170 movzx rax, word [rbp + 56]
171 push rax ; for ss
172 movzx rax, word [rbp + 32]
173 push rax ; for cs
174 mov rax, ds
175 push rax
176 mov rax, es
177 push rax
178 mov rax, fs
179 push rax
180 mov rax, gs
181 push rax
182
183 mov [rbp + 8], rcx ; save vector number
184
185 ;; UINT64 Rip;
186 push qword [rbp + 24]
187
188 ;; UINT64 Gdtr[2], Idtr[2];
189 xor rax, rax
190 push rax
191 push rax
192 sidt [rsp]
193 xchg rax, [rsp + 2]
194 xchg rax, [rsp]
195 xchg rax, [rsp + 8]
196
197 xor rax, rax
198 push rax
199 push rax
200 sgdt [rsp]
201 xchg rax, [rsp + 2]
202 xchg rax, [rsp]
203 xchg rax, [rsp + 8]
204
205 ;; UINT64 Ldtr, Tr;
206 xor rax, rax
207 str ax
208 push rax
209 sldt ax
210 push rax
211
212 ;; UINT64 RFlags;
213 push qword [rbp + 40]
214
215 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
216 mov rax, cr8
217 push rax
218 mov rax, cr4
219 or rax, 0x208
220 mov cr4, rax
221 push rax
222 mov rax, cr3
223 push rax
224 mov rax, cr2
225 push rax
226 xor rax, rax
227 push rax
228 mov rax, cr0
229 push rax
230
231 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
232 mov rax, dr7
233 push rax
234 mov rax, dr6
235 push rax
236 mov rax, dr3
237 push rax
238 mov rax, dr2
239 push rax
240 mov rax, dr1
241 push rax
242 mov rax, dr0
243 push rax
244
245 ;; FX_SAVE_STATE_X64 FxSaveState;
246 sub rsp, 512
247 mov rdi, rsp
248 db 0xf, 0xae, 0x7 ;fxsave [rdi]
249
250 ;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
251 cld
252
253 ;; UINT32 ExceptionData;
254 push qword [rbp + 16]
255
256 ;; Prepare parameter and call
257 mov rcx, [rbp + 8]
258 mov rdx, rsp
259 ;
260 ; Per X64 calling convention, allocate maximum parameter stack space
261 ; and make sure RSP is 16-byte aligned
262 ;
263 sub rsp, 4 * 8 + 8
264 call ASM_PFX(CommonExceptionHandler)
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 lea rax, [AsmIdtVectorBegin]
373 mov qword [rcx], rax
374 mov qword [rcx + 0x8], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
375 lea rax, [HookAfterStubHeaderBegin]
376 mov qword [rcx + 0x10], rax
377
378 ; Fix up CommonInterruptEntry address
379 lea rax, [ASM_PFX(CommonInterruptEntry)]
380 lea rcx, [AsmIdtVectorBegin]
381 %rep 32
382 mov qword [rcx + (JmpAbsoluteAddress - 8 - HookAfterStubHeaderBegin)], rax
383 add rcx, (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
384 %endrep
385 ; Fix up HookAfterStubHeaderEnd
386 lea rax, [HookAfterStubHeaderEnd]
387 lea rcx, [JmpAbsoluteAddress]
388 mov qword [rcx - 8], rax
389
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