OSDev.org

The Place to Start for Operating System Developers
It is currently Sun Sep 20, 2020 2:23 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: Any better FAT16 bootsectors out there?
PostPosted: Fri Nov 06, 2009 11:32 am 
Offline
Member
Member
User avatar

Joined: Mon Jul 28, 2008 9:46 am
Posts: 310
Location: Ontario, Canada
I tried to use the FAT16 boot sector code from FreeDOS and the one on osdever.net but had no luck with either of them. I've decided to switch from FAT32 (aka FAT28) to FAT16 since it seems a bit easier to maintain.

In the end I wrote my own and the code is below. It works correctly but has no error checking. Anything better out there?

bootsec.asm:
Code:
org 0x7C00

entry:
   jmp short begin
   nop

%define bsOemName   bp+0x03    ; OEM label (8)
%define bsBytesPerSec   bp+0x0B    ; bytes/sector (dw)
%define bsSecsPerClust   bp+0x0D    ; sectors/allocation unit (db)
%define bsResSectors   bp+0x0E    ; # reserved sectors (dw)
%define bsFATs      bp+0x10    ; # of fats (db)
%define bsRootDirEnts   bp+0x11    ; Max # of root dir entries (dw)
%define bsSectors   bp+0x13    ; # sectors total in image (dw)
%define bsMedia    bp+0x15    ; media descriptor (db)
%define bsSecsPerFat   bp+0x16    ; # sectors in a fat (dw)
%define bsSecsPerTrack   bp+0x18    ; # sectors/track
%define bsHeads      bp+0x1A    ; # heads (dw)
%define bsHidden    bp+0x1C    ; # hidden sectors (dd)
%define bsSectorHuge   bp+0x20    ; # sectors if > 65536 (dd)
%define bsDriveNumber   bp+0x24    ; (dw)
%define bsSigniture   bp+0x26    ; (db)
%define bsVolumeSerial   bp+0x27    ; (dd)
%define bsVolumeLabel   bp+0x2B    ; (11)
%define bsSysID      bp+0x36    ; (8)

times 0x3B db 0            ; Code starts at offset 0x3E

begin:
   mov [bsDriveNumber], dl   ; BIOS passes drive number in DL
   xor eax, eax
   xor esi, esi
   xor edi, edi
   mov ds, ax
   mov es, ax
   mov bp, 0x7c00

; read in the root cluster
; check for the filename
; if found save the starting cluster
; if not then error

;fatstart = bsResSectors

;rootcluster = bsResSectors + (bsFATs * bsSecsPerFat)
; 4 + (2 * 254) = sector 512

;datastart = bsResSectors + (bsFATs * bsSecsPerFat) + ((bsRootDirEnts * 32) / bsBytesPerSec)
; 4 + (2 * 254) + ((512 * 32) / 512) = sector 544

;cluster X starting sector
; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart

ff:
   mov ax, [bsSecsPerFat]
   shl ax, 1   ; quick multiply by two
   add ax, [bsResSectors]
   mov [rootstart], ax

   mov bx, [bsRootDirEnts]
   shr bx, 4   ; bx = (bx * 32) / 512
   add bx, ax   ; BX now holds the datastart sector number
   mov [datastart], bx
   
ff_next_sector:
   mov bx, 0x8000
   mov si, bx
   mov di, bx
   call readsector

; Search for file name, and find start cluster.
ff_next_entry:
   mov cx, 11
   mov si, filename
   repe cmpsb
   jz ff_done      ; note that di now is at dirent+11

   add di, byte 0x20
   and di, byte -0x20
   cmp di, [bsBytesPerSec]
   jnz ff_next_entry
   ; load next sector
   dec dx         ; next sector in cluster
   jnz ff_next_sector

ff_done:
   add di, 15
   mov ax, [di]   ; AX now holds the starting cluster #

; At this point we have found the file we want and know the cluster where the file starts

   mov bx, 0x8000   ; We want to load to 0x0000:0x8000
loadfile:   
   call readcluster
   cmp ax, 0xFFF8   ; Have we reached the end cluster marker?
   jg loadfile   ; If not then load another
   
   jmp 0x0000:0x8000

   
   
;------------------------------------------------------------------------------
; Read a sector from disk, using LBA
; input:   EAX - 32-bit DOS sector number
;      ES:BX - destination buffer
; output:   ES:BX points one byte after the last byte read
;      EAX - next sector
readsector:
   push dx
   push si
   push di

read_it:
   push eax   ; Save the sector number
   mov di, sp   ; remember parameter block end

   push byte 0   ; other half of the 32 bits at [C]
   push byte 0   ; [C] sector number high 32bit
   push eax   ; [8] sector number low 32bit
   push es    ; [6] buffer segment
   push bx    ; [4] buffer offset
   push byte 1   ; [2] 1 sector (word)
   push byte 16   ; [0] size of parameter block (word)

   mov si, sp
   mov dl, [bsDriveNumber]
   mov ah, 42h   ; EXTENDED READ
   int 0x13   ; http://hdebruijn.soo.dto.tudelft.nl/newpage/interupt/out-0700.htm#0651

   mov sp, di   ; remove parameter block from stack
   pop eax      ; Restore the sector number

   jnc read_ok    ; jump if no error

   push ax
   xor ah, ah   ; else, reset and retry
   int 0x13
   pop ax
   jmp read_it

read_ok:
   inc eax       ; next sector
   add bx, 512      ; Add bytes per sector
   jnc no_incr_es      ; if overflow...

incr_es:
   mov dx, es
   add dh, 0x10      ; ...add 1000h to ES
   mov es, dx

no_incr_es:
   pop di
   pop si
   pop dx
   ret
;------------------------------------------------------------------------------


;------------------------------------------------------------------------------
; Read a cluster from disk, using LBA
; input:   AX - 16-bit cluster number
;      ES:BX - destination buffer
; output:   ES:BX points one byte after the last byte read
;      AX - next cluster
readcluster:
   push cx
   mov [tcluster], ax      ; save our cluster value
;cluster X starting sector
; starting sector = (bsSecsPerClust * (cluster# - 2)) + datastart
   xor cx, cx
   sub ax, 2
   mov cl, byte [bsSecsPerClust]
   imul cx      ; EAX now holds starting sector
   add ax, word [datastart]   ; add the datastart offset

   xor cx, cx
   mov cl, byte [bsSecsPerClust]
readcluster_nextsector:
   call readsector
   dec cx
   cmp cx, 0
   jne readcluster_nextsector

; Great! We read a cluster.. now find out where the next cluster is
   push bx   ; save our memory pointer
   mov bx, 0x7E00   ; load a sector from the root cluster here
   push bx
   mov ax, [bsResSectors]
   call readsector
   pop bx   ; bx points to 0x7e00 again
   mov ax, [tcluster] ; ax holds the cluster # we just read
   shl ax, 1   ; multipy by 2
   add bx, ax
   mov ax, [bx]
   
   pop bx   ; restore our memory pointer
   pop cx
   
   ret
;------------------------------------------------------------------------------

msg_Load db "Loading... ", 0
msg_Error db "No "
filename db "PURE64  SYS", 0
datastart dw 0x0000
rootstart dw 0x0000
tcluster dw 0x0000

times 510-$+$$ db 0

sign dw 0xAA55


-Ian

_________________
BareMetal OS - http://www.returninfinity.com/
Mono-tasking 64-bit OS for x86-64 based computers, written entirely in Assembly


Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Sat Nov 07, 2009 2:39 pm 
Offline
Member
Member

Joined: Thu Jul 07, 2005 11:00 pm
Posts: 1546
ReturnInfinity wrote:
I tried to use the FAT16 boot sector code from FreeDOS and the one on osdever.net but had no luck with either of them. I've decided to switch from FAT32 (aka FAT28) to FAT16 since it seems a bit easier to maintain.

In the end I wrote my own and the code is below. It works correctly but has no error checking. Anything better out there?

<snip>

-Ian


I don't think your going to find many bootloaders in general with much error checking..

_________________
My new NEW blag


Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Sun Nov 08, 2009 8:52 pm 
Offline
Member
Member
User avatar

Joined: Wed Feb 07, 2007 1:45 pm
Posts: 1401
Location: Eugene, OR, US
Here is a bootsector that quok and I wrote together, and optimized heavily. (GAS at&t syntax)

Currently it works with both FAT12 and FAT16, looks in the home directory for a second-stage bootloader called "osloader" (ELF format, load address 0x40000, entry address 0x40120), loads it, and jumps to it.
It's been moderately tested, and actually exposes a bug in some versions of the bochs BIOS.


Attachments:
fat_boot.S [14.11 KiB]
Downloaded 721 times
Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Wed Nov 11, 2009 9:46 am 
Offline
Member
Member

Joined: Sun Jan 14, 2007 9:15 pm
Posts: 2566
Location: Sydney, Australia (I come from a land down under!)
I'm surprised nobody has commented on bewing's contribution to this thread. This is a high quality bootsector in only 512 bytes that supports both FAT12 and FAT16 - no small feat!

My hat's off to you guys for a fantastic contribution to the community :)

_________________
Pedigree | GitHub | Twitter | LinkedIn


Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Thu Nov 12, 2009 12:36 pm 
Offline
Member
Member
User avatar

Joined: Tue Oct 17, 2006 9:29 pm
Posts: 2423
Location: Canada
And thanks to quok losing much hair, and sending countless images via email.. it's one of the very few bootloaders that work on my older 486 laptop.

_________________
Image
Twitter: @canadianbryan. Award by smcerm, I stole it. Original was larger.


Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Fri Nov 13, 2009 11:51 am 
Offline
Member
Member
User avatar

Joined: Mon Jul 28, 2008 9:46 am
Posts: 310
Location: Ontario, Canada
bewing, thanks for the post .. I'll take a look at that code.

_________________
BareMetal OS - http://www.returninfinity.com/
Mono-tasking 64-bit OS for x86-64 based computers, written entirely in Assembly


Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Fri Nov 13, 2009 2:35 pm 
Offline
Member
Member

Joined: Fri Oct 20, 2006 10:14 am
Posts: 313
@bewing

I haven´t looked that deep into the source, but maybe with mine you could get your bootsector even smaller. For this you should look how I handled my vars.


Attachments:
bootsect_lba.asm [4.18 KiB]
Downloaded 349 times
Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Fri Nov 13, 2009 8:24 pm 
Offline
Member
Member
User avatar

Joined: Wed Feb 07, 2007 1:45 pm
Posts: 1401
Location: Eugene, OR, US
You are assuming that a sector is 512 bytes, which simplifies the code but will not work on (for example) CDROMs that are not doing emulation.
You are also using Int13h extensions (for your READ EXTENDED function), which will not work on floppies at all -- but from what I can see, this code is FAT16-specific anyway.
You are also assuming that the FAT will fit in one 64k memory page, which is not at all certain.
But, in general, pretty good code! :D

Using bp the way you do may actually save a few bytes, truly -- since all my addresses are 2 bytes, and the bp offset may only be one byte, and there is no sib byte in rmode.


Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Sat Nov 14, 2009 1:00 am 
Offline
Member
Member

Joined: Fri Oct 20, 2006 10:14 am
Posts: 313
Yeah this code is fat16 specific and I also have a bootsector which works with CHS and the "old" int13h code. You are wrong that I assuming that the FAT goes into one 64k page, I (and my code) know that the FAT can be as large as 2 64k pages and I´m testing for it.

I would have one question. Why should someone use FAT for a CD (w/o emulation)?


Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Sat Nov 14, 2009 5:59 pm 
Offline
Member
Member
User avatar

Joined: Wed Feb 07, 2007 1:45 pm
Posts: 1401
Location: Eugene, OR, US
> Why should someone use FAT for a CD (w/o emulation)?

That was just a hypothetical example. There will (in the future) be devices that have sectorsizes that are not 512 bytes -- because they already exist. It may not be reasonable for CDs to use FAT, but it may be reasonable on some kind of non-512b-sector flash memory device that I don't know about.

> You are wrong that I assuming that the FAT goes into one 64k page

From what I saw, you load the FAT in one gulp. There are many BIOSes that cannot handle more than 127 sectors, 128 sectors, or 64K in one read using Int13h ax=42. When using that BIOS function, I always stick to 32K per read, just to make sure -- and keep page boundaries as aligned as reasonably possible.


Top
 Profile  
 
 Post subject: Re: Any better FAT16 bootsectors out there?
PostPosted: Sun Nov 15, 2009 2:15 am 
Offline
Member
Member

Joined: Fri Oct 20, 2006 10:14 am
Posts: 313
Yeah, you are right, I think I will change this. In my bootsector which doesn´t use the extended int13h functions there my "load_chs" function is also looping and loads only 0x7f (I think so) sectors. But if I will find some time I will change my bootsector so that it will use the values which are in the bpb.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Octocontrabass and 10 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group