Home | History | Annotate | Download | only in X64
      1 ;------------------------------------------------------------------------------ ;
      2 ; Copyright (c) 2012 - 2014, 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 ;   x64 CPU Exception Handler
     18 ;
     19 ; Notes:
     20 ;
     21 ;------------------------------------------------------------------------------
     22 
     23 ;
     24 ; CommonExceptionHandler()
     25 ;
     26 externdef CommonExceptionHandler:near
     27 
     28 EXTRN mErrorCodeFlag:DWORD    ; Error code flags for exceptions
     29 EXTRN mDoFarReturnFlag:QWORD  ; Do far return flag
     30 
     31 data SEGMENT
     32 
     33 .code
     34 
     35 ALIGN   8
     36 
     37 AsmIdtVectorBegin:
     38 REPEAT  32
     39     db      6ah        ; push  #VectorNum
     40     db      ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
     41     push    rax
     42     mov     rax, CommonInterruptEntry
     43     jmp     rax
     44 ENDM
     45 AsmIdtVectorEnd:
     46 
     47 HookAfterStubHeaderBegin:
     48     db      6ah        ; push
     49 @VectorNum:
     50     db      0          ; 0 will be fixed 
     51     push    rax
     52     mov     rax, HookAfterStubHeaderEnd
     53     jmp     rax
     54 HookAfterStubHeaderEnd:
     55     mov     rax, rsp
     56     and     sp,  0fff0h        ; make sure 16-byte aligned for exception context
     57     sub     rsp, 18h           ; reserve room for filling exception data later
     58     push    rcx
     59     mov     rcx, [rax + 8]
     60     bt      mErrorCodeFlag, ecx
     61     jnc     @F
     62     push    [rsp]             ; push additional rcx to make stack alignment
     63 @@:
     64     xchg    rcx, [rsp]        ; restore rcx, save Exception Number in stack
     65     push    [rax]             ; push rax into stack to keep code consistence
     66 
     67 ;---------------------------------------;
     68 ; CommonInterruptEntry                  ;
     69 ;---------------------------------------;
     70 ; The follow algorithm is used for the common interrupt routine.
     71 ; Entry from each interrupt with a push eax and eax=interrupt number
     72 ; Stack frame would be as follows as specified in IA32 manuals:
     73 ;
     74 ; +---------------------+ <-- 16-byte aligned ensured by processor
     75 ; +    Old SS           +
     76 ; +---------------------+
     77 ; +    Old RSP          +
     78 ; +---------------------+
     79 ; +    RFlags           +
     80 ; +---------------------+
     81 ; +    CS               +
     82 ; +---------------------+
     83 ; +    RIP              +
     84 ; +---------------------+
     85 ; +    Error Code       +
     86 ; +---------------------+
     87 ; +   Vector Number     +
     88 ; +---------------------+
     89 ; +    RBP              +
     90 ; +---------------------+ <-- RBP, 16-byte aligned
     91 ; The follow algorithm is used for the common interrupt routine.
     92 CommonInterruptEntry PROC PUBLIC  
     93     cli
     94     pop     rax
     95     ;
     96     ; All interrupt handlers are invoked through interrupt gates, so
     97     ; IF flag automatically cleared at the entry point
     98     ;
     99     xchg    rcx, [rsp]      ; Save rcx into stack and save vector number into rcx
    100     and     rcx, 0FFh
    101     cmp     ecx, 32         ; Intel reserved vector for exceptions?
    102     jae     NoErrorCode
    103     bt      mErrorCodeFlag, ecx
    104     jc      @F
    105 
    106 NoErrorCode:
    107 
    108     ;
    109     ; Push a dummy error code on the stack
    110     ; to maintain coherent stack map
    111     ;
    112     push    [rsp]
    113     mov     qword ptr [rsp + 8], 0
    114 @@:       
    115     push    rbp
    116     mov     rbp, rsp
    117     push    0             ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
    118     push    0             ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
    119 
    120     ;
    121     ; Stack:
    122     ; +---------------------+ <-- 16-byte aligned ensured by processor
    123     ; +    Old SS           +
    124     ; +---------------------+
    125     ; +    Old RSP          +
    126     ; +---------------------+
    127     ; +    RFlags           +
    128     ; +---------------------+
    129     ; +    CS               +
    130     ; +---------------------+
    131     ; +    RIP              +
    132     ; +---------------------+
    133     ; +    Error Code       +
    134     ; +---------------------+
    135     ; + RCX / Vector Number +
    136     ; +---------------------+
    137     ; +    RBP              +
    138     ; +---------------------+ <-- RBP, 16-byte aligned
    139     ;
    140 
    141 
    142     ;
    143     ; Since here the stack pointer is 16-byte aligned, so
    144     ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
    145     ; is 16-byte aligned
    146     ;
    147 
    148 ;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
    149 ;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;
    150     push r15
    151     push r14
    152     push r13
    153     push r12
    154     push r11
    155     push r10
    156     push r9
    157     push r8
    158     push rax
    159     push qword ptr [rbp + 8]   ; RCX
    160     push rdx
    161     push rbx
    162     push qword ptr [rbp + 48]  ; RSP
    163     push qword ptr [rbp]       ; RBP
    164     push rsi
    165     push rdi
    166 
    167 ;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;  insure high 16 bits of each is zero
    168     movzx   rax, word ptr [rbp + 56]
    169     push    rax                      ; for ss
    170     movzx   rax, word ptr [rbp + 32]
    171     push    rax                      ; for cs
    172     mov     rax, ds
    173     push    rax
    174     mov     rax, es
    175     push    rax
    176     mov     rax, fs
    177     push    rax
    178     mov     rax, gs
    179     push    rax
    180 
    181     mov     [rbp + 8], rcx               ; save vector number
    182 
    183 ;; UINT64  Rip;
    184     push    qword ptr [rbp + 24]
    185 
    186 ;; UINT64  Gdtr[2], Idtr[2];
    187     xor     rax, rax
    188     push    rax
    189     push    rax
    190     sidt    [rsp]
    191     xchg    rax, [rsp + 2]
    192     xchg    rax, [rsp]
    193     xchg    rax, [rsp + 8]
    194 
    195     xor     rax, rax
    196     push    rax
    197     push    rax
    198     sgdt    [rsp]
    199     xchg    rax, [rsp + 2]
    200     xchg    rax, [rsp]
    201     xchg    rax, [rsp + 8]
    202 
    203 ;; UINT64  Ldtr, Tr;
    204     xor     rax, rax
    205     str     ax
    206     push    rax
    207     sldt    ax
    208     push    rax
    209 
    210 ;; UINT64  RFlags;
    211     push    qword ptr [rbp + 40]
    212 
    213 ;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
    214     mov     rax, cr8
    215     push    rax
    216     mov     rax, cr4
    217     or      rax, 208h
    218     mov     cr4, rax
    219     push    rax
    220     mov     rax, cr3
    221     push    rax
    222     mov     rax, cr2
    223     push    rax
    224     xor     rax, rax
    225     push    rax
    226     mov     rax, cr0
    227     push    rax
    228 
    229 ;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    230     mov     rax, dr7
    231     push    rax
    232     mov     rax, dr6
    233     push    rax
    234     mov     rax, dr3
    235     push    rax
    236     mov     rax, dr2
    237     push    rax
    238     mov     rax, dr1
    239     push    rax
    240     mov     rax, dr0
    241     push    rax
    242 
    243 ;; FX_SAVE_STATE_X64 FxSaveState;
    244     sub rsp, 512
    245     mov rdi, rsp
    246     db 0fh, 0aeh, 07h ;fxsave [rdi]
    247 
    248 ;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
    249     cld
    250 
    251 ;; UINT32  ExceptionData;
    252     push    qword ptr [rbp + 16]
    253 
    254 ;; Prepare parameter and call
    255     mov     rcx, [rbp + 8]
    256     mov     rdx, rsp
    257     ;
    258     ; Per X64 calling convention, allocate maximum parameter stack space
    259     ; and make sure RSP is 16-byte aligned
    260     ;
    261     sub     rsp, 4 * 8 + 8
    262     mov     rax, CommonExceptionHandler
    263     call    rax
    264     add     rsp, 4 * 8 + 8
    265 
    266     cli
    267 ;; UINT64  ExceptionData;
    268     add     rsp, 8
    269 
    270 ;; FX_SAVE_STATE_X64 FxSaveState;
    271 
    272     mov rsi, rsp
    273     db 0fh, 0aeh, 0Eh ; fxrstor [rsi]
    274     add rsp, 512
    275 
    276 ;; UINT64  Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
    277 ;; Skip restoration of DRx registers to support in-circuit emualators
    278 ;; or debuggers set breakpoint in interrupt/exception context
    279     add     rsp, 8 * 6
    280 
    281 ;; UINT64  Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
    282     pop     rax
    283     mov     cr0, rax
    284     add     rsp, 8   ; not for Cr1
    285     pop     rax
    286     mov     cr2, rax
    287     pop     rax
    288     mov     cr3, rax
    289     pop     rax
    290     mov     cr4, rax
    291     pop     rax
    292     mov     cr8, rax
    293 
    294 ;; UINT64  RFlags;
    295     pop     qword ptr [rbp + 40]
    296 
    297 ;; UINT64  Ldtr, Tr;
    298 ;; UINT64  Gdtr[2], Idtr[2];
    299 ;; Best not let anyone mess with these particular registers...
    300     add     rsp, 48
    301 
    302 ;; UINT64  Rip;
    303     pop     qword ptr [rbp + 24]
    304 
    305 ;; UINT64  Gs, Fs, Es, Ds, Cs, Ss;
    306     pop     rax
    307     ; mov     gs, rax ; not for gs
    308     pop     rax
    309     ; mov     fs, rax ; not for fs
    310     ; (X64 will not use fs and gs, so we do not restore it)
    311     pop     rax
    312     mov     es, rax
    313     pop     rax
    314     mov     ds, rax
    315     pop     qword ptr [rbp + 32]  ; for cs
    316     pop     qword ptr [rbp + 56]  ; for ss
    317 
    318 ;; UINT64  Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
    319 ;; UINT64  R8, R9, R10, R11, R12, R13, R14, R15;
    320     pop     rdi
    321     pop     rsi
    322     add     rsp, 8               ; not for rbp
    323     pop     qword ptr [rbp + 48] ; for rsp
    324     pop     rbx
    325     pop     rdx
    326     pop     rcx
    327     pop     rax
    328     pop     r8
    329     pop     r9
    330     pop     r10
    331     pop     r11
    332     pop     r12
    333     pop     r13
    334     pop     r14
    335     pop     r15
    336 
    337     mov     rsp, rbp
    338     pop     rbp
    339     add     rsp, 16
    340     cmp     qword ptr [rsp - 32], 0  ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
    341     jz      DoReturn
    342     cmp     qword ptr [rsp - 40], 1  ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
    343     jz      ErrorCode
    344     jmp     qword ptr [rsp - 32]
    345 ErrorCode:
    346     sub     rsp, 8
    347     jmp     qword ptr [rsp - 24]
    348 
    349 DoReturn:
    350     cmp     mDoFarReturnFlag, 0   ; Check if need to do far return instead of IRET
    351     jz      DoIret
    352     push    rax
    353     mov     rax, rsp          ; save old RSP to rax
    354     mov     rsp, [rsp + 20h]   
    355     push    [rax + 10h]       ; save CS in new location
    356     push    [rax + 8h]        ; save EIP in new location
    357     push    [rax + 18h]       ; save EFLAGS in new location
    358     mov     rax, [rax]        ; restore rax
    359     popfq                     ; restore EFLAGS
    360     DB      48h               ; prefix to composite "retq" with next "retf"
    361     retf                      ; far return
    362 DoIret:
    363     iretq
    364 
    365 CommonInterruptEntry ENDP
    366 
    367 ;-------------------------------------------------------------------------------------
    368 ;  GetTemplateAddressMap (&AddressMap);
    369 ;-------------------------------------------------------------------------------------
    370 ; comments here for definition of address map
    371 AsmGetTemplateAddressMap   PROC
    372     mov     rax, offset AsmIdtVectorBegin
    373     mov     qword ptr [rcx], rax
    374     mov     qword ptr [rcx + 8h],  (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
    375     mov     rax, offset HookAfterStubHeaderBegin
    376     mov     qword ptr [rcx + 10h], rax
    377     ret
    378 AsmGetTemplateAddressMap   ENDP
    379 
    380 ;-------------------------------------------------------------------------------------
    381 ;  AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
    382 ;-------------------------------------------------------------------------------------
    383 AsmVectorNumFixup   PROC
    384     mov     rax, rdx
    385     mov     [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
    386     ret
    387 AsmVectorNumFixup   ENDP
    388 
    389 END
    390