; 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 ; 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 ; mformat keeps writing until here ; if we place init earlier, code gets overwritten ; this also marks the end for the BPB 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 ; 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 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 pop ax ret ; Reset open file info fclose: mov [cclus], bx mov word [csec], 0 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