Home | History | Annotate | Download | only in X64
      1 #
      2 # Copyright (c) 2010, 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 #    AsmDispatchExecute.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:    EFI_STATUS
     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 orignal GDTR and CS
     47     #
     48     movl    %ds, %eax
     49     push    %rax
     50     movl    %cs, %eax
     51     push    %rax
     52     subq    $0x10, %rsp
     53     sgdt    (%rsp)
     54     #
     55     # load internal GDT
     56     #
     57     lgdt    (%r9)
     58     #
     59     # Save general purpose register and rflag register
     60     #
     61     pushfq
     62     push    %rdi
     63     push    %rsi
     64     push    %rbp
     65     push    %rbx
     66 
     67     #
     68     # save CR3
     69     #
     70     movq    %cr3, %rax
     71     movq    %rax, %rbp
     72 
     73     #
     74     # Prepare the CS and return address for the transition from 32-bit to 64-bit mode
     75     #
     76     movq    $0x10, %rax              # load long mode selector
     77     shl     $32, %rax
     78     lea     ReloadCS(%rip), %r9   #Assume the ReloadCS is under 4G
     79     orq     %r9, %rax
     80     push    %rax
     81     #
     82     # Save parameters for 32-bit function call
     83     #
     84     movq    %r8, %rax
     85     shl     $32, %rax
     86     orq     %rdx, %rax
     87     push    %rax
     88     #
     89     # save the 32-bit function entry and the return address into stack which will be
     90     # retrieve in compatibility mode.
     91     #
     92     lea     ReturnBack(%rip), %rax   #Assume the ReloadCS is under 4G
     93     shl     $32, %rax
     94     orq     %rcx, %rax
     95     push    %rax
     96 
     97     #
     98     # let rax save DS
     99     #
    100     movq    $0x18, %rax
    101 
    102     #
    103     # Change to Compatible Segment
    104     #
    105     movq    $8, %rcx               # load compatible mode selector
    106     shl     $32, %rcx
    107     lea     Compatible(%rip), %rdx # assume address < 4G
    108     orq     %rdx, %rcx
    109     push    %rcx
    110     .byte   0xcb                # retf
    111 
    112 Compatible:
    113     # reload DS/ES/SS to make sure they are correct referred to current GDT
    114     movw    %ax, %ds
    115     movw    %ax, %es
    116     movw    %ax, %ss
    117 
    118     #
    119     # Disable paging
    120     #
    121     movq    %cr0, %rcx
    122     btc     $31, %ecx
    123     movq    %rcx, %cr0
    124     #
    125     # Clear EFER.LME
    126     #
    127     movl    $0xC0000080, %ecx
    128     rdmsr
    129     btc     $8, %eax
    130     wrmsr
    131 
    132 # Now we are in protected mode
    133     #
    134     # Call 32-bit function. Assume the function entry address and parameter value is less than 4G
    135     #
    136     pop    %rax                 # Here is the function entry
    137     #
    138     # Now the parameter is at the bottom of the stack,  then call in to IA32 function.
    139     #
    140     jmp   *%rax
    141 ReturnBack:
    142     pop   %rcx                  # drop param1
    143     pop   %rcx                  # drop param2
    144 
    145     #
    146     # restore CR4
    147     #
    148     movq    %cr4, %rax
    149     bts     $5, %eax
    150     movq    %rax, %cr4
    151 
    152     #
    153     # restore CR3
    154     #
    155     movl    %ebp, %eax
    156     movq    %rax, %cr3
    157 
    158     #
    159     # Set EFER.LME to re-enable ia32-e
    160     #
    161     movl    $0xC0000080, %ecx
    162     rdmsr
    163     bts     $8, %eax
    164     wrmsr
    165     #
    166     # Enable paging
    167     #
    168     movq    %cr0, %rax
    169     bts     $31, %eax
    170     mov     %rax, %cr0
    171 # Now we are in compatible mode
    172 
    173     #
    174     # Reload cs register
    175     #
    176     .byte   0xcb                # retf
    177 ReloadCS:
    178     #
    179     # Now we're in Long Mode
    180     #
    181     #
    182     # Restore C register and eax hold the return status from 32-bit function.
    183     # Note: Do not touch rax from now which hold the return value from IA32 function
    184     #
    185     pop     %rbx
    186     pop     %rbp
    187     pop     %rsi
    188     pop     %rdi
    189     popfq
    190     #
    191     # Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
    192     #
    193     lgdt    (%rsp)
    194     #
    195     # drop GDT descriptor in stack
    196     #
    197     addq    $0x10, %rsp
    198     #
    199     # switch to orignal CS and GDTR
    200     #
    201     pop     %r9                 # get  CS
    202     shl     $32, %r9            # rcx[32..47] <- Cs
    203     lea     ReturnToLongMode(%rip), %rcx
    204     orq     %r9, %rcx
    205     push    %rcx
    206     .byte   0xcb                # retf
    207 ReturnToLongMode:
    208     #
    209     # Reload original DS/ES/SS
    210     #
    211     pop     %rcx
    212     movl    %ecx, %ds
    213     movl    %ecx, %es
    214     movl    %ecx, %ss
    215     ret
    216 
    217