1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
|
#------------------------------------------------------------------------------
#
# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php.
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
# Module Name:
#
# Thunk16.S
#
# Abstract:
#
# Real mode thunk
#
#------------------------------------------------------------------------------
#include <Library/BaseLib.h>
ASM_GLOBAL ASM_PFX(m16Start), ASM_PFX(m16Size), ASM_PFX(mThunk16Attr), ASM_PFX(m16Gdt), ASM_PFX(m16GdtrBase), ASM_PFX(mTransition)
ASM_GLOBAL ASM_PFX(InternalAsmThunk16)
# define the structure of IA32_REGS
.set _EDI, 0 #size 4
.set _ESI, 4 #size 4
.set _EBP, 8 #size 4
.set _ESP, 12 #size 4
.set _EBX, 16 #size 4
.set _EDX, 20 #size 4
.set _ECX, 24 #size 4
.set _EAX, 28 #size 4
.set _DS, 32 #size 2
.set _ES, 34 #size 2
.set _FS, 36 #size 2
.set _GS, 38 #size 2
.set _EFLAGS, 40 #size 4
.set _EIP, 44 #size 4
.set _CS, 48 #size 2
.set _SS, 50 #size 2
.set IA32_REGS_SIZE, 52
.text
.code16
ASM_PFX(m16Start):
SavedGdt: .space 6
ASM_PFX(BackFromUserCode):
push %ss
push %cs
calll L_Base1 # push eip
L_Base1:
pushfl
cli # disable interrupts
push %gs
push %fs
push %es
push %ds
pushal
.byte 0x66, 0xba # mov edx, imm32
ASM_PFX(ThunkAttr): .space 4
testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15, %dl
jz 1f
movw $0x2401, %ax
int $0x15
cli # disable interrupts
jnc 2f
1:
testb $THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL, %dl
jz 2f
inb $0x92, %al
orb $2, %al
outb %al, $0x92 # deactivate A20M#
2:
xorl %eax, %eax
movw %ss, %ax
leal IA32_REGS_SIZE(%esp), %ebp
mov %ebp, (_ESP - IA32_REGS_SIZE)(%bp)
mov (_EIP - IA32_REGS_SIZE)(%bp), %bx
shll $4, %eax
addl %eax, %ebp
.byte 0x66, 0xb8 # mov eax, imm32
SavedCr4: .space 4
movl %eax, %cr4
lgdtl %cs:(SavedGdt - L_Base1)(%bx)
.byte 0x66, 0xb8 # mov eax, imm32
SavedCr0: .space 4
movl %eax, %cr0
.byte 0xb8 # mov ax, imm16
SavedSs: .space 2
movl %eax, %ss
.byte 0x66, 0xbc # mov esp, imm32
SavedEsp: .space 4
lretl # return to protected mode
_EntryPoint: .long ASM_PFX(ToUserCode) - ASM_PFX(m16Start)
.word 0x8
_16Idtr: .word 0x3ff
.long 0
_16Gdtr: .word GdtEnd - _NullSegDesc - 1
_16GdtrBase: .long _NullSegDesc
ASM_PFX(ToUserCode):
movw %ss, %dx
movw %cx, %ss # set new segment selectors
movw %cx, %ds
movw %cx, %es
movw %cx, %fs
movw %cx, %gs
movl %eax, %cr0 # real mode starts at next instruction
# which (per SDM) *must* be a far JMP.
ljmpw $0,$0 # will be filled in by InternalAsmThunk16
L_Base: # to point here.
movl %ebp, %cr4
movw %si, %ss # set up 16-bit stack segment
xchgl %ebx, %esp # set up 16-bit stack pointer
movw IA32_REGS_SIZE(%esp), %bp # get BackToUserCode address from stack
mov %dx, %cs:(SavedSs - ASM_PFX(BackFromUserCode))(%bp)
mov %ebx, %cs:(SavedEsp - ASM_PFX(BackFromUserCode))(%bp)
lidtl %cs:(_16Idtr - ASM_PFX(BackFromUserCode))(%bp)
popal
pop %ds
pop %es
pop %fs
pop %gs
popfl
lretl # transfer control to user code
_NullSegDesc: .quad 0
_16CsDesc:
.word -1
.word 0
.byte 0
.byte 0x9b
.byte 0x8f # 16-bit segment, 4GB limit
.byte 0
_16DsDesc:
.word -1
.word 0
.byte 0
.byte 0x93
.byte 0x8f # 16-bit segment, 4GB limit
.byte 0
GdtEnd:
.code32
#
# @param RegSet The pointer to a IA32_DWORD_REGS structure
# @param Transition The pointer to the transition code
# @return The address of the 16-bit stack after returning from user code
#
ASM_PFX(InternalAsmThunk16):
push %ebp
push %ebx
push %esi
push %edi
push %ds
push %es
push %fs
push %gs
movl 36(%esp), %esi # esi <- RegSet
movzwl _SS(%esi), %edx
mov _ESP(%esi), %edi
add $(-(IA32_REGS_SIZE + 4)), %edi
movl %edi, %ebx # ebx <- stack offset
imul $0x10, %edx, %eax
push $(IA32_REGS_SIZE / 4)
addl %eax, %edi # edi <- linear address of 16-bit stack
pop %ecx
rep
movsl # copy RegSet
movl 40(%esp), %eax # eax <- address of transition code
movl %edx, %esi # esi <- 16-bit stack segment
lea (SavedCr0 - ASM_PFX(m16Start))(%eax), %edx
movl %eax, %ecx
andl $0xf, %ecx
shll $12, %eax
lea (ASM_PFX(BackFromUserCode) - ASM_PFX(m16Start))(%ecx), %ecx
movw %cx, %ax
stosl # [edi] <- return address of user code
addl $(L_Base - ASM_PFX(BackFromUserCode)), %eax
movl %eax, (L_Base - SavedCr0 - 4)(%edx)
sgdtl (SavedGdt - SavedCr0)(%edx)
sidtl 0x24(%esp)
movl %cr0, %eax
movl %eax, (%edx) # save CR0 in SavedCr0
andl $0x7ffffffe, %eax # clear PE, PG bits
movl %cr4, %ebp
mov %ebp, (SavedCr4 - SavedCr0)(%edx)
andl $0xffffffcf, %ebp # clear PAE, PSE bits
pushl $0x10
pop %ecx # ecx <- selector for data segments
lgdtl (_16Gdtr - SavedCr0)(%edx)
pushfl
lcall *(_EntryPoint - SavedCr0)(%edx)
popfl
lidtl 0x24(%esp)
lea -IA32_REGS_SIZE(%ebp), %eax
pop %gs
pop %fs
pop %es
pop %ds
pop %edi
pop %esi
pop %ebx
pop %ebp
ret
.const:
ASM_PFX(m16Size): .word ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start)
ASM_PFX(mThunk16Attr): .word ASM_PFX(ThunkAttr) - ASM_PFX(m16Start)
ASM_PFX(m16Gdt): .word _NullSegDesc - ASM_PFX(m16Start)
ASM_PFX(m16GdtrBase): .word _16GdtrBase - ASM_PFX(m16Start)
ASM_PFX(mTransition): .word _EntryPoint - ASM_PFX(m16Start)
|