--- /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
+ .code\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
+AsmExecute32BitCode PROC\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, 10h\r
+ sgdt fword ptr [rsp]\r
+ ;\r
+ ; load internal GDT\r
+ ;\r
+ lgdt fword ptr [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, 10h ; load long mode selector\r
+ shl rax, 32\r
+ mov r9, OFFSET 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, OFFSET 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, 018h\r
+\r
+ ;\r
+ ; Change to Compatible Segment\r
+ ;\r
+ mov rcx, 08h ; load compatible mode selector\r
+ shl rcx, 32\r
+ mov rdx, OFFSET 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, 0C0000080h\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, 0C0000080h\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 fword ptr[rsp]\r
+ ;\r
+ ; drop GDT descriptor in stack\r
+ ;\r
+ add rsp, 10h\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, OFFSET @F\r
+ or rcx, r9\r
+ push rcx\r
+ retf\r
+@@:\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
+AsmExecute32BitCode ENDP\r
+\r
+ END\r