]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
CpuException: Avoid allocating code pages for DXE instance
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / X64 / ExceptionHandlerAsm.nasm
1 ;------------------------------------------------------------------------------ ;
2 ; Copyright (c) 2012 - 2022, 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 %define VC_EXCEPTION 29
22
23 extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions
24 extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag
25 extern ASM_PFX(CommonExceptionHandler)
26
27 SECTION .data
28
29 DEFAULT REL
30 SECTION .text
31
32 ALIGN 8
33
34 ; Generate 32 IDT vectors.
35 ; 32 IDT vectors are enough because interrupts (32+) are not enabled in SEC and PEI phase.
36 AsmIdtVectorBegin:
37 %assign Vector 0
38 %rep 32
39 push byte %[Vector]
40 push rax
41 mov rax, ASM_PFX(CommonInterruptEntry)
42 jmp rax
43 %assign Vector Vector+1
44 %endrep
45 AsmIdtVectorEnd:
46
47 HookAfterStubHeaderBegin:
48 db 0x6a ; 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, 0xfff0 ; make sure 16-byte aligned for exception context
57 sub rsp, 0x18 ; reserve room for filling exception data later
58 push rcx
59 mov rcx, [rax + 8]
60 bt [ASM_PFX(mErrorCodeFlag)], ecx
61 jnc .0
62 push qword [rsp] ; push additional rcx to make stack alignment
63 .0:
64 xchg rcx, [rsp] ; restore rcx, save Exception Number in stack
65 push qword [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 global ASM_PFX(CommonInterruptEntry)
93 ASM_PFX(CommonInterruptEntry):
94 cli
95 pop rax
96 ;
97 ; All interrupt handlers are invoked through interrupt gates, so
98 ; IF flag automatically cleared at the entry point
99 ;
100 xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx
101 and rcx, 0xFF
102 cmp ecx, 32 ; Intel reserved vector for exceptions?
103 jae NoErrorCode
104 bt [ASM_PFX(mErrorCodeFlag)], ecx
105 jc HasErrorCode
106
107 NoErrorCode:
108
109 ;
110 ; Push a dummy error code on the stack
111 ; to maintain coherent stack map
112 ;
113 push qword [rsp]
114 mov qword [rsp + 8], 0
115 HasErrorCode:
116 push rbp
117 mov rbp, rsp
118 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
119 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
120
121 ;
122 ; Stack:
123 ; +---------------------+ <-- 16-byte aligned ensured by processor
124 ; + Old SS +
125 ; +---------------------+
126 ; + Old RSP +
127 ; +---------------------+
128 ; + RFlags +
129 ; +---------------------+
130 ; + CS +
131 ; +---------------------+
132 ; + RIP +
133 ; +---------------------+
134 ; + Error Code +
135 ; +---------------------+
136 ; + RCX / Vector Number +
137 ; +---------------------+
138 ; + RBP +
139 ; +---------------------+ <-- RBP, 16-byte aligned
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 [rbp + 8] ; RCX
160 push rdx
161 push rbx
162 push qword [rbp + 48] ; RSP
163 push qword [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 [rbp + 56]
169 push rax ; for ss
170 movzx rax, word [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 [rbp + 24]
185
186 ;; UINT64 Gdtr[2], Idtr[2];
187 xor rax, rax
188 push rax
189 push rax
190 sidt [rsp]
191 mov bx, word [rsp]
192 mov rax, qword [rsp + 2]
193 mov qword [rsp], rax
194 mov word [rsp + 8], bx
195
196 xor rax, rax
197 push rax
198 push rax
199 sgdt [rsp]
200 mov bx, word [rsp]
201 mov rax, qword [rsp + 2]
202 mov qword [rsp], rax
203 mov word [rsp + 8], bx
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 cmp qword [rbp + 8], VC_EXCEPTION
233 je VcDebugRegs ; For SEV-ES (#VC) Debug registers ignored
234
235 mov rax, dr7
236 push rax
237 mov rax, dr6
238 push rax
239 mov rax, dr3
240 push rax
241 mov rax, dr2
242 push rax
243 mov rax, dr1
244 push rax
245 mov rax, dr0
246 push rax
247 jmp DrFinish
248
249 VcDebugRegs:
250 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 are skipped for #VC to avoid exception recursion
251 xor rax, rax
252 push rax
253 push rax
254 push rax
255 push rax
256 push rax
257 push rax
258
259 DrFinish:
260 ;; FX_SAVE_STATE_X64 FxSaveState;
261 sub rsp, 512
262 mov rdi, rsp
263 fxsave [rdi]
264
265 ;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
266 cld
267
268 ;; UINT32 ExceptionData;
269 push qword [rbp + 16]
270
271 ;; Prepare parameter and call
272 mov rcx, [rbp + 8]
273 mov rdx, rsp
274 ;
275 ; Per X64 calling convention, allocate maximum parameter stack space
276 ; and make sure RSP is 16-byte aligned
277 ;
278 sub rsp, 4 * 8 + 8
279 mov rax, ASM_PFX(CommonExceptionHandler)
280 call rax
281 add rsp, 4 * 8 + 8
282
283 cli
284 ;; UINT64 ExceptionData;
285 add rsp, 8
286
287 ;; FX_SAVE_STATE_X64 FxSaveState;
288
289 mov rsi, rsp
290 fxrstor [rsi]
291 add rsp, 512
292
293 ;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
294 ;; Skip restoration of DRx registers to support in-circuit emualators
295 ;; or debuggers set breakpoint in interrupt/exception context
296 add rsp, 8 * 6
297
298 ;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
299 pop rax
300 mov cr0, rax
301 add rsp, 8 ; not for Cr1
302 pop rax
303 mov cr2, rax
304 pop rax
305 mov cr3, rax
306 pop rax
307 mov cr4, rax
308 pop rax
309 mov cr8, rax
310
311 ;; UINT64 RFlags;
312 pop qword [rbp + 40]
313
314 ;; UINT64 Ldtr, Tr;
315 ;; UINT64 Gdtr[2], Idtr[2];
316 ;; Best not let anyone mess with these particular registers...
317 add rsp, 48
318
319 ;; UINT64 Rip;
320 pop qword [rbp + 24]
321
322 ;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
323 pop rax
324 ; mov gs, rax ; not for gs
325 pop rax
326 ; mov fs, rax ; not for fs
327 ; (X64 will not use fs and gs, so we do not restore it)
328 pop rax
329 mov es, rax
330 pop rax
331 mov ds, rax
332 pop qword [rbp + 32] ; for cs
333 pop qword [rbp + 56] ; for ss
334
335 ;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
336 ;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
337 pop rdi
338 pop rsi
339 add rsp, 8 ; not for rbp
340 pop qword [rbp + 48] ; for rsp
341 pop rbx
342 pop rdx
343 pop rcx
344 pop rax
345 pop r8
346 pop r9
347 pop r10
348 pop r11
349 pop r12
350 pop r13
351 pop r14
352 pop r15
353
354 mov rsp, rbp
355 pop rbp
356 add rsp, 16
357 cmp qword [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
358 jz DoReturn
359 cmp qword [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
360 jz ErrorCode
361 jmp qword [rsp - 32]
362 ErrorCode:
363 sub rsp, 8
364 jmp qword [rsp - 24]
365
366 DoReturn:
367 cmp qword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
368 jz DoIret
369 push rax
370 mov rax, rsp ; save old RSP to rax
371 mov rsp, [rsp + 0x20]
372 push qword [rax + 0x10] ; save CS in new location
373 push qword [rax + 0x8] ; save EIP in new location
374 push qword [rax + 0x18] ; save EFLAGS in new location
375 mov rax, [rax] ; restore rax
376 popfq ; restore EFLAGS
377 retfq
378 DoIret:
379 iretq
380
381 ;-------------------------------------------------------------------------------------
382 ; GetTemplateAddressMap (&AddressMap);
383 ;-------------------------------------------------------------------------------------
384 ; comments here for definition of address map
385 global ASM_PFX(AsmGetTemplateAddressMap)
386 ASM_PFX(AsmGetTemplateAddressMap):
387 mov rax, AsmIdtVectorBegin
388 mov qword [rcx], rax
389 mov qword [rcx + 0x8], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
390 mov rax, HookAfterStubHeaderBegin
391 mov qword [rcx + 0x10], rax
392 ret
393
394 ;-------------------------------------------------------------------------------------
395 ; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
396 ;-------------------------------------------------------------------------------------
397 global ASM_PFX(AsmVectorNumFixup)
398 ASM_PFX(AsmVectorNumFixup):
399 mov rax, rdx
400 mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
401 ret
402