org 0 fdc: ; FDC Descriptor as per ECMA-107 jmp _startup times (0x03 - ($-$$)) nop .oem: db "2B" ; creating system identifier times (0x0B - ($-$$)) db " " ; space-padded .ss: dw 0x200 ; sector size .sc: db 0 ; sectors per cluster .rsc: dw 2 ; reserved sector count .fn: db 0 ; number of file allocation tables .rde: dw 0 ; 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 0 .spt: dw 9 ; sectors per track .nos: dw 2 ; number of sides (heads) .po: dd 0 ; partition offset (in LBA blocks) .lrgts: dw 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 " " _startup: xor ax, ax mov ds, ax mov es, ax mov cx, 0x0100 mov si, 0x7C00 mov di, 0x0500 rep movsw jmp 0x0050:.lowstart .lowstart: mov ax, cs mov ds, ax mov ss, ax xor sp, sp call print_inline db "VBR: Using", 0 mov [fdc.drv], dl ; backup drive number .adjust_chs: mov ah, 0x08 int 0x13 ; required, QEMU detects 360kB as 1200kB with CHS 80 2 15 jc .noadjust ; skip if function does not exist inc dh mov [fdc.nos], dh mov ax, cx and ax, 0x003F mov [fdc.spt], ax ; no adjustment because sectors are 1-indexed mov ax, cx xchg al, ah mov cl,6 shr ah,cl inc ax ; convert from maximum number (0-based) to total number (1-based) of cylinders mul word [fdc.nos] ; number of tracks = number of cylinders * heads mul word [fdc.spt] ; number of sectors = number of tracks * sectors per track mov [fdc.ts], ax call print_inline db " BIOS", 0 .noadjust: call print_inline db " CHS ", 0 mov ax, [fdc.ts] div word [fdc.nos] div word [fdc.spt] call print_number call print_inline db ",", 0 mov ax, [fdc.nos] call print_number call print_inline db ",", 0 mov ax, [fdc.spt] call print_number call print_inline db 0x0A, 0x0D, 0 mov ax, 0x0070 mov es, ax xor bx, bx call loadrootdir call dump .end: hlt jmp .end ; Load root directory into memory ; in es data segment loadrootdir: push bx push cx mov bx, [fdc.ss] ; bytes per sector mov cl, 5 shr bx, cl ; div by 2^5, 32 bytes per directory entity mov ax, [fdc.rde] ; number of root directory entities xor dx, dx div bx mov cx, ax mov ax, [fdc.sf] mul byte [fdc.fn] add ax, [fdc.rsc] xor bx, bx ; load at beginning of es .loop: call loadblk loop .loop pop cx pop bx ret ; Load a cluster from cluster offset ; in ax cluster number ; es:bx buffer loadcl: mov ax, [fdc.sf] mul byte [fdc.fn] add ax, [fdc.rsc] call print16 ret ; Load a single block into memory ; in ax sector number ; es:bx buffer ; out al error code, ; carry set if error loadblk: push ax push cx push dx xor dx, dx div word [fdc.spt] ; ax:temp = (lba / spt) inc dx ; dx:sector = (lba % spt) + 1 mov cl, dl ; sector number xor dx, dx div word [fdc.nos] ; ax:cylinder = (tmp / heads) ; dx:head = (tmp % heads) mov ch, al ; cylinder number mov dh, dl ; head number mov dl, [fdc.drv] ; driver number mov ax, 0x0201 ; ah=0x02 al=0x01 int 0x13 pop dx pop cx pop ax inc ax add bx, 0x0200 ret print_number: mov cx, 0x000A xor dx, dx div cx ; ax = dx:ax / 10, dx = dx:ax % 10 and ax, ax jz .print push dx call print_number pop dx .print: mov al, dl add al, 0x30 mov ah, 0x0e int 0x10 ret print_inline: pop si push bx .loop: lodsb cmp al, 0x00 je .end mov bx, 0x0000 mov ah, 0x0e int 0x10 cmp al, 0x0D jmp .loop .end: pop bx push si ret dump: mov si, bx mov cx, 0x10 .nextline: mov ax, si call print16 mov al, 0x3A call printc mov al, 0x20 call printc push cx mov cx, 0x0020 .words: es lodsb call print8 loop .words pop cx mov al, 0x0A call printc mov al, 0x0D call printc loop .nextline ret %include "print.asm" times (0x1F0 - ($-$$)) db 0 str_bootfile: db "BOOT" times (0x1F8 - ($-$$)) db " " db "BIN" times (0x1FE - ($-$$)) db 0 dw 0xAA55