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