--- /dev/null
+#\r
+# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php.\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+# Module Name:\r
+#\r
+# Thunk64To32.asm\r
+#\r
+# Abstract:\r
+#\r
+# This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then\r
+# transit back to long mode.\r
+#\r
+#-------------------------------------------------------------------------------\r
+\r
+#----------------------------------------------------------------------------\r
+# Procedure: AsmExecute32BitCode\r
+#\r
+# Input: None\r
+#\r
+# Output: None\r
+#\r
+# Prototype: UINT32\r
+# AsmExecute32BitCode (\r
+# IN UINT64 Function,\r
+# IN UINT64 Param1,\r
+# IN UINT64 Param2,\r
+# IN IA32_DESCRIPTOR *InternalGdtr\r
+# );\r
+#\r
+#\r
+# Description: A thunk function to execute 32-bit code in long mode.\r
+#\r
+#----------------------------------------------------------------------------\r
+\r
+ASM_GLOBAL ASM_PFX(AsmExecute32BitCode)\r
+ASM_PFX(AsmExecute32BitCode):\r
+ #\r
+ # save IFLAG and disable it\r
+ #\r
+ pushfq\r
+ cli\r
+\r
+ #\r
+ # save orignal GDTR and CS\r
+ #\r
+ movl %ds, %eax\r
+ push %rax\r
+ movl %cs, %eax\r
+ push %rax\r
+ subq $0x10, %rsp\r
+ sgdt (%rsp)\r
+ #\r
+ # load internal GDT\r
+ #\r
+ lgdt (%r9)\r
+ #\r
+ # Save general purpose register and rflag register\r
+ #\r
+ pushfq\r
+ push %rdi\r
+ push %rsi\r
+ push %rbp\r
+ push %rbx\r
+\r
+ #\r
+ # save CR3\r
+ #\r
+ movq %cr3, %rax\r
+ movq %rax, %rbp\r
+\r
+ #\r
+ # Prepare the CS and return address for the transition from 32-bit to 64-bit mode\r
+ #\r
+ movq $0x10, %rax # load long mode selector\r
+ shl $32, %rax\r
+ lea ReloadCS(%rip), %r9 #Assume the ReloadCS is under 4G\r
+ orq %r9, %rax\r
+ push %rax\r
+ #\r
+ # Save parameters for 32-bit function call\r
+ #\r
+ movq %r8, %rax\r
+ shl $32, %rax\r
+ orq %rdx, %rax\r
+ push %rax\r
+ #\r
+ # save the 32-bit function entry and the return address into stack which will be\r
+ # retrieve in compatibility mode.\r
+ #\r
+ lea ReturnBack(%rip), %rax #Assume the ReloadCS is under 4G\r
+ shl $32, %rax\r
+ orq %rcx, %rax\r
+ push %rax\r
+\r
+ #\r
+ # let rax save DS\r
+ #\r
+ movq $0x18, %rax\r
+\r
+ #\r
+ # Change to Compatible Segment\r
+ #\r
+ movq $8, %rcx # load compatible mode selector\r
+ shl $32, %rcx\r
+ lea Compatible(%rip), %rdx # assume address < 4G\r
+ orq %rdx, %rcx\r
+ push %rcx\r
+ .byte 0xcb # retf\r
+\r
+Compatible:\r
+ # reload DS/ES/SS to make sure they are correct referred to current GDT\r
+ movw %ax, %ds\r
+ movw %ax, %es\r
+ movw %ax, %ss\r
+\r
+ #\r
+ # Disable paging\r
+ #\r
+ movq %cr0, %rcx\r
+ btc $31, %ecx\r
+ movq %rcx, %cr0\r
+ #\r
+ # Clear EFER.LME\r
+ #\r
+ movl $0xC0000080, %ecx\r
+ rdmsr\r
+ btc $8, %eax\r
+ wrmsr\r
+\r
+# Now we are in protected mode\r
+ #\r
+ # Call 32-bit function. Assume the function entry address and parameter value is less than 4G\r
+ #\r
+ pop %rax # Here is the function entry\r
+ #\r
+ # Now the parameter is at the bottom of the stack, then call in to IA32 function.\r
+ #\r
+ jmp *%rax\r
+ReturnBack:\r
+ movl %eax, %ebx # save return status\r
+ pop %rcx # drop param1\r
+ pop %rcx # drop param2\r
+\r
+ #\r
+ # restore CR4\r
+ #\r
+ movq %cr4, %rax\r
+ bts $5, %eax\r
+ movq %rax, %cr4\r
+\r
+ #\r
+ # restore CR3\r
+ #\r
+ movl %ebp, %eax\r
+ movq %rax, %cr3\r
+\r
+ #\r
+ # Set EFER.LME to re-enable ia32-e\r
+ #\r
+ movl $0xC0000080, %ecx\r
+ rdmsr\r
+ bts $8, %eax\r
+ wrmsr\r
+ #\r
+ # Enable paging\r
+ #\r
+ movq %cr0, %rax\r
+ bts $31, %eax\r
+ mov %rax, %cr0\r
+# Now we are in compatible mode\r
+\r
+ #\r
+ # Reload cs register\r
+ #\r
+ .byte 0xcb # retf\r
+ReloadCS:\r
+ #\r
+ # Now we're in Long Mode\r
+ #\r
+ #\r
+ # Restore C register and eax hold the return status from 32-bit function.\r
+ # Note: Do not touch rax from now which hold the return value from IA32 function\r
+ #\r
+ movl %ebx, %eax # put return status to EAX\r
+ pop %rbx\r
+ pop %rbp\r
+ pop %rsi\r
+ pop %rdi\r
+ popfq\r
+ #\r
+ # Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.\r
+ #\r
+ lgdt (%rsp)\r
+ #\r
+ # drop GDT descriptor in stack\r
+ #\r
+ addq $0x10, %rsp\r
+ #\r
+ # switch to orignal CS and GDTR\r
+ #\r
+ pop %r9 # get CS\r
+ shl $32, %r9 # rcx[32..47] <- Cs\r
+ lea ReturnToLongMode(%rip), %rcx\r
+ orq %r9, %rcx\r
+ push %rcx\r
+ .byte 0xcb # retf\r
+ReturnToLongMode:\r
+ #\r
+ # Reload original DS/ES/SS\r
+ #\r
+ pop %rcx\r
+ movl %ecx, %ds\r
+ movl %ecx, %es\r
+ movl %ecx, %ss\r
+\r
+ #\r
+ # Restore IFLAG\r
+ #\r
+ popfq\r
+\r
+ ret\r
+\r