rdos/boot/vbr.asm
2019-03-29 21:40:44 +00:00

256 lines
4.2 KiB
NASM

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