Home | History | Annotate | Download | only in X64
      1 ;
      2 ; Copyright (c) 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 ;
     12 ; Module Name:
     13 ;
     14 ;    Thunk64To32.asm
     15 ;
     16 ; Abstract:
     17 ;
     18 ;   This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then
     19 ;   transit back to long mode.
     20 ;
     21 ;-------------------------------------------------------------------------------
     22     .code
     23 ;----------------------------------------------------------------------------
     24 ; Procedure:    AsmExecute32BitCode
     25 ;
     26 ; Input:        None
     27 ;
     28 ; Output:       None
     29 ;
     30 ; Prototype:    UINT32
     31 ;               AsmExecute32BitCode (
     32 ;                 IN UINT64           Function,
     33 ;                 IN UINT64           Param1,
     34 ;                 IN UINT64           Param2,
     35 ;                 IN IA32_DESCRIPTOR  *InternalGdtr
     36 ;                 );
     37 ;
     38 ;
     39 ; Description:  A thunk function to execute 32-bit code in long mode.
     40 ;
     41 ;----------------------------------------------------------------------------
     42 AsmExecute32BitCode    PROC
     43     ;
     44     ; save IFLAG and disable it
     45     ;
     46     pushfq
     47     cli
     48 
     49     ;
     50     ; save orignal GDTR and CS
     51     ;
     52     mov     rax, ds
     53     push    rax
     54     mov     rax, cs
     55     push    rax
     56     sub     rsp, 10h
     57     sgdt    fword ptr [rsp]
     58     ;
     59     ; load internal GDT
     60     ;
     61     lgdt    fword ptr [r9]
     62     ;
     63     ; Save general purpose register and rflag register
     64     ;
     65     pushfq
     66     push    rdi
     67     push    rsi
     68     push    rbp
     69     push    rbx
     70 
     71     ;
     72     ; save CR3
     73     ;
     74     mov     rax, cr3
     75     mov     rbp, rax
     76 
     77     ;
     78     ; Prepare the CS and return address for the transition from 32-bit to 64-bit mode
     79     ;
     80     mov     rax, 10h              ; load long mode selector
     81     shl     rax, 32
     82     mov     r9, OFFSET ReloadCS   ;Assume the ReloadCS is under 4G
     83     or      rax, r9
     84     push    rax
     85     ;
     86     ; Save parameters for 32-bit function call
     87     ;
     88     mov     rax, r8
     89     shl     rax, 32
     90     or      rax, rdx
     91     push    rax
     92     ;
     93     ; save the 32-bit function entry and the return address into stack which will be
     94     ; retrieve in compatibility mode.
     95     ;
     96     mov     rax, OFFSET ReturnBack   ;Assume the ReloadCS is under 4G
     97     shl     rax, 32
     98     or      rax, rcx
     99     push    rax
    100 
    101     ;
    102     ; let rax save DS
    103     ;
    104     mov     rax, 018h
    105 
    106     ;
    107     ; Change to Compatible Segment
    108     ;
    109     mov     rcx, 08h               ; load compatible mode selector
    110     shl     rcx, 32
    111     mov     rdx, OFFSET Compatible ; assume address < 4G
    112     or      rcx, rdx
    113     push    rcx
    114     retf
    115 
    116 Compatible:
    117     ; reload DS/ES/SS to make sure they are correct referred to current GDT
    118     mov     ds, ax
    119     mov     es, ax
    120     mov     ss, ax
    121 
    122     ;
    123     ; Disable paging
    124     ;
    125     mov     rcx, cr0
    126     btc     ecx, 31
    127     mov     cr0, rcx
    128     ;
    129     ; Clear EFER.LME
    130     ;
    131     mov     ecx, 0C0000080h
    132     rdmsr
    133     btc     eax, 8
    134     wrmsr
    135 
    136 ; Now we are in protected mode
    137     ;
    138     ; Call 32-bit function. Assume the function entry address and parameter value is less than 4G
    139     ;
    140     pop    rax                 ; Here is the function entry
    141     ;
    142     ; Now the parameter is at the bottom of the stack,  then call in to IA32 function.
    143     ;
    144     jmp   rax
    145 ReturnBack:
    146     mov   ebx, eax             ; save return status
    147     pop   rcx                  ; drop param1
    148     pop   rcx                  ; drop param2
    149 
    150     ;
    151     ; restore CR4
    152     ;
    153     mov     rax, cr4
    154     bts     eax, 5
    155     mov     cr4, rax
    156 
    157     ;
    158     ; restore CR3
    159     ;
    160     mov     eax, ebp
    161     mov     cr3, rax
    162 
    163     ;
    164     ; Set EFER.LME to re-enable ia32-e
    165     ;
    166     mov     ecx, 0C0000080h
    167     rdmsr
    168     bts     eax, 8
    169     wrmsr
    170     ;
    171     ; Enable paging
    172     ;
    173     mov     rax, cr0
    174     bts     eax, 31
    175     mov     cr0, rax
    176 ; Now we are in compatible mode
    177 
    178     ;
    179     ; Reload cs register
    180     ;
    181     retf
    182 ReloadCS:
    183     ;
    184     ; Now we're in Long Mode
    185     ;
    186     ;
    187     ; Restore C register and eax hold the return status from 32-bit function.
    188     ; Note: Do not touch rax from now which hold the return value from IA32 function
    189     ;
    190     mov     eax, ebx ; put return status to EAX
    191     pop     rbx
    192     pop     rbp
    193     pop     rsi
    194     pop     rdi
    195     popfq
    196     ;
    197     ; Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
    198     ;
    199     lgdt    fword ptr[rsp]
    200     ;
    201     ; drop GDT descriptor in stack
    202     ;
    203     add     rsp, 10h
    204     ;
    205     ; switch to orignal CS and GDTR
    206     ;
    207     pop     r9                 ; get  CS
    208     shl     r9,  32            ; rcx[32..47] <- Cs
    209     mov     rcx, OFFSET @F
    210     or      rcx, r9
    211     push    rcx
    212     retf
    213 @@:
    214     ;
    215     ; Reload original DS/ES/SS
    216     ;
    217     pop     rcx
    218     mov     ds, rcx
    219     mov     es, rcx
    220     mov     ss, rcx
    221 
    222     ;
    223     ; Restore IFLAG
    224     ;
    225     popfq
    226 
    227     ret
    228 AsmExecute32BitCode   ENDP
    229 
    230     END
    231