forked from asweeney86/tinyboot
-
Notifications
You must be signed in to change notification settings - Fork 1
/
loader.s
168 lines (126 loc) · 4.71 KB
/
loader.s
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
.global loader
.section .data
.align 0x1000
_kernel_pd:
.space 0x1000, 0x00
_kernel_pt:
.space 0x1000, 0x00
_kernel_low_pt:
.space 0x1000, 0x00
.set INITSTACKSIZE, 0x10000
initstack:
.space INITSTACKSIZE, 0x00
.section .text
.code32
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set MEMINFO, 1<<1 # provide memory map
.set FLAGS, ALIGN | MEMINFO # this is the Multiboot 'flag' field
.set MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum required
.align 4
multiboot_header:
.long MAGIC
.long FLAGS
.long CHECKSUM
loader:
mov $(initstack + INITSTACKSIZE), %esp
subl $KERNEL_HIGH_VMA, %esp
call init_boot_paging_ia32
addl $KERNEL_HIGH_VMA, %esp
mov %esp, %ebp
call kmain
the_end:
hlt
jmp the_end
init_boot_paging_ia32:
push %eax
push %ebx
push %edx
push %ecx
mov $_kernel_pd, %eax # get virtual address of kernel pd
sub $KERNEL_HIGH_VMA, %eax # adjust to physical address
mov $_kernel_low_pt, %ebx # get virtual address of kernel low pt
sub $KERNEL_HIGH_VMA, %ebx # adjust to physical address
or $0x1, %ebx # set present flag
mov %ebx, (%eax) # set the pde
push %eax
mov $KERNEL_HIGH_VMA, %eax # get virtual address offset
shr $22, %eax # calculate index in the pd
mov $4, %ecx
mul %ecx # calculate byte offset (4bytes each entry)
mov %eax, %edx
pop %eax
push %eax # save the real address for later
add %edx, %eax # move the pointer in the pd to the correct entry.
mov $_kernel_pt, %ebx # get virtual address of kernel main pt
sub $KERNEL_HIGH_VMA, %ebx # adjust to physical address
or $0x1, %ebx # mark present
mov %ebx, (%eax) # set the pde
pop %ebx # pop saved address of the kernel PD
mov $0x100000, %ecx # map the low 1MB
_idmap_first_mb_loop:
mov %ecx, %edx # phys == virt (identity mapping)
call boot_map_page_ia32 # do the mapping
sub $0x1000, %ecx # one page down.
jnz _idmap_first_mb_loop # if not zero, continue (DON'T map zero :))
mov $KERNEL_BOOT_VMA, %ecx # this is the _very_ beginning :)
mov $_core_end, %eax # virtual address of end
sub $KERNEL_HIGH_VMA, %eax # now it is physical.
_map_kernel:
mov %ecx, %edx # phys == virt (identity mapping)
call boot_map_page_ia32 # do the mapping
push %ecx
add $KERNEL_HIGH_VMA, %ecx # now map the virtual address to the same physical one
call boot_map_page_ia32 # do it
pop %ecx
add $0x1000, %ecx # on to the next page.
cmp %eax, %ecx
jle _map_kernel # continue untill all the kernel is mapped.
mov %ebx, %cr3 # use the kernel pd
mov %cr0, %eax # get the current cr0 value
or $(1 << 31), %eax # enable paging
mov %eax, %cr0 # now re-set the cr0 register.
pop %ecx
pop %edx
pop %ebx
pop %eax
ret
boot_map_page_ia32:
# ebx: physical addr of kernel PD
# ecx: the virtual address to map
# edx: the physical address to map to
push %eax
push %ebx
push %ecx
push %edx
push %edx # push physical address
push %ecx # push virtual address
mov %ecx, %eax
shr $22, %eax
mov $4, %ecx
mul %ecx # now we have the offset in eax
add %eax, %ebx # now ebx points to the phys addr of a pt if present
mov (%ebx), %eax
mov %eax, %ecx
and $0x1, %ecx # check present flag
cmp $0x0, %ecx
je the_end # if zero, PANIC!
and $0xFFFFF000, %eax # clear off possible flags from the PDE.
pop %edx # the virtual address.
push %eax
mov %edx, %eax
shr $0xC, %eax # shift right to discard non-significant bits.
and $0x3FF, %eax # and away not-relevant bits on the left.
mov $0x4, %ecx # each entry is 4 bytes
mul %ecx
mov %eax, %ebx # now in ebx: the offset into the PT for the PTE.
pop %eax
pop %edx # the phsyical target address
add %ebx, %eax # add offset to pt. this is the final location now.
or $0x1, %edx # mark present...
mov %edx, (%eax) # and insert into pt.
pop %edx
pop %ecx
pop %ebx
pop %eax
ret