]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseLib/X64/Thunk16.nasm
MdePkg BaseLib NASM Thunk16: Use bits 16 for 16-bit code
[mirror_edk2.git] / MdePkg / Library / BaseLib / X64 / Thunk16.nasm
1
2 #include "BaseLibInternals.h"
3
4 ;------------------------------------------------------------------------------
5 ;
6 ; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
7 ; This program and the accompanying materials
8 ; are licensed and made available under the terms and conditions of the BSD License
9 ; which accompanies this distribution. The full text of the license may be found at
10 ; http://opensource.org/licenses/bsd-license.php.
11 ;
12 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 ;
15 ; Module Name:
16 ;
17 ; Thunk.asm
18 ;
19 ; Abstract:
20 ;
21 ; Real mode thunk
22 ;
23 ;------------------------------------------------------------------------------
24
25 global ASM_PFX(m16Size)
26 global ASM_PFX(mThunk16Attr)
27 global ASM_PFX(m16Gdt)
28 global ASM_PFX(m16GdtrBase)
29 global ASM_PFX(mTransition)
30 global ASM_PFX(m16Start)
31
32 struc IA32_REGS
33
34 ._EDI: resd 1
35 ._ESI: resd 1
36 ._EBP: resd 1
37 ._ESP: resd 1
38 ._EBX: resd 1
39 ._EDX: resd 1
40 ._ECX: resd 1
41 ._EAX: resd 1
42 ._DS: resw 1
43 ._ES: resw 1
44 ._FS: resw 1
45 ._GS: resw 1
46 ._EFLAGS: resq 1
47 ._EIP: resd 1
48 ._CS: resw 1
49 ._SS: resw 1
50 .size:
51
52 endstruc
53
54 SECTION .data
55
56 ;
57 ; These are global constant to convey information to C code.
58 ;
59 ASM_PFX(m16Size) DW InternalAsmThunk16 - ASM_PFX(m16Start)
60 ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttr - ASM_PFX(m16Start)
61 ASM_PFX(m16Gdt) DW _NullSeg - ASM_PFX(m16Start)
62 ASM_PFX(m16GdtrBase) DW _16GdtrBase - ASM_PFX(m16Start)
63 ASM_PFX(mTransition) DW _EntryPoint - ASM_PFX(m16Start)
64
65 SECTION .text
66
67 ASM_PFX(m16Start):
68
69 SavedGdt:
70 dw 0
71 dq 0
72
73 ;------------------------------------------------------------------------------
74 ; _BackFromUserCode() takes control in real mode after 'retf' has been executed
75 ; by user code. It will be shadowed to somewhere in memory below 1MB.
76 ;------------------------------------------------------------------------------
77 _BackFromUserCode:
78 ;
79 ; The order of saved registers on the stack matches the order they appears
80 ; in IA32_REGS structure. This facilitates wrapper function to extract them
81 ; into that structure.
82 ;
83 BITS 16
84 push ss
85 push cs
86 o32 call dword .Base ; push eip
87 .Base:
88 push dword 0 ; reserved high order 32 bits of EFlags
89 pushfd
90 cli ; disable interrupts
91 push gs
92 push fs
93 push es
94 push ds
95 pushad
96 DB 66h, 0bah ; mov edx, imm32
97 .ThunkAttr: dd 0
98 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
99 jz .1
100 mov ax, 2401h
101 int 15h
102 cli ; disable interrupts
103 jnc .2
104 .1:
105 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
106 jz .2
107 in al, 92h
108 or al, 2
109 out 92h, al ; deactivate A20M#
110 .2:
111 xor eax, eax
112 mov ax, ss
113 lea ebp, [esp + IA32_REGS.size]
114 mov [bp - IA32_REGS.size + IA32_REGS._ESP], ebp
115 mov ebx, [bp - IA32_REGS.size + IA32_REGS._EIP]
116 shl eax, 4 ; shl eax, 4
117 add ebp, eax ; add ebp, eax
118 mov eax, cs
119 shl eax, 4
120 lea eax, [eax + ebx + (.64BitCode - .Base)]
121 mov [cs:bx + (.64Eip - .Base)], eax
122 DB 66h, 0b8h ; mov eax, imm32
123 .SavedCr4: DD 0
124 mov cr4, eax
125 o32 lgdt [cs:bx + (SavedGdt - .Base)]
126 mov ecx, 0c0000080h
127 rdmsr
128 or ah, 1
129 wrmsr
130 DB 66h, 0b8h ; mov eax, imm32
131 .SavedCr0: DD 0
132 mov cr0, eax
133 DB 66h, 0eah ; jmp far cs:.64Bit
134 .64Eip: DD 0
135 .SavedCs: DW 0
136 .64BitCode:
137 BITS 64
138 nop
139 db 048h, 0bch ; mov rsp, imm64
140 .SavedSp: DQ 0 ; restore stack
141 nop
142 ret
143
144 _EntryPoint:
145 DD _ToUserCode - ASM_PFX(m16Start)
146 DW CODE16
147 _16Gdtr:
148 DW GDT_SIZE - 1
149 _16GdtrBase:
150 DQ _NullSeg
151 _16Idtr:
152 DW (1 << 10) - 1
153 DD 0
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:
160 BITS 16
161 mov ss, dx ; set new segment selectors
162 mov ds, dx
163 mov es, dx
164 mov fs, dx
165 mov gs, dx
166 mov ecx, 0c0000080h
167 mov cr0, eax ; real mode starts at next instruction
168 rdmsr
169 and ah, ~1
170 wrmsr
171 mov cr4, ebp
172 mov ss, si ; set up 16-bit stack segment
173 mov esp, ebx ; set up 16-bit stack pointer
174 call dword .Base ; push eip
175 .Base:
176 pop ebp ; ebp <- address of .Base
177 push word [dword esp + IA32_REGS.size + 2]
178 lea ax, [bp + (.RealMode - .Base)]
179 push ax
180 retf ; execution begins at next instruction
181 .RealMode:
182
183 o32 lidt [cs:bp + (_16Idtr - .Base)]
184
185 popad
186 pop ds
187 pop es
188 pop fs
189 pop gs
190 popfd
191 lea esp, [esp + 4] ; skip high order 32 bits of EFlags
192
193 o32 retf ; transfer control to user code
194
195 ALIGN 8
196
197 CODE16 equ _16Code - $
198 DATA16 equ _16Data - $
199 DATA32 equ _32Data - $
200
201 _NullSeg DQ 0
202 _16Code:
203 DW -1
204 DW 0
205 DB 0
206 DB 9bh
207 DB 8fh ; 16-bit segment, 4GB limit
208 DB 0
209 _16Data:
210 DW -1
211 DW 0
212 DB 0
213 DB 93h
214 DB 8fh ; 16-bit segment, 4GB limit
215 DB 0
216 _32Data:
217 DW -1
218 DW 0
219 DB 0
220 DB 93h
221 DB 0cfh ; 16-bit segment, 4GB limit
222 DB 0
223
224 GDT_SIZE equ $ - _NullSeg
225
226 ;------------------------------------------------------------------------------
227 ; IA32_REGISTER_SET *
228 ; EFIAPI
229 ; InternalAsmThunk16 (
230 ; IN IA32_REGISTER_SET *RegisterSet,
231 ; IN OUT VOID *Transition
232 ; );
233 ;------------------------------------------------------------------------------
234 global ASM_PFX(InternalAsmThunk16)
235 ASM_PFX(InternalAsmThunk16):
236 BITS 64
237 push rbp
238 push rbx
239 push rsi
240 push rdi
241
242 mov ebx, ds
243 push rbx ; Save ds segment register on the stack
244 mov ebx, es
245 push rbx ; Save es segment register on the stack
246 mov ebx, ss
247 push rbx ; Save ss segment register on the stack
248
249 push fs
250 push gs
251 mov rsi, rcx
252 movzx r8d, word [rsi + IA32_REGS._SS]
253 mov edi, [rsi + IA32_REGS._ESP]
254 lea rdi, [edi - (IA32_REGS.size + 4)]
255 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
256 mov ebx, edi ; ebx <- stack for 16-bit code
257 push IA32_REGS.size / 4
258 add edi, eax ; edi <- linear address of 16-bit stack
259 pop rcx
260 rep movsd ; copy RegSet
261 lea ecx, [rdx + (_BackFromUserCode.SavedCr4 - ASM_PFX(m16Start))]
262 mov eax, edx ; eax <- transition code address
263 and edx, 0fh
264 shl eax, 12 ; segment address in high order 16 bits
265 lea ax, [rdx + (_BackFromUserCode - ASM_PFX(m16Start))] ; offset address
266 stosd ; [edi] <- return address of user code
267
268 sgdt [rsp + 60h] ; save GDT stack in argument space
269 movzx r10, word [rsp + 60h] ; r10 <- GDT limit
270 lea r11, [rcx + (InternalAsmThunk16 - _BackFromUserCode.SavedCr4) + 0xf]
271 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer
272
273 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4)], r10w ; save the limit of shadowed GDT table
274 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4) + 2], r11 ; save the base address of shadowed GDT table
275
276 mov rsi, [rsp + 62h] ; rsi <- the original GDT base address
277 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table
278 inc rcx ; rcx <- the size of memory to copy
279 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table
280 rep movsb ; perform memory copy to shadow GDT table
281 mov rcx, r10 ; restore the orignal rcx before memory copy
282 mov rdi, r11 ; restore the original rdi before memory copy
283
284 sidt [rsp + 50h] ; save IDT stack in argument space
285 mov rax, cr0
286 mov [rcx + (_BackFromUserCode.SavedCr0 - _BackFromUserCode.SavedCr4)], eax
287 and eax, 7ffffffeh ; clear PE, PG bits
288 mov rbp, cr4
289 mov [rcx], ebp ; save CR4 in _BackFromUserCode.SavedCr4
290 and ebp, ~30h ; clear PAE, PSE bits
291 mov esi, r8d ; esi <- 16-bit stack segment
292 push DATA32
293 pop rdx ; rdx <- 32-bit data segment selector
294 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4)]
295 mov ss, edx
296 pushfq
297 lea edx, [rdx + DATA16 - DATA32]
298 lea r8, [REL .RetFromRealMode]
299 push r8
300 mov r8d, cs
301 mov [rcx + (_BackFromUserCode.SavedCs - _BackFromUserCode.SavedCr4)], r8w
302 mov [rcx + (_BackFromUserCode.SavedSp - _BackFromUserCode.SavedCr4)], rsp
303 jmp dword far [rcx + (_EntryPoint - _BackFromUserCode.SavedCr4)]
304 .RetFromRealMode:
305 popfq
306 lgdt [rsp + 60h] ; restore protected mode GDTR
307 lidt [rsp + 50h] ; restore protected mode IDTR
308 lea eax, [rbp - IA32_REGS.size]
309 pop gs
310 pop fs
311 pop rbx
312 mov ss, ebx
313 pop rbx
314 mov es, ebx
315 pop rbx
316 mov ds, ebx
317
318 pop rdi
319 pop rsi
320 pop rbx
321 pop rbp
322
323 ret