;-------------------
; diskinfo.asm - displays data found in boot loader.
; James Vahn - Public Domain

cseg segment
assume cs:cseg
org 100h

;*********************************************************************
; Variable declarations.

 o      EQU offset                      ;Saves some typing later. 8-)
 w      EQU word ptr
 b      EQU byte ptr

_epb    STRUC                         ;Extended Parameter Block if>32 megs
        sector          dd ?            ;Logical sector
        nsects          dw ?            ;Number of sectors to read/write
        bufoff          dw ?            ;Far pointer to disk buffer
        bufseg          dw ?            ;
_epb    ENDS

_bpb    STRUC                         ;Boot Record Block - BPB
        dummy    db 3 dup (?)           ;JMP -> (usually loader code)
        OEMname  db 8 dup (?)           ;DOS Manufacturer
        sectsize        dw ?            ;bytes per sector
        clsize          db ?            ;Sectors per cluster
        ressect         dw ?            ;Number of reserved sectors
        fats            db ?            ;Number of FATs
        rootnum         dw ?            ;Number of Root entries
        numsects        dw ?            ;Number of logical sectors (if<32m,0)
        mdb             db ?            ;Media Descriptor Byte
        fatsize         dw ?            ;FAT size in sectors
        trksize         dw ?            ;Sectors per track
        heads           dw ?            ;Number of heads
        hidden          dd ?            ;Number of hidden sectors
        bigsects        dd ?            ;Number of logical sectors (if>32m)
        drive           db ?            ;Physical drive (FD=0, HD=80h)
        nada            db ?            ;Reserved for DOS, unknown
        DOSsig          db ?            ;DOS signature, 29h
        serial          dd ?            ;Serial number
        dlabel  db 11 dup (?)           ;Disk label
        systype db 8  dup (?)           ;System type
_bpb    ENDS

_txt    STRUC
        oem     db 13,10,'                OEM Manufacturer  $'
        ssize   db 13,10,'                Bytes per sector  $'
        csize   db 13,10,'             Sectors per cluster  $'
        rserv   db 13,10,'      Number of reserved sectors  $'
        nfats   db 13,10,'                  Number of FATs  $'
        nroot   db 13,10,'      Max number of Root entries  $'
        nusects db 13,10,'       Number of logical sectors  $'
        media   db 13,10,'           Media Descriptor Byte  $'
        sfat    db 13,10,'             FAT size in sectors  $'
        spt     db 13,10,'               Sectors per track  $'
        nheads  db 13,10,'                 Number of heads  $'
        nhsects db 13,10,'        Number of hidden sectors  $'
        ph_drv  db 13,10,'             Physical drive type  $'
        sernum  db 13,10,'                   Serial number  $'
        dsklbl  db 13,10,'       Disk label in Boot Sector  $'
        dsklbl2 db 13,10,'    Disk label in Root Directory  $'
        system  db 13,10,'                File system type  $'
_txt    ENDS

;**************************************************************************
; Our code begins..

Begin:
        mov     dx,o signon             ;Print a sign-on message.
        call    prnt
        mov     al,es:[80h]             ;Get command line parameter.
        cmp     al,2
        jb      _df                     ;No parameters, default to C:
        mov     al,es:[82h]
        or      al,00100000b
        sub     al,'a'                  ;Convert to Number. A=0, B=1, etc.
        mov     src_drv,al
  _df:
        mov     [epb.bufseg],cs         ;Setup extended parameter block.
        mov     [epb.bufoff],o bpb      ; Buffer pointer.
        mov     [epb.nsects],01h        ; Number of sectors to read.
        mov     w[epb.sector+2],0       ; Read first absolute sector.
        mov     w[epb.sector],0         ; sector = 0,0,0,0
        call    read

        mov     dx,o txt.OEM            ;Display OEM of boot sector.
        call    prnt
        mov     si,o bpb.OEMname
        mov     cx,8
  sout: lodsb
        int     29h
        loop    sout

        mov     dx,o txt.ssize          ;Display sector size.
        call    prnt
        mov     ax,bpb.sectsize
        call    Bin2DEC

        mov     dx,o txt.csize          ;Display cluster size.
        call    prnt
        mov     ah,0
        mov     al,bpb.clsize
        call    Bin2DEC

        mov     dx,o txt.rserv          ;Display reserved sectors.
        call    prnt
        mov     ax,bpb.ressect
        call    Bin2DEC

        mov     dx,o txt.nfats          ;Display number of FATs.
        call    prnt
        mov     ah,0
        mov     al,bpb.fats
        call    Bin2DEC

        mov     dx,o txt.nroot          ;Display max. number of root
        call    prnt                    ; entries.
        mov     ax,bpb.rootnum
        call    Bin2DEC

        mov     dx,o txt.nusects        ;Display number of logical sectors
        call    prnt                    ; on the drive.
        mov     dx,0
        mov     ax,bpb.numsects
        cmp     ax,0
        jne     _bp
        mov     ax,w bpb.bigsects
        mov     dx,w bpb.bigsects + 2
   _bp: call    _32bin2DEC

        mov     dx,o txt.media          ;Display Media Descriptor Byte
        call    prnt
        mov     ah,0
        mov     al,bpb.mdb
        call    Bin2HEX

        mov     dx,o txt.sfat           ;Display size of FAT.
        call    prnt
        mov     ax,bpb.fatsize
        call    Bin2DEC

        mov     dx,o txt.spt            ;Display sectors per track.
        call    prnt
        mov     ax,bpb.trksize
        call    Bin2DEC

        mov     dx,o txt.nheads         ;Display number of heads.
        call    prnt
        mov     ax,bpb.heads
        call    Bin2DEC

        mov     dx,o txt.nhsects        ;Display number of hidden sectors.
        call    prnt
        mov     ax,w bpb.hidden
        mov     dx,w bpb.hidden + 2
        call    _32Bin2DEC

        mov     dx,o txt.ph_drv         ;Display physical drive number.
        call    prnt
        mov     ah,0
        mov     al,bpb.drive
        call    Bin2DEC

        mov     dx,o txt.sernum         ;Display serial number.
        call    prnt
        mov     ax,w bpb.serial + 2
        call    Bin2HEX
        mov     al,'-'
        int     29h
        mov     ax,w bpb.serial
        call    Bin2HEX

        mov     dx,o txt.dsklbl         ;Display disk label found in
        call    prnt                    ; boot sector.
        mov     si,o bpb.dlabel
        mov     cx,11
 sout2: lodsb
        int     29h
        loop    sout2

     ;**************************************************************
     ;Sometimes there is no disk label in the boot sector, so here ;
     ; we will search the root directory for one.                  ;
     ;**************************************************************

        mov     al,[bpb.fats]           ;Get disk label from Root directory.
        mov     ah,0                    ;
        mul     [bpb.fatsize]           ;Number of FATs * size of each
        add     ax,[bpb.ressect]        ; plus #of reserved sectors = root.
        mov     w[epb.sector+2],dx      ;Save this in the parameter block.
        mov     w[epb.sector],ax        ; DX:AX -> root sector
                                        ;
        mov     ax,[bpb.rootnum]        ;Number of sectors in root directory
        mov     bx,20h                  ; that we need to read.
        mul     bx                      ; #of Entries *  20h bytes each
        div     [bpb.sectsize]          ; divided by bytes per sector (512).
        add     ax,1                    ;
        mov     [epb.nsects],ax         ;
                                        ;
        mov     [epb.bufseg],cs         ;Setup extended parameter block.
        mov     [epb.bufoff],o buffer   ; Buffer pointer.
        call    read                    ;
                                        ;
        mov     cntr,0                  ;
        mov     dx,o txt.dsklbl2        ;Display "disk label" text.
        call    prnt                    ;
        mov     si,o buffer             ;
        add     si,0Bh                  ;attribute offset. Bit 3 = label.
  srch: mov     al,[si]                 ;
        add     si,20h
        inc     cntr                    ;
        mov     bx,cntr                 ;
        cmp     bx,[bpb.rootnum]        ;
        ja      exit                    ;All entries have been tested.
        test    al,00001000b            ;Is bit 3 set?
        jz      srch                    ; no, look for more.
        ;cmp     al,28h
        ;jne     srch
        sub     si,2Bh                  ;Found the attribute, get label.
        mov     cx,11                   ;Label is 11 bytes, padded with
 sout3: lodsb                           ; spaces. Print everything via
        int     29h                     ; INT 29.
        loop    sout3                   ;

        mov     dx,o txt.system         ;Display system type (FAT16, FAT12)
        call    prnt
        mov     si,o bpb.systype
        mov     cx,8
 sout4: lodsb
        int     29h
        loop    sout4

exit:   mov     al,0                    ;No errors, drop through.
error:  mov     ah,4Ch                  ;Exit to DOS, errorlevel = AL
        int     21h
;*************************************************************************
 prnt proc near
  ;Print text, enter with offset in DX.
  ;
        mov ah,9
        int 21h
        ret
endp

;*************************************************************************
 read proc near
  ; Read the drive, data returned in buffer.
  ;
        mov     al,src_drv              ;Drive number.
        mov     bx,epb.bufoff
        mov     cx,[epb.nsects]         ;Number of sectors to read.
        mov     dx,w[epb.sector]        ;Starting logical sector.
        int     25h
        jc      big1
        jmp     rd_ok                   ;No carry: a small partition.
big1:
        popf                            ;It must be a >32 meg partition
        mov     al,src_drv              ; so try again.
        mov     bx,o epb
        mov     cx,-1                   ;Flag for large partition.
        int     25h
        jnc     rd_ok
        popf
        pop     dx                      ;Clean stack.
        mov     al,1                    ;An error occured, exit errlv 1.
        jmp     error
rd_ok:
        popf
        ret
endp

;*************************************************************************
 write proc near
  ; write the buffer to the drive.  Unused procedure.
  ;
        mov     al,src_drv              ;Drive number.
        mov     bx,o buffer
        mov     cx,[epb.nsects]         ;Number of sectors to read.
        mov     dx,w[epb.sector]        ;Starting logical sector.
        int     26h
        jc      big1a
        jmp     wt_ok                   ;No carry: a small partition.
big1a:
        popf                            ;It must be a >32 meg partition
        mov     al,src_drv              ; so try again.
        mov     bx,o epb
        mov     cx,-1                   ;Flag for large partition.
        int     26h
        jnc     wt_ok
        popf
        pop     dx                      ;Clean stack.
        mov     al,1                    ;An error occured, exit errlv 1.
        jmp     error
wt_ok:
        popf
        ret
endp

;********************************************
 Bin2DEC proc near
  ;Converts AX to DEC ASCII output
        mov     dx,0
        call    _32Bin2DEC
        ret
endp

;*********************************************
 Bin2HEX proc near
  ;Convert AX to HEX ASCII output
  ;Uses AX, BX, CX, DX

bin2he: mov     cx,4                    ;4 hex digits
        mov     bx,10h                  ;divisor
bin2h1: xor     dx,dx                   ;zero DX for 16 bit divide
        div     bx                      ;leaves quotient in AX
        add     dl,'0'                  ;convert remainder to ASCII
        cmp     dl,'9'
        jna     bin2h2
        add     dl,'A'-'9'-1
bin2h2: push    dx                      ;put on stack
        loop    bin2h1
        mov     cx,4                    ;Do 4 HEX digits.
bin2h3: pop     ax                      ;pop most significant digit first
        mov     dl,al                   ;output HEX digit in AL
        mov     ah,02h
        int     21h
        loop    bin2h3
        ret
endp

;*************************************************************************
 _32bin2DEC proc near
   ; Converts unsigned integer in DX:AX to ASCII output.
   ; Uses AX,BX,CX,DX

_doubleword2:
        call    _doubleword_div10
        cmp     ax, dx          ;See if dx:ax=0
        jnz     L1
        or      ax, ax
        jz      L2
L1:
        push    bx
        call    _doubleword2
        pop     bx
L2:
        mov     al, bl
        or      al, '0'
        push    dx
        mov     dl, al
        mov     ah, 02h
        int     21h
        pop     dx
        ret

_doubleword_div10:
        mov     cx, 10
        mov     bx, ax
        xchg    ax, dx
        xor     dx, dx
        div     cx
        xchg    bx, ax
        div     cx
        xchg    dx, bx
        ret
endp

;*************************************************************************
; The data definitions.
signon    db 'DiskInfo - display data in boot loader.',13,10
          db '           Syntax: diskinfo <a b c d ...>',13,10,36
cntr      dw    0      ;General purpose counter.
txt       _txt <>      ;Program text.
src_drv   db    2      ;Target drive from command line, default to C:
epb       _epb <>      ;Extended DOS parameters.
bpb       _bpb <>      ;BIOS parameter block from first sector. Dynamic.
buffer    dw    ?      ;Data buffer. Dynamic, do not move.
;**************************************************************************

cseg    ends
end     Begin

