flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Error in fatgen103

Author
Thread Post new topic Reply to topic
Mike Gonta



Joined: 26 Dec 2010
Posts: 243
Mike Gonta 28 Mar 2011, 01:41
There is an error in the FAT Volume Initialization algorithm (on page 21) to calculate the number of sectors in a FAT32
File Allocation Table. Even though the document is over 10 years old it's still the most current.
fatgen103, page 21 wrote:
Do not spend too much time trying to figure out why this math works. The basis for the computation is complicated;
It's actually quite simple. Start with the total sectors, subtract the reserved sectors and the sectors used for both FATs.
Then add two clusters to account for the first two FAT entries. The total data sectors of the volume must be less or equal
to 4GB-1 for FAT32 and the MBR table. These sectors are not managed by the FAT. This leaves the total data sectors,
divide by the sectors per cluster for the total data clusters. Divide the total data clusters by the sector size divided by 4
to get the total FAT sectors. Any fractional remainder will require one extra FAT sector.
Code:
  FATSz = DskSize - BPB_ResvdSecCnt - (2 * FATSz) + (2 * BPB_SecPerClus)/ BPB_SecPerClus * (BPB_BytsPerSec / 4)    
Multiply both sides by (BPB_SecPerClus * (BPB_BytsPerSec / 4))
Code:
    FATSz * (BPB_SecPerClus * (BPB_BytsPerSec / 4)) = DskSize - BPB_ResvdSecCnt - (2 * FATSz) + (2 * BPB_SecPerClus)    
Add (2 * FATSz) to both sides
Code:
   (FATSz * (BPB_SecPerClus * (BPB_BytsPerSec / 4))) + (2 * FATSz) = DskSize - BPB_ResvdSecCnt + (2 * BPB_SecPerClus)    
Combine the FATSz
Code:
    FATSz * ((BPB_SecPerClus * (BPB_BytsPerSec / 4)) + 2) = DskSize - BPB_ResvdSecCnt + (2 * BPB_SecPerClus)    
Finally divide both sides by ((BPB_SecPerClus * (BPB_BytsPerSec / 4)) + 2) to get FATSz. Round up any fractional remainder.
Code:
    FATSz = (DskSize - BPB_ResvdSecCnt + (2 * BPB_SecPerClus)) / ((BPB_SecPerClus * (BPB_BytsPerSec / 4)) + 2)    

This is different (and much simpler) than the MS version:
fatgen103, page 21 wrote:
Code:
RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1)) / BPB_BytsPerSec;
TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors);
TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
If(FATType == FAT32)
TmpVal2 = TmpVal2 / 2;
FATSz = (TMPVal1 + (TmpVal2 - 1)) / TmpVal2;    
fatgen103, page 13 wrote:
Note that on a FAT32 volume the BPB_RootEntCnt value is always 0, so on a FAT32 volume RootDirSectors is always 0.

Here's the FASM code which works as either use16 or use32. Note edx:eax is the 64 bit total bytes size.
Code:
  shrd eax, edx, cl             ; ecx is BPB_BytsPerSec exponent, 512=9, 2048=11, 4096=12
  shr edx, cl                   ; divide size by 512 for DskSize
  movzx ebx, WORD [BPB_ResvdSecCnt]
  sub eax, ebx
  sbb edx, 0                    ; DskSize - BPB_ResvdSecCnt
  movzx ebx, BYTE [BPB_SecPerClus]
  add eax, ebx
  add eax, ebx                  ; + (2 * BPB_SecPerClus)
  jnc .1
  mov eax, -1                   ; max size 4GB-1
.1:
  sub ecx, 2
  shl ebx, cl
  add ebx, 2                    ; (BPB_SecPerClus * (BPB_BytsPerSec / 4)) + 2
  xor edx, edx
  div ebx                       ; (DskSize - BPB_ResvdSecCnt) / ((BPB_SecPerClus * (BPB_BytsPerSec / 4)) + 2)
  cmp edx, 0
  adc eax, 0                    ; need one extra sector if any remainder    

Format any size USB flash drive FAT32. Using a disk editor like HxD the following variables are located at the following offsets from the start of the first volume sector.
Code:
BPB_SecPerClus                    equ 13 ; BYTE
BPB_ResvdSecCnt                   equ 14 ; WORD
BPB_NumFATs                       equ 16 ; BYTE
DskSize                           equ 32 ; DWORD
FATSz                             equ 36 ; DWORD    

Do the math and check the FATSz as actually formatted.

Edit: Added correction to code by revolution
Edit: Added size of sector calculation and compensation for first two FAT entries.

_________________
Mike Gonta
look and see - many look but few see

https://mikegonta.com


Last edited by Mike Gonta on 29 Mar 2011, 09:03; edited 2 times in total
Post 28 Mar 2011, 01:41
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20298
Location: In your JS exploiting you and your system
revolution 28 Mar 2011, 01:52
Mike Gonta wrote:
Code:
  shrd edx, eax, 9              ; divide size by 512 for DskSize    
If you want to divide EDX:EAX by 512 then you should do this:
Code:
shrd eax,edx,9
shr edx,9    
Mike Gonta wrote:
Code:
  sub eax, ebx                  ; DskSize - BPB_ResvdSecCnt    
If you need to subtract a 32 bit number from a 64 bit number you need to propagate the carry:
Code:
sub eax,ebx
sbb edx,0    
Post 28 Mar 2011, 01:52
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.