]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFspWrapperPkg/Library/BaseFspApiLib/X64/Thunk64To32.S
DynamicTablesPkg: GTDT updates for ACPI 6.3
[mirror_edk2.git] / IntelFspWrapperPkg / Library / BaseFspApiLib / X64 / Thunk64To32.S
1 #
2 # Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
3 # SPDX-License-Identifier: BSD-2-Clause-Patent
4 #
5 #
6 # Module Name:
7 #
8 # Thunk64To32.asm
9 #
10 # Abstract:
11 #
12 # This is the assembly code to transition from long mode to compatibility mode to execute 32-bit code and then
13 # transit back to long mode.
14 #
15 #-------------------------------------------------------------------------------
16
17 #----------------------------------------------------------------------------
18 # Procedure: AsmExecute32BitCode
19 #
20 # Input: None
21 #
22 # Output: None
23 #
24 # Prototype: UINT32
25 # AsmExecute32BitCode (
26 # IN UINT64 Function,
27 # IN UINT64 Param1,
28 # IN UINT64 Param2,
29 # IN IA32_DESCRIPTOR *InternalGdtr
30 # );
31 #
32 #
33 # Description: A thunk function to execute 32-bit code in long mode.
34 #
35 #----------------------------------------------------------------------------
36
37 ASM_GLOBAL ASM_PFX(AsmExecute32BitCode)
38 ASM_PFX(AsmExecute32BitCode):
39 #
40 # save IFLAG and disable it
41 #
42 pushfq
43 cli
44
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
112 Compatible:
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
141 ReturnBack:
142 movl %eax, %ebx # save return status
143 pop %rcx # drop param1
144 pop %rcx # drop param2
145
146 #
147 # restore CR4
148 #
149 movq %cr4, %rax
150 bts $5, %eax
151 movq %rax, %cr4
152
153 #
154 # restore CR3
155 #
156 movl %ebp, %eax
157 movq %rax, %cr3
158
159 #
160 # Set EFER.LME to re-enable ia32-e
161 #
162 movl $0xC0000080, %ecx
163 rdmsr
164 bts $8, %eax
165 wrmsr
166 #
167 # Enable paging
168 #
169 movq %cr0, %rax
170 bts $31, %eax
171 mov %rax, %cr0
172 # Now we are in compatible mode
173
174 #
175 # Reload cs register
176 #
177 .byte 0xcb # retf
178 ReloadCS:
179 #
180 # Now we're in Long Mode
181 #
182 #
183 # Restore C register and eax hold the return status from 32-bit function.
184 # Note: Do not touch rax from now which hold the return value from IA32 function
185 #
186 movl %ebx, %eax # put return status to EAX
187 pop %rbx
188 pop %rbp
189 pop %rsi
190 pop %rdi
191 popfq
192 #
193 # Switch to orignal GDT and CS. here rsp is pointer to the orignal GDT descriptor.
194 #
195 lgdt (%rsp)
196 #
197 # drop GDT descriptor in stack
198 #
199 addq $0x10, %rsp
200 #
201 # switch to orignal CS and GDTR
202 #
203 pop %r9 # get CS
204 shl $32, %r9 # rcx[32..47] <- Cs
205 lea ReturnToLongMode(%rip), %rcx
206 orq %r9, %rcx
207 push %rcx
208 .byte 0xcb # retf
209 ReturnToLongMode:
210 #
211 # Reload original DS/ES/SS
212 #
213 pop %rcx
214 movl %ecx, %ds
215 movl %ecx, %es
216 movl %ecx, %ss
217
218 #
219 # Restore IFLAG
220 #
221 popfq
222
223 ret
224