; Bootsector for FAT12/FAT16 filesystems ; Takes defines: ; FAT12 FAT has 1.5 bytes per entry ; FAT16 FAT has WORD per entry cpu 8086 org 0x0800 jmp short init nop %include "inc/bpb.asm" times ( 0x0B - ($-$$) ) db 0 params: times bpb_size db 0 ; Area for BPB times ( 0x3E - ($-$$) ) 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.direntries] 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.fatnumber] fatlp: add ax, [bp+bpb.fatsectors] adc dx, 0 loop fatlp pop cx readf: ; add offset to FAT table to DX:AX add ax, word [bp+bpb.reservedsects] adc dx, 0 readp: ; read sector DX:AX from partition add ax, word [bp+bpb.sectoroffset] adc dx, word [bp+bpb.sectoroffset+2] jnc ($+5) call errcll 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 ; calculate CHS data div word [bp+bpb.tracksectors] ; ax:temp = (lba / spt) inc dx ; dx:sector = (lba % spt) + 1 mov cl, dl ; sector number xor dx, dx div word [bp+bpb.heads] ; ax:cylinder = (tmp / heads) ; dx:head = (tmp % heads) mov ch, al ; cylinder number mov dh, dl ; head number mov dl, [bp+bpb.drivenum] ; 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 ; increment sector num + write offset add ax, 1 adc dx, 0 add bx, 0x20 ; loop on CX loop chslp ret 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 address of cluster within sector pop si %ifdef FAT12 push si ; times 1.5 mov ax, si shr ax, 1 add si, ax add si, buf lodsw pop si test si, 1 jz .odd .even: mov cl, 4 shr ax, cl jmp .done .odd: and ax, 0x0FFF .done: xor dx, dx %endif %ifdef FAT16 ; double sal si, 1 ; make sure its within sector range and si, 0x1FF add si, buf ; load word lodsw xor dx, dx %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.clustersects] 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.clustersects] 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, [bp+bpb.direntries] mov cl, 4 shr ax, cl mov cx, ax xor ax, ax xor dx, dx mov bx, 0x07C0 jmp readr ; 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 %ifdef FAT12 cmp word ax, 0x0FF8 %endif %ifdef FAT16 cmp word ax, 0xFFF8 %endif jc lloop ret main: ; Set up BP to point to BPB ; Relative addressing saves one instruction byte per access mov bp, params ; Save DL contents mov [bp+bpb.drivenum], dl ; 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+bpb.drivenum] ; restore potential partition table pop si pop ds jmp 0x7C00 ; Padding and signature times (0x1FE - ($-$$)) db 0 dw 0xAA55 buf: