forked from StevenBaby/onix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
loader.asm
245 lines (189 loc) · 5.05 KB
/
loader.asm
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
[org 0x1000]
dd 0x55aa; 魔数,用于判断错误
kernel_size: dd KERNEL_SIZE; 内核大小
; 打印字符串
mov si, loading
call print
; xchg bx, bx; 断点
detect_memory:
; 将 ebx 置为 0
xor ebx, ebx
; es:di 结构体的缓存位置
mov ax, 0
mov es, ax
mov edi, ards_buffer
mov edx, 0x534d4150; 固定签名
.next:
; 子功能号
mov eax, 0xe820
; ards 结构的大小 (字节)
mov ecx, 20
; 调用 0x15 系统调用
int 0x15
; 如果 CF 置位,表示出错
jc error
; 将缓存指针指向下一个结构体
add di, cx
; 将结构体数量加一
inc dword [ards_count]
cmp ebx, 0
jnz .next
mov si, detecting
call print
; xchg bx, bx
; mov byte [0xb8000], 'P'
jmp prepare_protected_mode
prepare_protected_mode:
; xchg bx, bx; 断点
cli; 关闭中断
; 打开 A20 线
in al, 0x92
or al, 0b10
out 0x92, al
lgdt [gdt_ptr]; 加载 gdt
; 启动保护模式
mov eax, cr0
or eax, 1
mov cr0, eax
; 用跳转来刷新缓存,启用保护模式
jmp dword code_selector:protect_mode
print:
mov ah, 0x0e
.next:
mov al, [si]
cmp al, 0
jz .done
int 0x10
inc si
jmp .next
.done:
ret
loading:
db "Loading Onix...", 10, 13, 0; \n\r
detecting:
db "Detecting Memory Success...", 10, 13, 0; \n\r
error:
mov si, .msg
call print
hlt; 让 CPU 停止
jmp $
.msg db "Loading Error!!!", 10, 13, 0
[bits 32]
protect_mode:
; xchg bx, bx; 断点
mov ax, data_selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax; 初始化段寄存器
mov esp, 0x10000; 修改栈顶
sub esp, 4 * 3; 三个变量
mov dword [esp], 0; 读出的数量
mov dword [esp + 4], 10 ; ecx 初始扇区位置
mov dword [esp + 8], 0x18000; edi 目标内存位置
BLOCK_SIZE equ 200 ; 一次读取的扇区数量
.read_block:
mov edi, [esp + 8] ; 读取的目标内存
mov ecx, [esp + 4] ; 起始扇区
mov bl, BLOCK_SIZE ; 扇区数量
call read_disk ; 读取内核
add dword [esp + 8], BLOCK_SIZE * 512 ; edi 目标内存位置
add dword [esp + 4], BLOCK_SIZE ; ecx 初始扇区位置
mov eax, [kernel_size]
add dword [esp], BLOCK_SIZE * 512
cmp dword [esp], eax; 判断已读数量与 kernel_size 的大小
jl .read_block
mov eax, 0x20220205; 内核魔数
mov ebx, ards_count; ards 数量指针
jmp dword code_selector:0x20000
ud2; 表示出错
read_disk:
; 设置读写扇区的数量
mov dx, 0x1f2
mov al, bl
out dx, al
inc dx; 0x1f3
mov al, cl; 起始扇区的前八位
out dx, al
inc dx; 0x1f4
shr ecx, 8
mov al, cl; 起始扇区的中八位
out dx, al
inc dx; 0x1f5
shr ecx, 8
mov al, cl; 起始扇区的高八位
out dx, al
inc dx; 0x1f6
shr ecx, 8
and cl, 0b1111; 将高四位置为 0
mov al, 0b1110_0000;
or al, cl
out dx, al; 主盘 - LBA 模式
inc dx; 0x1f7
mov al, 0x20; 读硬盘
out dx, al
xor ecx, ecx; 将 ecx 清空
mov cl, bl; 得到读写扇区的数量
.read:
push cx; 保存 cx
call .waits; 等待数据准备完毕
call .reads; 读取一个扇区
pop cx; 恢复 cx
loop .read
ret
.waits:
mov dx, 0x1f7
.check:
in al, dx
jmp $+2; nop 直接跳转到下一行
jmp $+2; 一点点延迟
jmp $+2
and al, 0b1000_1000
cmp al, 0b0000_1000
jnz .check
ret
.reads:
mov dx, 0x1f0
mov cx, 256; 一个扇区 256 字
.readw:
in ax, dx
jmp $+2; 一点点延迟
jmp $+2
jmp $+2
mov [edi], ax
add edi, 2
loop .readw
ret
code_selector equ (1 << 3)
data_selector equ (2 << 3)
memory_base equ 0; 内存开始的位置:基地址
; 内存界限 4G / 4K - 1
memory_limit equ ((1024 * 1024 * 1024 * 4) / (1024 * 4)) - 1
gdt_ptr:
dw (gdt_end - gdt_base) - 1
dd gdt_base
gdt_base:
dd 0, 0; NULL 描述符
gdt_code:
dw memory_limit & 0xffff; 段界限 0 ~ 15 位
dw memory_base & 0xffff; 基地址 0 ~ 15 位
db (memory_base >> 16) & 0xff; 基地址 16 ~ 23 位
; 存在 - dlp 0 - S _ 代码 - 非依从 - 可读 - 没有被访问过
db 0b_1_00_1_1_0_1_0;
; 4k - 32 位 - 不是 64 位 - 段界限 16 ~ 19
db 0b1_1_0_0_0000 | (memory_limit >> 16) & 0xf;
db (memory_base >> 24) & 0xff; 基地址 24 ~ 31 位
gdt_data:
dw memory_limit & 0xffff; 段界限 0 ~ 15 位
dw memory_base & 0xffff; 基地址 0 ~ 15 位
db (memory_base >> 16) & 0xff; 基地址 16 ~ 23 位
; 存在 - dlp 0 - S _ 数据 - 向上 - 可写 - 没有被访问过
db 0b_1_00_1_0_0_1_0;
; 4k - 32 位 - 不是 64 位 - 段界限 16 ~ 19
db 0b1_1_0_0_0000 | (memory_limit >> 16) & 0xf;
db (memory_base >> 24) & 0xff; 基地址 24 ~ 31 位
gdt_end:
ards_count:
dd 0
ards_buffer: