here is the boot sector code i am using for my OS (it's simple as the floppy has no actual file system yet, i read code raw from pre-defined sectors. i've got it commented, hopefully it's easy to understand.
Code: Select all
org 7C00h
jmp entry
nop
;BIOS parameter block data
oem db 'MT86',0,0,0,0 ;8-byte OEM identifier
bytespersect dw 512
sectperclust db 1 ;no real FAT filesystem on disk yet, this value is irrelevant
reservedsect dw 1 ;so is this one
numoffats db 1 ;and this one
rootentries dw 0 ;yep, you guessed it. irrelevant!
totalsects dw 2880 ;ditto
descriptor db 0F0h ;media descriptor (0F0h = 1.44 MB floppy)
sectsperfat dw 2 ;irrelevant for now
spt db 18, 0 ;sectors per track
heads db 2 ;what it says
hiddensects dw 0,0 ;32-bit, but meaningless value on a floppy
totalsects2 dw 0,0 ;same deal
entry:
mov ax, cs
mov ds, ax ;our variables are right here in the code segment, so change ds to cs
mov si, offset banner
call printmsg ;print "loading" message
mov ax, 0E00h ;the sector after the boot sector contains the MT86 OS
mov es, ax ;multi-tasking code, and it needs to be loaded into 0E00h:0000h
mov bx, 0 ;offset 0
mov [retry], 0
read1:
cmp [retry], 8 ;if we've retried 8 times due to errors,
je loadfail ;then we throw in the towel
mov ah, 2 ;int 13h function 2 = read sector(s)
mov al, 1 ;we want one sector
mov cl, [sect]
mov ch, [cyl]
mov dh, [head]
int 13h ;do the call
inc [retry]
jc read1
inc [sect]
mov ax, 1000h ;the rest of the data on this disk is the main kernel,
mov es, ax ;and we want it at 1000h:0000h
mov bx, 0 ;offset 0
mov [retry], 0
read:
cmp [retry], 8
je loadfail
push bx ;save our current destination offset on the stack, in case a buggy BIOS destroys BX
mov ah, 2
mov al, 1
mov cl, [sect]
mov ch, [cyl]
mov dh, [head]
int 13h
pop bx ;pop offset back into BX
inc [retry]
jc read
mov [retry], 0 ;if successful read, reset the retry count for the next sector
mov ah, 0Eh ;print a dot after each sector is read to indicate progress
mov al, '.'
int 10h
add bx, 512 ;increase destination offset with each new sector read
dec [readcount]
cmp [readcount], 0 ;have we read all the sectors we wanted to now?
jz done ;then finished with disk reads...
inc [sect] ;increment current sector
mov al, [sect]
cmp al, [spt] ;is it now higher than our max sector value?
ja inchead ;then go wrap it around and increment the head
jmp read ;otherwise, read next sector
inchead:
mov [sect], 1 ;reset current sector number
inc [head] ;increment current head
mov al, [head]
cmp al, [heads] ;has it reached the maximum?
je inccyl ;go wrap it around and increment the cylinder
jmp read ;otherwise, read next sector
inccyl:
mov [head], 0 ;reset current head
inc [cyl] ;increment cylinder
jmp read ;read next sector
done: ;now jump to the kernel entry point 1000h:0100h
mov ax, 1000h ;set up segments and stack
mov ss, ax
mov sp, 0000h
mov ds, ax
mov es, ax
push ax ;we'll use the CS:IP push and retf trick
mov ax, 100h
push ax
retf
printmsg: ;enter with near offset to ASCII-Z string in SI
cld
nextchar:
lodsb
cmp al, 0
jz printdone
mov ah, 0Eh
int 10h
jmp nextchar
printdone:
ret
loadfail:
mov si, offset error
call printmsg
hlt
sect db 2
head db 0
cyl db 0
retry db 0
readcount db 32 ;number of sectors to read when loading kernel
banner db 'Loading MT86 kernel', 0
error db 'disk error!',13,10,13,10,'System halted.', 0
and, proof it actually works
booting my own "OS" in an 8086 PC emulator i wrote myself.. when it's time to geek out, i spare no expenses.