; Memory layout: %define self 0x00600 ; 1 sector %define fattab 0x01000 ; variable size %define rootdir 0x06000 ; variable size %define psp (prog - 0x100) %define prog 0x07C00 %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 push 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 load_file mov bp, 0x3332 jc error ; setup int 19h call if prog returns mov WORD [psp], 0x19CD ; clean registers xor ax, ax xor cx, cx xor dx, dx xor bx, bx ; restore boot drive number mov dl, [fdc.drv] ; setup segment registers push ss pop ds push ss pop es ; jump into target 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 ; add partition offset (required for HDD) add ax, [fdc.po] adc dx, [fdc.po+2] ; 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 filename: db "KERNEL COM" times (0x1FE - ($-$$)) db 0 dw 0xAA55