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