org 0x7600 ; Memory layout: ; 060:0000 PSP for loaded program ; 060:0100 Loaded program ; 060:7800 Our code (= 0:7C00) ; 060:8000 FAT table ; 060:E000 Root directory ; 060:FF00 Stack area init: jmp 0x060:main 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 " " ; 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, 0x0030 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, 0x0031 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, 0xE000 mov cx, [fdc.rde] .loop: call file_match je read_clusters add si, 0x20 loop .loop 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, 0x0100 .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, 0x8000 ; 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 main: cli ; Everything in one segment, stack starts on top mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, ax mov [fdc.drv], dl ; save drive number in fdc sti ; load fat table into memory mov ax, [fdc.rsc] mov cx, [fdc.sf] xor dx, dx mov bx, 0x8000 call load_sectors ; calculate length of rootdir mov ax, [fdc.rde] dec ax mov cl, 4 shr ax, cl ; 32 bytes per entry inc ax mov cx, ax ; load root dir xor dx, dx mov ax, [fdc.sf] mul byte [fdc.fn] add ax, [fdc.rsc] mov bx, 0xE000 call load_sectors ; remember where we left off ; clusters start after rootdir mov [cluster_offset], ax call load_file mov bp, 0x0032 jc error ; get length of arguments mov cx, 0x007F mov di, arguments xor ax, ax repe scasb sub di, arguments mov cx, di ; setup arguments field mov [0x080], cl mov di, [0x081] mov si, arguments rep movsb ; setup int 19h call at 0000, and push its address to stack mov WORD [0000], 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 0x0100 error: mov ax, bp mov ah, 0x0e mov bx, 7 int 0x10 mov al, 0x21 int 0x10 xor ax, ax int 0x16 int 0x19 cluster_offset: dw 0 times (0x174 - ($-$$)) db 0 filename: db "KERNEL COM" arguments: db " ", 0 times (0x1FE - ($-$$)) db 0 dw 0xAA55