FAT32
FAT32
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.
Does anyone here have experience with it? I could use help, or even "cheat" and look at someone's complete and working code.
- Combuster
- 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
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.
- 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.
Re: FAT32
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.
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.
[nx] kernel: http://github.com/zhiayang/nx
Re: FAT32
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.requimrar wrote: I did however find https://github.com/ishanthilina/USB-FAT ... c/boot.asm. Hope it helps.
I'll read your wiki and get back.
Re: FAT32
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".
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
Re: FAT32
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 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.
Re: FAT32
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 herealexfru wrote:Code: Select all
FindNameCycle: cmp byte [es:di], ch jne FindNameNotEnd jmp ErrFind ; end of root directory (NULL entry found)
Re: FAT32
Hi,
Cheers,
Brendan
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).
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...Richy wrote: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 herealexfru wrote:Code: Select all
FindNameCycle: cmp byte [es:di], ch jne FindNameNotEnd jmp ErrFind ; end of root directory (NULL entry found)
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.
Re: FAT32
I added different messages to differentiate the errors and isolate the problem lines. But thanks for the sarcasm, it's very useful.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).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...Richy wrote: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 herealexfru wrote:Code: Select all
FindNameCycle: cmp byte [es:di], ch jne FindNameNotEnd jmp ErrFind ; end of root directory (NULL entry found)
Cheers,
Brendan
Re: FAT32
Your error checking does not work at all here. There will be "no errors" every time.alexfru wrote:Code: Select all
ReadSectorLBANext: ... ... int 13h push cs pop ds add sp, 16 jc short ErrRead ... ...
Re: FAT32
It worked years ago. But, of course, there could be a bug or two. I'll take a look.Richy wrote: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 herealexfru wrote:Code: Select all
FindNameCycle: cmp byte [es:di], ch jne FindNameNotEnd jmp ErrFind ; end of root directory (NULL entry found)
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.
Re: FAT32
Yeah, that jc after add won't do the right thing. Thanks for spotting!Antti wrote:Your error checking does not work at all here. There will be "no errors" every time.alexfru wrote:Code: Select all
ReadSectorLBANext: ... ... int 13h push cs pop ds add sp, 16 jc short ErrRead ... ...
UPD: those add and jc instructions can be swapped to fix the error checking problem.
Re: FAT32
Yes, yes, and yes.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?
Indeed, thank you Antti.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.
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.
Re: FAT32
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.
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.