forked from FDOS/kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
boot32.asm
397 lines (343 loc) · 12.2 KB
/
boot32.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
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
; +--------+
; | |
; | |
; |--------| 4000:0000
; | |
; | FAT |
; | |
; |--------| 2000:0000
; |BOOT SEC|
; |RELOCATE|
; |--------| 1FE0:0000
; | |
; | |
; | |
; | |
; |--------|
; |BOOT SEC|
; |ORIGIN | 07C0:0000
; |--------|
; | |
; | |
; | |
; |--------|
; |KERNEL |
; |LOADED |
; |--------| 0060:0000
; | |
; +--------+
;%define MULTI_SEC_READ 1
segment .text
%define BASE 0x7c00
org BASE
Entry: jmp short real_start
nop
; bp is initialized to 7c00h
%define bsOemName bp+0x03 ; OEM label
%define bsBytesPerSec bp+0x0b ; bytes/sector
%define bsSecPerClust bp+0x0d ; sectors/allocation unit
%define bsResSectors bp+0x0e ; # reserved sectors
%define bsFATs bp+0x10 ; # of fats
%define bsRootDirEnts bp+0x11 ; # of root dir entries
%define bsSectors bp+0x13 ; # sectors total in image
%define bsMedia bp+0x15 ; media descrip: fd=2side9sec, etc...
%define sectPerFat bp+0x16 ; # sectors in a fat
%define sectPerTrack bp+0x18 ; # sectors/track
%define nHeads bp+0x1a ; # heads
%define nHidden bp+0x1c ; # hidden sectors
%define nSectorHuge bp+0x20 ; # sectors if > 65536
%define xsectPerFat bp+0x24 ; Sectors/Fat
%define xrootClst bp+0x2c ; Starting cluster of root directory
%define drive bp+0x40 ; Drive number
times 52h - ($ - $$) db 0
; The filesystem ID is used by lDOS's instsect (by ecm)
; by default to validate that the filesystem matches.
db "FAT32"
times 5Ah - ($ - $$) db 32
%define LOADSEG 0x0060
%define FATSEG 0x2000
%define fat_sector bp+0x48 ; last accessed sector of the FAT
%define loadsegoff_60 bp+loadseg_off-Entry ; FAR pointer = 60:0
%define loadseg_60 bp+loadseg_seg-Entry
%define fat_start bp+0x5e ; first FAT sector
%define data_start bp+0x62 ; first data sector
%define fat_secmask bp+0x66 ; number of clusters in a FAT sector - 1
%define fat_secshift bp+0x68 ; fat_secmask+1 = 2^fat_secshift
;-----------------------------------------------------------------------
; ENTRY
;-----------------------------------------------------------------------
real_start: cld
cli
sub ax, ax
mov ds, ax
mov bp, 0x7c00
mov ax, 0x1FE0
mov es, ax
mov si, bp
mov di, bp
mov cx, 0x0100
rep movsw ; move boot code to the 0x1FE0:0x0000
jmp word 0x1FE0:cont
loadseg_off dw 0
loadseg_seg dw LOADSEG
cont: mov ds, ax
mov ss, ax
lea sp, [bp-0x20]
sti
mov [drive], dl ; BIOS passes drive number in DL
; call print
; db "Loading ",0
; Calc Params
; Fat_Start
mov si, word [nHidden]
mov di, word [nHidden+2]
add si, word [bsResSectors]
adc di, byte 0
mov word [fat_start], si
mov word [fat_start+2], di
; Data_Start
mov al, [bsFATs]
cbw
push ax
mul word [xsectPerFat+2]
add di, ax
pop ax
mul word [xsectPerFat]
add ax, si
adc dx, di
mov word[data_start], ax
mov word[data_start+2], dx
; fat_secmask
mov ax, word[bsBytesPerSec]
shr ax, 1
shr ax, 1
dec ax
mov word [fat_secmask], ax
; fat_secshift
; cx = temp
; ax = fat_secshift
xchg ax, cx ; cx = 0 after movsw
inc cx
secshift: inc ax
shr cx, 1
cmp cx, 1
jne secshift
mov byte [fat_secshift], al
dec cx
; FINDFILE: Searches for the file in the root directory.
;
; Returns:
; DX:AX = first cluster of file
mov word [fat_sector], cx ; CX is 0 after "dec"
mov word [fat_sector + 2], cx
mov ax, word [xrootClst]
mov dx, word [xrootClst + 2]
ff_next_cluster:
push dx ; save cluster
push ax
call convert_cluster
jc boot_error ; EOC encountered
ff_next_sector:
push bx ; save sector count
les bx, [loadsegoff_60]
call readDisk
push dx ; save sector
push ax
mov ax, [bsBytesPerSec]
; Search for KERNEL.SYS file name, and find start cluster.
ff_next_entry: mov cx, 11
mov si, filename
mov di, ax
sub di, 0x20
repe cmpsb
jz ff_done
sub ax, 0x20
jnz ff_next_entry
pop ax ; restore sector
pop dx
pop bx ; restore sector count
dec bx
jnz ff_next_sector
ff_find_next_cluster:
pop ax ; restore current cluster
pop dx
call next_cluster
jmp short ff_next_cluster
ff_done:
mov ax, [es:di+0x1A-11] ; get cluster number
mov dx, [es:di+0x14-11]
c4:
sub bx, bx ; ES points to LOADSEG
c5: push dx
push ax
push bx
call convert_cluster
jc boot_success
mov di, bx
pop bx
c6:
call readDisk
dec di
jnz c6
pop ax
pop dx
call next_cluster
jmp short c5
boot_error:
xor ah,ah
int 0x16 ; wait for a key
int 0x19 ; reboot the machine
; input:
; DX:AX - cluster
; output:
; DX:AX - next cluster
; CX = 0
; modify:
; DI
next_cluster:
push es
mov di, ax
and di, [fat_secmask]
mov cx, [fat_secshift]
cn_loop:
shr dx,1
rcr ax,1
dec cx
jnz cn_loop ; DX:AX fat sector where our
; cluster resides
; DI - cluster index in this
; sector
shl di,1 ; DI - offset in the sector
shl di,1
add ax, [fat_start]
adc dx, [fat_start+2] ; DX:AX absolute fat sector
push bx
mov bx, FATSEG
mov es, bx
sub bx, bx
cmp ax, [fat_sector]
jne cn1 ; if the last fat sector we
; read was this, than skip
cmp dx,[fat_sector+2]
je cn_exit
cn1:
mov [fat_sector],ax ; save the fat sector number,
mov [fat_sector+2],dx ; we are going to read
call readDisk
cn_exit:
pop bx
mov ax, [es:di] ; DX:AX - next cluster
mov dx, [es:di + 2] ;
pop es
ret
boot_success:
mov bl, [drive]
jmp far [loadsegoff_60]
; Convert cluster to the absolute sector
;input:
; DX:AX - target cluster
;output:
; DX:AX - absoulute sector
; BX - [bsSectPerClust]
;modify:
; CX
convert_cluster:
cmp dx,0x0fff
jne c3
cmp ax,0xfff8
jb c3 ; if cluster is EOC (carry is set), do ret
stc
ret
c3:
mov cx, dx ; sector = (cluster - 2)*clussize +
; + data_start
sub ax, 2
sbb cx, byte 0 ; CX:AX == cluster - 2
mov bl, [bsSecPerClust]
sub bh, bh
xchg cx, ax ; AX:CX == cluster - 2
mul bx ; first handle high word
; DX must be 0 here
xchg ax, cx ; then low word
mul bx
add dx, cx ; DX:AX target sector
add ax, [data_start]
adc dx, [data_start + 2]
ret
; prints text after call to this function.
print_1char:
xor bx, bx ; video page 0
mov ah, 0x0E ; else print it
int 0x10 ; via TTY mode
print: pop si ; this is the first character
print1: lodsb ; get token
push si ; stack up potential return address
cmp al, 0 ; end of string?
jne print_1char ; until done
ret ; and jump to it
;input:
; DX:AX - 32-bit DOS sector number
; ES:BX - destination buffer
;output:
; ES:BX points one byte after the last byte read.
; DX:AX - next sector
;modify:
; ES if DI * bsBytesPerSec >= 65536, CX
readDisk:
read_next: push dx
push ax
;
; translate sector number to BIOS parameters
;
;
; abs = sector offset in track
; + head * sectPerTrack offset in cylinder
; + track * sectPerTrack * nHeads offset in platter
;
xchg ax, cx
mov al, [sectPerTrack]
mul byte [nHeads]
xchg ax, cx
; cx = nHeads * sectPerTrack <= 255*63
; dx:ax = abs
div cx
; ax = track, dx = sector + head * sectPertrack
xchg ax, dx
; dx = track, ax = sector + head * sectPertrack
div byte [sectPerTrack]
; dx = track, al = head, ah = sector
mov cx, dx
; cx = track, al = head, ah = sector
; the following manipulations are necessary in order to
; properly place parameters into registers.
; ch = cylinder number low 8 bits
; cl = 7-6: cylinder high two bits
; 5-0: sector
mov dh, al ; save head into dh for bios
xchg ch, cl ; set cyl no low 8 bits
ror cl, 1 ; move track high bits into
ror cl, 1 ; bits 7-6 (assumes top = 0)
inc ah ; sector offset from 1
or cl, ah ; merge sector into cylinder
mov ax, 0x0201
mov dl, [drive]
int 0x13
pop ax
pop dx
jnc read_ok ; jump if no error
xor ah, ah ; else, reset floppy
int 0x13
jmp short read_next
read_ok:
add bx, word [bsBytesPerSec]
jnc no_incr_es ; if overflow...
mov cx, es
add ch, 0x10 ; ...add 1000h to ES
mov es, cx
no_incr_es:
add ax,byte 1
adc dx,byte 0
ret
times 0x01f1-$+$$ db 0
filename db "KERNEL SYS",0,0
sign dw 0xAA55