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