Code: Select all
;------------------------------------------------------------;
; BOS - FAT12 bootsector ;
;------------------------------------------------------------;
; - FAT12 compatible. ;
; - Loads a binary file from the floppy, max ~576kb. ;
; - Sets A20 and protected mode. ;
; ;
; Thanks to: Petroff Heroj and John S. Fine for examples. ;
; ;
; by: Christoffer Bubach, 2003-2005 ;
; ;
;------------------------------------------------------------;
;Patched by bashcommando no credit needed;
; other notes:
; this code is public domain, and you can use it for
; anything you want. but if you do, please act polite and
; give credit. ;-)
;
; mem map
; 0x0000:0x0000 -> 0x0000:0x0500 BIOS stuff
; 0x0000:0x0500 -> 0x0000:0x2100 root
; 0x0000:0x2100 -> 0x0000:0x3300 fat
; 0x0000:0x3300 -> 0x0000:0x7c00 18,25kb free space
; 0x0000:0x7c00 -> 0x0000:0x7e00 bootsector
; 0x0000:0x7e00 <- 0x0000:0xffff 32,5kb stack
; 0x1000:0x0000 -> 0x9000:0xffff 576kb free space
; 0xa000:0x0000 -> ............. VGA mem etc.
use16
org 0x7C00
boot: jmp near start
nop
;------------------------------------------;
; Standard BIOS Parameter Block, "BPB". ;
;------------------------------------------;
bpbOEM db 'BOS 0.03'
bpbSectSize dw 512
bpbClustSize db 1
bpbReservedSec dw 1
bpbFats db 2
bpbRootSize dw 224
bpbTotalSect dw 2880
bpbMedia db 240
bpbFatSize dw 9
bpbTrackSect dw 18
bpbHeads dw 2
bpbHiddenSect dd 0
bpbLargeSect dd 0
;---------------------------------;
; extended BPB for FAT12/FAT16 ;
;---------------------------------;
bpbDriveNo db 0
bpbReserved db 0
bpbSignature db 0 ; 0 = nothing more. 41 = three more (below)..
; bpbID dd 1
; bpbVolumeLabel db 'BOOT FLOPPY'
; bpbFileSystem db 'FAT12 '
;----------------------------------------;
; starting point of bootsector code ;
;----------------------------------------;
start:
cli
xor ax, ax ; initialize all the necessary
mov ds, ax ; registers.
mov es, ax
mov ss, ax
mov sp, 0xFFFF ; Stack..
mov [bpbDriveNo], dl
sti
;----------------------------------;
; clear screen and print some ;
;----------------------------------;
mov ax, 3 ; Set mode 0x03
int 0x10
mov bp, loading ; Print loading message.
mov ax, 0x1301
mov bx, 7
mov cx, 12
mov dx, 0x0102
int 0x10
mov bl, 2 ; Set cursor.
mov ah, 2
mov dx, 0x0201
int 0x10
mov ah, 9 ; Print 14 green dots.
mov al, '.'
mov cx, 14
int 0x10
;---------------------------;
; load FAT and root ;
;---------------------------;
mov di, 0x0050 ; Load the root to
mov ax, 19 ; 0x0000:0x0500 (0x500/0x10)
mov cx, 14
call read_sectors
mov di, 0x0210 ; Load the fat to
mov ax, 1 ; 0x0000:0x2100
mov cx, 9
call read_sectors
;------------------------;
; search for the file ;
;------------------------;
mov dx, [bpbRootSize]
mov bx, 0x0500
filesearch:
cld
mov si, filename
mov cx, 11
mov di, bx
repe cmpsb
je found
add bx, 32
dec dx
jz error
jmp filesearch
;-----------------------------------;
; variables & functions ;
;-----------------------------------;
loading db 'Starting BOS'
filename db 'KERNEL SYS'
failure db 'Read error!'
a20_on db 1
;-----------------------------------------------;
; read a number of sectors (one at a time) ;
;-----------------------------------------------;
; in: ;
; di = segment to save at ;
; ax = sector to read ;
; cx = number of sectors ;
; out: ;
; di = updated (added for next read) ;
; ax = updated (added for next read) ;
;-----------------------------------------------;
read_sectors:
pusha
mov bl, byte [bpbTrackSect] ; bl = number of sectors per track
div bl ; al = ax / bl
mov cl, ah ; cl = real sector number
add cl, 1
xor ah, ah ; del the rest of the div before
mov bl, byte [bpbHeads] ; bl = number of heads
div bl ; ah = rest of ( ax / bx ), al = ax / bx
mov ch, al ; ch = number of track
mov dh, ah ; dh = the head number
mov ax, cx ; save cx in ax
mov cx, 6 ; try it 6 times
.next_try:
push es
push cx
mov cx, ax ; restore cx
push cx
xor ax, ax
mov dl, [bpbDriveNo] ; reset drive
push dx
int 0x13
jc .failed
pop dx
pop cx
xor bx, bx
mov es, di
mov ax, 0x0201 ; function 2, 1 sector
int 0x13
jnc .ok ; if it was ok, check next..
.failed:
pop dx
pop ax
pop cx
pop es
loop .next_try ; else try once again if there is an error
jmp error ; if cx = 0 and the read operation always failed, halt
.ok:
pop cx ; from the next_try loop
pop es
popa
add di, 32 ; add 32 (512/16) to segment
inc ax ; add sector counter
loop read_sectors
ret
;----------------------------------------------------;
; show a message and wait for a key before reboot ;
;----------------------------------------------------;
error:
;push 0x0000
;pop es
mov bp, failure
mov ax, 0x1301
mov bx, 4
mov cx, 43
mov dx, 0x0401
int 0x10
mov ah, 0
int 0x16
int 0x19
;-----------------------------------;
; the file is found, load it. ;
;-----------------------------------;
found:
mov bp, [bx+26] ; bp=cluster number from directory entry
mov di, 0x1000 ; 1000 (segment)
.next_block:
xor cx, cx
mov cl, [bpbClustSize] ; reset sector count to 1 cluster
mov si, bp ; si=next should-be cluster for
; contiguous reads
.next_contiguous:
mov ax, 3 ; 3
mul si ; multiply cluster number by 3
; dx assumed to be 0, it's a floppy!
shr ax, 1 ; divide by two
push bp
xchg bp, ax ; bp=ax
mov ax, word [0x2100+bp] ; ax=FAT element with junk
; (addressing with bp)
pop bp
jc .odd_cluster ; jump if the value was odd
.even_cluster:
and ax, 0x0FFF ; leave only lower 12 bits
jmp .got_cluster ; got it
.odd_cluster:
push cx ; preserve sector count
mov cl, 4 ; shift four bits right
shr ax, cl ; (leave only bits 4-15)
pop cx ; restore sector count
.got_cluster:
inc si ; si=current cluster+1
cmp ax, si ; next cluster=current cluster+1?
jne .force_read ; is it still contiguous?
add cl, [bpbClustSize] ; increase sector count by 1 cluster
adc ch, 0
jmp .next_contiguous
.force_read:
xchg bp, ax ; ax=bp (base cluster), bp=new cluster
dec ax ; decrease by 2 to get the actual... (1)
dec ax ; ...cluster number (2)
xor dx, dx
mov dl, [bpbClustSize]
mul dx ; multiply by sectors per cluster
; (dx ignored)
add ax, 33 ; assume data-area start at sector 33
call read_sectors ; read cx sectors at ax to es:0 :)
cmp bp, 0x0FF8 ; the new cluster is EOF (FF8-FFF)?
jb .next_block ; if not in this range, read next block
;-----------------------;
; the file is loaded ;
;-----------------------;
quit:
a20: ; Enable A20
in al, 0x64
test al, 2
jnz a20
mov al, 0xD1
out 0x64, al
.d6:
in al, 0x64
and ax, 2
jnz .d6
mov al, 0xDF
out 0x60, al
.a20_check:
mov al, byte [fs:0] ; check a20, is it on?
mov ah, al
not al
xchg al, byte [gs:0x10]
cmp ah, byte [fs:0]
mov [gs:0x10], al
jz floppy_off
mov byte [a20_on], 0 ; it's not on save for file..
floppy_off:
mov dx, 0x3F2 ; turn of the floppy motor.
mov al, 0
out dx, al
pmode:
cli ; set protected mode (32-bit)
lgdt [gdtr]
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:flush
;----------------------------------------;
; start of 32-bit area. ;
; flush segments and jump to kernel ;
;----------------------------------------;
use32
flush:
mov eax, 0x10 ; refresh all segment registers
mov ds, eax
mov es, eax
mov fs, eax
mov gs, eax
mov ss, eax
mov esp, 0xfffc
mov eax, 0xB05B007 ; report "BOSboot".. ;-)
mov bl, [a20_on] ; report if a20 is on.
jmp 0x08:0x10000 ; jump to loaded file (64kb in mem)
;--------------------------------;
; global descriptor table (gdt) ;
;--------------------------------;
gdt: dw 0x0000, 0x0000, 0x0000, 0x0000
codesel: dw 0xFFFF, 0x0000, 0x9800, 0x00CF
datasel: dw 0xFFFF, 0x0000, 0x9200, 0x00CF
gdt_end:
gdtr: dw gdt_end - gdt - 1
dd gdt
;-------------------------------------;
; set the BOOT-signature at byte 510. ;
;-------------------------------------;
resb boot+512-2-$
dw 0xAA55