278 lines
4.3 KiB
NASM
278 lines
4.3 KiB
NASM
; 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
|
|
|
|
jmp near init
|
|
|
|
; current cluster number
|
|
cclus: dw 0
|
|
; sector number in cluster
|
|
csec: dw 0
|
|
|
|
times (0x0B - ($-$$)) db 0
|
|
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
|
|
|
|
; mformat keeps writing until here
|
|
; if we place init earlier, code gets overwritten
|
|
times (62 - ($-$$)) nop
|
|
|
|
init: xor ax, ax
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov ss, ax
|
|
mov sp, 0x0600
|
|
|
|
; Relocate and jump
|
|
mov di, sp
|
|
mov si, 0x7C00
|
|
mov cx, 0x0100
|
|
rep movsw
|
|
jmp 0: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
|
|
|
|
; Read sector into ES:BX
|
|
; Sector number has been previously set with seek
|
|
read: push 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 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
|
|
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:
|
|
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
|
|
pop cx
|
|
je .found
|
|
add si, 0x20
|
|
loop .loop
|
|
stc
|
|
.found: pop si
|
|
pop cx
|
|
ret
|
|
.name: db "HELLO "
|
|
.ext: db "COM"
|
|
|
|
fopen:
|
|
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
|
|
pop bx
|
|
pop dx
|
|
pop cx
|
|
pop ax
|
|
ret
|
|
|
|
fread: push ax
|
|
push cx
|
|
push dx
|
|
cmp word [cs:cclus], 0
|
|
je .err
|
|
call clusec
|
|
push ax
|
|
mov ax, [cs:cclus]
|
|
sub ax, 2
|
|
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
|
|
adc dx, 0
|
|
; dx:ax now point to the sector that should be read next
|
|
call seek
|
|
call read
|
|
jmp .ret
|
|
.err: stc
|
|
.ret: pop dx
|
|
pop cx
|
|
pop ax
|
|
ret
|
|
|
|
main: mov [seek.dl], dl ; save drive number
|
|
|
|
call fopen
|
|
mov bx, 0x1100
|
|
call fread
|
|
|
|
mov ax, 0x0100
|
|
mov ds, ax
|
|
mov es, ax
|
|
call 0x100:0x100
|
|
|
|
.hlt: hlt
|
|
jmp .hlt
|
|
|
|
; Padding and signature
|
|
times (0x1FE - ($-$$)) db 0
|
|
dw 0xAA55
|