]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/X64/Thunk64To32.nasm
IntelFsp2WrapperPkg BaseFspWrapperApiLib: Convert X64/Thunk64To32.asm to NASM
[mirror_edk2.git] / IntelFsp2WrapperPkg / Library / BaseFspWrapperApiLib / X64 / Thunk64To32.nasm
CommitLineData
24498828
LG
1;\r
2; Copyright (c) 2016, 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.nasm\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 DEFAULT REL\r
23 SECTION .text\r
24;----------------------------------------------------------------------------\r
25; Procedure: AsmExecute32BitCode\r
26;\r
27; Input: None\r
28;\r
29; Output: None\r
30;\r
31; Prototype: UINT32\r
32; AsmExecute32BitCode (\r
33; IN UINT64 Function,\r
34; IN UINT64 Param1,\r
35; IN UINT64 Param2,\r
36; IN IA32_DESCRIPTOR *InternalGdtr\r
37; );\r
38;\r
39;\r
40; Description: A thunk function to execute 32-bit code in long mode.\r
41;\r
42;----------------------------------------------------------------------------\r
43global 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 mov rax, ds\r
55 push rax\r
56 mov rax, cs\r
57 push rax\r
58 sub rsp, 0x10\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 mov rax, cr3\r
77 mov rbp, rax\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 mov rax, dword 0x10 ; load long mode selector\r
83 shl rax, 32\r
84 mov r9, ReloadCS ;Assume the ReloadCS is under 4G\r
85 or rax, r9\r
86 push rax\r
87 ;\r
88 ; Save parameters for 32-bit function call\r
89 ;\r
90 mov rax, r8\r
91 shl rax, 32\r
92 or rax, rdx\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 mov rax, ReturnBack ;Assume the ReloadCS is under 4G\r
99 shl rax, 32\r
100 or rax, rcx\r
101 push rax\r
102\r
103 ;\r
104 ; let rax save DS\r
105 ;\r
106 mov rax, dword 0x18\r
107\r
108 ;\r
109 ; Change to Compatible Segment\r
110 ;\r
111 mov rcx, dword 0x8 ; load compatible mode selector\r
112 shl rcx, 32\r
113 mov rdx, Compatible ; assume address < 4G\r
114 or rcx, rdx\r
115 push rcx\r
116 retf\r
117\r
118Compatible:\r
119 ; reload DS/ES/SS to make sure they are correct referred to current GDT\r
120 mov ds, ax\r
121 mov es, ax\r
122 mov ss, ax\r
123\r
124 ;\r
125 ; Disable paging\r
126 ;\r
127 mov rcx, cr0\r
128 btc ecx, 31\r
129 mov cr0, rcx\r
130 ;\r
131 ; Clear EFER.LME\r
132 ;\r
133 mov ecx, 0xC0000080\r
134 rdmsr\r
135 btc eax, 8\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 mov ebx, eax ; 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 mov rax, cr4\r
156 bts eax, 5\r
157 mov cr4, rax\r
158\r
159 ;\r
160 ; restore CR3\r
161 ;\r
162 mov eax, ebp\r
163 mov cr3, rax\r
164\r
165 ;\r
166 ; Set EFER.LME to re-enable ia32-e\r
167 ;\r
168 mov ecx, 0xC0000080\r
169 rdmsr\r
170 bts eax, 8\r
171 wrmsr\r
172 ;\r
173 ; Enable paging\r
174 ;\r
175 mov rax, cr0\r
176 bts eax, 31\r
177 mov cr0, rax\r
178; Now we are in compatible mode\r
179\r
180 ;\r
181 ; Reload cs register\r
182 ;\r
183 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 mov eax, ebx ; 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 add rsp, 0x10\r
206 ;\r
207 ; switch to orignal CS and GDTR\r
208 ;\r
209 pop r9 ; get CS\r
210 shl r9, 32 ; rcx[32..47] <- Cs\r
211 mov rcx, .0\r
212 or rcx, r9\r
213 push rcx\r
214 retf\r
215.0:\r
216 ;\r
217 ; Reload original DS/ES/SS\r
218 ;\r
219 pop rcx\r
220 mov ds, rcx\r
221 mov es, rcx\r
222 mov ss, rcx\r
223\r
224 ;\r
225 ; Restore IFLAG\r
226 ;\r
227 popfq\r
228\r
229 ret\r
230\r