One thing this helps with is that I am indeed reading the entire FAT into memory ahead of time. While this is a Bad Idea if reading FAT16 or FAT32, it is workable for FAT12.
Now,
my current code is
Code:
extract_next_fat12_entry:
;; address_of_FAT_entry = fat_buffer + (current_cluster + current_cluster / 2)
mov ax, bx ; BX == current cluster
shr ax, 1 ; current_cluster / 2
add ax, bx ; (current_cluster + current_cluster / 2) == FAT entry offset
add di, ax ; index fat buffer by offset
mov ax, [di] ; get the indexed entry
test bx, 1 ; check if the existing entry is odd
jz .even
.odd:
shr ax, lo_nibble_shift ; extract the high bits
ret
.even:
and ax, hi_nibble_mask ; extract the low bits
ret
My test code, using entry values which should all be valid in my test FAT, is
Code:
mov bx, 0
.test_loop:
mov di, fat_mockup
call extract_next_fat12_entry
call print_hex_word
write nl
inc bx
cmp bx, 5
jl .test_loop
In my test code I use a mocked-up truncated FAT, defined as
Code:
fat_mockup db 0xF0, 0xFF, 0xFF, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0x00
This is based on the actual FAT on my test disk, which contains a single-sector STAGE2.BIN file added by mounting the disk and copying the file to it. See
Wikipedia's example FAT12 cluster map to compare this to.
The resulting values are extracted
Code:
0FF0 - the FAT ID
0FFF - end of chain, in this case the reserved sectors
0000 - unused entry; this should be an end of chain for the STAGE2.SYS file, instead
0FFF - end of chain
0FFF - end of chain, should be an unused entry
Which compares to the values I actually present in the
As far as I can tell, the entries should instead be (as words, to match what is returned by the code):
Code:
0FF0 - the FAT ID, always this value
0FFF - the reserved sector, always this value
0F00 - end of chain, for the single sector file
0FF0 - end of used FAT entries
0000 - unused entry
So it isn't quite right still.
The attached screenshot is of the hexl-mode view of the relevant parts of the disk image, with the first five FAT entries highlighted.