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