summaryrefslogtreecommitdiff
path: root/rt/+x86_64/realcall.S
blob: 46745f85ecaaa699d3522c22ee447775d7971f70 (plain)
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