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