]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.S
Add IntelFsp2Pkg and IntelFsp2WrapperPkg.
[mirror_edk2.git] / IntelFsp2WrapperPkg / Library / BaseFspWrapperApiLib / X64 / Thunk64To32.S
diff --git a/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.S b/IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.S
new file mode 100644 (file)
index 0000000..b6b5c1a
--- /dev/null
@@ -0,0 +1,230 @@
+#\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