]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Foundation/Library/EdkIIGlueLib/Library/BaseLib/X64/Thunk16.asm
Fix the issue that the high 16-bit of EAX may contain invalid data, which cause bad...
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / EdkIIGlueLib / Library / BaseLib / X64 / Thunk16.asm
1 ; Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
2 ; This program and the accompanying materials
3 ; are licensed and made available under the terms and conditions of the BSD License
4 ; which accompanies this distribution. The full text of the license may be found at
5 ; http://opensource.org/licenses/bsd-license.php
6 ;
7 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
8 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
9 ;
10 ; Module Name:
11 ;
12 ; Thunk.asm
13 ;
14 ; Abstract:
15 ;
16 ; Real mode thunk
17 ;
18 ;------------------------------------------------------------------------------
19
20 EXTERNDEF m16Start:BYTE
21 EXTERNDEF m16Size:WORD
22 EXTERNDEF mThunk16Attr:WORD
23 EXTERNDEF m16Gdt:WORD
24 EXTERNDEF m16GdtrBase:WORD
25 EXTERNDEF mTransition:WORD
26
27 THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2
28 THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4
29
30 IA32_REGS STRUC 4t
31 _EDI DD ?
32 _ESI DD ?
33 _EBP DD ?
34 _ESP DD ?
35 _EBX DD ?
36 _EDX DD ?
37 _ECX DD ?
38 _EAX DD ?
39 _DS DW ?
40 _ES DW ?
41 _FS DW ?
42 _GS DW ?
43 _EFLAGS DQ ?
44 _EIP DD ?
45 _CS DW ?
46 _SS DW ?
47 IA32_REGS ENDS
48
49 .const
50
51 m16Size DW InternalAsmThunk16 - m16Start
52 mThunk16Attr DW _ThunkAttr - m16Start
53 m16Gdt DW _NullSeg - m16Start
54 m16GdtrBase DW _16GdtrBase - m16Start
55 mTransition DW _EntryPoint - m16Start
56
57 .code
58
59 m16Start LABEL BYTE
60
61 SavedGdt LABEL FWORD
62 DW ?
63 DQ ?
64
65 ;------------------------------------------------------------------------------
66 ; _BackFromUserCode() takes control in real mode after 'retf' has been executed
67 ; by user code. It will be shadowed to somewhere in memory below 1MB.
68 ;------------------------------------------------------------------------------
69 _BackFromUserCode PROC
70 ;
71 ; The order of saved registers on the stack matches the order they appears
72 ; in IA32_REGS structure. This facilitates wrapper function to extract them
73 ; into that structure.
74 ;
75 ; Some instructions for manipulation of segment registers have to be written
76 ; in opcode since 64-bit MASM prevents accesses to those registers.
77 ;
78 DB 16h ; push ss
79 DB 0eh ; push cs
80 DB 66h
81 call @Base ; push eip
82 @Base:
83 DB 66h
84 push 0 ; reserved high order 32 bits of EFlags
85 pushf ; pushfd actually
86 cli ; disable interrupts
87 push gs
88 push fs
89 DB 6 ; push es
90 DB 1eh ; push ds
91 DB 66h, 60h ; pushad
92 DB 66h, 0bah ; mov edx, imm32
93 _ThunkAttr DD ?
94 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
95 jz @1
96 mov eax, 15cd2401h ; mov ax, 2401h & int 15h
97 cli ; disable interrupts
98 jnc @2
99 @1:
100 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
101 jz @2
102 in al, 92h
103 or al, 2
104 out 92h, al ; deactivate A20M#
105 @2:
106 mov ax, ss
107 lea bp, [esp + sizeof (IA32_REGS)]
108 ;
109 ; rsi in the following 2 instructions is indeed bp in 16-bit code
110 ;
111 mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp
112 DB 66h
113 mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP
114 shl ax, 4 ; shl eax, 4
115 add bp, ax ; add ebp, eax
116 mov ax, cs
117 shl ax, 4
118 lea ax, [eax + ebx + (@64BitCode - @Base)]
119 DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (@64Eip - @Base)], eax
120 DW @64Eip - @Base
121 DB 66h, 0b8h ; mov eax, imm32
122 SavedCr4 DD ?
123 mov cr4, rax
124 ;
125 ; rdi in the instruction below is indeed bx in 16-bit code
126 ;
127 DB 66h, 2eh ; 2eh is "cs:" segment override
128 lgdt fword ptr [rdi + (SavedGdt - @Base)]
129 DB 66h
130 mov ecx, 0c0000080h
131 rdmsr
132 or ah, 1
133 wrmsr
134 DB 66h, 0b8h ; mov eax, imm32
135 SavedCr0 DD ?
136 mov cr0, rax
137 DB 66h, 0eah ; jmp far cs:@64Bit
138 @64Eip DD ?
139 SavedCs DW ?
140 @64BitCode:
141 db 090h
142 db 067h, 0bch ; mov esp, imm32
143 SavedSp DD ? ; restore stack
144 nop
145 ret
146 _BackFromUserCode ENDP
147
148 _EntryPoint DD _ToUserCode - m16Start
149 DW CODE16
150 _16Gdtr LABEL FWORD
151 DW GDT_SIZE - 1
152 _16GdtrBase DQ _NullSeg
153 _16Idtr FWORD (1 SHL 10) - 1
154
155 ;------------------------------------------------------------------------------
156 ; _ToUserCode() takes control in real mode before passing control to user code.
157 ; It will be shadowed to somewhere in memory below 1MB.
158 ;------------------------------------------------------------------------------
159 _ToUserCode PROC
160 mov ss, edx ; set new segment selectors
161 mov ds, edx
162 mov es, edx
163 mov fs, edx
164 mov gs, edx
165 DB 66h
166 mov ecx, 0c0000080h
167 mov cr0, rax ; real mode starts at next instruction
168 rdmsr
169 and ah, NOT 1
170 wrmsr
171 mov cr4, rbp
172 mov ss, esi ; set up 16-bit stack segment
173 mov sp, bx ; set up 16-bit stack pointer
174 DB 66h ; make the following call 32-bit
175 call @Base ; push eip
176 @Base:
177 pop bp ; ebp <- address of @Base
178 push [esp + sizeof (IA32_REGS) + 2]
179 lea eax, [rsi + (@RealMode - @Base)] ; rsi is "bp" in 16-bit code
180 push rax
181 retf ; execution begins at next instruction
182 @RealMode:
183 DB 66h, 2eh ; CS and operand size override
184 lidt fword ptr [rsi + (_16Idtr - @Base)]
185 DB 66h, 61h ; popad
186 DB 1fh ; pop ds
187 DB 07h ; pop es
188 pop fs
189 pop gs
190 popf ; popfd
191 lea sp, [esp + 4] ; skip high order 32 bits of EFlags
192 DB 66h ; make the following retf 32-bit
193 retf ; transfer control to user code
194 _ToUserCode ENDP
195
196 CODE16 = _16Code - $
197 DATA16 = _16Data - $
198 DATA32 = _32Data - $
199
200 _NullSeg DQ 0
201 _16Code LABEL QWORD
202 DW -1
203 DW 0
204 DB 0
205 DB 9bh
206 DB 8fh ; 16-bit segment, 4GB limit
207 DB 0
208 _16Data LABEL QWORD
209 DW -1
210 DW 0
211 DB 0
212 DB 93h
213 DB 8fh ; 16-bit segment, 4GB limit
214 DB 0
215 _32Data LABEL QWORD
216 DW -1
217 DW 0
218 DB 0
219 DB 93h
220 DB 0cfh ; 16-bit segment, 4GB limit
221 DB 0
222
223 GDT_SIZE = $ - _NullSeg
224
225 ;------------------------------------------------------------------------------
226 ; IA32_REGISTER_SET *
227 ; EFIAPI
228 ; InternalAsmThunk16 (
229 ; IN IA32_REGISTER_SET *RegisterSet,
230 ; IN OUT VOID *Transition
231 ; );
232 ;------------------------------------------------------------------------------
233 InternalAsmThunk16 PROC USES rbp rbx rsi rdi
234 mov rbx, ds
235 push rbx ; Save ds segment register on the stack
236 mov rbx, es
237 push rbx ; Save es segment register on the stack
238 mov rbx, ss
239 push rbx ; Save ss segment register on the stack
240
241 push fs
242 push gs
243 mov rsi, rcx
244 movzx r8d, (IA32_REGS ptr [rsi])._SS
245 mov edi, (IA32_REGS ptr [rsi])._ESP
246 lea rdi, [edi - (sizeof (IA32_REGS) + 4)]
247 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
248 mov ebx, edi ; ebx <- stack for 16-bit code
249 push sizeof (IA32_REGS) / 4
250 add edi, eax ; edi <- linear address of 16-bit stack
251 pop rcx
252 rep movsd ; copy RegSet
253 lea ecx, [rdx + (SavedCr4 - m16Start)]
254 mov eax, edx ; eax <- transition code address
255 and edx, 0fh
256 shl eax, 12 ; segment address in high order 16 bits
257 lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address
258 stosd ; [edi] <- return address of user code
259 sgdt fword ptr [rcx + (SavedGdt - SavedCr4)]
260 sidt fword ptr [rsp + 50h] ; save IDT stack in argument space
261 mov rax, cr0
262 mov [rcx + (SavedCr0 - SavedCr4)], eax
263 and eax, 7ffffffeh ; clear PE, PG bits
264 mov rbp, cr4
265 mov [rcx], ebp ; save CR4 in SavedCr4
266 and ebp, 300h ; clear all but PCE and OSFXSR bits
267 mov esi, r8d ; esi <- 16-bit stack segment
268 DB 6ah, DATA32 ; push DATA32
269 pop rdx ; rdx <- 32-bit data segment selector
270 lgdt fword ptr [rcx + (_16Gdtr - SavedCr4)]
271 mov ss, edx
272 pushfq
273 lea edx, [rdx + DATA16 - DATA32]
274 lea r8, @RetFromRealMode
275 push r8
276 mov r8d, cs
277 mov [rcx + (SavedCs - SavedCr4)], r8w
278 mov [rcx + (SavedSp - SavedCr4)], esp
279 jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]
280 @RetFromRealMode:
281 popfq
282 lidt fword ptr [rsp + 50h] ; restore protected mode IDTR
283 lea eax, [rbp - sizeof (IA32_REGS)]
284 pop gs
285 pop fs
286 pop rbx
287 mov ss, rbx
288 pop rbx
289 mov es, rbx
290 pop rbx
291 mov ds, rbx
292 ret
293 InternalAsmThunk16 ENDP
294
295 END