FAT12 Bootsector Problem [SOLVED] (Off-By-1 Error)
Posted: Thu Aug 20, 2009 3:35 pm
I've been working on a bootsector for FAT12 that loads a simple flat (up to) 64KB real mode binary to 0x1000:0000 and runs it. So far it works great except for one thing: after a few sectors it just stops working properly. It says it loaded all of the data, and doesn't give any errors (it should display a message and busywait if there is an error), but when the program it loads tries to access data after a certain point it just gets whatever was there previously. I've checked the disk image, and everything looks fine (all of the data is there, is sequential in cluster count, and the FAT maps properly). I'm 99.9% sure I'm doing something stupid in the loading code:
It just falls apart about halfway through. I've already fixed a couple of bugs, but unfortunately none of them have been the cause of this problem. If you need more info (i.e. the hex of the relevant parts of the FAT, the sectors of the data file, etc.) I'd be happy to give it to you. Lastly, if any of the comments are wrong, they probably are. I just now went back and commented it to help me try and figure out what my own code is doing. Remember kids: Don't wait until later; always comment your code!
Thank you for taking the time to fix my stupid mistakes .
Code: Select all
loadLoop:
;; Save the current cluster
push ax
;; Find the LBA of the cluster
dec ax
dec ax
mul byte [Boot.SPC]
;; These were calculated earlier
add ax, [ROOTSTART]
add ax, [ROOTLENGTH]
;; Load all of the sectors in the cluster
movzx cx, byte [Boot.SPC]
.clusterLoop:
push cx
push ax
;; Convert the cluster's LBA to CHS
call getCHS
;; only want one sector (in case a cluster crosses a track boundary)
mov al, 1
;; Get the destination
mov bx, di
call readDiskCHS
;; Automatically advance destination pointer
add di, [Boot.BPS]
;; get the LBA and move to the next cluster
pop ax
inc ax
;; Get the loop counter and loop
pop cx
loop .clusterLoop
;; Get the current cluster's number back
pop ax
;; Save it, we'll need it for even/odd checking
push ax
;; Get the byte index into the FAT of the cluster (* by 1.5)
mov bx, ax
shr bx, 1
add ax, bx
;; From that we can figure the sector index of the cluster in the FAT
;; and the byte index into this sector of the cluster
xor dx, dx
div ax, word [Boot.BPS]
inc dx
mov si, dx
add ax, [Boot.RSC]
;; SI = cluster's index, AX = cluster's FAT sector
;; Save the destination segment so we don't interfere
;; and use DS for smaller instructions
push es
;; A.K.A. mov es, ds
push ds
pop es
;; Save the sector LBA (we want this one and the next one)
push ax
;; Load it
call getCHS
mov bx, freeSpace
add si, bx
mov al, 1
call readDiskCHS
;; Get the next sector in case the cluster index spans two
;; of them
pop ax
inc ax
push bx
call getCHS
pop bx
add bx, [Boot.BPS]
mov al, 1
call readDiskCHS
;; Get the real destination back now due to stack layout
pop es
;; Get the last cluster (the one we just loaded) for even/odd checking
pop bx
mov ax, [si]
test bx, 1
jnz .odd
;; if even, lop off top 4 bits
shl ax, 4
.odd:
;; Shift down to get the actual number
shr ax, 4
cmp ax, 0x0FF0
jb loadLoop
Thank you for taking the time to fix my stupid mistakes .