• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# Copyright (c) 2010, 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#    AsmDispatchExecute.asm
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
23#----------------------------------------------------------------------------
24# Procedure:    AsmExecute32BitCode
25#
26# Input:        None
27#
28# Output:       None
29#
30# Prototype:    EFI_STATUS
31#               AsmExecute32BitCode (
32#                 IN UINT64           Function,
33#                 IN UINT64           Param1,
34#                 IN UINT64           Param2,
35#                 IN IA32_DESCRIPTOR  *InternalGdtr
36#                 );
37#
38#
39# Description:  A thunk function to execute 32-bit code in long mode.
40#
41#----------------------------------------------------------------------------
42
43ASM_GLOBAL ASM_PFX(AsmExecute32BitCode)
44ASM_PFX(AsmExecute32BitCode):
45    #
46    # save orignal GDTR and CS
47    #
48    movl    %ds, %eax
49    push    %rax
50    movl    %cs, %eax
51    push    %rax
52    subq    $0x10, %rsp
53    sgdt    (%rsp)
54    #
55    # load internal GDT
56    #
57    lgdt    (%r9)
58    #
59    # Save general purpose register and rflag register
60    #
61    pushfq
62    push    %rdi
63    push    %rsi
64    push    %rbp
65    push    %rbx
66
67    #
68    # save CR3
69    #
70    movq    %cr3, %rax
71    movq    %rax, %rbp
72
73    #
74    # Prepare the CS and return address for the transition from 32-bit to 64-bit mode
75    #
76    movq    $0x10, %rax              # load long mode selector
77    shl     $32, %rax
78    lea     ReloadCS(%rip), %r9   #Assume the ReloadCS is under 4G
79    orq     %r9, %rax
80    push    %rax
81    #
82    # Save parameters for 32-bit function call
83    #
84    movq    %r8, %rax
85    shl     $32, %rax
86    orq     %rdx, %rax
87    push    %rax
88    #
89    # save the 32-bit function entry and the return address into stack which will be
90    # retrieve in compatibility mode.
91    #
92    lea     ReturnBack(%rip), %rax   #Assume the ReloadCS is under 4G
93    shl     $32, %rax
94    orq     %rcx, %rax
95    push    %rax
96
97    #
98    # let rax save DS
99    #
100    movq    $0x18, %rax
101
102    #
103    # Change to Compatible Segment
104    #
105    movq    $8, %rcx               # load compatible mode selector
106    shl     $32, %rcx
107    lea     Compatible(%rip), %rdx # assume address < 4G
108    orq     %rdx, %rcx
109    push    %rcx
110    .byte   0xcb                # retf
111
112Compatible:
113    # reload DS/ES/SS to make sure they are correct referred to current GDT
114    movw    %ax, %ds
115    movw    %ax, %es
116    movw    %ax, %ss
117
118    #
119    # Disable paging
120    #
121    movq    %cr0, %rcx
122    btc     $31, %ecx
123    movq    %rcx, %cr0
124    #
125    # Clear EFER.LME
126    #
127    movl    $0xC0000080, %ecx
128    rdmsr
129    btc     $8, %eax
130    wrmsr
131
132# Now we are in protected mode
133    #
134    # Call 32-bit function. Assume the function entry address and parameter value is less than 4G
135    #
136    pop    %rax                 # Here is the function entry
137    #
138    # Now the parameter is at the bottom of the stack,  then call in to IA32 function.
139    #
140    jmp   *%rax
141ReturnBack:
142    pop   %rcx                  # drop param1
143    pop   %rcx                  # drop param2
144
145    #
146    # restore CR4
147    #
148    movq    %cr4, %rax
149    bts     $5, %eax
150    movq    %rax, %cr4
151
152    #
153    # restore CR3
154    #
155    movl    %ebp, %eax
156    movq    %rax, %cr3
157
158    #
159    # Set EFER.LME to re-enable ia32-e
160    #
161    movl    $0xC0000080, %ecx
162    rdmsr
163    bts     $8, %eax
164    wrmsr
165    #
166    # Enable paging
167    #
168    movq    %cr0, %rax
169    bts     $31, %eax
170    mov     %rax, %cr0
171# Now we are in compatible mode
172
173    #
174    # Reload cs register
175    #
176    .byte   0xcb                # retf
177ReloadCS:
178    #
179    # Now we're in Long Mode
180    #
181    #
182    # Restore C register and eax hold the return status from 32-bit function.
183    # Note: Do not touch rax from now which hold the return value from IA32 function
184    #
185    pop     %rbx
186    pop     %rbp
187    pop     %rsi
188    pop     %rdi
189    popfq
190    #
191    # Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
192    #
193    lgdt    (%rsp)
194    #
195    # drop GDT descriptor in stack
196    #
197    addq    $0x10, %rsp
198    #
199    # switch to orignal CS and GDTR
200    #
201    pop     %r9                 # get  CS
202    shl     $32, %r9            # rcx[32..47] <- Cs
203    lea     ReturnToLongMode(%rip), %rcx
204    orq     %r9, %rcx
205    push    %rcx
206    .byte   0xcb                # retf
207ReturnToLongMode:
208    #
209    # Reload original DS/ES/SS
210    #
211    pop     %rcx
212    movl    %ecx, %ds
213    movl    %ecx, %es
214    movl    %ecx, %ss
215    ret
216
217