Home > Software design >  How can I read more than one sector with BIOS calls?
How can I read more than one sector with BIOS calls?

Time:09-18

I have a bootsector which is meant to load a file called BOOT.BIN from a floppy disk image. However I can not figure out how to read more than one sector from the file. The FAT 12 is at 0x10000. The BOOT.BIN file will be put at 0x40000. The code:

foundfile:
        mov word ax,[es:di 0x0f]
        push ax ;save file cluster
        ;now to parse the fat
        mov dx,second_boot_segment
        mov es,dx
        xor bx,bx
        
        read_file_sector:
            pop ax ;retrieve file cluster
            mov byte dl,[drive_num]
            mov cx,ax
            add cx,31
            push ax ;save cluster number
            mov al,1
            call readdisk
            pop ax ;retrieve cluster number
            
        find_clusters:
            push es
            push bx
            mov cx,fat_segment
            mov es,cx
            xor bx,bx
            xor dx,dx
            mov cx,3
            mul cx
            shr ax,1
            ;ax is now (clusternum*3)/2
            test ax,1
            
            jz short evennum
            
            oddnum:
                shr ax,4
                jmp short find_clusters_continued
                
            evennum:
                and ax,0x0fff
                
            find_clusters_continued:
                cmp ax,0x0ff0
                jae short finishedread ;read all of file
                
                mov word ax,[es:bx]
                
                pop bx
                pop es
                
                push ax
                
                add bx,512 ;next sector
                jmp short read_file_sector
                
        finishedread:
            jmp second_boot_segment:0000
            jmp fatalerror

======================================================================== readdisk and other functions:

readdisk: ;input: es:bx for where disk data is stored, al for sectors, cx for lba, drive_num for drive output: carry flag on error, ah is return type, al is the number of sectors read
        push dx ;save dx
        call lbatochs
        mov byte dl,[drive_num]
        mov ah,2
        int 13h
        jc short resetdisk
        mov byte dl,[drive_num]
        pop dx ;restore dx
        ret
        
        resetdisk:
            push ax
            mov ah,0
            int 13h
            jc short fatalerror
            pop ax
            jmp short readdisk

    fatalerror:
        mov ax,0x0003 ;ah = 0 al = 3
        int 10h
        
        mov si,boot_error
        mov ax,0xb800
        mov es,ax
        xor bx,bx
        cld
        
        printloop:
            lodsb
            or al,al ;is the last character read
            jz short infloop
            mov ah,0x0f ;color
            mov word [es:bx],ax ;write to vram
            add bl,2 ;as long a the text is less than 256 bytes this works
            jmp short printloop
    
    lbatochs: ;input: cx for lba, output: cx for cylinder and sector, and dh for head
        push ax ;save for later
        push bx ;save bx
        
        ;find temp variable
        xor dx,dx
        mov ax,cx ;ax now has lba
        push ax ;save lba
        mov word bx,[sects_per_track] ;sectors per track
        div bx ;ax is now temp
        
        ;cylinder
        push ax ;save temp
        xor dx,dx
        mov word bx,[num_heads] ;number of heads
        div bx ;ax is now cylinder
        mov cx,ax ;cx stores cylinder
        pop ax ;retrieve temp
        ;cx is now cylinder
        
        ;head
        push dx ;heads already in dx
        
        ;sector
        pop dx ;pop dx to get stack value underneath it
        pop ax ;retrieve lba
        push dx ;push dx back on
        push cx ;save cylinder
        xor dx,dx
        mov word bx,[sects_per_track]
        div bx
        inc dx ;dx now has sectors
        mov bx,dx ;now bx has sectors
        pop cx
        pop dx
        
        ;put params together
        mov ch,cl ;cylinder in ch
        mov cl,bl ;sector in cl
        mov dh,dl ;head in dh
        mov dl,0 ;erase dl
        
        pop bx ;load old bx
        pop ax ;load old ax
        ret
``` This read disk code likely is not causing the issues as I have loaded many other sectors with this.

CodePudding user response:

int 13h with ah=02 is supposed to take the number of sections in al, see http://www.ctyme.com/intr/rb-0607.htm. Currently you do mov al, 1 before calling readdisk, and that value is preserved through the call of lbatochs, so you read 1 sector.

If you want 42 sectors, change it to mov al, 42. Or refactor readdisk in some other way.

CodePudding user response:

  readfat:
       mov byte dl,[es:bx]

This instruction makes no sense! There's nothing useful to read (yet) at that spot.


However I can not figure out how to read more than one sector from the file.

The reason is that your code forgets to actually loop back to the readfat label. Once you've loaded a next clusternumber you need to jump back to the top of the loop instead of immediately far jumping to the BOOT.BIN binary.

Note that it will not be enough to just insert the missing jmp! Because the necessary add bx, 512 gets destroyed by the pop bx instruction, all the sectors will arrive on top of each other.

Because of

This read disk code likely is not causing the issues as I have loaded many other sectors with this.

I did not investigate that part of your code. See if next rewrite works for you:

foundfile:
        mov  ax, [es:di 0x0F]  ; dirFirstCluster
        mov  bx, 0x4000
        mov  es, bx
        xor  bx, bx
READSECTOR:
        push es                ; (1)
        push bx                ; (2)
        push ax                ; (3)
        add  ax, 31
        mov  cx, ax
        mov  al, 1
        call readdisk
        pop  ax                ; (3)
        mov  dx, 3
        mul  dx
        shr  ax, 1
        jnc  short evenclus
oddclus:
        shr  ax, 4
evenclus:
        and  ax, 0x0FFF
        cmp  ax, 0x0FF8
        jae  finishedread

        mov  bx, 0x1000        ; FAT
        mov  es, bx
        mov  bx, ax
        mov  ax, [es:bx]       ; Following cluster number
        pop  bx                ; (2)
        pop  es                ; (1)
        ADD  BX, 512       <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        JMP  READSECTOR    <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

finishedread:
        jmp  0x4000:0000
        jmp  fatalerror

CodePudding user response:

I have figured out how to write the loop by myself.

Here is the code if you want to see it:

foundfile:
    mov word ax,[es:di 0x0f]
    push ax ;save file cluster
    ;now to parse the fat
    mov dx,second_boot_segment
    mov es,dx ;second_boot_segment
    xor bx,bx ;offset for es
    xor di,di ;offset for es when reading the fat
    
    read_file_sector:
        pop cx ;get file cluster and put in cx
        add cx,31
        push ax ;save cluster again
        mov byte al,[sects_per_cluster] ;cluster size
        call readdisk
        pop ax ;retrieve cluster
        push es
        
    find_cluster:
        mov cx,3
        xor dx,dx
        mul cx ;multiply cluster number by 3
        shr ax,1 ;divide cluster number by 2
        mov cx,fat_segment
        mov es,cx
        mov di,ax
        mov word ax,[es:di]

        jnc short evenclus
        
        oddclus:
            shr ax,4
            jmp short continue_findcluster
            
        evenclus:
            and ax,0x0fff
            
        continue_findcluster:
            cmp ax,0x0ff0
            jae finishedread
            
            add bx,512
            pop es
            push ax ;save cluster for loop
            jmp short read_file_sector
        
    finishedread:
        jmp second_boot_segment:0000
        jmp fatalerror
  • Related