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;
29CommonExceptionHandler             PROTO   C
30
31.data
32
33EXTRN mErrorCodeFlag:DWORD            ; Error code flags for exceptions
34EXTRN mDoFarReturnFlag:DWORD          ; Do far return flag
35
36.code
37
38ALIGN   8
39
40;
41; exception handler stub table
42;
43AsmIdtVectorBegin:
44REPEAT  32
45    db      6ah        ; push  #VectorNum
46    db      ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
47    push    eax
48    mov     eax, CommonInterruptEntry
49    jmp     eax
50ENDM
51AsmIdtVectorEnd:
52
53HookAfterStubBegin:
54    db      6ah        ; push
55VectorNum:
56    db      0          ; 0 will be fixed 
57    push    eax
58    mov     eax, HookAfterStubHeaderEnd
59    jmp     eax
60HookAfterStubHeaderEnd:
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
91CommonInterruptEntry 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
109NoErrorCode:
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
140HasErrorCode:
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
165ErrorCodeAndVectorOnStack:
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]
394ErrorCode:
395    sub     esp, 4
396    jmp     dword ptr [esp - 12]
397
398DoReturn:    
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
409DoIret:
410    iretd
411
412CommonInterruptEntry 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;-----------------------------------------------------------------------------;
443AsmGetTemplateAddressMap  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
456AsmGetTemplateAddressMap  ENDP
457
458;-------------------------------------------------------------------------------------
459;  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
460;-------------------------------------------------------------------------------------
461AsmVectorNumFixup   proc near public
462    mov     eax, dword ptr [esp + 8]
463    mov     ecx, [esp + 4]
464    mov     [ecx + (VectorNum - HookAfterStubBegin)], al
465    ret
466AsmVectorNumFixup   ENDP
467END
468