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 43ASM_GLOBAL ASM_PFX(AsmExecute32BitCode) 44ASM_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 118Compatible: 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 147ReturnBack: 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 184ReloadCS: 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 215ReturnToLongMode: 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