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