Home | History | Annotate | Download | only in X64
      1 ;------------------------------------------------------------------------------ ;
      2 ; Copyright (c) 2009 - 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 ;   SmiEntry.asm
     14 ;
     15 ; Abstract:
     16 ;
     17 ;   Code template of the SMI handler for a particular processor
     18 ;
     19 ;-------------------------------------------------------------------------------
     20 
     21 ;
     22 ; Variables referenced by C code
     23 ;
     24 EXTERNDEF   SmiRendezvous:PROC
     25 EXTERNDEF   CpuSmmDebugEntry:PROC
     26 EXTERNDEF   CpuSmmDebugExit:PROC
     27 EXTERNDEF   gcStmSmiHandlerTemplate:BYTE
     28 EXTERNDEF   gcStmSmiHandlerSize:WORD
     29 EXTERNDEF   gcStmSmiHandlerOffset:WORD
     30 EXTERNDEF   gStmSmiCr3:DWORD
     31 EXTERNDEF   gStmSmiStack:DWORD
     32 EXTERNDEF   gStmSmbase:DWORD
     33 EXTERNDEF   gStmXdSupported:BYTE
     34 EXTERNDEF   gStmSmiHandlerIdtr:FWORD
     35 
     36 MSR_IA32_MISC_ENABLE  EQU     1A0h
     37 MSR_EFER      EQU     0c0000080h
     38 MSR_EFER_XD   EQU     0800h
     39 
     40 ;
     41 ; Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR
     42 ;
     43 DSC_OFFSET    EQU     0fb00h
     44 DSC_GDTPTR    EQU     48h
     45 DSC_GDTSIZ    EQU     50h
     46 DSC_CS        EQU     14h
     47 DSC_DS        EQU     16h
     48 DSC_SS        EQU     18h
     49 DSC_OTHERSEG  EQU     1ah
     50 ;
     51 ; Constants relating to CPU State Save Area
     52 ;
     53 SSM_DR6         EQU     0ffd0h
     54 SSM_DR7         EQU     0ffc8h
     55 
     56 PROTECT_MODE_CS EQU     08h
     57 PROTECT_MODE_DS EQU     20h
     58 LONG_MODE_CS    EQU     38h
     59 TSS_SEGMENT     EQU     40h
     60 GDT_SIZE        EQU     50h
     61 
     62     .code
     63 
     64 gcStmSmiHandlerTemplate    LABEL   BYTE
     65 
     66 _StmSmiEntryPoint:
     67     ;
     68     ; The encoding of BX in 16-bit addressing mode is the same as of RDI in 64-
     69     ; bit addressing mode. And that coincidence has been used in the following
     70     ; "64-bit like" 16-bit code. Be aware that once RDI is referenced as a
     71     ; base address register, it is actually BX that is referenced.
     72     ;
     73     DB      0bbh                        ; mov bx, imm16
     74     DW      offset _StmGdtDesc - _StmSmiEntryPoint + 8000h  ; bx = GdtDesc offset
     75 ; fix GDT descriptor
     76     DB      2eh, 0a1h                   ; mov ax, cs:[offset16]
     77     DW      DSC_OFFSET + DSC_GDTSIZ
     78     DB      48h                         ; dec ax
     79     DB      2eh
     80     mov     [rdi], eax                  ; mov cs:[bx], ax
     81     DB      66h, 2eh, 0a1h              ; mov eax, cs:[offset16]
     82     DW      DSC_OFFSET + DSC_GDTPTR
     83     DB      2eh
     84     mov     [rdi + 2], ax               ; mov cs:[bx + 2], eax
     85     DB      66h, 2eh
     86     lgdt    fword ptr [rdi]             ; lgdt fword ptr cs:[bx]
     87 ; Patch ProtectedMode Segment
     88     DB      0b8h                        ; mov ax, imm16
     89     DW      PROTECT_MODE_CS             ; set AX for segment directly
     90     DB      2eh
     91     mov     [rdi - 2], eax              ; mov cs:[bx - 2], ax
     92 ; Patch ProtectedMode entry
     93     DB      66h, 0bfh                   ; mov edi, SMBASE
     94 gStmSmbase    DD    ?
     95     lea     ax, [edi + (@ProtectedMode - _StmSmiEntryPoint) + 8000h]
     96     DB      2eh
     97     mov     [rdi - 6], ax               ; mov cs:[bx - 6], eax
     98 ; Switch into @ProtectedMode
     99     mov     rbx, cr0
    100     DB      66h
    101     and     ebx, 9ffafff3h
    102     DB      66h
    103     or      ebx, 00000023h
    104 
    105     mov     cr0, rbx
    106     DB      66h, 0eah
    107     DD      ?
    108     DW      ?
    109 
    110 _StmGdtDesc    FWORD   ?
    111 @ProtectedMode:
    112     mov     ax, PROTECT_MODE_DS
    113     mov     ds, ax
    114     mov     es, ax
    115     mov     fs, ax
    116     mov     gs, ax
    117     mov     ss, ax
    118     DB      0bch                   ; mov esp, imm32
    119 gStmSmiStack   DD      ?
    120     jmp     ProtFlatMode
    121 
    122 ProtFlatMode:
    123     DB      0b8h                        ; mov eax, offset gStmSmiCr3
    124 gStmSmiCr3     DD      ?
    125     mov     cr3, rax
    126     mov     eax, 668h                   ; as cr4.PGE is not set here, refresh cr3
    127     mov     cr4, rax                    ; in PreModifyMtrrs() to flush TLB.
    128 ; Load TSS
    129     sub     esp, 8                      ; reserve room in stack
    130     sgdt    fword ptr [rsp]
    131     mov     eax, [rsp + 2]              ; eax = GDT base
    132     add     esp, 8
    133     mov     dl, 89h
    134     mov     [rax + TSS_SEGMENT + 5], dl ; clear busy flag
    135     mov     eax, TSS_SEGMENT
    136     ltr     ax
    137 
    138 ; enable NXE if supported
    139     DB      0b0h                        ; mov al, imm8
    140 gStmXdSupported     DB      1
    141     cmp     al, 0
    142     jz      @SkipXd
    143 ;
    144 ; Check XD disable bit
    145 ;
    146     mov     ecx, MSR_IA32_MISC_ENABLE
    147     rdmsr
    148     sub     esp, 4
    149     push    rdx                        ; save MSR_IA32_MISC_ENABLE[63-32]
    150     test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]
    151     jz      @f
    152     and     dx, 0FFFBh                 ; clear XD Disable bit if it is set
    153     wrmsr
    154 @@:
    155     mov     ecx, MSR_EFER
    156     rdmsr
    157     or      ax, MSR_EFER_XD            ; enable NXE
    158     wrmsr
    159     jmp     @XdDone
    160 @SkipXd:
    161     sub     esp, 8
    162 @XdDone:
    163 
    164 ; Switch into @LongMode
    165     push    LONG_MODE_CS                ; push cs hardcore here
    166     call    Base                       ; push return address for retf later
    167 Base:
    168     add     dword ptr [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
    169 
    170     mov     ecx, MSR_EFER
    171     rdmsr
    172     or      ah, 1                      ; enable LME
    173     wrmsr
    174     mov     rbx, cr0
    175     or      ebx, 080010023h            ; enable paging + WP + NE + MP + PE
    176     mov     cr0, rbx
    177     retf
    178 @LongMode:                              ; long mode (64-bit code) starts here
    179     mov     rax, offset gStmSmiHandlerIdtr
    180     lidt    fword ptr [rax]
    181     lea     ebx, [rdi + DSC_OFFSET]
    182     mov     ax, [rbx + DSC_DS]
    183     mov     ds, eax
    184     mov     ax, [rbx + DSC_OTHERSEG]
    185     mov     es, eax
    186     mov     fs, eax
    187     mov     gs, eax
    188     mov     ax, [rbx + DSC_SS]
    189     mov     ss, eax
    190 
    191 CommonHandler:
    192     mov     rbx, [rsp + 0x08]           ; rbx <- CpuIndex
    193 
    194     ;
    195     ; Save FP registers
    196     ;
    197     sub     rsp, 200h
    198     DB      48h                         ; FXSAVE64
    199     fxsave  [rsp]
    200 
    201     add     rsp, -20h
    202 
    203     mov     rcx, rbx
    204     mov     rax, CpuSmmDebugEntry
    205     call    rax
    206 
    207     mov     rcx, rbx
    208     mov     rax, SmiRendezvous          ; rax <- absolute addr of SmiRedezvous
    209     call    rax
    210 
    211     mov     rcx, rbx
    212     mov     rax, CpuSmmDebugExit
    213     call    rax
    214 
    215     add     rsp, 20h
    216 
    217     ;
    218     ; Restore FP registers
    219     ;
    220     DB      48h                         ; FXRSTOR64
    221     fxrstor [rsp]
    222 
    223     add     rsp, 200h
    224 
    225     mov     rax, offset ASM_PFX(gStmXdSupported)
    226     mov     al, [rax]
    227     cmp     al, 0
    228     jz      @f
    229     pop     rdx                       ; get saved MSR_IA32_MISC_ENABLE[63-32]
    230     test    edx, BIT2
    231     jz      @f
    232     mov     ecx, MSR_IA32_MISC_ENABLE
    233     rdmsr
    234     or      dx, BIT2                  ; set XD Disable bit if it was set before entering into SMM
    235     wrmsr
    236 
    237 @@:
    238     rsm
    239 
    240 _StmSmiHandler:
    241 ;
    242 ; Check XD disable bit
    243 ;
    244     xor     r8, r8
    245     mov     rax, offset ASM_PFX(gStmXdSupported)
    246     mov     al, [rax]
    247     cmp     al, 0
    248     jz      @StmXdDone
    249     mov     ecx, MSR_IA32_MISC_ENABLE
    250     rdmsr
    251     mov     r8, rdx                   ; save MSR_IA32_MISC_ENABLE[63-32]
    252     test    edx, BIT2                  ; MSR_IA32_MISC_ENABLE[34]
    253     jz      @f
    254     and     dx, 0FFFBh                 ; clear XD Disable bit if it is set
    255     wrmsr
    256 @@:
    257     mov     ecx, MSR_EFER
    258     rdmsr
    259     or      ax, MSR_EFER_XD            ; enable NXE
    260     wrmsr
    261 @StmXdDone:
    262     push    r8
    263 
    264     ; below step is needed, because STM does not run above code.
    265     ; we have to run below code to set IDT/CR0/CR4
    266     mov     rax, offset gStmSmiHandlerIdtr
    267     lidt    fword ptr [rax]
    268 
    269     mov     rax, cr0
    270     or      eax, 80010023h              ; enable paging + WP + NE + MP + PE
    271     mov     cr0, rax
    272     mov     rax, cr4
    273     mov     eax, 668h                   ; as cr4.PGE is not set here, refresh cr3
    274     mov     cr4, rax                    ; in PreModifyMtrrs() to flush TLB.
    275     ; STM init finish
    276     jmp     CommonHandler
    277 
    278 gcStmSmiHandlerSize    DW      $ - _StmSmiEntryPoint
    279 gcStmSmiHandlerOffset  DW      _StmSmiHandler - _StmSmiEntryPoint
    280 
    281     END
    282