; Memory layout: %define segment 0x00100 %define self (0x7C00-(segment<<4)) ; 1 sector %define fattab (self+0x200) ; variable size %define rootdir 0x00100 ; variable size %define prog 0x0F000 ; 4K at the end for OS 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 " " ; mformat keeps writing until here ; if we place init earlier, code gets overwritten times (62 - ($-$$)) nop init: cli jmp segment:main main: ; Stack grows down from 64k mov ax, cs mov ss, ax mov sp, prog mov ds, ax mov es, ax 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 ; Load kernel mov bx, prog mov ax, kernel_name call load_file mov bp, 0x3332 jc error mov dl, [fdc.drv] ; jump into kernel jmp segment:prog ; Load a file into memory ; IN AX pointer to 8.3 filename ; ES:BX pointer to target area ; OUT CF flag set if error ; DI file size in bytes (<64K) load_file: mov si, rootdir mov cx, [fdc.rde] .search: push cx push si mov di, ax mov cx, 11 repe cmpsb pop si pop cx je .read add si, 0x20 loop .search xor di, di stc ret .read: mov ax, [si+0x1A] mov di, [si+0x1C] jmp read_clusters ; Read the file given by cluster number ; into the target program area ; in ax cluster number read_clusters: ; 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 read_clusters ret ; 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 error: mov ax, bp mov ah, 0x0e mov bx, 7 int 0x10 mov al, 0x21 int 0x10 xor ax, ax int 0x16 int 0x19 kernel_name: db "BDOS BIN" times (0x1FE - ($-$$)) db 0 dw 0xAA55