--- /dev/null
+;\r
+; Copyright (c) 2016, 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.nasm\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
+ DEFAULT REL\r
+ SECTION .text\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
+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
+ mov rax, ds\r
+ push rax\r
+ mov rax, cs\r
+ push rax\r
+ sub rsp, 0x10\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
+ mov rax, cr3\r
+ mov rbp, rax\r
+\r
+ ;\r
+ ; Prepare the CS and return address for the transition from 32-bit to 64-bit mode\r
+ ;\r
+ mov rax, dword 0x10 ; load long mode selector\r
+ shl rax, 32\r
+ mov r9, ReloadCS ;Assume the ReloadCS is under 4G\r
+ or rax, r9\r
+ push rax\r
+ ;\r
+ ; Save parameters for 32-bit function call\r
+ ;\r
+ mov rax, r8\r
+ shl rax, 32\r
+ or rax, rdx\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
+ mov rax, ReturnBack ;Assume the ReloadCS is under 4G\r
+ shl rax, 32\r
+ or rax, rcx\r
+ push rax\r
+\r
+ ;\r
+ ; let rax save DS\r
+ ;\r
+ mov rax, dword 0x18\r
+\r
+ ;\r
+ ; Change to Compatible Segment\r
+ ;\r
+ mov rcx, dword 0x8 ; load compatible mode selector\r
+ shl rcx, 32\r
+ mov rdx, Compatible ; assume address < 4G\r
+ or rcx, rdx\r
+ push rcx\r
+ retf\r
+\r
+Compatible:\r
+ ; reload DS/ES/SS to make sure they are correct referred to current GDT\r
+ mov ds, ax\r
+ mov es, ax\r
+ mov ss, ax\r
+\r
+ ;\r
+ ; Disable paging\r
+ ;\r
+ mov rcx, cr0\r
+ btc ecx, 31\r
+ mov cr0, rcx\r
+ ;\r
+ ; Clear EFER.LME\r
+ ;\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ btc eax, 8\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
+ mov ebx, eax ; save return status\r
+ pop rcx ; drop param1\r
+ pop rcx ; drop param2\r
+\r
+ ;\r
+ ; restore CR4\r
+ ;\r
+ mov rax, cr4\r
+ bts eax, 5\r
+ mov cr4, rax\r
+\r
+ ;\r
+ ; restore CR3\r
+ ;\r
+ mov eax, ebp\r
+ mov cr3, rax\r
+\r
+ ;\r
+ ; Set EFER.LME to re-enable ia32-e\r
+ ;\r
+ mov ecx, 0xC0000080\r
+ rdmsr\r
+ bts eax, 8\r
+ wrmsr\r
+ ;\r
+ ; Enable paging\r
+ ;\r
+ mov rax, cr0\r
+ bts eax, 31\r
+ mov cr0, rax\r
+; Now we are in compatible mode\r
+\r
+ ;\r
+ ; Reload cs register\r
+ ;\r
+ 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
+ mov eax, ebx ; 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
+ add rsp, 0x10\r
+ ;\r
+ ; switch to orignal CS and GDTR\r
+ ;\r
+ pop r9 ; get CS\r
+ shl r9, 32 ; rcx[32..47] <- Cs\r
+ mov rcx, .0\r
+ or rcx, r9\r
+ push rcx\r
+ retf\r
+.0:\r
+ ;\r
+ ; Reload original DS/ES/SS\r
+ ;\r
+ pop rcx\r
+ mov ds, rcx\r
+ mov es, rcx\r
+ mov ss, rcx\r
+\r
+ ;\r
+ ; Restore IFLAG\r
+ ;\r
+ popfq\r
+\r
+ ret\r
+\r