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
|
.code64
.globl real.regs
real.regs:
reax:
.int 0x0
rebx:
.int 0x0
recx:
.int 0x0
redx:
.int 0x0
redi:
.int 0x0
resi:
.int 0x0
# :real_call
# This function is intended to be called from long mode
# and calls another function in real mode. Note that precautions have
# to be made. Recall that real mode can only access below 0xFFFFF.
# So the target function, and objects of arguments passed to it cannot
# be located above that. A reasonable scheme is to put the result
# in a buffer and then, once back in long mode, copy its content to higher
# above.
# The procedure to go from Long Mode back to Real Mode is explained in much details
# in the AMD64 Programmer's Manual Vol. 2, in particular, the figure 1-6. in section 1.3.
.globl real.call
real.call:
# :Push all the segments registers
push %rbx
push %r12
push %r13
push %r14
push %r15
push %di
cli
lgdt gdtr32
pushq $(gdt32_code - gdt32)
pushq $real_call_to_pmode_down
retfq
.code32
real_call_to_pmode_down:
# :Here, we are in compatibility mode (32 bits)
# :Disable paging
mov %cr0, %eax
and $~(1 << 31), %eax
mov %eax, %cr0
# :Disabling long mode in msr
mov $0xc0000080, %ecx
rdmsr
and $~(1 << 8), %eax
wrmsr
# :Here we are in true protected mode (32 bits)
# Let's continue our descent to real mode
# by switching our gdt to 16 bits
lgdt gdtr16
ljmp $(gdt16_code - gdt16), $real_call_to_16bits_pmode_down
.code16
real_call_to_16bits_pmode_down:
# :Disable protected mode
mov %cr0, %eax
and $~1, %eax
mov %eax, %cr0
ljmp $0, $real_call_to_16bits_rmode_down
real_call_to_16bits_rmode_down:
mov $0, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov %ax, %gs
mov %ax, %fs
# :real mode, yay
lidt bios_idtr
sti
mov rebx, %ebx
mov recx, %ecx
mov redx, %edx
mov redi, %edi
mov resi, %esi
pop %ax
call *%ax
mov %eax, reax
mov %ebx, rebx
mov %ecx, recx
mov %edx, redx
mov %edi, redi
mov %esi, resi
cli
# :Restore protected mode
mov %cr0, %eax
or $1, %eax
mov %eax, %cr0
lgdt gdtr32
ljmp $(gdt32_code - gdt32), $real_call_to_pmode_up
.code32
real_call_to_pmode_up:
# :Restore PAE (probably unneeded)
mov %cr4, %eax
or $(1 << 5), %eax
mov %eax, %cr4
# :Restore long mode
mov $0xc0000080, %ecx
rdmsr
or $(1 << 8), %eax
wrmsr
# :Restore paging
mov %cr0, %eax
or $1 << 31, %eax
mov %eax, %cr0
lgdt gdtr64
ljmp $(gdt64_code - gdt64), $real_call_to_longmode_up
.code64
real_call_to_longmode_up:
mov $(gdt64_data - gdt64), %ax
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
mov %ax, %es
mov %ax, %ds
real_call_end:
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
ret
.globl testt
testt:
mov $1, %al
mov $0x43, %bh
mov $0x6, %ah
mov $0, %ch
mov $0, %cl
mov $5, %dh
mov $5, %dl
int $0x10
ret
|