Search code examples
assemblyx86nasmbootloaderfat

Why isn't my root directory being loaded? (FAT12)


I am writing a stage 1 bootloader in assembly with which I am attempting to load the FAT12 filesystem into memory so that I can load my stage 2 bootloader. I have managed to load the FATs into memory, however I am struggling to load the root directory into memory.

I am currently using this for reference and have produced the following:

.load_root:
    ;es is 0x7c0
    xor dx, dx              ; blank dx for division
    mov si, fat_loaded      ; inform user that FAT is loaded
    call print
    mov al, [FATcount]      ; calculate how many sectors into the disk must be loaded
    mul word [SectorsPerFAT]
    add al, [ReservedSectors]
    div byte [SectorsPerTrack]
    mov ch, ah              ; Store quotient in ch for cylinder number
    mov cl, al              ; Store remainder in cl for sector number

    xor dx, dx
    xor ax, ax
    mov al, ch              ; get back to "absolute" sector number
    mul byte [SectorsPerTrack]
    add al, cl
    mul word [BytesPerSector]
    mov bx,ax               ; Memory offset to load to data into memory after BOTH FATs (should be 0x2600, physical address should be 0xA200)

    xor dx, dx              ; blank dx for division
    mov ax, 32
    mul word [MaxDirEntries]
    div word [BytesPerSector] ; number of sectors root directory takes up (should be 14)

    xor dh, dh              ; head 0
    mov dl, [boot_device]   ; boot device

    mov ah, 0x02            ; select read mode

    int 13h
    cmp ah, 0
    je .load_OS
    mov si, error_text
    call print
    jmp $

However, if I inspect the memory at 0xA200 with gdb, I just see 0s. My root directory does contain a file -- I have put a file called OS.BIN in the root directory to test with.

Using info registers in gdb after the read operation gives the following output:

eax            0xe      14
ecx            0x101    257
edx            0x0      0
ebx            0x2600   9728
esp            0x76d0   0x76d0
ebp            0x0      0x0
esi            0x16d    365
edi            0x0      0
eip            0x7cdd   0x7cdd
eflags         0x246    [ PF ZF IF ]
cs             0x0      0
ss             0x53     83
ds             0x7c0    1984
es             0x7c0    1984
fs             0x0      0
gs             0x0      0

The status of the operation is 0, the number of sectors read is 14, and es:bx points to 0xA200, but x/32b 0xa200 shows 32 0s, when I would expecting to see the data for OS.BIN.

EDIT I did info registers before the interrupt and the output is the following:

eax            0x20e    526
ecx            0x101    257
edx            0x0      0
ebx            0x2600   9728
esp            0x76d0   0x76d0
ebp            0x0      0x0
esi            0x161    353
edi            0x0      0
eip            0x7cc8   0x7cc8
eflags         0x246    [ PF ZF IF ]
cs             0x0      0
ss             0x53     83
ds             0x7c0    1984
es             0x7c0    1984
fs             0x0      0
gs             0x0      0

Which is the same as after, except the function request number has been replaced with the status code.

Where am I going wrong? Am I reading from the wrong CHS address? Or some other simple mistake? And how can I correct this?

I am using fat_imgen to make my disk image. Command for creating the disk image is fat_imgen -c -f floppy.flp -F -s bootloader.bin and command for adding OS.BIN to the image is fat_imgen -m -f floppy.flp -i OS.BIN


I have a BIOS Parameter Block (BPB) that represents a 1.44MB floppy using FAT12:

jmp short loader
times 9 db 0

BytesPerSector: dw 512
SectorsPerCluster: db 1
ReservedSectors: dw 1
FATcount: db 2
MaxDirEntries: dw 224
TotalSectors: dw 2880
db 0
SectorsPerFAT: dw 9
SectorsPerTrack: dw 18
NumberOfHeads: dw 2
dd 0
dd 0
dw 0
BootSignature: db 0x29
VolumeID: dd 77
VolumeLabel: db "Bum'dOS   ",0
FSType: db "FAT12   "

I have another function that appears to work that loads the FAT12 table to memory address 0x7c0:0x0200 (physical address 0x07e00):

;;;Start loading File Allocation Table (FAT)
.load_fat:
    mov ax, 0x07c0          ; address from start of programs
    mov es, ax
    mov ah, 0x02            ; set to read
    mov al, [SectorsPerFAT]   ; how many sectors to load
    xor ch, ch              ; cylinder 0
    mov cl, [ReservedSectors]  ; Load FAT1
    add cl, byte 1
    xor dh, dh              ; head 0
    mov bx, 0x0200          ; read data to 512B after start of code
    int 13h
    cmp ah, 0
    je .load_root
    mov si, error_text
    call print
    hlt

Solution

  • I ended up scrapping loading the root directory after loading the FATs. In the end, I modified my .load_fat routine to load both FATs and the root directory at the same time (essentially reading 32 sectors after the boot sector, but in a way that still allows me to easily modify the disk geometry).

    The code for this is below:

    .load_fat:
        mov ax, 0x07c0          ; address from start of programs
        mov es, ax
        mov al, [SectorsPerFAT] ; how many sectors to load
        mul byte [FATcount]     ; load both FATs
        mov dx, ax
        push dx
        xor dx, dx              ; blank dx for division
        mov ax, 32
        mul word [MaxDirEntries]
        div word [BytesPerSector] ; number of sectors for root directory
        pop dx
        add ax, dx              ; add root directory length and FATs length -- load all three at once
        xor dh,dh
        mov dl, [boot_device]
    
        xor ch, ch              ; cylinder 0
        mov cl, [ReservedSectors]  ; Load from after boot sector
        add cl, byte 1
        xor dh, dh              ; head 0
        mov bx, 0x0200          ; read data to 512B after start of code
        mov ah, 0x02            ; set to read
        int 13h
        cmp ah, 0
        je .load_root
        mov si, error_text
        call print
        hlt
    

    Though not the way I intended to solve the problem, it does the job and I can move on from this to continue development.

    EDIT

    I think I worked out where the old code was going wrong, anyway. I was incrementing the cylinder after sector 18, when I should have been incrementing the head. It's CHS, not HCS, for a reason!