Add IntelFsp2Pkg and IntelFsp2WrapperPkg.
[mirror_edk2.git] / IntelFsp2WrapperPkg / Library / BaseFspWrapperApiLib / X64 / Thunk64To32.S
CommitLineData
cf1d4549
JY
1#\r
2# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
3# This program and the accompanying materials\r
4# are licensed and made available under the terms and conditions of the BSD License\r
5# which accompanies this distribution. The full text of the license may be found at\r
6# http://opensource.org/licenses/bsd-license.php.\r
7#\r
8# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
9# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
10#\r
11#\r
12# Module Name:\r
13#\r
14# Thunk64To32.asm\r
15#\r
16# Abstract:\r
17#\r
18# This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then\r
19# transit back to long mode.\r
20#\r
21#-------------------------------------------------------------------------------\r
22\r
23#----------------------------------------------------------------------------\r
24# Procedure: AsmExecute32BitCode\r
25#\r
26# Input: None\r
27#\r
28# Output: None\r
29#\r
30# Prototype: UINT32\r
31# AsmExecute32BitCode (\r
32# IN UINT64 Function,\r
33# IN UINT64 Param1,\r
34# IN UINT64 Param2,\r
35# IN IA32_DESCRIPTOR *InternalGdtr\r
36# );\r
37#\r
38#\r
39# Description: A thunk function to execute 32-bit code in long mode.\r
40#\r
41#----------------------------------------------------------------------------\r
42\r
43ASM_GLOBAL ASM_PFX(AsmExecute32BitCode)\r
44ASM_PFX(AsmExecute32BitCode):\r
45 #\r
46 # save IFLAG and disable it\r
47 #\r
48 pushfq\r
49 cli\r
50\r
51 #\r
52 # save orignal GDTR and CS\r
53 #\r
54 movl %ds, %eax\r
55 push %rax\r
56 movl %cs, %eax\r
57 push %rax\r
58 subq $0x10, %rsp\r
59 sgdt (%rsp)\r
60 #\r
61 # load internal GDT\r
62 #\r
63 lgdt (%r9)\r
64 #\r
65 # Save general purpose register and rflag register\r
66 #\r
67 pushfq\r
68 push %rdi\r
69 push %rsi\r
70 push %rbp\r
71 push %rbx\r
72\r
73 #\r
74 # save CR3\r
75 #\r
76 movq %cr3, %rax\r
77 movq %rax, %rbp\r
78\r
79 #\r
80 # Prepare the CS and return address for the transition from 32-bit to 64-bit mode\r
81 #\r
82 movq $0x10, %rax # load long mode selector\r
83 shl $32, %rax\r
84 lea ReloadCS(%rip), %r9 #Assume the ReloadCS is under 4G\r
85 orq %r9, %rax\r
86 push %rax\r
87 #\r
88 # Save parameters for 32-bit function call\r
89 #\r
90 movq %r8, %rax\r
91 shl $32, %rax\r
92 orq %rdx, %rax\r
93 push %rax\r
94 #\r
95 # save the 32-bit function entry and the return address into stack which will be\r
96 # retrieve in compatibility mode.\r
97 #\r
98 lea ReturnBack(%rip), %rax #Assume the ReloadCS is under 4G\r
99 shl $32, %rax\r
100 orq %rcx, %rax\r
101 push %rax\r
102\r
103 #\r
104 # let rax save DS\r
105 #\r
106 movq $0x18, %rax\r
107\r
108 #\r
109 # Change to Compatible Segment\r
110 #\r
111 movq $8, %rcx # load compatible mode selector\r
112 shl $32, %rcx\r
113 lea Compatible(%rip), %rdx # assume address < 4G\r
114 orq %rdx, %rcx\r
115 push %rcx\r
116 .byte 0xcb # retf\r
117\r
118Compatible:\r
119 # reload DS/ES/SS to make sure they are correct referred to current GDT\r
120 movw %ax, %ds\r
121 movw %ax, %es\r
122 movw %ax, %ss\r
123\r
124 #\r
125 # Disable paging\r
126 #\r
127 movq %cr0, %rcx\r
128 btc $31, %ecx\r
129 movq %rcx, %cr0\r
130 #\r
131 # Clear EFER.LME\r
132 #\r
133 movl $0xC0000080, %ecx\r
134 rdmsr\r
135 btc $8, %eax\r
136 wrmsr\r
137\r
138# Now we are in protected mode\r
139 #\r
140 # Call 32-bit function. Assume the function entry address and parameter value is less than 4G\r
141 #\r
142 pop %rax # Here is the function entry\r
143 #\r
144 # Now the parameter is at the bottom of the stack, then call in to IA32 function.\r
145 #\r
146 jmp *%rax\r
147ReturnBack:\r
148 movl %eax, %ebx # save return status\r
149 pop %rcx # drop param1\r
150 pop %rcx # drop param2\r
151\r
152 #\r
153 # restore CR4\r
154 #\r
155 movq %cr4, %rax\r
156 bts $5, %eax\r
157 movq %rax, %cr4\r
158\r
159 #\r
160 # restore CR3\r
161 #\r
162 movl %ebp, %eax\r
163 movq %rax, %cr3\r
164\r
165 #\r
166 # Set EFER.LME to re-enable ia32-e\r
167 #\r
168 movl $0xC0000080, %ecx\r
169 rdmsr\r
170 bts $8, %eax\r
171 wrmsr\r
172 #\r
173 # Enable paging\r
174 #\r
175 movq %cr0, %rax\r
176 bts $31, %eax\r
177 mov %rax, %cr0\r
178# Now we are in compatible mode\r
179\r
180 #\r
181 # Reload cs register\r
182 #\r
183 .byte 0xcb # retf\r
184ReloadCS:\r
185 #\r
186 # Now we're in Long Mode\r
187 #\r
188 #\r
189 # Restore C register and eax hold the return status from 32-bit function.\r
190 # Note: Do not touch rax from now which hold the return value from IA32 function\r
191 #\r
192 movl %ebx, %eax # put return status to EAX\r
193 pop %rbx\r
194 pop %rbp\r
195 pop %rsi\r
196 pop %rdi\r
197 popfq\r
198 #\r
199 # Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.\r
200 #\r
201 lgdt (%rsp)\r
202 #\r
203 # drop GDT descriptor in stack\r
204 #\r
205 addq $0x10, %rsp\r
206 #\r
207 # switch to orignal CS and GDTR\r
208 #\r
209 pop %r9 # get CS\r
210 shl $32, %r9 # rcx[32..47] <- Cs\r
211 lea ReturnToLongMode(%rip), %rcx\r
212 orq %r9, %rcx\r
213 push %rcx\r
214 .byte 0xcb # retf\r
215ReturnToLongMode:\r
216 #\r
217 # Reload original DS/ES/SS\r
218 #\r
219 pop %rcx\r
220 movl %ecx, %ds\r
221 movl %ecx, %es\r
222 movl %ecx, %ss\r
223\r
224 #\r
225 # Restore IFLAG\r
226 #\r
227 popfq\r
228\r
229 ret\r
230\r