1#------------------------------------------------------------------------------
2#*
3#*   Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
4#*   This program and the accompanying materials
5#*   are licensed and made available under the terms and conditions of the BSD License
6#*   which accompanies this distribution.  The full text of the license may be found at
7#*   http://opensource.org/licenses/bsd-license.php
8#*
9#*   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10#*   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11#*
12#*    ExceptionHandlerAsm.S
13#*
14#*   Abstract:
15#*
16#*     IA32 CPU Exception Handler
17#
18#------------------------------------------------------------------------------
19
20
21#.MMX
22#.XMM
23
24ASM_GLOBAL ASM_PFX(CommonExceptionHandler)
25ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
26ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
27
28#EXTRN ASM_PFX(mErrorCodeFlag):DWORD           # Error code flags for exceptions
29#EXTRN ASM_PFX(mDoFarReturnFlag):DWORD         # Do far return flag
30
31.text
32
33#
34# exception handler stub table
35#
36Exception0Handle:
37    .byte   0x6a    #  push #VectorNum
38    .byte   0
39    pushl   %eax
40    .byte   0xB8
41    .long   ASM_PFX(CommonInterruptEntry)
42    jmp     *%eax
43Exception1Handle:
44    .byte   0x6a    #  push #VectorNum
45    .byte   1
46    pushl   %eax
47    .byte   0xB8
48    .long   ASM_PFX(CommonInterruptEntry)
49    jmp     *%eax
50Exception2Handle:
51    .byte   0x6a    #  push #VectorNum
52    .byte   2
53    pushl   %eax
54    .byte   0xB8
55    .long   ASM_PFX(CommonInterruptEntry)
56    jmp     *%eax
57Exception3Handle:
58    .byte   0x6a    #  push #VectorNum
59    .byte   3
60    pushl   %eax
61    .byte   0xB8
62    .long   ASM_PFX(CommonInterruptEntry)
63    jmp     *%eax
64Exception4Handle:
65    .byte   0x6a    #  push #VectorNum
66    .byte   4
67    pushl   %eax
68    .byte   0xB8
69    .long   ASM_PFX(CommonInterruptEntry)
70    jmp     *%eax
71Exception5Handle:
72    .byte   0x6a    #  push #VectorNum
73    .byte   5
74    pushl   %eax
75    .byte   0xB8
76    .long   ASM_PFX(CommonInterruptEntry)
77    jmp     *%eax
78Exception6Handle:
79    .byte   0x6a    #  push #VectorNum
80    .byte   6
81    pushl   %eax
82    .byte   0xB8
83    .long   ASM_PFX(CommonInterruptEntry)
84    jmp     *%eax
85Exception7Handle:
86    .byte   0x6a    #  push #VectorNum
87    .byte   7
88    pushl   %eax
89    .byte   0xB8
90    .long   ASM_PFX(CommonInterruptEntry)
91    jmp     *%eax
92Exception8Handle:
93    .byte   0x6a    #  push #VectorNum
94    .byte   8
95    pushl   %eax
96     .byte   0xB8
97    .long   ASM_PFX(CommonInterruptEntry)
98    jmp     *%eax
99Exception9Handle:
100    .byte   0x6a    #  push #VectorNum
101    .byte   9
102    pushl   %eax
103    .byte   0xB8
104    .long   ASM_PFX(CommonInterruptEntry)
105    jmp     *%eax
106Exception10Handle:
107    .byte   0x6a    #  push #VectorNum
108    .byte   10
109    pushl   %eax
110    .byte   0xB8
111    .long   ASM_PFX(CommonInterruptEntry)
112    jmp     *%eax
113Exception11Handle:
114    .byte   0x6a    #  push #VectorNum
115    .byte   11
116    pushl   %eax
117    .byte   0xB8
118    .long   ASM_PFX(CommonInterruptEntry)
119    jmp     *%eax
120Exception12Handle:
121    .byte   0x6a    #  push #VectorNum
122    .byte   12
123    pushl   %eax
124    .byte   0xB8
125    .long   ASM_PFX(CommonInterruptEntry)
126    jmp     *%eax
127Exception13Handle:
128    .byte   0x6a    #  push #VectorNum
129    .byte   13
130    pushl   %eax
131    .byte   0xB8
132    .long   ASM_PFX(CommonInterruptEntry)
133    jmp     *%eax
134Exception14Handle:
135    .byte   0x6a    #  push #VectorNum
136    .byte   14
137    pushl   %eax
138    .byte   0xB8
139    .long   ASM_PFX(CommonInterruptEntry)
140    jmp     *%eax
141Exception15Handle:
142    .byte   0x6a    #  push #VectorNum
143    .byte   15
144    pushl   %eax
145    .byte   0xB8
146    .long   ASM_PFX(CommonInterruptEntry)
147    jmp     *%eax
148Exception16Handle:
149    .byte   0x6a    #  push #VectorNum
150    .byte   16
151    pushl   %eax
152    .byte   0xB8
153    .long   ASM_PFX(CommonInterruptEntry)
154    jmp     *%eax
155Exception17Handle:
156    .byte   0x6a    #  push #VectorNum
157    .byte   17
158    pushl   %eax
159    .byte   0xB8
160    .long   ASM_PFX(CommonInterruptEntry)
161    jmp     *%eax
162Exception18Handle:
163    .byte   0x6a    #  push #VectorNum
164    .byte   18
165    pushl   %eax
166    .byte   0xB8
167    .long   ASM_PFX(CommonInterruptEntry)
168    jmp     *%eax
169Exception19Handle:
170    .byte   0x6a    #  push #VectorNum
171    .byte   19
172    pushl   %eax
173    .byte   0xB8
174    .long   ASM_PFX(CommonInterruptEntry)
175    jmp     *%eax
176Exception20Handle:
177    .byte   0x6a    #  push #VectorNum
178    .byte   20
179    pushl   %eax
180    .byte   0xB8
181    .long   ASM_PFX(CommonInterruptEntry)
182    jmp     *%eax
183Exception21Handle:
184    .byte   0x6a    #  push #VectorNum
185    .byte   21
186    pushl   %eax
187    .byte   0xB8
188    .long   ASM_PFX(CommonInterruptEntry)
189    jmp     *%eax
190Exception22Handle:
191    .byte   0x6a    #  push #VectorNum
192    .byte   22
193    pushl   %eax
194    .byte   0xB8
195    .long   ASM_PFX(CommonInterruptEntry)
196    jmp     *%eax
197Exception23Handle:
198    .byte   0x6a    #  push #VectorNum
199    .byte   23
200    pushl   %eax
201    .byte   0xB8
202    .long   ASM_PFX(CommonInterruptEntry)
203    jmp     *%eax
204Exception24Handle:
205    .byte   0x6a    #  push #VectorNum
206    .byte   24
207    pushl   %eax
208    .byte   0xB8
209    .long   ASM_PFX(CommonInterruptEntry)
210    jmp     *%eax
211Exception25Handle:
212    .byte   0x6a    #  push #VectorNum
213    .byte   25
214    pushl   %eax
215    .byte   0xB8
216    .long   ASM_PFX(CommonInterruptEntry)
217    jmp     *%eax
218Exception26Handle:
219    .byte   0x6a    #  push #VectorNum
220    .byte   26
221    pushl   %eax
222    .byte   0xB8
223    .long   ASM_PFX(CommonInterruptEntry)
224    jmp     *%eax
225Exception27Handle:
226    .byte   0x6a    #  push #VectorNum
227    .byte   27
228    pushl   %eax
229    .byte   0xB8
230    .long   ASM_PFX(CommonInterruptEntry)
231    jmp     *%eax
232Exception28Handle:
233    .byte   0x6a    #  push #VectorNum
234    .byte   28
235    pushl   %eax
236    .byte   0xB8
237    .long   ASM_PFX(CommonInterruptEntry)
238    jmp     *%eax
239Exception29Handle:
240    .byte   0x6a    #  push #VectorNum
241    .byte   29
242    pushl   %eax
243    .byte   0xB8
244    .long   ASM_PFX(CommonInterruptEntry)
245    jmp     *%eax
246Exception30Handle:
247    .byte   0x6a    #  push #VectorNum
248    .byte   30
249    pushl   %eax
250    .byte   0xB8
251    .long   ASM_PFX(CommonInterruptEntry)
252    jmp     *%eax
253Exception31Handle:
254    .byte   0x6a    #  push #VectorNum
255    .byte   31
256    pushl   %eax
257    .byte   0xB8
258    .long   ASM_PFX(CommonInterruptEntry)
259    jmp     *%eax
260
261HookAfterStubBegin:
262    .byte   0x6a       # push
263VectorNum:
264    .byte   0          # 0 will be fixed
265    pushl   %eax
266    .byte   0xB8       # movl    ASM_PFX(HookAfterStubHeaderEnd), %eax
267    .long   ASM_PFX(HookAfterStubHeaderEnd)
268    jmp     *%eax
269ASM_GLOBAL ASM_PFX(HookAfterStubHeaderEnd)
270ASM_PFX(HookAfterStubHeaderEnd):
271    popl    %eax
272    subl    $8, %esp        # reserve room for filling exception data later
273    pushl   8(%esp)
274    xchgl   (%esp), %ecx    # get vector number
275    bt      %ecx, ASM_PFX(mErrorCodeFlag)
276    jnc     NoErrorData
277    pushl    (%esp)         # addition push if exception data needed
278NoErrorData:
279    xchg    (%esp), %ecx    # restore ecx
280    pushl   %eax
281
282#---------------------------------------;
283# CommonInterruptEntry                  ;
284#---------------------------------------;
285# The follow algorithm is used for the common interrupt routine.
286
287ASM_GLOBAL ASM_PFX(CommonInterruptEntry)
288ASM_PFX(CommonInterruptEntry):
289    cli
290    popl    %eax
291    #
292    # All interrupt handlers are invoked through interrupt gates, so
293    # IF flag automatically cleared at the entry point
294    #
295
296    #
297    # Get vector number from top of stack
298    #
299    xchgl   (%esp), %ecx
300    andl    $0x0FF, %ecx      # Vector number should be less than 256
301    cmpl    $32, %ecx         # Intel reserved vector for exceptions?
302    jae     NoErrorCode
303    bt      %ecx, ASM_PFX(mErrorCodeFlag)
304    jc      HasErrorCode
305
306NoErrorCode:
307
308    #
309    # Stack:
310    # +---------------------+
311    # +    EFlags           +
312    # +---------------------+
313    # +    CS               +
314    # +---------------------+
315    # +    EIP              +
316    # +---------------------+
317    # +    ECX              +
318    # +---------------------+ <-- ESP
319    #
320    # Registers:
321    #   ECX - Vector Number
322    #
323
324    #
325    # Put Vector Number on stack
326    #
327    pushl   %ecx
328
329    #
330    # Put 0 (dummy) error code on stack, and restore ECX
331    #
332    xorl    %ecx, %ecx  # ECX = 0
333    xchgl   4(%esp), %ecx
334
335    jmp     ErrorCodeAndVectorOnStack
336
337HasErrorCode:
338
339    #
340    # Stack:
341    # +---------------------+
342    # +    EFlags           +
343    # +---------------------+
344    # +    CS               +
345    # +---------------------+
346    # +    EIP              +
347    # +---------------------+
348    # +    Error Code       +
349    # +---------------------+
350    # +    ECX              +
351    # +---------------------+ <-- ESP
352    #
353    # Registers:
354    #   ECX - Vector Number
355    #
356
357    #
358    # Put Vector Number on stack and restore ECX
359    #
360    xchgl   (%esp), %ecx
361
362ErrorCodeAndVectorOnStack:
363    pushl   %ebp
364    movl    %esp, %ebp
365
366    #
367    # Stack:
368    # +---------------------+
369    # +    EFlags           +
370    # +---------------------+
371    # +    CS               +
372    # +---------------------+
373    # +    EIP              +
374    # +---------------------+
375    # +    Error Code       +
376    # +---------------------+
377    # +    Vector Number    +
378    # +---------------------+
379    # +    EBP              +
380    # +---------------------+ <-- EBP
381    #
382
383    #
384    # Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
385    # is 16-byte aligned
386    #
387    andl    $0x0fffffff0, %esp
388    subl    $12, %esp
389
390    subl    $8, %esp
391    pushl   $0         # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
392    pushl   $0         # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
393
394#; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
395    pushl   %eax
396    pushl   %ecx
397    pushl   %edx
398    pushl   %ebx
399    leal    24(%ebp), %ecx
400    pushl   %ecx                          # ESP
401    pushl   (%ebp)              # EBP
402    pushl   %esi
403    pushl   %edi
404
405#; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
406    movl    %ss, %eax
407    pushl   %eax
408    movzwl  16(%ebp), %eax
409    pushl   %eax
410    movl    %ds, %eax
411    pushl   %eax
412    movl    %es, %eax
413    pushl   %eax
414    movl    %fs, %eax
415    pushl   %eax
416    movl    %gs, %eax
417    pushl   %eax
418
419#; UINT32  Eip;
420    movl    12(%ebp), %eax
421    pushl   %eax
422
423#; UINT32  Gdtr[2], Idtr[2];
424    subl    $8, %esp
425    sidt    (%esp)
426    movl    2(%esp), %eax
427    xchgl   (%esp), %eax
428    andl    $0x0FFFF, %eax
429    movl    %eax, 4(%esp)
430
431    subl    $8, %esp
432    sgdt    (%esp)
433    movl    2(%esp), %eax
434    xchgl   (%esp), %eax
435    andl    $0x0FFFF, %eax
436    movl    %eax, 4(%esp)
437
438#; UINT32  Ldtr, Tr;
439    xorl    %eax, %eax
440    str     %ax
441    pushl   %eax
442    sldt    %ax
443    pushl   %eax
444
445#; UINT32  EFlags;
446    movl    20(%ebp), %eax
447    pushl   %eax
448
449#; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
450## insure FXSAVE/FXRSTOR is enabled in CR4...
451## ... while we're at it, make sure DE is also enabled...
452    mov     $1, %eax
453    pushl   %ebx                         # temporarily save value of ebx on stack
454    cpuid                                # use CPUID to determine if FXSAVE/FXRESTOR
455                                         # and DE are supported
456    popl    %ebx                         # retore value of ebx that was overwritten
457                                         # by CPUID
458    movl    %cr4, %eax
459    pushl   %eax                         # push cr4 firstly
460    testl   $BIT24, %edx                 # Test for FXSAVE/FXRESTOR support
461    jz      L1
462    orl     $BIT9, %eax                  # Set CR4.OSFXSR
463L1:
464    testl   $BIT2, %edx                  # Test for Debugging Extensions support
465    jz      L2
466    orl     $BIT3, %eax                  # Set CR4.DE
467L2:
468    movl    %eax, %cr4
469    movl    %cr3, %eax
470    pushl   %eax
471    movl    %cr2, %eax
472    pushl   %eax
473    xorl    %eax, %eax
474    pushl   %eax
475    movl    %cr0, %eax
476    pushl   %eax
477
478#; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
479    movl    %dr7, %eax
480    pushl   %eax
481    movl    %dr6, %eax
482    pushl   %eax
483    movl    %dr3, %eax
484    pushl   %eax
485    movl    %dr2, %eax
486    pushl   %eax
487    movl    %dr1, %eax
488    pushl   %eax
489    movl    %dr0, %eax
490    pushl   %eax
491
492#; FX_SAVE_STATE_IA32 FxSaveState;
493    subl    $512, %esp
494    movl    %esp, %edi
495    testl   $BIT24, %edx     # Test for FXSAVE/FXRESTOR support.
496                             # edx still contains result from CPUID above
497    jz      L3
498    .byte      0x0f, 0x0ae, 0x07 #fxsave [edi]
499L3:
500
501#; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
502    cld
503
504#; UINT32  ExceptionData;
505    pushl   8(%ebp)
506
507#; Prepare parameter and call
508    movl    %esp, %edx
509    pushl   %edx
510    movl    4(%ebp), %edx
511    pushl   %edx
512
513    #
514    # Call External Exception Handler
515    #
516    call    ASM_PFX(CommonExceptionHandler)
517    addl    $8, %esp
518
519    cli
520#; UINT32  ExceptionData;
521    addl    $4, %esp
522
523#; FX_SAVE_STATE_IA32 FxSaveState;
524    movl    %esp, %esi
525    movl    $1, %eax
526    cpuid                    # use CPUID to determine if FXSAVE/FXRESTOR
527                             # are supported
528    testl   $BIT24, %edx     # Test for FXSAVE/FXRESTOR support
529    jz      L4
530    .byte      0x0f, 0x0ae, 0x0e # fxrstor [esi]
531L4:
532    addl    $512, %esp
533
534#; UINT32  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
535#; Skip restoration of DRx registers to support in-circuit emualators
536#; or debuggers set breakpoint in interrupt/exception context
537    addl    $24, %esp
538
539#; UINT32  Cr0, Cr1, Cr2, Cr3, Cr4;
540    popl    %eax
541    movl    %eax, %cr0
542    addl    $4, %esp    # not for Cr1
543    popl    %eax
544    movl    %eax, %cr2
545    popl    %eax
546    movl    %eax, %cr3
547    popl    %eax
548    movl    %eax, %cr4
549
550#; UINT32  EFlags;
551    popl    20(%ebp)
552
553#; UINT32  Ldtr, Tr;
554#; UINT32  Gdtr[2], Idtr[2];
555#; Best not let anyone mess with these particular registers...
556    addl    $24, %esp
557
558#; UINT32  Eip;
559    popl    12(%ebp)
560
561#; UINT32  Gs, Fs, Es, Ds, Cs, Ss;
562#; NOTE - modified segment registers could hang the debugger...  We
563#;        could attempt to insulate ourselves against this possibility,
564#;        but that poses risks as well.
565#;
566    popl    %gs
567    popl    %fs
568    popl    %es
569    popl    %ds
570    popl    16(%ebp)
571    popl    %ss
572
573#; UINT32  Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
574    popl    %edi
575    popl    %esi
576    addl    $4, %esp   # not for ebp
577    addl    $4, %esp   # not for esp
578    popl    %ebx
579    popl    %edx
580    popl    %ecx
581    popl    %eax
582
583    popl    -8(%ebp)
584    popl    -4(%ebp)
585    movl    %ebp, %esp
586    popl    %ebp
587    addl    $8, %esp
588    cmpl    $0, -16(%esp)  # check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
589    jz      DoReturn
590    cmpl    $1, -20(%esp)  # check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
591    jz      ErrorCode
592    jmp     *-16(%esp)
593ErrorCode:
594    subl    $4, %esp
595    jmp     *-12(%esp)
596
597DoReturn:
598    cmpl    $0, ASM_PFX(mDoFarReturnFlag)
599    jz      DoIret
600    pushl   8(%esp)       # save EFLAGS
601    addl    $16, %esp
602    pushl   -8(%esp)      # save CS in new location
603    pushl   -8(%esp)      # save EIP in new location
604    pushl   -8(%esp)      # save EFLAGS in new location
605    popfl                 # restore EFLAGS
606    lret                  # far return
607
608DoIret:
609    iretl
610
611
612#---------------------------------------;
613# _AsmGetTemplateAddressMap             ;
614#---------------------------------------;
615#
616# Protocol prototype
617#   AsmGetTemplateAddressMap (
618#     EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
619#   );
620#
621# Routine Description:
622#
623#  Return address map of interrupt handler template so that C code can generate
624#  interrupt table.
625#
626# Arguments:
627#
628#
629# Returns:
630#
631#   Nothing
632#
633#
634# Input:  [ebp][0]  = Original ebp
635#         [ebp][4]  = Return address
636#
637# Output: Nothing
638#
639# Destroys: Nothing
640#-----------------------------------------------------------------------------;
641#-------------------------------------------------------------------------------------
642#  AsmGetAddressMap (&AddressMap);
643#-------------------------------------------------------------------------------------
644ASM_GLOBAL ASM_PFX(AsmGetTemplateAddressMap)
645ASM_PFX(AsmGetTemplateAddressMap):
646
647        pushl       %ebp
648        movl        %esp,%ebp
649        pushal
650
651        movl        0x8(%ebp), %ebx
652        movl        $Exception0Handle, (%ebx)
653        movl        $(Exception1Handle - Exception0Handle), 0x4(%ebx)
654        movl        $(HookAfterStubBegin), 0x8(%ebx)
655
656        popal
657        popl        %ebp
658        ret
659#-------------------------------------------------------------------------------------
660#  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
661#-------------------------------------------------------------------------------------
662ASM_GLOBAL ASM_PFX(AsmVectorNumFixup)
663ASM_PFX(AsmVectorNumFixup):
664        movl  8(%esp), %eax
665        movl  4(%esp), %ecx
666        movb  %al, (VectorNum - HookAfterStubBegin)(%ecx)
667        ret
668