-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathboot.asm
327 lines (242 loc) · 6.19 KB
/
boot.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
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
org 0x7c00
jmp start
nop
BS_OEMName db 'StanBoot'
BPB_BytesPerSec dw 512
BPB_SecPerClus db 1
BPB_RsvdSecCnt dw 1
BPB_NumFATs db 2
BPB_RootEntCnt dw 224
BPB_TotSec16 dw 2880
BPB_Media db 0xf0
BPB_FATSz16 dw 9
BPB_SecPerTrk dw 18
BPB_NumHeads dw 2
BPB_HiddSec dd 0
BPB_TotSec32 dd 0
BS_DrvNum db 0
BS_Reserved1 db 0
BS_BootSig db 0x29
BS_VolID dd 0
BS_VolLab db 'boot loader'
BS_FileSysType db 'FAT12 '
start :
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7c00
; 设置堆栈的位置
; push 0000h
; push 0f0fh
; push 4000h
; call clean_screen
; jmp $
push 0204h
push word [len]
push mess
push 0003h
call print
; jmp $
xor ah, ah
xor dl, dl
int 13h
; 重置磁盘驱动器
push 1000h
push file_name
push 1140h
call load_file_fat12
jmp 0x1140:0x00
; clean_screen:
; ; 函数原型:void clean_screen(word 左上(bp+8), word 右下(bp+6), word 颜色(bp+4))
; push bp
; mov bp, sp
; pusha
; mov ax, 0600h
; mov bx, [ss:bp+4] ;第三个参数
; mov dx, [ss:bp+6] ;第二个参数
; mov cx, [ss:bp+8] ;第一个参数
; int 10h
; mov ax, [ss:bp+2] ;获取返回地址的位置
; mov [ss:bp+8], ax ;将返回地址放入第一个参数所在的地方
; popa
; pop bp
; add sp, 6 ;弹出参数
; ret
print:
; 函数原型: void print(word 光标位置(bp+10), word 字符串长度(bp+8), word 字符串地址(bp+6), word 文字颜色(bp+4))
push bp
mov bp, sp
pusha
mov ax, 1301h ;输出
mov dx, [ss:bp+10]
mov cx, [ss:bp+8]
push es ;如果在函数内部修改了段寄存器,必须要注意保存和恢复,popa,pusha与段寄存器无关
mov bx, ds
mov es, bx
mov bx, [ss:bp+4]
mov bh, 00h
push bp
mov bp, [ss:bp+6]
int 10h
pop bp
pop es
mov ax, [ss:bp+2] ;获取返回地址的位置
mov [ss:bp+10], ax ;将返回地址放入第一个参数所在的地方
popa
pop bp
add sp, 8 ;弹出参数
ret
load_sector:
; 函数原型:void load_sector(word sector_index(bp+8), word sector_num(bp+6), word address(bp+4))
push bp
mov bp, sp
pusha
mov ax, [ss:bp+8]
mov cx, [ss:bp+6]
mov si, [ss:bp+4]
mov bl, 18
div bl
mov dh, al
and dh, 1
shr al, 1
mov ch, al
inc ah
mov al, cl
mov cl, ah
push es
read:
mov ah, 02h
mov bx, si
mov es, bx
mov bx, 0
mov dl, 0
int 13h
jc read
pop es
mov ax, [ss:bp+2] ;获取返回地址的位置
mov [ss:bp+8], ax ;将返回地址放入第一个参数所在的地方
popa
pop bp
add sp, 6 ;弹出参数
ret
load_file_fat12:
; 函数原型:void load_file_fat12(word tmp_address(bp+8), word filename(bp+6), word address(bp+4))
; tmp_address用来暂存目录项和FAT表,最长会占用9*520字节,filename是要寻找的名字的地址,address是最后要存储的文件地址
push bp
mov bp, sp
pusha
push es
;我决定将此处的三个循环变量改造为局部变量,使用堆栈存储
push word 19 ;目录扇区序号 sp+4-------di+4
push word 0 ;扇区内目录项偏移 sp+2------di+2
push word 0 ;目录项内文件名字字母序号 sp----di
mov di, sp
search_dir:
cmp word [ss:di+4], 33 ;如果所有目录扇区已搜索完成,失败
jz find_fail ;jz是当前述二者相等时会执行
push word [ss:di+4] ;当前依旧是有效目录扇区,那么开始准备读入扇区
push word 0001h ;扇区序号是[sp+4],读入1个扇区
push word [ss:bp+8] ;读入到0x1000:0000 即0x10000
call load_sector
inc word [ss:di+4] ;下一个扇区序号是加一
mov word [ss:di+2], 0 ;准备开始在已经加载的扇区内搜索各个目录项
search_one_sector:
cmp word [ss:di+2], 520 ;目录项搜索完毕就失败,检查下一个扇区
jz search_dir
mov si, 1000h
mov es, si ;将es寄存器设置为目录扇区在内存中的段地址
mov bx, [ss:di+2] ;将当前目录项的起始偏移载入bx
add word [ss:di+2], 32 ;生成下一个目录项的偏移
mov word [ss:di], 0 ;生成要搜索的字母的偏移0
mov si, 0
mov ds, si ;设置ds为0,这是为了后面loadsb
mov si, [ss:bp+6] ;将目标文件名载入si
search_one_entry:
cmp word [ss:di], 11 ;比较当前搜索的字母的序号,如果等于11代表检查成功
jz find_file
inc word [ss:di] ;字母序号加一
lodsb ;从ds:si加载一个字节进入al,自增si
cmp al, byte [es:bx] ;比较目标字母和当前字母是否一致
jz one_character_success ;如果一致自增bx之后,开始比较下一个字母
jmp search_one_sector ;不一致搜索下一个目录项
one_character_success:
inc bx
jmp search_one_entry
find_file:
add sp, 6 ;弹出3个局部变量
add bx, 15 ;检查文件名成功之后,bx加15就是这个目录项中存储首簇序号的位置
mov ax, [es:bx] ;将首簇序号加载进入ax寄存器
pop es
jmp load_fat
find_fail:
add sp, 6 ;弹出3个局部变量
pop es
jmp $
load_fat:
push word 1
push word 9
push word [ss:bp+8]
call load_sector ;加载所有FAT表
mov si, [ss:bp+4] ;保存loader加载到的地址
mov bx, [ss:bp+8] ;在es内存入1000h,用来和bx配合获取FAT项
mov es, bx
parse_fat:
push ax ;保存首簇序号到堆栈
cmp ax, 0fffh
jz file_load_done
add ax, 31
push ax
push 1
push si
call load_sector ;读取一个loader扇区
add si, 20h ;下一个扇区si加20h即 200h->520B
pop ax ;恢复首簇地址,并重新压入
push ax
mov cl, 2
div cl
mov cl, 3
mul cl
mov bx, ax
mov al, [es:bx]
mov ah, 0
inc bx
mov ch, [es:bx]
and ch, 0fh
mov cl, 0
add ax, cx
mov cl, [es:bx]
mov ch, 0
shr cx, 4
inc bx
mov dl, [es:bx]
mov dh, 0
shl dx, 4
add cx, dx
mov bx, ax
pop ax
; push ax
mov dl, 2
div dl
cmp ah, 0
jz get_even_fat
jmp get_odd_fat
get_even_fat:
mov ax, bx
jmp parse_fat
get_odd_fat:
mov ax, cx
jmp parse_fat
file_load_done:
pop ax ;弹出首簇序号
mov ax, [ss:bp+2] ;获取返回地址的位置
mov [ss:bp+8], ax ;将返回地址放入第一个参数所在的地方
popa
pop bp
add sp, 6 ;弹出参数
ret
mess: db "hello, stan!"
len: dw $-mess
file_name: db "LOADER BIN", 0
times 510-($-$$) db 0
dw 0xaa55