The MASM Forum

Miscellaneous => 16 bit DOS Programming => Topic started by: MichaelTripi68 on January 16, 2013, 02:28:51 AM

Title: Need Help!! Reading a floppy (FAT12) root directory.
Post by: MichaelTripi68 on January 16, 2013, 02:28:51 AM
RECAP:  I am writing a floppy based boot loader only at this time in 16-bit mode.  Essentially, I am trying to write a basic bootable O/S based off of the FAT12 file system.  Later, when I am more experienced, I wlll write something more challenging.
Up to this point, I have only coded basic boot code that the BIOS will load and execute at 0000:7C00.  I have been having MAJOR issues with reading the root directory from the floppy drive using INT 13h.   My buffer is always blank and no entries show up.
Based on "classic" documentation for FAT12 FLOPPY, it indicates that the root directory should start at the 20th sector (1 sector for boot record, 2 fats  taking up 9 sectors each followed by root directory at the next sector...the 20th.)  I have used DEBUG.EXE to load a sector at a time and dump contents to determine where it resides.  Apparently, DEBUG indicates that the root directory starts at the 14th sector!!!??  (used command:   L 100 0 13 1  ...I think debug is "zero based" on sector selection).   I'm so confused now!!!  All I want to do at this point is read the floppy root directory and display the filenames on the screen so that I know I'm accessing the floppy root directory correctly.
Can anyone help me out??
Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: FORTRANS on January 16, 2013, 03:27:55 AM
Hi,

   The only thing that comes to mind is that DEBUG uses
hexadecimal by default, and 20D equals 14H.

Regards,

Steve N.
Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: dedndave on January 16, 2013, 03:55:42 AM
you cannot assume that each FAT will consume 9 sectors
you should calculate this value, based on the BIOS parameter block (BPB) values in the boot sector

sector numbers are 1-based, while the other parameters are 0-based
Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: MichaelW on January 16, 2013, 04:01:28 AM
This is an older version of the code I posted in another of your threads -- perhaps it can provide something useful.

;---------------------------------------------------------------
; This file is the source for a boot loader (boot sector) that
; moves itself up to the top of conventional memory, locates
; and reads a file from the boot diskette, loads the contents
; of the file into memory starting at absolute address 500h,
; and then does a far jump to that address. The code includes
; the components necessary for the system (DOS/Windows) to
; recognize it as a valid boot sector for a 3.5 inch 1.44MB
; diskette, and this in turn allows the system to access the
; diskette file system normally.
;
; Normal structure of a 3.5 inch 1.44MB diskette:
;
;   Boot sector (512 bytes:c=0,h=0,s=1)
;   FATs (2*9*512 bytes:c=0,h=0,s=2 to c=0,h=1,s=1)
;   Root directory (224*32 bytes:c=0,h=1,s=2 to c=0,h=1,s=15)
;   File and directory space (starts at c=0,h=1,s=16)
;
; Diskettes use a 12-bit FAT. Because the first two FAT entries
; (000 and 001) are reserved, the entry that corresponds to
; cluster 0 starts at the fourth byte. The remaining FAT
; entries should be interpreted is as follows:
;
;   000h            = free cluster
;   001h            = unused code
;   FF0-FF6h        = reserved
;   FF7h            = bad cluster
;   FF8-FFFh        = last cluster of file
;   any other value = link to next cluster in file
;
; For example, assuming the file occupies three clusters and
; starts at the third entry (002):
;
; reserved [003]    [FFF]
; |      | ||  |    ||  |
; F0 FF FF 03 40 00 FF 6F
;             |  ||
;             [004]
;
; Although somewhat difficult to follow because each entry
; is 1.5 bytes, the third entry (002) points to the fourth
; (003), the fourth (003) to the fifth (004), and the fifth
; (004) contains FFFh indicating that the associated cluster
; is the last cluster of the file.
;---------------------------------------------------------------

; Declare a structure for a boot sector header that includes
; all but the 3-byte bsJump field of the BOOTSECTOR structure
; from the Microsoft MS-DOS Programmers Reference (versions
; 5 and 6). The initializers for the essential fields were
; taken from a 3.5 inch 1.44MB diskette formatted under
; Windows 98 SE, but they should be valid for any of the
; later versions of MS-DOS and AFAIK Windows 9x/NT/2000/XP.
;
; Per the MS-DOS Programmers Reference, the structure must
; appear at the beginning of the first sector on the disk.
; The 3-byte bsJump field was left out of the header
; structure so it could be coded separately.
;
BSHEADER struct 
  bsOemName            db "XXXXXXXX"      ; must be 8 bytes
  bsBytesPerSector     dw 512             ; start of BPB
  bsSectorsPerCluster  db 1
  bsReservedSectors    dw 1               ; boot sector only
  bsFats               db 2
  bsRootDirEntries     dw 224
  bsSectors            dw 2880
  bsMedia              db 0f0h
  bsFatSectors         dw 9
  bsSectorsPerTrack    dw 18
  bsHeads              dw 2
  bsHiddenSectors      dd 0
  bsHugeSectors        dd 0               ; end of BPB
  bsDriveNumber        db 0
  bsReserved           db 0
  bsBootSignature      db 29h
  bsVolumeId           dd 12345678h 
  bsVolumeLabel        db 'JUST A TEST'   ; must be 11 bytes
  bsFileSystemType     db 'FAT12   '      ; must be 8 bytes
BSHEADER ENDS

; This structure, included here to serve only as a template,
; is from the MS-DOS Programmers Reference.
;
; Directory entries are 32 bytes each.
;
DIRENTRY STRUCT
  deName          db 8 dup(?)
  deExtension     db 3 dup(?)
  deAttribute     db ?
  deReserved      db 10 dup(?)
  deTime          dw ?
  deDate          dw ?
  deStartCluster  dw ?
  deFileSize      dd ?
DIRENTRY ENDS

.386

; Specify USE16 to force address and operand size to 16 bits.
;
_TEXT SEGMENT USE16

    ; For MASM 6+ ASSUME CS in not necessary.
    ;
    ASSUME ds:_TEXT,es:_TEXT,ss:_TEXT

    ; The BIOS will load the boot sector at address 0000:7C00.
    ;
    ORG   7C00h

  entry:

    ; Use 'NEAR PTR' to force MASM to encode a 3-byte jump.
    ;
    jmp   NEAR PTR init

    ; Define the header.
    ;
    bsh BSHEADER <>

    ; Define the data.
    ;
    dest        dw OFFSET entry2, 97dfh
    filename    db 'STARTUP BIN'
                db ' not found, system halted', 13, 10, 0
    readerror   db 'Error reading diskette', 13, 10, 0
    ok          db 'ok', 13, 10, 0 

  init:

    ; Copy the entire boot sector to address 97DFh:7C00h
    ; (absolute address 9F9F0h) near the top of conventional
    ; memory, avoiding the top 1024KB just in case the BIOS
    ; is using it.
    ;
    xor   ax, ax
    mov   ds, ax
    mov   si, 7c00h
    mov   di, si
    mov   es, dest+2
    mov   cx, 512
    cld
    rep   movsb

    ; Do a far jump to the copy of the boot sector, bypassing
    ; the instructions that precede entry2.
    ;
    jmp   DWORD PTR dest

  entry2:

    ; Set DS, ES, and SS to the new segment address.
    ;
    push  cs
    pop   ds
    push  cs
    pop   es
    push  cs
    pop   ss

    ; This initial SP value will cause the stack to use
    ; memory immediately below the boot sector code.
    ;
    mov   sp, 7C00h
   
    ; We need 224*32 = 7,168 bytes of memory to store the
    ; root directory. Allowing a generous 512 bytes for
    ; the stack, we can use offset address 5E00h for the
    ; base of the storage buffer.
    ;
    BUFFER_BASE EQU 5E00h
   
    ; Load the root directory into the storage buffer.
    ;
    mov   al, 14          ; number of sectors
    mov   ch, 0           ; cylinder number
    mov   cl, 2           ; starting sector number
    mov   dh, 1           ; head number
    call  readdisk
    jnc   @F
    mov   si, OFFSET readerror
    call  print
    jmp   $               ; dynamic halt   
  @@:   

    ; Scan the directory for the target file.
    ;
    mov   bx, BUFFER_BASE
    mov   cx, 224

  dirloop:

    push  cx
    mov   cx, 11
    mov   di, bx
    mov   si, OFFSET filename
    repz  cmpsb
    pop   cx
    jz    match
    add   bx, 32
    loop  dirloop

    ; Not found, display and halt.
    ;
    mov   si, OFFSET filename
    call  print
    jmp   $

  match:
    mov   si, OFFSET ok
    call  print
    jmp   $ 

    ;mov   ax,[bx].deStartCluster
    ;ASSUME bx:NOTHING

;---------------------------------------------------------------
; This code uses the BIOS Write Teletype function to display
; an ASCIIZ string.
;
; Parameters:
;   ds:si = address of string
; Uses:
;   ax bx si
; Returns:
;   nothing 
;---------------------------------------------------------------
;
  print:
    mov   ah, 0Eh
    xor   bx, bx
  @@:
    lodsb
    or    al, al
    jz    @F
    int   10h
    jmp   @B
  @@:
    ret
   
;---------------------------------------------------------------
; This code uses the BIOS Read Disk Sectors function to read
; sectors from the first diskette drive into memory. The drive
; number and destination address (ES:BUFFER_BASE) are hard
; coded, and the read cannot span tracks.
;
; Parameters:
;   al    = number of sectors to read (cannot span tracks)
;   ch    = cylinder number (0-79)
;   cl    = starting sector number (1-18)
;   dh    = head number (0-1)
; Uses:
;   ax bx cx dx si
; Returns:
;   CF set on error
;---------------------------------------------------------------
;
  readdisk:
    mov   si, 4           ; maximum of 4 tries
    xor   dl, dl          ; drive = 0
    mov   bx, BUFFER_BASE
  @@:
    mov   ah, 2           ; read disk sectors
    int   13h
    jnc   @F              ; finished if no error
    xor   ah, ah          ; reset diskette drive and controller
    int   13h
    jc    @F              ; finished if error
    dec   si              ; dec does not affect carry flag
    jnz   @B
  @@:
    ret

comment ^
AH = 02h
AL = number of sectors to read (must be nonzero)
CH = low eight bits of cylinder number
CL = sector number 1-63 (bits 0-5)
     high two bits of cylinder (bits 6-7, hard disk only)
DH = head number
DL = drive number (bit 7 set for hard disk)
ES:BX -> data buffer
 
AH = 00h
DL = drive (if bit 7 is set both hard disks and floppy disks reset)
  Return: AH = status (see #00234)
CF clear if successful (returned AH=00h)
CF set on error
^
;---------------------------------------------------------------
; This code is from the MS-DOS Encyclopedia, Ray Duncan (ed.),
; Microsoft Press, 1988.
;
; Obtains the next link number from a 12-bit FAT.
;
; Parameters:
;   ax    = current entry (cluster) number
;   ds:bx = address of FAT (must be contiguous)
; Uses:
;   bx cx
; Returns:
;   ax    = next link number
;---------------------------------------------------------------
;
  next12:
    add   bx,ax    ; ds:bx = partial index
    shr   ax,1     ; ax = offset/2
                   ; carry = shift needed
    pushf          ; save carry
    add   bx,ax    ; ds:bx = next cluster number index
    mov   ax,[bx]  ; ax = next cluster number
    popf           ; carry = shift needed
    jc    shift    ; skip if using top 12 bits
    and   ax,0fffh ; ax = lower 12 bits
    ret
  shift:
    mov   cx,4     ; cx = shift count
    shr   ax,cl    ; ax = top 12 bits in lower 12 bits
    ret
;---------------------------------------------------------------

    ; MAKEIT.BAT generates a listing file that can be used to
    ; determine exactly what MASM assembled, and how much of
    ; the 512 bytes allocated for a boot sector has been filled
    ; with code and data. For this source, there are 365 free
    ; bytes between the above RET instruction and the signature.
    ;
    org   7C00h + 510
    db    55h,0AAh

_TEXT ENDS

end entry

Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: dedndave on January 16, 2013, 04:24:47 AM
my guess is that you are trying to read "sector number 20" from track 0, head 0
you need to take into account that each head/track on a 1.44 mb floppy has only 18 sectors   :P

the stepping order is
sector
head
cylinder

in this file, i disassembled a boot sector from DOS 5.0 to see how it works
you can see how the root directory sector and first data sector are calculated
Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: Vortex on January 16, 2013, 06:04:10 AM
Hi MichaelTripi68,

Maybe off-topic but you can have a loot at Mtools :

QuoteMtools is a collection of utilities to access MS-DOS disks from GNU and Unix without mounting them. It supports Win'95 style long file names, OS/2 Xdf disks and 2m disks (store up to 1992k on a high density 3 1/2 disk). In addition to file access, it supports many FAT-specific features: volume labels, FAT-specific file attributes (hidden, system, ...), "bad block" map maintenance, access to remote floppy drives, Iomega ZIP disk protection, "secure" erase, display of file's on-disk layout, etc.

http://www.gnu.org/software/mtools/intro.html
Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: MichaelTripi68 on January 16, 2013, 07:05:41 AM
Thanks everyone....I will have time later after work to try your suggestions/code samples.
Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: sinsi on January 16, 2013, 09:09:48 AM
Debug also uses int 25h to read/write which is not CHS, more like LBA.
Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: dedndave on January 16, 2013, 09:14:26 AM
that's the "absolute" read function (i think 26h is the absolute write)
it can work on CHS - you just have to calculate the sector

EDIT: neither of those is available at boot-time, however   :icon_eek:
Title: Re: Need Help!! Reading a floppy (FAT12) root directory.
Post by: MichaelW on January 16, 2013, 01:06:42 PM
Ane even after boot they are limited to logical sectors.