; Memory layout: %define mbr 0x00600 ; 1 sector %define self 0x00800 ; 1 sector %define fattab 0x01000 ; variable size %define rootdir 0x06000 ; variable size %define psp (prog - 0x100) %define prog 0x07C00 %define filename (psp + 0x5C + 1) %define arguments (psp + 0x81) org self jmp short init cluster_offset: dw 0 times (0x0B - ($-$$)) db 0 fdc: .ss: dw 0x200 ; sector size .sc: db 2 ; sectors per cluster .rsc: dw 1 ; reserved sector count .fn: db 2 ; number of file allocation tables .rde: dw 0x70 ; number of root directory entries .ts: dw 720 ; total number of sectors .mi: ; medium identifier db 0xFD ; 5.25-inch Double sided, 40 tracks per side, 9 sectors per track (360 KB) .sf: ; sectors per fat dw 2 .spt: dw 9 ; sectors per track .nos: dw 2 ; number of sides (heads) .po: dd 0 ; partition offset (in LBA blocks) .lrgts: dd 0 .drv: db 0 ; drive number db 0 db 0x29 ; efdc signature .vid: dd 0 ; volume id .vlabel: db "2B" times (54 - ($-$$)) db " " .fstype: db "FAT12" times (62 - ($-$$)) db " " init: cli ; Stack grows down from PSP + 64k mov ax, (psp >> 4) mov ss, ax xor sp, sp ; Relocate from [prog] to [self] xor ax, ax mov ds, ax mov es, ax mov si, prog mov di, self mov cx, 0x100 rep movsw jmp 0:main main: mov [fdc.drv], dl ; save drive number in fd sti ; load fat table into memory mov ax, [fdc.rsc] mov cx, [fdc.sf] xor dx, dx mov bx, fattab call load_sectors ; calculate length of rootdir mov ax, [fdc.rde] mov cl, 4 shr ax, cl ; 32 bytes per entry mov cx, ax ; load root dir xor dx, dx mov ax, [fdc.sf] mul byte [fdc.fn] add ax, [fdc.rsc] mov bx, rootdir call load_sectors ; remember where we left off ; clusters start after rootdir mov [cluster_offset], ax call parse_cmdline call load_file mov bp, 0x3332 jc error ; setup int 19h call at 0000, and push its address to stack mov WORD [psp], 0x19CD push sp ; clear out registers and jump into target xor ax, ax xor cx, cx xor dx, dx xor bx, bx mov dl, [fdc.drv] jmp 0x07B0:0x0100 ; Read sectors from disk ; Does not return on error ; ax and bx will be incremented, cx decremented ; in dx:ax sector number ; es:bx buffer ; cx number of sectors to read ; out dx:ax next sector to read ; es:bx next free buffer ; cx zero load_sectors: ; fail instantly if reading sectors > 16 bit test dx, dx mov bp, 0x3330 jnz error .loop: push ax push cx push dx ; calculate CHS data div word [cs:fdc.spt] ; ax:temp = (lba / spt) inc dx ; dx:sector = (lba % spt) + 1 mov cl, dl ; sector number xor dx, dx div word [cs:fdc.nos] ; ax:cylinder = (tmp / heads) ; dx:head = (tmp % heads) mov ch, al ; cylinder number mov dh, dl ; head number mov dl, [cs:fdc.drv] ; driver number mov ax, 0x0201 ; ah=0x02 al=0x01 int 0x13 mov bp, 0x3331 jc error pop dx pop cx pop ax ; count up for next sector add bx, 0x0200 inc ax loop .loop ret ; Load the file in [filename] ; or exit with carry set load_file: mov si, rootdir mov cx, [fdc.rde] .loop: call file_match je read_clusters add si, 0x20 loop .loop stc ret ; Compares the FAT dirent against [filename] ; in ds:si filename ; out ZF zero flag set if equal file_match: push cx push si mov di, filename mov cx, 11 repe cmpsb pop si pop cx ret ; Read the file given by cluster number ; into the target program area ; in ax cluster number read_clusters: add si, 0x1A lodsw mov bx, prog .loop: ; read cluster into area for target file push ax sub ax, 2 mul BYTE [fdc.sc] add ax, [cluster_offset] xor dx, dx mov cx, [fdc.sc] xor ch, ch call load_sectors pop ax ; calculate index in FAT mov si, ax shr si, 1 add si, ax add si, fattab ; load entry from FAT, truncate to 12 bit mov dx, [si] test ax, 1 jz .noshift mov cl, 4 shr dx, 4 .noshift: mov ax, dx and ax, 0x0FFF cmp ax, 0x0FF8 jc .loop ret error: mov ax, bp mov ah, 0x0e mov bx, 7 int 0x10 mov al, 0x21 int 0x10 xor ax, ax int 0x16 int 0x19 parse_cmdline: mov si, cmdline mov di, filename .cleanout: push di mov cx, 0x0A mov al, 0x20 rep stosb pop di .base_loop: call .read cmp al, 0x2E je .ext_start cmp al, 0x20 je .args_start stosb jmp .base_loop .ext_start: mov di, (filename + 8) .ext_loop: call .read cmp al, 0x20 je .args_start stosb jmp .ext_loop .args_start: mov di, (psp + 0x81) .args_loop: lodsb test al, al jz .args_end stosb jmp .args_loop .args_end: mov ax, di sub ax, (psp + 0x81) mov [psp+0x80], al mov al, 0x0D stosb ret .read: lodsb test al, al jnz .ret pop ax .ret: ret cmdline: db CMDLINE, 0 times (0x1FE - ($-$$)) db 0 dw 0xAA55