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