Pave way for supporting FAT16 and FAT12

This commit is contained in:
Nero 2020-04-06 19:20:15 +00:00
parent e34accfcff
commit f46871502c
3 changed files with 273 additions and 537 deletions

View File

@ -48,20 +48,41 @@ vga11.com: cp437.bin
%.bs: boot/%.asm
$(NASM) $(NASM_ARGS) -o $@ $<
# Special case: variations of FAT vbr
fat1.bs: boot/fat.asm
$(NASM) $(NASM_ARGS) -DFAT12 -DCHS -o $@ $<
fat4.bs: boot/fat.asm
$(NASM) $(NASM_ARGS) -DFAT16 -DCHS -o $@ $<
fat6.bs: boot/fat.asm
$(NASM) $(NASM_ARGS) -DFAT16 -DCHS -DLARGE -o $@ $<
fatb.bs: boot/fat.asm
$(NASM) $(NASM_ARGS) -DFAT32 -DCHS -DLARGE -o $@ $<
fatc.bs: boot/fat.asm
$(NASM) $(NASM_ARGS) -DFAT32 -DLBA -DLARGE -o $@ $<
fate.bs: boot/fat.asm
$(NASM) $(NASM_ARGS) -DFAT16 -DLBA -DLARGE -o $@ $<
# BIOS option roms
%.rom: rom/%.asm utils/fix-rom
$(NASM) $(NASM_ARGS) -o $@ $< && utils/fix-rom $@
fdimage.img: fat.bs $(DISTFILES)
mformat -C -i $@ -f $(FLOPPY) -B fat.bs ::
mcopy -i $@ $(DISTFILES) ::
fdimage.img: fat1.bs $(DISTFILES)
mformat -C -i $@ -f $(FLOPPY) -B fat1.bs ::
mmd -i $@ ::rdos
mcopy -i $@ $(DISTFILES) ::rdos
mattrib -i $@ +s ::rdos ::rdos/kernel.bs
hdimage.img: mbr.bs fdimage.img
cat mbr.bs fdimage.img >$@
part.img: fat32.bs $(DISTFILES)
part.img: fatc.bs $(DISTFILES)
dd if=/dev/zero bs=1024 count=33k of=$@
mformat -i $@ -F -B fat32.bs ::
mformat -i $@ -F -B fatc.bs ::
mmd -i $@ ::rdos
mcopy -i $@ $(DISTFILES) ::rdos
mattrib -i $@ +s ::rdos ::rdos/kernel.bs

View File

@ -1,293 +1,289 @@
; Bootsector for FAT12 filesystems
; Memory layout:
; 0000-03FF IVT
; 0400-0500 Bios data area
; 0501-0600 Stack for us
; 0600-0800 This code
org 0x0600
; 0800-0A00 Buffer for disk
buf: equ 0x0800
; Bootsector for FAT32 filesystems
; Takes defines:
; FAT12 FAT has 1.5 bytes per entry
; FAT16 FAT has WORD per entry
; FAT32 FAT has DWORD per entry
; CHS uses int13h/AH=02h
; LARGE requires 32 bit sector numbers
; LBA uses int13h/AH=42h
cpu 8086
jmp near init
org 0x0800
jmp short init
nop
; current cluster number
cclus: dw 0
; sector number in cluster
csec: dw 0
%include "inc/bpb.asm"
times (0x0B - ($-$$)) db 0
; BIOS PARAMETER BLOCK
fdc: ; sector size
.ss: dw 0x200
; sectors per cluster
.sc: db 2
; reserved sector count
.rsc: dw 1
.fn: ; number of file allocation tables
db 2
.rde: ; number of root directory entries
dw 0x70
.ts: ; total number of sectors
dw 720
.mid: db 0xFD
.sf: dw 2
.spt: dw 9
.nos: dw 2
.po: dd 0
.lrgts: ; large sector count - relevant if .ts is 0
dd 0
bpb: equ 0x080B
; mformat keeps writing until here
; if we place init earlier, code gets overwritten
; this also marks the end for the BPB
times (62 - ($-$$)) nop
; Area for BPB
times ( 0x5A - ($-$$) ) db 0
init: xor ax, ax
mov ss, ax
mov sp, 0x7C00
; save potential partition table entry
push ds
push si
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x0600
; Relocate and jump
mov di, sp
mov si, 0x7C00
mov di, 0x0800
mov cx, 0x0100
rep movsw
jmp 0:main
jmp 0x0:main
; Set adress for sector read/write
; Number is relative to current partition
; IN dx:ax sector number
seek: push ax
push dx
push ds
push cs
pop ds
; add partition offset (required for HDD)
add ax, [fdc.po]
adc dx, [fdc.po+2]
; ax:temp = (lba / spt)
; dx:sector = (lba % spt) + 1
div word [fdc.spt]
inc dx
; Sector number (bits 0-5) into CL
; This is blindly assumed to never exeed 63
mov byte [.cl], dl
; ax:cylinder = (tmp / heads)
; dx:head = (tmp % heads)
xor dx, dx
div word [fdc.nos]
; Cylinder number bit 0-7 into CH
mov byte [.ch], al
; Head number into DL
mov byte [.dh], dl
; Bits 8-9 of cylinder number into bits 6-7 of CL
and ah, 0x03
ror ah, 1
ror ah, 1
or byte [.cl], ah
pop ds
pop dx
pop ax
ret
.cl: db 0
.ch: db 0
.dl: db 0
.dh: db 0
%include "inc/booterr.asm"
; Read sector into ES:BX
; Sector number has been previously set with seek
read: push ax
; offsets relative to FS
readd: ; add offset of cluster data area to DX:AX
push cx
push dx
; ah = int13 subfunction 2
; al = read 1 sector
mov ax, 0x0201
; load seek data into registers
mov cx, word [cs:seek.cl]
mov dx, word [cs:seek.dl]
int 0x13
int 3
pop dx
pop cx
pop ax
ret
; Get start sector of root dirrectory
; OUT ax sector number
dirsec: ; Multiply sectors per fat with number of fats
mov ax, [cs:fdc.sf]
mul byte [cs:fdc.fn]
; Add number of reserved sectors
add ax, [cs:fdc.rsc]
ret
; Get root directory length in sectors
; OUT cx sectors
dirlen: push ax
mov ax, [cs:fdc.rde]
mov di, [bp+bpb_rde]
mov cl, 4
shr ax, cl ; 32 bytes per entry
mov cx, ax
pop ax
ret
; Get first sector of data area
; OUT ax sector number
clusec: push cx
call dirsec
call dirlen
add ax, cx
shr di, cl ; 32 bytes per entry
add ax, di
adc dx, 0
pop cx
ret: ret
; Get total number of sectors
; OUT: dx:ax number of sectors
secnum: xor dx, dx
mov ax, [cs:fdc.ts]
test ax, ax
jnz ret
mov ax, [cs:fdc.lrgts]
mov dx, [cs:fdc.lrgts+2]
ret
; Get number of clusters
; OUT: ax number of clusters
; Cant overflow for FAT16 :P
clunum: push cx
push dx
call clusec
mov cx, ax
call secnum
sub ax, cx
sbb dx, 0
mov cl, byte [cs:fdc.sc]
xor ch, ch
div cx
pop dx
pop cx
ret
; Scan current buffer for matching file
; IN ds = cs
; es = cs
; OUT bx start cluster if file found
; trashed if no match
; carry is set if no file was found
scadir:
readr: ; add offset to rootdir to DX:AX (FAT12/FAT16 only)
push cx
push si
mov si, buf
mov cx, 0x10
.loop: push cx
push si
mov bx, [si+0x1A]
mov di, .name
mov cx, 11
repe cmpsb
pop si
xor ch, ch
mov cl, byte [bp+bpb_fn]
fatlp: add ax, [bp+bpb7_lsf]
adc dx, [bp+bpb7_lsf+2]
loop fatlp
pop cx
je .found
add si, 0x20
loop .loop
stc
.found: pop si
pop cx
ret
.name: db "HELLO "
.ext: db "COM"
readf: ; add offset to FAT table to DX:AX
add ax, word [bp+bpb_rsc]
adc dx, 0
readp: ; read sector DX:AX from partition
add ax, word [bp+bpb_po]
adc dx, word [bp+bpb_po+2]
jnc ($+5)
call errcll
fopen:
%ifdef LBA
read_: ; read sector DX:AX from disk
; this uses the EBIOS extensions
; qword sector number DX:AX
push cs
push cs
push dx
push ax
; dword target buffer: BX:0
push bx
push cs
; word sector number
push cx
; size & passing
mov di, 0x10
push di
mov si, sp
mov ah, 0x42
mov dl, [bp+bpb7_dn]
stc
int 0x13
jnc ($+5)
call errcll
add sp, di
ret
%endif
%ifdef CHS
read_: ; read sector DX:AX from disk
; uses basic CHS disk IO
; this cant reliable read over track boundaries
; so we read each single sector in loop over CX
chslp: push ax
push cx
push dx
push bx
push ds
push es
cmp word [cclus], 0
jne .err
xor ax, ax
mov ds, ax
mov es, ax
call dirsec
call dirlen
.loop: xor dx, dx
mov bx, buf
call seek
call read
call scadir
jnc .found
inc ax
loop .loop
.err: stc
jmp .ret
.found: mov [cclus], bx
mov word [csec], 0
.ret: pop es
pop ds
; calculate CHS data
div word [bp+bpb_spt] ; ax:temp = (lba / spt)
inc dx ; dx:sector = (lba % spt) + 1
mov cl, dl ; sector number
xor dx, dx
div word [bp+bpb_nos] ; ax:cylinder = (tmp / heads)
; dx:head = (tmp % heads)
mov ch, al ; cylinder number
mov dh, dl ; head number
mov dl, [bp+bpb7_dn] ; drive number
; set up read buffer
mov es, bx
xor bx, bx
; call bios
mov ax, 0x0201
int 0x13
jnc ($+5)
call errcll
pop bx
pop dx
pop cx
pop ax
ret
fread: push ax
push cx
push dx
; abort if there is no file opened
cmp word [cs:cclus], 0
je .err
; get start sector for data area
call clusec
push ax
; get current cluster number
mov ax, [cs:cclus]
; clusters are 2-indexed
sub ax, 2
; multiply that with sectors per cluster
mov cl, [cs:fdc.sc]
xor ch, ch
mul word cx
; add current cluster offset, cluster start and current sector
pop cx
add cx, [cs:csec]
add ax, cx
; increment sector num + write offset
add ax, 1
adc dx, 0
; dx:ax now point to the sector that should be read next
call seek
call read
jc .err
inc word [cs:csec]
jmp .ret
.err: ; in case of error, trash current state
call fclose
stc
.ret: pop dx
pop cx
add bx, 0x20
; loop on CX
loop chslp
ret
%endif
next: ; Advances DX:AX to next FAT entry
push ax
push bx
; shift 2 left for dword-sized FAT entries
; shift 9 right for sector size
mov cl, 7
shftl: clc
rcr dx, 1
rcr ax, 1
loop shftl
mov bx, 0xA0
%ifdef FAT12
; FAT item might span over two sectors
mov cx, 2
%else
mov cx, 1
%endif
call readf
pop bx
; get lower part of cluster number
pop si
%ifdef FAT16
; double
sal si, 1
%endif
%ifdef FAT32
; multiply with 4
sal si, 1
sal si, 1
%endif
; make sure its within sector range
and si, 0x1FF
add si, buf
%ifdef FAT16
; load word from FAT
lodsw
xor dx, dx
%endif
%ifdef FAT32
; load dword from FAT
lodsw
mov dx, [si]
%endif
ret
; reads current cluster into [dest]
readc: ; load cluster number
push ax
push dx
; subtract the two dummy entries from FAT start
sub ax, 2
sbb dx, 0
; convert cluster number to sector number
; this is some cheapo multiplication with 2^n
mov cl, [bp+bpb_sc]
l02: shr cl, 1
jz l02e
clc
rcl ax, 1
rcl dx, 1
jmp l02
l02e:
; dx:ax is now sector num in data area
mov cx, [bp+bpb_sc]
xor ch, ch
call readd
xchg di, cx
mov cl, 5
sal di, cl
add bx, di
pop dx
pop ax
ret
; Reset open file info
fclose: mov [cclus], bx
mov word [csec], 0
; Load root directory
loadr: mov ax, 2
xor dx, dx
jmp load
; Load file identified by fsattr
; Directory data is expected at 0x07C00
loadf: mov si, (0x7C00-0x20)
sloop: add si, 0x20
; check if entry is valid
mov al, [si]
; unallocated direntry
test al, al
jnz ($+5)
call errcll
; deleted files
cmp al, 0xE2
je sloop
; check attr
mov al, [si+11]
and al, 0x5C
cmp al, ah
jne sloop
mov ax, [si+0x1A]
mov dx, [si+0x14]
; Load cluster chain DX:AX to 0x07C00
load: mov bx, 0x07C0
lloop: call readc
call next
cmp word dx, 0x0FFF
jne lloop
ret
main: mov [seek.dl], dl ; save drive number
main: ; Set up BP to point to BPB
; Relative addressing saves one instruction byte per access
mov bp, bpb
; Save DL contents
mov [bp+bpb7_dn], dl
call fopen
mov bx, 0x1100
call fread
; load root directory
call loadr
; search for first system directory
mov ah, 0x14
call loadf
; search for first system file
mov ah, 0x04
call loadf
mov ax, 0x0100
mov ds, ax
mov es, ax
call 0x100:0x100
; restore drive number
mov dl, [bp+bpb7_dn]
.hlt: hlt
jmp .hlt
; restore potential partition table
pop si
pop ds
jmp 0x7C00
; Padding and signature
times (0x1FE - ($-$$)) db 0
dw 0xAA55
buf:

View File

@ -1,281 +0,0 @@
; Bootsector for FAT32 filesystems
org 0x0800
cpu 8086
jmp short init
nop
%include "inc/bpb.asm"
bpb: equ 0x080B
; Area for BPB
times ( 0x5A - ($-$$) ) db 0
init: xor ax, ax
mov ss, ax
mov sp, 0x7C00
; save potential partition table entry
push ds
push si
mov ds, ax
mov es, ax
mov si, 0x7C00
mov di, 0x0800
mov cx, 0x0100
rep movsw
jmp 0x0:main
%include "inc/booterr.asm"
; offsets relative to FS
readd: ; add offset of cluster data area to DX:AX
push cx
mov di, [bp+bpb_rde]
mov cl, 4
shr di, cl ; 32 bytes per entry
add ax, di
adc dx, 0
pop cx
readr: ; add offset to rootdir to DX:AX (FAT12/FAT16 only)
push cx
xor ch, ch
mov cl, byte [bp+bpb_fn]
fatlp: add ax, [bp+bpb7_lsf]
adc dx, [bp+bpb7_lsf+2]
loop fatlp
pop cx
readf: ; add offset to FAT table to DX:AX
add ax, word [bp+bpb_rsc]
adc dx, 0
readp: ; read sector DX:AX from partition
add ax, word [bp+bpb_po]
adc dx, word [bp+bpb_po+2]
jc dskerr
; This jump is overwritten with NOP's if LBA support
dskjmp: jmp rchs
rebios: ; read sector DX:AX from disk
; this uses the EBIOS extensions
; qword sector number DX:AX
push cs
push cs
push dx
push ax
; dword target buffer: BX:0
push bx
push cs
; word sector number
push cx
; size & passing
mov di, 0x10
push di
mov si, sp
mov ah, 0x42
mov dl, [bp+bpb7_dn]
stc
int 0x13
jc dskerr
add sp, di
ret
rchs: ; read sector DX:AX from disk
; uses basic CHS disk IO
; this cant reliable read over track boundaries
; so we read each single sector in loop over CX
chslp: push ax
push cx
push dx
push bx
; calculate CHS data
div word [bp+bpb_spt] ; ax:temp = (lba / spt)
inc dx ; dx:sector = (lba % spt) + 1
mov cl, dl ; sector number
xor dx, dx
div word [bp+bpb_nos] ; ax:cylinder = (tmp / heads)
; dx:head = (tmp % heads)
mov ch, al ; cylinder number
mov dh, dl ; head number
mov dl, [bp+bpb7_dn] ; drive number
; set up read buffer
mov es, bx
xor bx, bx
; call bios
mov ax, 0x0201
int 0x13
jc dskerr
pop bx
pop dx
pop cx
pop ax
; increment sector num + write offset
add ax, 1
adc dx, 0
add bx, 0x20
; loop on CX
loop chslp
ret
; error handling for disk errors
dskerr: call errcll
next: ; Advances DX:AX to next FAT entry
push ax
push bx
; shift 2 left for dword-sized FAT entries
; shift 9 right for sector size
mov cl, 7
shftl: clc
rcr dx, 1
rcr ax, 1
loop shftl
mov bx, 0xA0
mov cx, 1
call readf
pop bx
; get lower part of cluster number
pop si
; multiply with 4
sal si, 1
sal si, 1
; make sure its within sector range
and si, 0x1FF
add si, buf
; load dword from FAT
lodsw
mov dx, [si]
ret
; reads current cluster into [dest]
readc: ; load cluster number
push ax
push dx
; subtract the two dummy entries from FAT start
sub ax, 2
sbb dx, 0
; convert cluster number to sector number
; this is some cheapo multiplication with 2^n
mov cl, [bp+bpb_sc]
l02: shr cl, 1
jz l02e
clc
rcl ax, 1
rcl dx, 1
jmp l02
l02e:
; dx:ax is now sector num in data area
mov cx, [bp+bpb_sc]
xor ch, ch
call readd
xchg di, cx
mov cl, 5
sal di, cl
add bx, di
pop dx
pop ax
ret
; Load root directory
loadr: mov ax, 2
xor dx, dx
jmp load
; Load file identified by fsattr
; Directory data is expected at 0x07C00
loadf: mov si, (0x7C00-0x20)
sloop: add si, 0x20
; check if entry is valid
mov al, [si]
; unallocated direntry
test al, al
jz fserr
; deleted files
cmp al, 0xE2
je sloop
; check attr
mov al, [si+11]
and al, 0x5C
cmp al, ah
jne sloop
mov ax, [si+0x1A]
mov dx, [si+0x14]
; Load cluster chain DX:AX to 0x07C00
load: mov bx, 0x07C0
lloop: call readc
call next
cmp word dx, 0x0FFF
jne lloop
ret
main: ; Set up BP to point to BPB
; Relative addressing saves one instruction byte per access
mov bp, bpb
; Save DL contents
mov [bp+bpb7_dn], dl
; EBIOS is ignored for floppies (dl < 80h)
test dl, 0x80
jz noebio
; check for EBIOS support
mov bx, 0x55AA
mov ah, 0x41
; set carry to assume failure if int didnt do anything
stc
int 0x13
jc noebio
; disable CHS routine, fall into LBA routine instead
mov word [dskjmp], 0x9090
noebio: ; load root directory
call loadr
; search for first system directory
mov ah, 0x14
call loadf
; search for first system file
mov ah, 0x04
call loadf
; restore drive number
mov dl, [bp+bpb7_dn]
; restore potential partition table
pop si
pop ds
jmp 0x7C00
; error handling for file not found
fserr: call errcll
; Padding and signature
times (0x1FE - ($-$$)) db 0
dw 0xAA55
buf: