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
|
.code16
.section boot.stage1, "aw"
.include "rt/+x86_64/gdt16.S"
.include "rt/+x86_64/gdt32.S"
.include "rt/+x86_64/gdt64.S"
.include "rt/+x86_64/realcall.S"
.code16
_stage1_real:
xchg %bx, %bx
# :At this point, we are in the newly loaded code, but still in 16 bits Real Mode,
# we will want to switch to 32 bits protected mode
# This is done by
# (1) Loading the 32 bits GDT
# (2) Enabling protected mode bit
# (3) Loading segment registers with the data and code segment offsets
# in the GDT
# Load the 32 bits GDT by using lgdt on the gdtr32 structure
lgdt gdtr32
# :Enable the protected mode bit is bit 1 in %cr0
mov %cr0, %eax
or $1, %eax
mov %eax, %cr0
# :Longjumping to set the %cs segment register
# (the rest will be set there)
ljmp $gdt32_code - gdt32, $_stage1
# :Tell the assembler to emit 32 bits code from now on in the file
.code32
_stage1:
# :We are now in 32 bits protected mode!
# Our goal now is to load the stage 3 and to set up the long mode
# in order to get to our sweet 64 bits
xchg %bx, %bx
# :Load the rest of the 32 bits data segments (%cs was set by the longjump)
mov $gdt32_data - gdt32, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov %ax, %fs
mov %ax, %gs
pages_clear:
# :We know that the pages are located in free memory (in the 0x500 -> 0x7BFF zone)
# However, they might contain garbage so we need to free it
xchg %bx, %bx
mov $_p4, %edi
call pages_clear_page
mov $_p3, %edi
call pages_clear_page
mov $_p2, %edi
call pages_clear_page
mov $_p1, %edi
call pages_clear_page
pages_fill:
# :Set each page level's first entry to point to the next level
# in order to identity map the first 2 megabytes of memory
# :Here, we or with 3 in order to enable the
# 'present' bit and the 'rw' bit on the page entry
mov $_p3, %edi
or $3, %edi
mov %edi, (_p4)
# Recursive map the page 4
mov $_p4, %edi
or $3, %edi
mov $_p4, %ebx
mov %edi, 4088(%ebx)
mov $_p2, %edi
or $3, %edi
mov %edi, (_p3)
mov $_p1, %edi
or $3, %edi
mov $_p3, %ebx
mov %edi, 8(%ebx)
# :Now we are going to fill the first page
mov $(1 << 7| 0x3), %ebx
mov $512, %ecx
mov $_p2, %edi
pages_fill_p2_loop:
mov %ebx, (%edi)
add $0x200000, %ebx
add $8, %edi
loop pages_fill_p2_loop
mov $512, %ecx
mov $_p1, %edi
pages_fill_p1_loop:
mov %ebx, (%edi)
add $0x200000, %ebx
add $8, %edi
loop pages_fill_p1_loop
# :Now that the pages are prepared, we must set the %cr3 to point to the level 4
# page table. This register contains the address of the level 4 page
mov $_p4, %edi
mov %edi, %cr3
pages_enable_pae:
# :Enable the physical address extension, extends the virtually addressable
# space above 4GB. Also, this is required for long mode
# The PAE bit is the 5th bit of the %cr4 register
mov %cr4, %eax
or $1 << 5, %eax
mov %eax, %cr4
pages_enable_longmode_bit:
# :Enable the longmode bit. It is the 8th bit of the model specific register
# identified with 0xC00000080
mov $0xC0000080, %ecx
rdmsr
or $1 << 8, %eax
wrmsr
# :We are now in Compatibility mode. This is a transitational mode between 32 bits protected
# and long mode. We still have 2 things to do before entering long mode:
# (1) Enabling paging
# (2) Loading a 64 bits GDT
pages_enable_paging:
# :Enable the paging and also make sure that the protected mode is enabled
# Everything is in %cr0, paging is bit 31st and protected is bit 0th
mov %cr0, %eax
or $1 << 31 | 1 << 0, %eax
mov %eax, %cr0
reload_segments:
# :Last thing to do, reloading the segments
xchg %bx, %bx
lgdt gdtr64
ljmp $gdt64_code - gdt64, $stage1_long
# :pages_clear_page:
# Clears the page located at address
# pointed by %edi
pages_clear_page:
push %ecx
push %edi
mov $0x1000, %ecx
pages_clear_page_loop:
movb $0x0, (%edi)
inc %edi
loop pages_clear_page_loop
pop %edi
pop %ecx
ret
# :Tell the assembler to emit 64 bits code
.code64
stage1_long:
# :Finally! We are in long mode. We shall now setup the rest of the segments
# registers, as well as the stack, then jump to Hare
xchg %bx, %bx
mov $gdt64_data - gdt64, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %ss
mov %ax, %fs
mov %ax, %gs
# :Clear all the registers
# (QBE makes this assumption?)
xor %rax, %rax
xor %rbx, %rbx
xor %rcx, %rcx
xor %rdx, %rdx
xor %rdi, %rdi
xor %rsi, %rsi
xor %r8, %r8
xor %r9, %r9
xor %r10, %r10
xor %r11, %r11
xor %r12, %r12
xor %r13, %r13
xor %r14, %r14
xor %r15, %r15
xor %rbp, %rbp
cli
jmp _hare
|