]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseLib/X64/Thunk16.S
Check in implementation in GNU assembly for Thunk16.S in BaseLib.
[mirror_edk2.git] / MdePkg / Library / BaseLib / X64 / Thunk16.S
1 #------------------------------------------------------------------------------
2 #
3 # Copyright (c) 2006 - 2008, 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 # Thunk16.S
15 #
16 # Abstract:
17 #
18 # Real mode thunk
19 #
20 #------------------------------------------------------------------------------
21
22 #include <Library/BaseLib.h>
23
24 # define the structure of IA32_REGS
25 .equ _EDI, 0 #size 4
26 .equ _ESI, 4 #size 4
27 .equ _EBP, 8 #size 4
28 .equ _ESP, 12 #size 4
29 .equ _EBX, 16 #size 4
30 .equ _EDX, 20 #size 4
31 .equ _ECX, 24 #size 4
32 .equ _EAX, 28 #size 4
33 .equ _DS, 32 #size 2
34 .equ _ES, 34 #size 2
35 .equ _FS, 36 #size 2
36 .equ _GS, 38 #size 2
37 .equ _EFLAGS, 40 #size 8
38 .equ _EIP, 48 #size 4
39 .equ _CS, 52 #size 2
40 .equ _SS, 54 #size 2
41 .equ IA32_REGS_SIZE, 56
42
43 .data
44
45 m16Size: .word _InternalAsmThunk16 - m16Start
46 mThunk16Attr: .word _ThunkAttr - m16Start
47 m16Gdt: .word _NullSeg - m16Start
48 m16GdtrBase: .word _16GdtrBase - m16Start
49 mTransition: .word _EntryPoint - m16Start
50
51 .text
52
53 m16Start:
54
55 SavedGdt: .space 10
56
57 #------------------------------------------------------------------------------
58 # _BackFromUserCode() takes control in real mode after 'retf' has been executed
59 # by user code. It will be shadowed to somewhere in memory below 1MB.
60 #------------------------------------------------------------------------------
61 .globl ASM_PFX(BackFromUserCode)
62 ASM_PFX(BackFromUserCode):
63 #
64 # The order of saved registers on the stack matches the order they appears
65 # in IA32_REGS structure. This facilitates wrapper function to extract them
66 # into that structure.
67 #
68 # Some instructions for manipulation of segment registers have to be written
69 # in opcode since 64-bit MASM prevents accesses to those registers.
70 #
71 .byte 0x16 # push ss
72 .byte 0xe # push cs
73 .byte 0x66
74 call @Base # push eip
75 @Base:
76 .byte 0x66
77 pushq $0 # reserved high order 32 bits of EFlags
78 .byte 0x66, 0x9c # pushfd actually
79 cli # disable interrupts
80 push %gs
81 push %fs
82 .byte 6 # push es
83 .byte 0x1e # push ds
84 .byte 0x66,0x60 # pushad
85 .byte 0x66,0xba # mov edx, imm32
86 _ThunkAttr: .space 4
87 testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15, %dl
88 jz @1
89 movl $0x15cd2401,%eax # mov ax, 2401h & int 15h
90 cli # disable interrupts
91 jnc @2
92 @1:
93 testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL, %dl
94 jz @2
95 inb $0x92,%al
96 orb $2,%al
97 outb %al, $0x92 # deactivate A20M#
98 @2:
99 movl %ss,%eax
100 lea IA32_REGS_SIZE(%esp), %bp
101 #
102 # rsi in the following 2 instructions is indeed bp in 16-bit code
103 #
104 movw %bp, (_ESP - IA32_REGS_SIZE)(%rsi)
105 .byte 0x66
106 movl (_EIP - IA32_REGS_SIZE)(%rsi), %ebx
107 shlw $4,%ax # shl eax, 4
108 addw %ax,%bp # add ebp, eax
109 movw %cs,%ax
110 shlw $4,%ax
111 lea (@64BitCode - @Base)(%ebx, %eax), %ax
112 .byte 0x66,0x2e,0x89,0x87 # mov cs:[bx + (@64Eip - @Base)], eax
113 .word @64Eip - @Base
114 .byte 0x66,0xb8 # mov eax, imm32
115 SavedCr4: .space 4
116 movq %rax, %cr4
117 #
118 # rdi in the instruction below is indeed bx in 16-bit code
119 #
120 .byte 0x66,0x2e # 2eh is "cs:" segment override
121 lgdt (SavedGdt - @Base)(%rdi)
122 .byte 0x66
123 movl $0xc0000080,%ecx
124 rdmsr
125 orb $1,%ah
126 wrmsr
127 .byte 0x66,0xb8 # mov eax, imm32
128 SavedCr0: .space 4
129 movq %rax, %cr0
130 .byte 0x66,0xea # jmp far cs:@64Bit
131 @64Eip: .space 4
132 SavedCs: .space 2
133 @64BitCode:
134 movq %r8, %rsp
135 ret
136
137 _EntryPoint: .long ASM_PFX(ToUserCode) - m16Start
138 .word CODE16
139 _16Gdtr: .word GDT_SIZE - 1
140 _16GdtrBase: .quad $_NullSeg
141 _16Idtr: .word 0x3ff
142 .long 0
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 .globl ASM_PFX(ToUserCode)
149 ASM_PFX(ToUserCode):
150 movl %edx,%ss # set new segment selectors
151 movl %edx,%ds
152 movl %edx,%es
153 movl %edx,%fs
154 movl %edx,%gs
155 .byte 0x66
156 movl $0xc0000080,%ecx
157 movq %rax, %cr0
158 rdmsr
159 andb $0b11111110, %ah
160 wrmsr
161 movq %rbp, %cr4
162 movl %esi,%ss # set up 16-bit stack segment
163 movw %bx,%sp # set up 16-bit stack pointer
164 .byte 0x66 # make the following call 32-bit
165 call @Base1 # push eip
166 @Base1:
167 popw %bp # ebp <- address of @Base1
168 pushq (IA32_REGS_SIZE + 2)(%esp)
169 lea 0x0c(%rsi), %eax
170 pushq %rax
171 lret # execution begins at next instruction
172 @RealMode:
173 .byte 0x66,0x2e # CS and operand size override
174 lidt (_16Idtr - @Base1)(%rsi)
175 .byte 0x66,0x61 # popad
176 .byte 0x1f # pop ds
177 .byte 0x7 # pop es
178 .byte 0x0f, 0xa1 # pop fs
179 .byte 0x0f, 0xa9 # pop gs
180 .byte 0x66, 0x9d # popfd
181 leaw 4(%esp),%sp # skip high order 32 bits of EFlags
182 .byte 0x66 # make the following retf 32-bit
183 lret # transfer control to user code
184
185 .equ CODE16, ASM_PFX(16Code) - .
186 .equ DATA16, ASM_PFX(16Data) - .
187 .equ DATA32, ASM_PFX(32Data) - .
188
189 _NullSeg: .quad 0
190 ASM_PFX(16Code):
191 .word -1
192 .word 0
193 .byte 0
194 .byte 0x9b
195 .byte 0x8f # 16-bit segment, 4GB limit
196 .byte 0
197 ASM_PFX(16Data):
198 .word -1
199 .word 0
200 .byte 0
201 .byte 0x93
202 .byte 0x8f # 16-bit segment, 4GB limit
203 .byte 0
204 ASM_PFX(32Data):
205 .word -1
206 .word 0
207 .byte 0
208 .byte 0x93
209 .byte 0xcf # 16-bit segment, 4GB limit
210 .byte 0
211
212 .equ GDT_SIZE, . - ASM_PFX(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 # MISMATCH: "InternalAsmThunk16 PROC USES rbp rbx rsi rdi"
223
224 .globl ASM_PFX(InternalAsmThunk16)
225 ASM_PFX(InternalAsmThunk16):
226 pushq %rbp
227 pushq %rbx
228 pushq %rsi
229 pushq %rdi
230
231 movl %ds, %r10d # r9 ~ r11 are not accessible in 16-bit
232 movl %es, %r11d # so use them for saving seg registers
233 movl %ss, %r9d
234 .byte 0x0f, 0xa0 #push fs
235 .byte 0x0f, 0xa8 #push gs
236 movq %rcx, %rsi
237 movzwl _SS(%rsi), %r8d
238 movl _ESP(%rsi), %edi
239 lea -(IA32_REGS_SIZE + 4)(%edi), %rdi
240 imul $16, %r8d, %eax
241 movl %edi,%ebx # ebx <- stack for 16-bit code
242 pushq $(IA32_REGS_SIZE / 4)
243 addl %eax,%edi # edi <- linear address of 16-bit stack
244 popq %rcx
245 rep
246 movsl # copy RegSet
247 lea (SavedCr4 - m16Start)(%rdx), %ecx
248 movl %edx,%eax # eax <- transition code address
249 andl $0xf,%edx
250 shll $12,%eax # segment address in high order 16 bits
251 lea (_BackFromUserCode - m16Start)(%rdx), %ax
252 stosl # [edi] <- return address of user code
253 sgdt (SavedGdt - SavedCr4)(%rcx)
254 sidt 0x38(%rsp)
255 movq %cr0, %rax
256 movl %eax, (SavedCr0 - SavedCr4)(%rcx)
257 andl $0x7ffffffe,%eax # clear PE, PG bits
258 movq %cr4, %rbp
259 movl %ebp, (%rcx) # save CR4 in SavedCr4
260 andl $0x300,%ebp # clear all but PCE and OSFXSR bits
261 movl %r8d, %esi # esi <- 16-bit stack segment
262 .byte 0x6a, DATA32
263 popq %rdx
264 lgdt (_16Gdtr - SavedCr4)(%rcx)
265 movl %edx,%ss
266 pushfq
267 lea -8(%rdx), %edx
268 lea @RetFromRealMode, %r8
269 pushq %r8
270 movl %cs, %r8d
271 movw %r8w, (SavedCs - SavedCr4)(%rcx)
272 movq %rsp, %r8
273 .byte 0xff, 0x69 # jmp (_EntryPoint - SavedCr4)(%rcx)
274 .byte _EntryPoint - SavedCr4
275 @RetFromRealMode:
276 popfq
277 lidt 0x38(%rsp)
278 lea -IA32_REGS_SIZE(%rbp), %eax
279 .byte 0x0f, 0xa9 # pop gs
280 .byte 0x0f, 0xa1 # pop fs
281 movl %r9d, %ss
282 movl %r11d, %es
283 movl %r10d, %ds
284
285 popq %rdi
286 popq %rsi
287 popq %rbx
288 popq %rbp
289
290 ret