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