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