b77ba680429ce4db049a53d53954fc3620796720
[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 mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp
100 mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP
101 shl ax, 4 ; shl eax, 4
102 add bp, ax ; add ebp, eax
103 mov ax, cs
104 shl ax, 4
105 lea ax, [eax + ebx + (@64BitCode - @Base)]
106 DB 2eh ; cs:
107 mov [rdi + (@64Eip - @Base)], ax
108 DB 66h, 0b8h ; mov eax, imm32
109 SavedCr4 DD ?
110 mov cr4, rax
111 DB 66h, 2eh
112 lgdt fword ptr [rdi + (SavedGdt - @Base)]
113 DB 66h
114 mov ecx, 0c0000080h
115 rdmsr
116 or ah, 1
117 wrmsr
118 DB 66h, 0b8h ; mov eax, imm32
119 SavedCr0 DD ?
120 mov cr0, rax
121 DB 66h, 0eah ; jmp far cs:@64Bit
122 @64Eip DD ?
123 SavedCs DW ?
124 @64BitCode:
125 DB 48h, 0b8h ; mov rax, imm64
126 SavedRip DQ ?
127 jmp rax ; return to caller
128 _BackFromUserCode ENDP
129
130 _EntryPoint DD _ToUserCode - m16Start
131 DW CODE16
132 _16Gdtr LABEL FWORD
133 DW GDT_SIZE - 1
134 _16GdtrBase DQ _NullSeg
135 _16Idtr FWORD (1 SHL 10) - 1
136
137 ;------------------------------------------------------------------------------
138 ; _ToUserCode() takes control in real mode before passing control to user code.
139 ; It will be shadowed to somewhere in memory below 1MB.
140 ;------------------------------------------------------------------------------
141 _ToUserCode PROC
142 mov ss, edx ; set new segment selectors
143 mov ds, edx
144 mov es, edx
145 mov fs, edx
146 mov gs, edx
147 DB 66h
148 mov ecx, 0c0000080h
149 mov cr0, rax ; real mode starts at next instruction
150 rdmsr
151 and ah, NOT 1
152 wrmsr
153 mov cr4, rbp
154 mov ss, esi ; set up 16-bit stack segment
155 mov sp, bx ; set up 16-bit stack pointer
156 DB 66h
157 call @Base ; push eip
158 @Base:
159 pop bp ; ebp <- address of @Base
160 push [esp + sizeof (IA32_REGS) + 2]
161 lea eax, [rsi + (@RealMode - @Base)]
162 push rax
163 retf
164 @RealMode:
165 DB 66h, 2eh ; CS and operand size override
166 lidt fword ptr [rsi + (_16Idtr - @Base)]
167 DB 66h, 61h ; popad
168 DB 1fh ; pop ds
169 DB 07h ; pop es
170 pop fs
171 pop gs
172 popf ; popfd
173 lea sp, [esp + 4] ; skip high order 32 bits of EFlags
174 DB 66h
175 retf ; transfer control to user code
176 _ToUserCode ENDP
177
178 CODE16 = _16Code - $
179 DATA16 = _16Data - $
180 DATA32 = _32Data - $
181
182 _NullSeg DQ 0
183 _16Code LABEL QWORD
184 DW -1
185 DW 0
186 DB 0
187 DB 9bh
188 DB 8fh ; 16-bit segment, 4GB limit
189 DB 0
190 _16Data LABEL QWORD
191 DW -1
192 DW 0
193 DB 0
194 DB 93h
195 DB 8fh ; 16-bit segment, 4GB limit
196 DB 0
197 _32Data LABEL QWORD
198 DW -1
199 DW 0
200 DB 0
201 DB 93h
202 DB 0cfh ; 16-bit segment, 4GB limit
203 DB 0
204
205 GDT_SIZE = $ - _NullSeg
206
207 ;------------------------------------------------------------------------------
208 ; IA32_REGISTER_SET *
209 ; EFIAPI
210 ; InternalAsmThunk16 (
211 ; IN IA32_REGISTER_SET *RegisterSet,
212 ; IN OUT VOID *Transition
213 ; );
214 ;------------------------------------------------------------------------------
215 InternalAsmThunk16 PROC USES rbp rbx rsi rdi
216 mov r10d, ds
217 mov r11d, es
218 mov r9d, ss
219 push fs
220 push gs
221 mov rsi, rcx
222 movzx r8d, (IA32_REGS ptr [rsi])._SS
223 mov edi, (IA32_REGS ptr [rsi])._ESP
224 lea rdi, [edi - (sizeof (IA32_REGS) + 4)]
225 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
226 mov ebx, edi ; ebx <- stack for 16-bit code
227 push sizeof (IA32_REGS) / 4
228 add edi, eax ; edi <- linear address of 16-bit stack
229 pop rcx
230 rep movsd ; copy RegSet
231 lea ecx, [rdx + (SavedCr4 - m16Start)]
232 mov eax, edx ; eax <- transition code address
233 and edx, 0fh
234 shl eax, 12
235 lea ax, [rdx + (_BackFromUserCode - m16Start)]
236 stosd ; [edi] <- return address of user code
237 sgdt fword ptr [rcx + (SavedGdt - SavedCr4)]
238 sidt fword ptr [rsp + 38h] ; save IDT stack in argument space
239 mov rax, cr0
240 mov [rcx + (SavedCr0 - SavedCr4)], eax
241 and eax, 7ffffffeh ; clear PE, PG bits
242 mov rbp, cr4
243 mov [rcx], ebp ; save CR4 in SavedCr4
244 and ebp, 300h ; clear all but PCE and OSFXSR bits
245 mov esi, r8d ; esi <- 16-bit stack segment
246 DB 6ah, DATA32 ; push DATA32
247 pop rdx ; rdx <- 32-bit data segment selector
248 lgdt fword ptr [rcx + (_16Gdtr - SavedCr4)]
249 mov ss, edx
250 pushfq
251 lea edx, [rdx + DATA16 - DATA32]
252 lea r8, @RetFromRealMode
253 mov [rcx + (SavedRip - SavedCr4)], r8
254 mov r8d, cs
255 mov [rcx + (SavedCs - SavedCr4)], r8w
256 mov r8, rsp
257 jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]
258 @RetFromRealMode:
259 mov rsp, r8
260 popfq
261 lidt fword ptr [rsp + 38h] ; restore protected mode IDTR
262 lea eax, [rbp - sizeof (IA32_REGS)]
263 pop gs
264 pop fs
265 mov ss, r9d
266 mov es, r11d
267 mov ds, r10d
268 ret
269 InternalAsmThunk16 ENDP
270
271 END