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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
|
//
// Include common header file for this module.
//
#include <BaseLibInternals.h>
;------------------------------------------------------------------------------
;
; Copyright (c) 2006, Intel Corporation
; All rights reserved. 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:
;
; Thunk.asm
;
; Abstract:
;
; Real mode thunk
;
;------------------------------------------------------------------------------
EXTERNDEF m16Start:BYTE
EXTERNDEF m16Size:WORD
EXTERNDEF mThunk16Attr:WORD
EXTERNDEF m16Gdt:WORD
EXTERNDEF m16GdtrBase:WORD
EXTERNDEF mTransition:WORD
IA32_REGS STRUC 4t
_EDI DD ?
_ESI DD ?
_EBP DD ?
_ESP DD ?
_EBX DD ?
_EDX DD ?
_ECX DD ?
_EAX DD ?
_DS DW ?
_ES DW ?
_FS DW ?
_GS DW ?
_EFLAGS DQ ?
_EIP DD ?
_CS DW ?
_SS DW ?
IA32_REGS ENDS
.const
m16Size DW InternalAsmThunk16 - m16Start
mThunk16Attr DW _ThunkAttr - m16Start
m16Gdt DW _NullSeg - m16Start
m16GdtrBase DW _16GdtrBase - m16Start
mTransition DW _EntryPoint - m16Start
.code
m16Start LABEL BYTE
SavedGdt LABEL FWORD
DW ?
DQ ?
;------------------------------------------------------------------------------
; _BackFromUserCode() takes control in real mode after 'retf' has been executed
; by user code. It will be shadowed to somewhere in memory below 1MB.
;------------------------------------------------------------------------------
_BackFromUserCode PROC
;
; The order of saved registers on the stack matches the order they appears
; in IA32_REGS structure. This facilitates wrapper function to extract them
; into that structure.
;
; Some instructions for manipulation of segment registers have to be written
; in opcode since 64-bit MASM prevents accesses to those registers.
;
DB 16h ; push ss
DB 0eh ; push cs
DB 66h
call @Base ; push eip
@Base:
DB 66h
push 0 ; reserved high order 32 bits of EFlags
pushf ; pushfd actually
cli ; disable interrupts
push gs
push fs
DB 6 ; push es
DB 1eh ; push ds
DB 66h, 60h ; pushad
DB 66h, 0bah ; mov edx, imm32
_ThunkAttr DD ?
test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
jz @1
mov eax, 15cd2401h ; mov ax, 2401h & int 15h
cli ; disable interrupts
jnc @2
@1:
test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
jz @2
in al, 92h
or al, 2
out 92h, al ; deactivate A20M#
@2:
mov eax, ss
lea bp, [esp + sizeof (IA32_REGS)]
;
; rsi in the following 2 instructions is indeed bp in 16-bit code
;
mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp
DB 66h
mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP
shl ax, 4 ; shl eax, 4
add bp, ax ; add ebp, eax
mov ax, cs
shl ax, 4
lea ax, [eax + ebx + (@64BitCode - @Base)]
DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (@64Eip - @Base)], eax
DW @64Eip - @Base
DB 66h, 0b8h ; mov eax, imm32
SavedCr4 DD ?
mov cr4, rax
;
; rdi in the instruction below is indeed bx in 16-bit code
;
DB 66h, 2eh ; 2eh is "cs:" segment override
lgdt fword ptr [rdi + (SavedGdt - @Base)]
DB 66h
mov ecx, 0c0000080h
rdmsr
or ah, 1
wrmsr
DB 66h, 0b8h ; mov eax, imm32
SavedCr0 DD ?
mov cr0, rax
DB 66h, 0eah ; jmp far cs:@64Bit
@64Eip DD ?
SavedCs DW ?
@64BitCode:
mov rsp, r8 ; restore stack
ret
_BackFromUserCode ENDP
_EntryPoint DD _ToUserCode - m16Start
DW CODE16
_16Gdtr LABEL FWORD
DW GDT_SIZE - 1
_16GdtrBase DQ _NullSeg
_16Idtr FWORD (1 SHL 10) - 1
;------------------------------------------------------------------------------
; _ToUserCode() takes control in real mode before passing control to user code.
; It will be shadowed to somewhere in memory below 1MB.
;------------------------------------------------------------------------------
_ToUserCode PROC
mov ss, edx ; set new segment selectors
mov ds, edx
mov es, edx
mov fs, edx
mov gs, edx
DB 66h
mov ecx, 0c0000080h
mov cr0, rax ; real mode starts at next instruction
rdmsr
and ah, NOT 1
wrmsr
mov cr4, rbp
mov ss, esi ; set up 16-bit stack segment
mov sp, bx ; set up 16-bit stack pointer
DB 66h ; make the following call 32-bit
call @Base ; push eip
@Base:
pop bp ; ebp <- address of @Base
push [esp + sizeof (IA32_REGS) + 2]
lea eax, [rsi + (@RealMode - @Base)] ; rsi is "bp" in 16-bit code
push rax
retf ; execution begins at next instruction
@RealMode:
DB 66h, 2eh ; CS and operand size override
lidt fword ptr [rsi + (_16Idtr - @Base)]
DB 66h, 61h ; popad
DB 1fh ; pop ds
DB 07h ; pop es
pop fs
pop gs
popf ; popfd
lea sp, [esp + 4] ; skip high order 32 bits of EFlags
DB 66h ; make the following retf 32-bit
retf ; transfer control to user code
_ToUserCode ENDP
CODE16 = _16Code - $
DATA16 = _16Data - $
DATA32 = _32Data - $
_NullSeg DQ 0
_16Code LABEL QWORD
DW -1
DW 0
DB 0
DB 9bh
DB 8fh ; 16-bit segment, 4GB limit
DB 0
_16Data LABEL QWORD
DW -1
DW 0
DB 0
DB 93h
DB 8fh ; 16-bit segment, 4GB limit
DB 0
_32Data LABEL QWORD
DW -1
DW 0
DB 0
DB 93h
DB 0cfh ; 16-bit segment, 4GB limit
DB 0
GDT_SIZE = $ - _NullSeg
;------------------------------------------------------------------------------
; IA32_REGISTER_SET *
; EFIAPI
; InternalAsmThunk16 (
; IN IA32_REGISTER_SET *RegisterSet,
; IN OUT VOID *Transition
; );
;------------------------------------------------------------------------------
InternalAsmThunk16 PROC USES rbp rbx rsi rdi
mov r10d, ds ; r9 ~ r11 are not accessible in 16-bit
mov r11d, es ; so use them for saving seg registers
mov r9d, ss
push fs
push gs
mov rsi, rcx
movzx r8d, (IA32_REGS ptr [rsi])._SS
mov edi, (IA32_REGS ptr [rsi])._ESP
lea rdi, [edi - (sizeof (IA32_REGS) + 4)]
imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
mov ebx, edi ; ebx <- stack for 16-bit code
push sizeof (IA32_REGS) / 4
add edi, eax ; edi <- linear address of 16-bit stack
pop rcx
rep movsd ; copy RegSet
lea ecx, [rdx + (SavedCr4 - m16Start)]
mov eax, edx ; eax <- transition code address
and edx, 0fh
shl eax, 12 ; segment address in high order 16 bits
lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address
stosd ; [edi] <- return address of user code
sgdt fword ptr [rcx + (SavedGdt - SavedCr4)]
sidt fword ptr [rsp + 38h] ; save IDT stack in argument space
mov rax, cr0
mov [rcx + (SavedCr0 - SavedCr4)], eax
and eax, 7ffffffeh ; clear PE, PG bits
mov rbp, cr4
mov [rcx], ebp ; save CR4 in SavedCr4
and ebp, 300h ; clear all but PCE and OSFXSR bits
mov esi, r8d ; esi <- 16-bit stack segment
DB 6ah, DATA32 ; push DATA32
pop rdx ; rdx <- 32-bit data segment selector
lgdt fword ptr [rcx + (_16Gdtr - SavedCr4)]
mov ss, edx
pushfq
lea edx, [rdx + DATA16 - DATA32]
lea r8, @RetFromRealMode
push r8
mov r8d, cs
mov [rcx + (SavedCs - SavedCr4)], r8w
mov r8, rsp
jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]
@RetFromRealMode:
popfq
lidt fword ptr [rsp + 38h] ; restore protected mode IDTR
lea eax, [rbp - sizeof (IA32_REGS)]
pop gs
pop fs
mov ss, r9d
mov es, r11d
mov ds, r10d
ret
InternalAsmThunk16 ENDP
END
|