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