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 (

Code: Select all

mov eax, 0
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 8) :D

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.