]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
UefiCpuPkg: Replace Opcode with the corresponding instructions.
[mirror_edk2.git] / UefiCpuPkg / Library / CpuExceptionHandlerLib / Ia32 / ExceptionHandlerAsm.nasm
CommitLineData
ab7efb66 1;------------------------------------------------------------------------------ ;\r
2aa107c0 2; Copyright (c) 2016 - 2022, Intel Corporation. All rights reserved.<BR>\r
0acd8697 3; SPDX-License-Identifier: BSD-2-Clause-Patent\r
ab7efb66
LG
4;\r
5; Module Name:\r
6;\r
7; ExceptionHandlerAsm.Asm\r
8;\r
9; Abstract:\r
10;\r
11; IA32 CPU Exception Handler\r
12;\r
13; Notes:\r
14;\r
15;------------------------------------------------------------------------------\r
16\r
17;\r
18; CommonExceptionHandler()\r
19;\r
20extern ASM_PFX(CommonExceptionHandler)\r
21\r
22SECTION .data\r
23\r
24extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions\r
25extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag\r
26\r
27SECTION .text\r
28\r
29ALIGN 8\r
30\r
31;\r
32; exception handler stub table\r
33;\r
34AsmIdtVectorBegin:\r
2aa107c0 35%assign Vector 0\r
ab7efb66 36%rep 32\r
2aa107c0 37 push byte %[Vector];\r
ab7efb66
LG
38 push eax\r
39 mov eax, ASM_PFX(CommonInterruptEntry)\r
40 jmp eax\r
2aa107c0 41%assign Vector Vector+1\r
ab7efb66
LG
42%endrep\r
43AsmIdtVectorEnd:\r
44\r
45HookAfterStubBegin:\r
46 db 0x6a ; push\r
47VectorNum:\r
48 db 0 ; 0 will be fixed\r
49 push eax\r
50 mov eax, HookAfterStubHeaderEnd\r
51 jmp eax\r
52HookAfterStubHeaderEnd:\r
53 pop eax\r
54 sub esp, 8 ; reserve room for filling exception data later\r
55 push dword [esp + 8]\r
56 xchg ecx, [esp] ; get vector number\r
57 bt [ASM_PFX(mErrorCodeFlag)], ecx\r
58 jnc .0\r
59 push dword [esp] ; addition push if exception data needed\r
60.0:\r
61 xchg ecx, [esp] ; restore ecx\r
62 push eax\r
63\r
64;----------------------------------------------------------------------------;\r
65; CommonInterruptEntry ;\r
66;----------------------------------------------------------------------------;\r
67; The follow algorithm is used for the common interrupt routine.\r
68; Entry from each interrupt with a push eax and eax=interrupt number\r
69; Stack:\r
70; +---------------------+\r
71; + EFlags +\r
72; +---------------------+\r
73; + CS +\r
74; +---------------------+\r
75; + EIP +\r
76; +---------------------+\r
77; + Error Code +\r
78; +---------------------+\r
79; + Vector Number +\r
80; +---------------------+\r
81; + EBP +\r
82; +---------------------+ <-- EBP\r
83global ASM_PFX(CommonInterruptEntry)\r
84ASM_PFX(CommonInterruptEntry):\r
85 cli\r
86 pop eax\r
87 ;\r
88 ; All interrupt handlers are invoked through interrupt gates, so\r
89 ; IF flag automatically cleared at the entry point\r
90 ;\r
91\r
92 ;\r
93 ; Get vector number from top of stack\r
94 ;\r
95 xchg ecx, [esp]\r
96 and ecx, 0xFF ; Vector number should be less than 256\r
97 cmp ecx, 32 ; Intel reserved vector for exceptions?\r
98 jae NoErrorCode\r
99 bt [ASM_PFX(mErrorCodeFlag)], ecx\r
100 jc HasErrorCode\r
101\r
102NoErrorCode:\r
103\r
104 ;\r
105 ; Stack:\r
106 ; +---------------------+\r
107 ; + EFlags +\r
108 ; +---------------------+\r
109 ; + CS +\r
110 ; +---------------------+\r
111 ; + EIP +\r
112 ; +---------------------+\r
113 ; + ECX +\r
114 ; +---------------------+ <-- ESP\r
115 ;\r
116 ; Registers:\r
117 ; ECX - Vector Number\r
118 ;\r
119\r
120 ;\r
121 ; Put Vector Number on stack\r
122 ;\r
123 push ecx\r
124\r
125 ;\r
126 ; Put 0 (dummy) error code on stack, and restore ECX\r
127 ;\r
128 xor ecx, ecx ; ECX = 0\r
129 xchg ecx, [esp+4]\r
130\r
131 jmp ErrorCodeAndVectorOnStack\r
132\r
133HasErrorCode:\r
134\r
135 ;\r
136 ; Stack:\r
137 ; +---------------------+\r
138 ; + EFlags +\r
139 ; +---------------------+\r
140 ; + CS +\r
141 ; +---------------------+\r
142 ; + EIP +\r
143 ; +---------------------+\r
144 ; + Error Code +\r
145 ; +---------------------+\r
146 ; + ECX +\r
147 ; +---------------------+ <-- ESP\r
148 ;\r
149 ; Registers:\r
150 ; ECX - Vector Number\r
151 ;\r
152\r
153 ;\r
154 ; Put Vector Number on stack and restore ECX\r
155 ;\r
156 xchg ecx, [esp]\r
157\r
158ErrorCodeAndVectorOnStack:\r
159 push ebp\r
160 mov ebp, esp\r
161\r
162 ;\r
163 ; Stack:\r
164 ; +---------------------+\r
165 ; + EFlags +\r
166 ; +---------------------+\r
167 ; + CS +\r
168 ; +---------------------+\r
169 ; + EIP +\r
170 ; +---------------------+\r
171 ; + Error Code +\r
172 ; +---------------------+\r
173 ; + Vector Number +\r
174 ; +---------------------+\r
175 ; + EBP +\r
176 ; +---------------------+ <-- EBP\r
177 ;\r
178\r
179 ;\r
180 ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32\r
181 ; is 16-byte aligned\r
182 ;\r
183 and esp, 0xfffffff0\r
184 sub esp, 12\r
185\r
186 sub esp, 8\r
187 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
188 push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
189\r
190;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
191 push eax\r
192 push ecx\r
193 push edx\r
194 push ebx\r
195 lea ecx, [ebp + 6 * 4]\r
196 push ecx ; ESP\r
197 push dword [ebp] ; EBP\r
198 push esi\r
199 push edi\r
200\r
201;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r
202 mov eax, ss\r
203 push eax\r
204 movzx eax, word [ebp + 4 * 4]\r
205 push eax\r
206 mov eax, ds\r
207 push eax\r
208 mov eax, es\r
209 push eax\r
210 mov eax, fs\r
211 push eax\r
212 mov eax, gs\r
213 push eax\r
214\r
215;; UINT32 Eip;\r
216 mov eax, [ebp + 3 * 4]\r
217 push eax\r
218\r
219;; UINT32 Gdtr[2], Idtr[2];\r
220 sub esp, 8\r
221 sidt [esp]\r
222 mov eax, [esp + 2]\r
223 xchg eax, [esp]\r
224 and eax, 0xFFFF\r
225 mov [esp+4], eax\r
226\r
227 sub esp, 8\r
228 sgdt [esp]\r
229 mov eax, [esp + 2]\r
230 xchg eax, [esp]\r
231 and eax, 0xFFFF\r
232 mov [esp+4], eax\r
233\r
234;; UINT32 Ldtr, Tr;\r
235 xor eax, eax\r
236 str ax\r
237 push eax\r
238 sldt ax\r
239 push eax\r
240\r
241;; UINT32 EFlags;\r
242 mov eax, [ebp + 5 * 4]\r
243 push eax\r
244\r
245;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r
246 mov eax, 1\r
247 push ebx ; temporarily save value of ebx on stack\r
248 cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and DE\r
249 ; are supported\r
250 pop ebx ; retore value of ebx that was overwritten by CPUID\r
251 mov eax, cr4\r
252 push eax ; push cr4 firstly\r
253 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support\r
254 jz .1\r
255 or eax, BIT9 ; Set CR4.OSFXSR\r
256.1:\r
257 test edx, BIT2 ; Test for Debugging Extensions support\r
258 jz .2\r
259 or eax, BIT3 ; Set CR4.DE\r
260.2:\r
261 mov cr4, eax\r
262 mov eax, cr3\r
263 push eax\r
264 mov eax, cr2\r
265 push eax\r
266 xor eax, eax\r
267 push eax\r
268 mov eax, cr0\r
269 push eax\r
270\r
271;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
272 mov eax, dr7\r
273 push eax\r
274 mov eax, dr6\r
275 push eax\r
276 mov eax, dr3\r
277 push eax\r
278 mov eax, dr2\r
279 push eax\r
280 mov eax, dr1\r
281 push eax\r
282 mov eax, dr0\r
283 push eax\r
284\r
285;; FX_SAVE_STATE_IA32 FxSaveState;\r
286 sub esp, 512\r
287 mov edi, esp\r
288 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.\r
289 ; edx still contains result from CPUID above\r
290 jz .3\r
2aa107c0 291 fxsave [edi]\r
ab7efb66
LG
292.3:\r
293\r
294;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear\r
295 cld\r
296\r
297;; UINT32 ExceptionData;\r
298 push dword [ebp + 2 * 4]\r
299\r
300;; Prepare parameter and call\r
301 mov edx, esp\r
302 push edx\r
303 mov edx, dword [ebp + 1 * 4]\r
304 push edx\r
305\r
306 ;\r
307 ; Call External Exception Handler\r
308 ;\r
309 mov eax, ASM_PFX(CommonExceptionHandler)\r
310 call eax\r
311 add esp, 8\r
312\r
313 cli\r
314;; UINT32 ExceptionData;\r
315 add esp, 4\r
316\r
317;; FX_SAVE_STATE_IA32 FxSaveState;\r
318 mov esi, esp\r
319 mov eax, 1\r
320 cpuid ; use CPUID to determine if FXSAVE/FXRESTOR\r
321 ; are supported\r
322 test edx, BIT24 ; Test for FXSAVE/FXRESTOR support\r
323 jz .4\r
2aa107c0 324 fxrstor [esi]\r
ab7efb66
LG
325.4:\r
326 add esp, 512\r
327\r
328;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;\r
329;; Skip restoration of DRx registers to support in-circuit emualators\r
330;; or debuggers set breakpoint in interrupt/exception context\r
331 add esp, 4 * 6\r
332\r
333;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;\r
334 pop eax\r
335 mov cr0, eax\r
336 add esp, 4 ; not for Cr1\r
337 pop eax\r
338 mov cr2, eax\r
339 pop eax\r
340 mov cr3, eax\r
341 pop eax\r
342 mov cr4, eax\r
343\r
344;; UINT32 EFlags;\r
345 pop dword [ebp + 5 * 4]\r
346\r
347;; UINT32 Ldtr, Tr;\r
348;; UINT32 Gdtr[2], Idtr[2];\r
349;; Best not let anyone mess with these particular registers...\r
350 add esp, 24\r
351\r
352;; UINT32 Eip;\r
353 pop dword [ebp + 3 * 4]\r
354\r
355;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;\r
356;; NOTE - modified segment registers could hang the debugger... We\r
357;; could attempt to insulate ourselves against this possibility,\r
358;; but that poses risks as well.\r
359;;\r
360 pop gs\r
361 pop fs\r
362 pop es\r
363 pop ds\r
364 pop dword [ebp + 4 * 4]\r
365 pop ss\r
366\r
367;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;\r
368 pop edi\r
369 pop esi\r
370 add esp, 4 ; not for ebp\r
371 add esp, 4 ; not for esp\r
372 pop ebx\r
373 pop edx\r
374 pop ecx\r
375 pop eax\r
376\r
377 pop dword [ebp - 8]\r
378 pop dword [ebp - 4]\r
379 mov esp, ebp\r
380 pop ebp\r
381 add esp, 8\r
382 cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler\r
383 jz DoReturn\r
384 cmp dword [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag\r
385 jz ErrorCode\r
386 jmp dword [esp - 16]\r
387ErrorCode:\r
388 sub esp, 4\r
389 jmp dword [esp - 12]\r
390\r
391DoReturn:\r
392 cmp dword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET\r
393 jz DoIret\r
394 push dword [esp + 8] ; save EFLAGS\r
395 add esp, 16\r
396 push dword [esp - 8] ; save CS in new location\r
397 push dword [esp - 8] ; save EIP in new location\r
398 push dword [esp - 8] ; save EFLAGS in new location\r
399 popfd ; restore EFLAGS\r
400 retf ; far return\r
401\r
402DoIret:\r
403 iretd\r
404\r
405;---------------------------------------;\r
406; _AsmGetTemplateAddressMap ;\r
407;----------------------------------------------------------------------------;\r
408;\r
409; Protocol prototype\r
410; AsmGetTemplateAddressMap (\r
411; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap\r
412; );\r
413;\r
414; Routine Description:\r
415;\r
416; Return address map of interrupt handler template so that C code can generate\r
417; interrupt table.\r
418;\r
419; Arguments:\r
420;\r
421;\r
422; Returns:\r
423;\r
424; Nothing\r
425;\r
426;\r
427; Input: [ebp][0] = Original ebp\r
428; [ebp][4] = Return address\r
429;\r
430; Output: Nothing\r
431;\r
432; Destroys: Nothing\r
433;-----------------------------------------------------------------------------;\r
434global ASM_PFX(AsmGetTemplateAddressMap)\r
435ASM_PFX(AsmGetTemplateAddressMap):\r
436 push ebp ; C prolog\r
437 mov ebp, esp\r
438 pushad\r
439\r
440 mov ebx, dword [ebp + 0x8]\r
441 mov dword [ebx], AsmIdtVectorBegin\r
442 mov dword [ebx + 0x4], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32\r
443 mov dword [ebx + 0x8], HookAfterStubBegin\r
444\r
445 popad\r
446 pop ebp\r
447 ret\r
448\r
449;-------------------------------------------------------------------------------------\r
450; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);\r
451;-------------------------------------------------------------------------------------\r
452global ASM_PFX(AsmVectorNumFixup)\r
453ASM_PFX(AsmVectorNumFixup):\r
454 mov eax, dword [esp + 8]\r
455 mov ecx, [esp + 4]\r
456 mov [ecx + (VectorNum - HookAfterStubBegin)], al\r
457 ret\r