Page 1 of 1
FAT12 Bootloader
Posted: Thu Mar 04, 2004 5:27 am
by ich_will
Hi I have a problem with my bootloader, i want to write a fat12 bootloader but the bootloader says that it had found the file also if the file doesn't exist:
Code: Select all
; Values for a Standart 3.5 Floppy
; RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec ? 1)) / BPB_BytsPerSec = 14 (round down)
; FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FatSz16) + RootDirSectors = 33
; DataSec = BPB_TotSec16 ? (BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FatSz16) + RootDirSectors)
; CountofClusters = DataSec / BPB_SecPerClus
; FirstRootDirSecNum = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz16) = 19
load_kernel:
clc ; clear the carry flag
mov ecx, 5 ; try to reset the drive 5 times
reset_drive:
xor ax, ax ; ax = 0
mov dl, [bootdrive] ; dl = bootdrive
int 0x13 ; reset drive
jnc reset_ok ; if carry flag = 0
loop reset_drive ; else try it again if ecx != 0
jmp error ; if ecx = 0 and the reset always failed, halt
reset_ok:
mov ecx, 14 ; RootDirSectors
xor ch,ch ; number of track/cylinder
mov cl, 19 ; number of sector
next_sector:
push ecx
call read_sector ; read one sector to
call check_file ; check if the kernel is there
je found_kernel ; if return
add cl, byte 1
pop ecx
loop next_sector ; else try next sector
jmp error
found_kernel:
pop ecx
ret
read_sector
mov ecx, 5 ; try to read the sector 5 times
read_sector_next_try:
mov ax, sector_buf
mov es, ax ; address of the buffer
mov bx, 0x0000 ; offset of the buffer
mov ah, 0x02 ; function number 2 (read from disk)
mov al, 0x01 ; number of sectors to read
mov dl, [bootdrive] ; set drive
mov dh, 0x00 ; read/write head number
int 0x13
jnc load_ok ; if all is ok return
loop read_sector_next_try; try once again if there is an error
jmp error ; if ecx = 0 and the read operation always failed, halt
load_ok:
ret
check_file:
; push ecx
mov ecx, 16 ; 16 entrys per sec
mov si, sector_buf
mov di, KERNEL_NAME
check_next_file:
; clc
push di
push si
push ecx
mov cx,11 ; 8.3 FAT filename
rep cmpsb
pop ecx
pop si
pop di
je found_it ; the cpu jumps the first try, also if di and si are different :-(
add si,32 ; bytes/dirent
loop check_next_file
found_it:
; pop ecx
ret
error:
mov si, msg_failed
call putstr
cli
hlt
jmp $-2
[attachment deleted by admin]
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 5:43 am
by Pype.Clicker
just a thought: did you made sure *pop* doesn't alter the zero flag?
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 5:50 am
by Candy
old:
Code: Select all
check_next_file:
; clc
push di
push si
push ecx
mov cx,11 ; 8.3 FAT filename
rep cmpsb
pop ecx
pop si
pop di
je found_it ; the cpu jumps the first try, also if di and si are different :-(
add si,32 ; bytes/dirent
loop check_next_file
Suggestion:
Code: Select all
cld ; compare the correct direction
check_next_file:
mov cx,11 ; 8.3 FAT filename
repe cmpsb ; there's no cmp with rep. Use repe
je found_it_fix ; the cpu jumps the first try, also if di and si are different :-(
add si, cx ; AKA, whatever's left after the repe cmpsb
add si, 21
and di, 0FFE0h ; strip out the last 5 bits, aka go back to the last 32-byte mark
loop check_next_file
found_it_fix:
and si, 0FFE0h ; strip out the last 5 bits again
and di, 0FFE0h ; strip out the last 5 bits again
;si ready to use
jmp found_it
Note that the add si, cx / add si, 21 can be smaller than and si, 0FFE0h / add si, 32 even though they do the same. The second one is 3b/2b and the first is (in nasm) 2b/3b but can be done in 2b/2b saving you a byte if you care.
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 5:55 am
by Pype.Clicker
sdfzerftybfgqcvsdeazr (*slamming forhead on the keyboard*)
how could i miss that! REP goes on until CX is zero and REP(N)E does also stop when the proper condition is met on bit E ...
of course.
So your rep cmpsb actually checked just the last byte out of 11...
early optimization is the root of all ev1l
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 6:25 am
by ich_will
OK I change that:
Code: Select all
next_sector:
push ecx
call read_sector ; read one sector to
xor eax,eax
call check_file ; check if the kernel is there
cmp eax, 1 ; CHANGE: if the function sets eax to 1 the kernel is found
je found_kernel ; if return
add cl, byte 1
pop ecx
loop next_sector ; else try next sector
check_file:
mov ecx, 16 ; 16 entrys per sec
mov si, sector_buf
mov di, KERNEL_NAME
cld
check_next_file:
mov cx, 11 ; 8.3 FAT filename
repe cmpsb
je found_it ; the cpu jumps the first try, also if di and si are different :-(
add si, cx ; AKA, whatever's left after the repe cmpsb
add si, 21
and di, 0FFE0h ; strip out the last 5 bits, aka go back to the last 32-byte mark
loop check_next_file
mov eax, 0
ret
found_it:
and si, 0FFE0h ; strip out the last 5 bits again
and di, 0FFE0h ; strip out the last 5 bits again
mov eax, 1
ret
but the problem is the same
[attachment deleted by admin]
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 6:33 am
by Candy
Pype.Clicker wrote:
how could i miss that! REP goes on until CX is zero and REP(N)E does also stop when the proper condition is met on bit E ...
So your rep cmpsb actually checked just the last byte out of 11...
No, that's wrong. To put the reality in check:
_*THERE IS NO REP WITH CMPSx!*_
There's only REPE and REPNE. Rep means continue, and is completely useless, so there IS NO ENCODING FOR THIS OPCODE. Disassemble your code again and see it being turned into a REPE immediately.
Still, POP does modify the flags.
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 6:38 am
by Candy
Code: Select all
next_sector:
push ecx
call read_sector ; read one sector to
xor eax,eax
call check_file ; check if the kernel is there
cmp eax, 1 ; CHANGE: if the function sets eax to 1 the kernel is found
je found_kernel ; if return
add cl, byte 1
pop ecx
loop next_sector ; else try next sector
check_file:
mov ecx, 16 ; 16 entrys per sec
mov si, sector_buf
mov di, KERNEL_NAME
cld
check_next_file:
mov cx, 11 ; 8.3 FAT filename
repe cmpsb
je found_it ; the cpu jumps the first try, also if di and si are different :-(
add si, cx ; AKA, whatever's left after the repe cmpsb
add si, 21
and di, 0FFE0h ; strip out the last 5 bits, aka go back to the last 32-byte mark
loop check_next_file
mov eax, 0
ret
found_it:
and si, 0FFE0h ; strip out the last 5 bits again
and di, 0FFE0h ; strip out the last 5 bits again
mov eax, 1
ret
How do the loops work exactly? What are the loop variables, and do you change them?
Me personally would disadvise every use of loop, don't use it. Use dec <var> / jnz <somewhere> instead, it's even faster (on AMDs) and just as fast on intels. (remember the K5 / windows incompatibility? It executed loops too fast.). Also, try to check your own structure again with the modifications others suggest, and always understand the full code. If you don't you're doomed anyway.
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 7:06 am
by Pype.Clicker
it appears to me that the code Candy proposed will only work if both buffer and name starts on an offset that is multiple of 32 (or the 'and' will send you in the middle of an entry)
another thing is that there doesn't look (at least in the original version) like having a 'terminator' check when all the entries in the sector has been tested. So the test will scan the whole 64K and may eventually end up by comparing the reference filename against itself ...
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 7:44 am
by ich_will
How do the loops work exactly? What are the loop variables, and do you change them?
The next_sector loop:
1. save the ecx (loop counter) because it's changed in the
read_sector and check_file function.
2. read one sector into a buffer variable
3. set eax to 0 because check_file will set it to 1 if it find the
file (
before ret in check_file is
useless)
4. check the filenames loaded in the buffer
5. check if the function found the filename and jump out of
the loop
6. else add on byte to the cl register, for the read_sector
function ( use int 0x13 )
7. loop again (the loop instruction decrements ecx and
jump only if ecx is > 0)
The check_next_file loop:
1. compare 11 characters of si and di
2. jump out of the loop if the two registers containes the
same strings
3. set si to the next directory entry of the current sector
4. and loop again
5. if the file was found set eax to one
I think you know all this things. But I don't know what you whant to ask.
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 8:10 am
by Pype.Clicker
there are also problems in the modified loop, as 'cx' is used for both internal string scanning and for entries counting without being pushed/popped.
I don't have my instruction references here, but iirc the string operations like lodsb and stosb were known to operate on AL and i can't remember whether movsb and cmpsb also do so ...
Definitely, i think you should sketch what you want and draw where registers are used / saved / destroyed, etc.
You might love the 'sete' instruction too, which allows you to alter a register based on the Z flag ...
And as a final move, why do you push and xor extended version of the registers in a 16 bits code ? you're just adding useless 'o16' prefix bytes ...
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 11:14 am
by ASHLEY4
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Looks for a file with particular name ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input: DS:SI -> file name (11 chars) ;;
;; ES:DI -> root directory array ;;
;; DX = number of root entries ;;
;; Output: SI = cluster number ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FindName:
mov cx, 11
FindNameCycle:
cmp byte [es:di], ch
je FindNameFailed ; end of root directory
pusha
repe cmpsb
popa
je FindNameFound
add di, 32
dec dx
jnz FindNameCycle ; next root entry
FindNameFailed:
jmp ErrFind
FindNameFound:
mov si, [es:di+1Ah] ; si = cluster no.
Try this,it not my code.
ASHLEY4.
Re:FAT12 Bootloader
Posted: Thu Mar 04, 2004 12:09 pm
by Neo
u seem to be sing the ECX registers like a sort of hold-it-all. :-\ look at ur code after the reset_ok
Code: Select all
reset_ok:
mov ecx, 14 ; RootDirSectors
xor ch,ch ; number of track/cylinder
mov cl, 19 ; number of sector
theres no point in storing 14 in ECX if u overwrite CH and CL
Code: Select all
read_sector
mov ecx, 5 ; try to read the sector 5 times
read_sector_next_try:
mov ax, sector_buf
mov es, ax ; address of the buffer
mov bx, 0x0000 ; offset of the buffer
mov ah, 0x02 ; function number 2 (read from disk)
mov al, 0x01 ; number of sectors to read
mov dl, [bootdrive] ; set drive
mov dh, 0x00 ; read/write head number
int 0x13
the int 0x13 function 02 requires the CH and CL registers with the track and sector no. uve overwritten both with the loop variable 5 here.
HTH
Re:FAT12 Bootloader
Posted: Fri Mar 05, 2004 11:10 am
by ich_will
OK I change some things but it doesn't work:
Code: Select all
; Values for a Standart 3.5 Floppy
; RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec ? 1)) / BPB_BytsPerSec = 14 (round down)
; FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FatSz16) + RootDirSectors = 33
; DataSec = BPB_TotSec16 ? (BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FatSz16) + RootDirSectors)
; CountofClusters = DataSec / BPB_SecPerClus
; FirstRootDirSecNum = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz16) = 19
load_kernel:
clc ; clear the carry flag
mov cx, 5 ; try to reset the drive 5 times
reset_drive:
xor ax, ax ; ax = 0
mov dl, [bootdrive] ; dl = bootdrive
int 0x13 ; reset drive
jnc reset_ok ; if carry flag = 0
loop reset_drive ; else try it again if ecx != 0
jmp error ; if ecx = 0 and the reset always failed, halt
reset_ok:
mov cx, 14 ; RootDirSectors
next_sector:
push cx
mov bh, 1 ; number of track // track 1
mov bl, 1 ; number of sector (real sec num = 19 because 1track = 18 sectors)
call read_sector ; read one sector to
xor ax, ax ; zero ax (used for return value, if 1 the kernel is found else not)
call check_file ; check if the kernel is there
cmp ax, 1 ; if ax == 1
je found_kernel ; return
add bl, byte 1 ; next sector number
pop cx ; restore the loop counter
loop next_sector ; else try next sector
jmp error
found_kernel:
pop cx
ret
;----------------------------------------------;
;------------- read_sector --------------------;
;------ bh = number of track ------------------;
;------ bl = number of sector where to start --;
;----------------------------------------------;
read_sector:
mov cx, 5 ; try to read the sector 5 times
read_sector_next_try:
push cx
push bx
mov ch, bh
mov cl, bl
mov ax, sector_buf
mov es, ax ; address of the buffer
mov bx, 0x00 ; offset of the buffer
mov ah, 0x02 ; function number 2 (read from disk)
mov al, 0x01 ; number of sectors to read
mov dl, [bootdrive] ; set drive
mov dh, 0x00 ; read/write head number
int 0x13
jnc load_ok ; if all is ok return
pop bx
pop cx
loop read_sector_next_try; else try once again if there is an error
jmp error ; if cx = 0 and the read operation always failed, halt
load_ok:
pop bx
pop cx
ret
;----------------------------------------------;
;------------- check_file ---------------------;
;----------------------------------------------;
;------ return value: ax = 1 if the kernel ----;
;-------- is found else ax = 0 ----------------;
;----------------------------------------------;
check_file:
mov cx, 16 ; 16 entrys per sector
cld
mov si, sector_buf
mov di, KERNEL_NAME ; move the kernel name to di
check_next_file:
push cx ; save cx because its needed for the repe cmpsb instruction
mov cx, 11 ; 8.3 FAT filename = 11 characters to compare
repe cmpsb ; compare
je found_it ; the cpu jumps the first try, also if di and si are different :-(
; should only jump if the kernel is found
add si, cx ; AKA, whatever's left after the repe cmpsb
add si, 21 ; and add 21 to si ( 11 + 21 = 32 = one dir entry )
mov di, KERNEL_NAME ; move the kernel name to di
pop cx ; restore cx for use in the loop
loop check_next_file ; loop
mov ax, 0 ; if the kernel isn't found
ret
found_it:
pop cx ; if the kernel is found restore cx
; so the return address is valid
and si, 0FFE0h ; strip out the last 5 bits again
and di, 0FFE0h ; strip out the last 5 bits again
mov ax, 1 ; return value = kernel is found
ret
sector_buf:
times 16 dd 0
Re:FAT12 Bootloader
Posted: Fri Mar 05, 2004 12:16 pm
by ASHLEY4
The code i pasted, works in my boot loader (eg finds the file if its there or gives error message, no file found) ,if that code does not work in your loader, then it must be some other part of your code.(make shore the ds:si ,es:di,are pointing,as indecated.)
ASHLEY4.
Re:FAT12 Bootloader
Posted: Sat Mar 06, 2004 9:53 am
by ich_will
I got it
After a lot of tests i found out that the bugs are:
1. I load the sector to a buffer smaller than 512 byte
sector_buf:
times 16 dd 0 == 512 bit not byte
now I change it and load the sector to 0x50:0x00 == 0x500
2. I try to read the 19th sector with sector = 1 and track = 1
(second track) but i have to read it with sector = 1 ,
head = 1 and track = 0
Thanks for the Help.