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 
     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 
     43 ASM_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     movl    %ds, %eax
     55     push    %rax
     56     movl    %cs, %eax
     57     push    %rax
     58     subq    $0x10, %rsp
     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     movq    %cr3, %rax
     77     movq    %rax, %rbp
     78 
     79     #
     80     # Prepare the CS and return address for the transition from 32-bit to 64-bit mode
     81     #
     82     movq    $0x10, %rax              # load long mode selector
     83     shl     $32, %rax
     84     lea     ReloadCS(%rip), %r9   #Assume the ReloadCS is under 4G
     85     orq     %r9, %rax
     86     push    %rax
     87     #
     88     # Save parameters for 32-bit function call
     89     #
     90     movq    %r8, %rax
     91     shl     $32, %rax
     92     orq     %rdx, %rax
     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     lea     ReturnBack(%rip), %rax   #Assume the ReloadCS is under 4G
     99     shl     $32, %rax
    100     orq     %rcx, %rax
    101     push    %rax
    102 
    103     #
    104     # let rax save DS
    105     #
    106     movq    $0x18, %rax
    107 
    108     #
    109     # Change to Compatible Segment
    110     #
    111     movq    $8, %rcx               # load compatible mode selector
    112     shl     $32, %rcx
    113     lea     Compatible(%rip), %rdx # assume address < 4G
    114     orq     %rdx, %rcx
    115     push    %rcx
    116     .byte   0xcb                # retf
    117 
    118 Compatible:
    119     # reload DS/ES/SS to make sure they are correct referred to current GDT
    120     movw    %ax, %ds
    121     movw    %ax, %es
    122     movw    %ax, %ss
    123 
    124     #
    125     # Disable paging
    126     #
    127     movq    %cr0, %rcx
    128     btc     $31, %ecx
    129     movq    %rcx, %cr0
    130     #
    131     # Clear EFER.LME
    132     #
    133     movl    $0xC0000080, %ecx
    134     rdmsr
    135     btc     $8, %eax
    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     movl  %eax, %ebx            # save return status
    149     pop   %rcx                  # drop param1
    150     pop   %rcx                  # drop param2
    151 
    152     #
    153     # restore CR4
    154     #
    155     movq    %cr4, %rax
    156     bts     $5, %eax
    157     movq    %rax, %cr4
    158 
    159     #
    160     # restore CR3
    161     #
    162     movl    %ebp, %eax
    163     movq    %rax, %cr3
    164 
    165     #
    166     # Set EFER.LME to re-enable ia32-e
    167     #
    168     movl    $0xC0000080, %ecx
    169     rdmsr
    170     bts     $8, %eax
    171     wrmsr
    172     #
    173     # Enable paging
    174     #
    175     movq    %cr0, %rax
    176     bts     $31, %eax
    177     mov     %rax, %cr0
    178 # Now we are in compatible mode
    179 
    180     #
    181     # Reload cs register
    182     #
    183     .byte   0xcb                # 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     movl    %ebx, %eax # 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     addq    $0x10, %rsp
    206     #
    207     # switch to orignal CS and GDTR
    208     #
    209     pop     %r9                 # get  CS
    210     shl     $32, %r9            # rcx[32..47] <- Cs
    211     lea     ReturnToLongMode(%rip), %rcx
    212     orq     %r9, %rcx
    213     push    %rcx
    214     .byte   0xcb                # retf
    215 ReturnToLongMode:
    216     #
    217     # Reload original DS/ES/SS
    218     #
    219     pop     %rcx
    220     movl    %ecx, %ds
    221     movl    %ecx, %es
    222     movl    %ecx, %ss
    223 
    224     #
    225     # Restore IFLAG
    226     #
    227     popfq
    228 
    229     ret
    230 
    231