; 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 jmp [bp-2] 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 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 ; 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 loadr: mov ax, 2 xor dx, dx jmp load loadf: call search jne fserr mov ax, [si+0x1A] mov dx, [si+0x14] ; load cluster chain DX:AX to [dest]:0 load: mov bx, 0x07C0 lloop: call readc call next cmp word dx, 0x0FFF jne lloop ret ; Search for first entry with matching fsattr search: mov si, (0x7C00-0x20) loop: add si, 0x20 ; check if entry is valid mov al, [si] ; unallocated direntry test al, al jz fserr ; deleted files cmp al, 0xE2 je loop ; check attr mov al, [si+11] and al, 0x5C cmp al, ah jne loop ret main: mov bp, bpb mov [bp+bpb7_dn], dl ; check if EBIOS is supported mov bx, 0x55AA mov ah, 0x41 stc int 0x13 ; default: use CHS read mov ax, rchs jc noebio ; if EBIOS: use LBA read mov ax, rebios noebio: lea di, [bp-2] stosw ; 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 ; jump xor ax, ax xor cx, cx xor dx, dx xor bx, bx xor di, di ; 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: