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