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