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