FAT32

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Richy
Member
Member
Posts: 41
Joined: Wed Nov 19, 2008 10:03 am

FAT32

Post by Richy »

I've been struggling with writing FAT32 functions for over a week now. I want something simple: following pointers in the allocation table and reading the clusters to memory, in assembly and compact enough to run in a stage-1 bootloader. But every bug I solve seems to create two more, and while FAT12 is pretty popular with OS developers I find surprisingly little online about using FAT32.

Does anyone here have experience with it? I could use help, or even "cheat" and look at someone's complete and working code.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: FAT32

Post by Combuster »

Having FAT32 on real hardware most likely means:
- You have a partition table to deal with.
- It's not going to be a floppy, so you want to use the EDD calls instead of the AH=0..2 ones
- The root directory is stored like any other directory and doesn't follow immediately after the FAT.

So, while the logic of FAT may still be mostly the same, the amount of reuse that's possible is minimal. And most people just use GRUB (or more recently, EFI) to do the filesystem tasks instead.

It probably helps if you can point out where you're stuck at the moment.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
zhiayang
Member
Member
Posts: 368
Joined: Tue Dec 27, 2011 7:57 am
Libera.chat IRC: zhiayang

Re: FAT32

Post by zhiayang »

I don't understand the exact problem you're having. Are you having trouble
a. fitting a FAT32 parser into 512 bytes
b. grasping how FAT32 works
c. something else?

I can't help with problem (a), but for problem (b), I recently created http://wiki.osdev.org/User:Requimrar/FAT32.
I did however find https://github.com/ishanthilina/USB-FAT ... c/boot.asm. Hope it helps.
Richy
Member
Member
Posts: 41
Joined: Wed Nov 19, 2008 10:03 am

Re: FAT32

Post by Richy »

requimrar wrote: I did however find https://github.com/ishanthilina/USB-FAT ... c/boot.asm. Hope it helps.
I am familiar with QUASI bootloader. The problem with it is that it is hard-coded to load the first file in the RDT which has to be only one cluster in size. I'm trying to write a more general function, that searches the RTD for a specific file name (done) and follows the pointers in the FAT in order to load all clusters of it. That last one is where I'm stumbling for some reason. I wish I could tell you why... but if I knew, I would fix it! It just seems to stop loading clusters before the end of the file, so it cannot run the parts of the code after that point... or maybe it's mis-following the pointers and loading the wrong thing altogether.

I'll read your wiki and get back.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: FAT32

Post by alexfru »

I should probably start releasing this old code re-licensed under BSD license, but for educational purposes you can have it as-is.

This is a bootsector (FYI I've never tried it as an MBR replacement) to load a file with a given name from the root of a FAT32 disk. It then relocates and runs it as a regular DOS .EXE program if it finds the MZ signature or as a regular DOS .COM program otherwise.

Populate the BPB(s) with the proper values (just take them from your formatted FAT32 disk, where you want this bootsector installed).

Assemble with "nasm -f bin".

Code: Select all

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                          ;;
;;       "BootProg" Loader v 1.4 by Alexei A. Frounze (c) 2000-2005         ;;
;;                                                                          ;;
;;                                                                          ;;
;;                            Contact Information:                          ;;
;;                            ~~~~~~~~~~~~~~~~~~~~                          ;;
;; E-Mail:   [email protected]                                                ;;
;; Homepage: http://alexfru.chat.ru                                         ;;
;; Mirror:   http://alexfru.narod.ru                                        ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                  Thanks:                                 ;;
;;                                  ~~~~~~~                                 ;;
;;      Thanks Thomas Kjoernes (aka NowhereMan) for his excelent idea       ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                 Features:                                ;;
;;                                 ~~~~~~~~~                                ;;
;; - FAT32 supported using BIOS int 13h function 42h (i.e. it will only     ;;
;;   work with modern BIOSes supporting HDDs bigger than 8 GB)              ;;
;;                                                                          ;;
;; - Loads particular COM or EXE file placed to the root directory of a disk;;
;;   ("ProgramName" variable holds name of a file to be loaded)             ;;
;;                                                                          ;;
;; - Provides simple information about errors occured during load process   ;;
;;   ("E" message for "Read Error" or "file Not Found")                     ;;
;;                                                                          ;;
;;                                                                          ;;
;;                             Known Limitations:                           ;;
;;                             ~~~~~~~~~~~~~~~~~~                           ;;
;; - Works only on the 1st MBR partition which must be a PRI DOS partition  ;;
;;   with FAT32 (File System ID: 0Bh,0Ch)                                   ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                Known Bugs:                               ;;
;;                                ~~~~~~~~~~~                               ;;
;; - All bugs are fixed as far as I know. The boot sector tested on my      ;;
;;   HDD.                                                                   ;;
;;                                                                          ;;
;;                                                                          ;;
;;                                Memory Map:                               ;;
;;                                ~~~~~~~~~~~                               ;;
;;                 ┌────────────────────────┐                               ;;
;;                 │ Interrupt Vector Table │ 0000                          ;;
;;                 ├────────────────────────┤                               ;;
;;                 │     BIOS Data Area     │ 0040                          ;;
;;                 ├────────────────────────┤                               ;;
;;                 │ PrtScr Status / Unused │ 0050                          ;;
;;                 ├────────────────────────┤                               ;;
;;                 │   Image Load Address   │ 0060                          ;;
;;                 ├────────────────────────┤                               ;;
;;                 │    Available Memory    │ nnnn                          ;;
;;                 ├────────────────────────┤                               ;;
;;                 │     2KB Boot Stack     │ A000 - 512 - 2KB              ;;
;;                 ├────────────────────────┤                               ;;
;;                 │       Boot Sector      │ A000 - 512                    ;;
;;                 ├────────────────────────┤                               ;;
;;                                            A000                          ;;
;;                                                                          ;;
;;                                                                          ;;
;;                   Boot Image Startup (register values):                  ;;
;;                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                  ;;
;;  dl = boot drive number                                                  ;;
;;  cs:ip = program entry point                                             ;;
;;  ss:sp = program stack (don't confuse with boot sector's stack)          ;;
;;  COM program defaults: cs = ds = es = ss = 50h, sp = 0, ip = 100h        ;;
;;  EXE program defaults: ds = es = 50h, other stuff depends on EXE header  ;;
;;                                                                          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

[BITS 16]

?                       equ     0
ImageLoadSeg            equ     60h     ; <=07Fh because of "push byte ImageLoadSeg" instructions

[SECTION .text]

[ORG 0]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boot sector starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        jmp     short   start
        nop
bsOemName               DB      "BootProg"      ; 0x03

;;;;;;;;;;;;;;;;;;;;;;
;; BPB1 starts here ;;
;;;;;;;;;;;;;;;;;;;;;;

bpbBytesPerSector       DW      ?               ; 0x0B
bpbSectorsPerCluster    DB      ?               ; 0x0D
bpbReservedSectors      DW      ?               ; 0x0E
bpbNumberOfFATs         DB      ?               ; 0x10
bpbRootEntries          DW      ?               ; 0x11
bpbTotalSectors         DW      ?               ; 0x13
bpbMedia                DB      ?               ; 0x15
bpbSectorsPerFAT        DW      ?               ; 0x16
bpbSectorsPerTrack      DW      ?               ; 0x18
bpbHeadsPerCylinder     DW      ?               ; 0x1A
bpbHiddenSectors        DD      ?               ; 0x1C
bpbTotalSectorsBig      DD      ?               ; 0x20

;;;;;;;;;;;;;;;;;;;;
;; BPB1 ends here ;;
;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;
;; BPB2 starts here ;;
;;;;;;;;;;;;;;;;;;;;;;

bsSectorsPerFAT32               DD      ?               ; 0x24
bsExtendedFlags                 DW      ?               ; 0x28
bsFSVersion                     DW      ?               ; 0x2A
bsRootDirectoryClusterNo        DD      ?               ; 0x2C
bsFSInfoSectorNo                DW      ?               ; 0x30
bsBackupBootSectorNo            DW      ?               ; 0x32
bsreserved             times 12 DB      ?               ; 0x34
bsDriveNumber                   DB      ?               ; 0x40
bsreserved1                     DB      ?               ; 0x41
bsExtendedBootSignature         DB      ?               ; 0x42
bsVolumeSerialNumber            DD      ?               ; 0x43
bsVolumeLabel                   DB      "NO NAME    "   ; 0x47
bsFileSystemName                DB      "FAT32   "      ; 0x52

;;;;;;;;;;;;;;;;;;;;
;; BPB2 ends here ;;
;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Boot sector code starts here ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

start:
        cld

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; How much RAM is there? ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        int     12h             ; get conventional memory size (in KBs)
        shl     ax, 6           ; and convert it to paragraphs

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reserve some memory for the boot sector and the stack ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        sub     ax, 512 / 16    ; reserve 512 bytes for the boot sector code
        mov     es, ax          ; es:0 -> top - 512

        sub     ax, 2048 / 16   ; reserve 2048 bytes for the stack
        mov     ss, ax          ; ss:0 -> top - 512 - 2048
        mov     sp, 2048        ; 2048 bytes for the stack

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Copy ourself to top of memory ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        mov     cx, 256
        mov     si, 7C00h
        xor     di, di
        mov     ds, di
        rep     movsw

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Jump to relocated code ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        push    es
        push    byte main
        retf

main:
        push    cs
        pop     ds

        mov     [bsDriveNumber], dl     ; store boot drive number

        and     byte [bsRootDirectoryClusterNo+3], 0Fh ; mask cluster value
        mov     esi, [bsRootDirectoryClusterNo] ; esi=cluster # of root dir

RootDirReadContinue:
        push    byte ImageLoadSeg
        pop     es
        xor     bx, bx
        call    ReadCluster             ; read one cluster of root dir
        push    esi                     ; save esi=next cluster # of root dir
        pushf                           ; save carry="not last cluster" flag

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Look for a COM/EXE program to be load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        push    byte ImageLoadSeg
        pop     es
        xor     di, di                  ; es:di -> root entries array
        mov     si, ProgramName         ; ds:si -> program name

        mov     al, [bpbSectorsPerCluster]
        cbw
        mul     word [bpbBytesPerSector]; ax = bytes per cluster
        shr     ax, 5
        mov     dx, ax                  ; dx = # of dir entries to search in

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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: ESI = cluster number          ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FindName:
        mov     cx, 11
FindNameCycle:
        cmp     byte [es:di], ch
        jne     FindNameNotEnd
        jmp     ErrFind                 ; end of root directory (NULL entry found)
FindNameNotEnd:
        pusha
        repe    cmpsb
        popa
        je      FindNameFound
        add     di, 32
        dec     dx
        jnz     FindNameCycle           ; next root entry
        popf                            ; restore carry="not last cluster" flag
        pop     esi                     ; restore esi=next cluster # of root dir
        jc      RootDirReadContinue     ; continue to the next root dir cluster
        jmp     ErrFind                 ; end of root directory (dir end reached)
FindNameFound:
        push    word [es:di+14h]
        push    word [es:di+1Ah]
        pop     esi                     ; si = cluster no.

;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Load entire a program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;

        push    byte ImageLoadSeg
        pop     es
        xor     bx, bx
FileReadContinue:
        call    ReadCluster             ; read one cluster of root dir
        jc      FileReadContinue

;;;;;;;;;;;;;;;;;;;
;; Type checking ;;
;;;;;;;;;;;;;;;;;;;

        push    byte ImageLoadSeg
        pop     ds
        mov     ax, ds                  ; ax=ds=seg the program is loaded to

        cmp     word [0], 5A4Dh         ; "MZ" signature?

        je      RelocateEXE             ; yes, it's an EXE program

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Setup and Run COM program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        sub     ax, 10h                 ; "org 100h" stuff :)
        mov     es, ax
        mov     ds, ax
        mov     ss, ax
        xor     sp, sp
        push    es
        push    word 100h
        jmp     short Run

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Relocate, setup and run EXE program ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

RelocateEXE:

        add     ax, [08h]               ; ax = image base
        mov     cx, [06h]               ; cx = reloc items
        mov     bx, [18h]               ; bx = reloc table pointer

        jcxz    RelocationDone

ReloCycle:
        mov     di, [bx]                ; di = item ofs
        mov     dx, [bx+2]              ; dx = item seg (rel)
        add     dx, ax                  ; dx = item seg (abs)

        push    ds
        mov     ds, dx                  ; ds = dx
        add     [di], ax                ; fixup
        pop     ds

        add     bx, 4                   ; point to next entry
        loop    ReloCycle

RelocationDone:

        mov     bx, ax
        add     bx, [0Eh]
        mov     ss, bx                  ; ss for EXE
        mov     sp, [10h]               ; sp for EXE

        add     ax, [16h]               ; cs
        push    ax
        push    word [14h]              ; ip
Run:
        mov     dl, [cs:bsDriveNumber]  ; let program know boot drive

        ; set the magic number so the program knows who has loaded it:
        mov     si, 16381 ; prime number 2**14-3
        mov     di, 32749 ; prime number 2**15-19
        mov     bp, 65521 ; prime number 2**16-15

        retf

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a FAT32 cluster        ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Inout:  ES:BX -> buffer      ;;
;;           ESI = cluster no   ;;
;; Output:   ESI = next cluster ;;
;;         ES:BX -> next addr   ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadCluster:
        mov     ax, [bpbBytesPerSector]
        shr     ax, 2                           ; ax=# of FAT32 entries per sector
        cwde
        mov     ebp, esi                        ; ebp=esi=cluster #
        xchg    eax, esi
        cdq
        div     esi                             ; eax=FAT sector #, edx=entry # in sector
        movzx   edi, word [bpbReservedSectors]
        add     edi, [bpbHiddenSectors]
        add     eax, edi

        push    dx                              ; save dx=entry # in sector on stack
        mov     cx, 1
        call    ReadSectorLBA                   ; read 1 FAT32 sector

        pop     si                              ; si=entry # in sector
        add     si, si
        add     si, si
        and     byte [es:si+3], 0Fh             ; mask cluster value
        mov     esi, [es:si]                    ; esi=next cluster #

        lea     eax, [ebp-2]
        movzx   ecx, byte [bpbSectorsPerCluster]
        mul     ecx
        mov     ebp, eax

        movzx   eax, byte [bpbNumberOfFATs]
        mul     dword [bsSectorsPerFAT32]

        add     eax, ebp
        add     eax, edi

        call    ReadSectorLBA

        mov     ax, [bpbBytesPerSector]
        shr     ax, 4                   ; ax = paragraphs per sector
        mul     cx                      ; ax = paragraphs read

        mov     cx, es
        add     cx, ax
        mov     es, cx                  ; es:bx updated

        cmp     esi, 0FFFFFF8h          ; carry=0 if last cluster, and carry=1 otherwise
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Reads a sector using BIOS Int 13h fn 42h ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Input:  EAX = LBA                        ;;
;;         CX    = sector count             ;;
;;         ES:BX -> buffer address          ;;
;; Output: CF = 1 if error                  ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ReadSectorLBA:
        pushad

ReadSectorLBANext:
        pusha

        push    byte 0
        push    byte 0
        push    eax
        push    es
        push    bx
        push    byte 1
        push    byte 16

        mov     ah, 42h
        mov     dl, [bsDriveNumber]
        mov     si, sp
        push    ss
        pop     ds
        int     13h
        push    cs
        pop     ds

        add     sp, 16

        jc      short ErrRead

        popa
        dec     cx
        jz      ReadSectorLBADone2      ; last sector

        add     bx, [bpbBytesPerSector] ; adjust offset for next sector
        add     eax, byte 1             ; adjust LBA for next sector
        jmp     short ReadSectorLBANext

ReadSectorLBADone2:
        popad
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Error Messaging Code ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

ErrRead:
ErrFind:
        mov     ax, 0E00h+'E'
        mov     bx, 7
        int     10h
        jmp     short $

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Fill free space with zeroes ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                times (512-13-($-$$)) db 0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Name of a program to be load and run ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ProgramName     db      "STARTUP BIN"   ; name and extension must be padded
                                        ; with spaces (11 bytes total)

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; End of the sector ID ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

                dw      0AA55h
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: FAT32

Post by Brendan »

Hi,

For boot loaders designed for a FAT file system, one of the most important things to understand is that the first structure you need (the BPB) contains a "reservedSectors" field. This field says how many sectors are reserved (e.g. used by the boot loader) and can be any value from 1 to 65535. This means that your boot loader can use up to 31.5 MiB (in the reserved area at the start of the partition) before you need to care about accessing any files (in the file system) at all.

Also note that (at least in my opinion) to write acceptable code (especially where file systems are involved) you must use defensive programming. You should not (e.g.) assume that any of the data (in the BPB, in root directory entries, etc) is "sane" and instead you should build in sanity checks and error messages where possible. For a simple example, for the BPB you know that "reserved + hidden + number_of_FATs * sectors_per_FAT" must be less than "totalSectors". You can check this, and if you detect that something is wrong display a "BPB is corrupt" error message. If you don't do things like this; then sooner or later something will be wrong and nobody (especially the end user) will be able to figure out what happened. Instead of getting useful bug reports (where you know where to start looking for the problem because the user told you which of your nice descriptive error messages they're seeing) you'll get useless bug reports (where you give up and don't bother trying to find the problem because you don't even know where to start looking).

For an example; take a look at the QUASI bootloader code. There's probably about 50 different things that can go wrong (ranging from various structures on the disk that could have been corrupted, to things like BIOS returning "invalid command" errors); and there's only one "Kernel loading failed" error message. If a user sends a bug report saying they're getting a "Kernel loading failed" error message, where would you start looking for the problem?

Basically, for your boot loader to be better than a nasty hack, the sanity checks and all strings for all the possible/different error messages will not fit in 512 bytes; and therefore you need a larger boot loader (e.g. maybe 20 KiB or something) and need to use the "reservedSectors" field in the BPB to reserve space for it.

Note: This does have one downside - you can't easily convert an existing "data only" FAT file system (formatted with only one reserved sector) into your OSs boot partition. Instead you'd either format the partition to suit, or have code to relocate data and increase the reserved sectors if/when necessary. This is would only be a minor inconvenience, given that when someone is installing an OS it's very likely that they will need to create/format a file system for it anyway and you can reserve sectors at that time.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Richy
Member
Member
Posts: 41
Joined: Wed Nov 19, 2008 10:03 am

Re: FAT32

Post by Richy »

alexfru wrote:

Code: Select all


FindNameCycle:
        cmp     byte [es:di], ch
        jne     FindNameNotEnd
        jmp     ErrFind                 ; end of root directory (NULL entry found)

Doesn't work :( It catches the error in this jump here. If you say it works fine on your end, I think I'm going crazy here :|
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: FAT32

Post by Brendan »

Hi,
Brendan wrote:Also note that (at least in my opinion) to write acceptable code (especially where file systems are involved) you must use defensive programming. You should not (e.g.) assume that any of the data (in the BPB, in root directory entries, etc) is "sane" and instead you should build in sanity checks and error messages where possible. For a simple example, for the BPB you know that "reserved + hidden + number_of_FATs * sectors_per_FAT" must be less than "totalSectors". You can check this, and if you detect that something is wrong display a "BPB is corrupt" error message. If you don't do things like this; then sooner or later something will be wrong and nobody (especially the end user) will be able to figure out what happened. Instead of getting useful bug reports (where you know where to start looking for the problem because the user told you which of your nice descriptive error messages they're seeing) you'll get useless bug reports (where you give up and don't bother trying to find the problem because you don't even know where to start looking).
Richy wrote:
alexfru wrote:

Code: Select all

FindNameCycle:
        cmp     byte [es:di], ch
        jne     FindNameNotEnd
        jmp     ErrFind                 ; end of root directory (NULL entry found)
Doesn't work :( It catches the error in this jump here. If you say it works fine on your end, I think I'm going crazy here :|
Surely the error message 'E' is enough for you to tell the difference between an incorrect BPB, a dodgy FAT, a corrupt root directory or a missing file...


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Richy
Member
Member
Posts: 41
Joined: Wed Nov 19, 2008 10:03 am

Re: FAT32

Post by Richy »

Brendan wrote:Hi,
Brendan wrote:Also note that (at least in my opinion) to write acceptable code (especially where file systems are involved) you must use defensive programming. You should not (e.g.) assume that any of the data (in the BPB, in root directory entries, etc) is "sane" and instead you should build in sanity checks and error messages where possible. For a simple example, for the BPB you know that "reserved + hidden + number_of_FATs * sectors_per_FAT" must be less than "totalSectors". You can check this, and if you detect that something is wrong display a "BPB is corrupt" error message. If you don't do things like this; then sooner or later something will be wrong and nobody (especially the end user) will be able to figure out what happened. Instead of getting useful bug reports (where you know where to start looking for the problem because the user told you which of your nice descriptive error messages they're seeing) you'll get useless bug reports (where you give up and don't bother trying to find the problem because you don't even know where to start looking).
Richy wrote:
alexfru wrote:

Code: Select all

FindNameCycle:
        cmp     byte [es:di], ch
        jne     FindNameNotEnd
        jmp     ErrFind                 ; end of root directory (NULL entry found)
Doesn't work :( It catches the error in this jump here. If you say it works fine on your end, I think I'm going crazy here :|
Surely the error message 'E' is enough for you to tell the difference between an incorrect BPB, a dodgy FAT, a corrupt root directory or a missing file...


Cheers,

Brendan
I added different messages to differentiate the errors and isolate the problem lines. But thanks for the sarcasm, it's very useful.
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: FAT32

Post by Antti »

alexfru wrote:

Code: Select all

ReadSectorLBANext:
        ...
        ...
        int     13h
        push    cs
        pop     ds
        add     sp, 16
        jc      short ErrRead
        ...
        ...
Your error checking does not work at all here. There will be "no errors" every time.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: FAT32

Post by alexfru »

Richy wrote:
alexfru wrote:

Code: Select all


FindNameCycle:
        cmp     byte [es:di], ch
        jne     FindNameNotEnd
        jmp     ErrFind                 ; end of root directory (NULL entry found)

Doesn't work :( It catches the error in this jump here. If you say it works fine on your end, I think I'm going crazy here :|
It worked years ago. :) But, of course, there could be a bug or two. I'll take a look.

UPD: is the name a short 8.3 name? Is it all upper case? Are its name and extension parts properly padded with spaces?
Last edited by alexfru on Wed Sep 03, 2014 11:49 pm, edited 1 time in total.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: FAT32

Post by alexfru »

Antti wrote:
alexfru wrote:

Code: Select all

ReadSectorLBANext:
        ...
        ...
        int     13h
        push    cs
        pop     ds
        add     sp, 16
        jc      short ErrRead
        ...
        ...
Your error checking does not work at all here. There will be "no errors" every time.
Yeah, that jc after add won't do the right thing. Thanks for spotting!

UPD: those add and jc instructions can be swapped to fix the error checking problem.
Richy
Member
Member
Posts: 41
Joined: Wed Nov 19, 2008 10:03 am

Re: FAT32

Post by Richy »

alexfru wrote:UPD: is the name a short 8.3 name? Is it all upper case? Are its name and extension parts properly padded with spaces?
Yes, yes, and yes.
alexfru wrote: Yeah, that jc after add won't do the right thing. Thanks for spotting!

UPD: those add and jc instructions can be swapped to fix the error checking problem.
Indeed, thank you Antti.

I've swapped the lines, and now it gets past the previous point and actually catches in this jc instruction. So now it's having a read-cluster problem.
azblue
Member
Member
Posts: 147
Joined: Sat Feb 27, 2010 8:55 pm

Re: FAT32

Post by azblue »

Richy,
One thing I found helpful for learning how a file system works is to use a program that can dump the contents of a sector to the memory. Try to "manually" load a program -- find it in the RDE, find what cluster it starts on, find the next cluster, etc. This helps ensure that you properly understand the file system before you start coding.
Post Reply