You are on page 1of 12

;*******************************************************************

; Copyright (C) 1991-2008 Pierre R. Desloover. All rights reserved.


; Title: LOG2PHY.ASM Version: 1.0 Date: 10-21-91
; Masm: 5.0+ or 6.0, Link to .EXE image
;*******************************************************************

DOSSEG
.MODEL SMALL

.DATA

TRUE = 0ffh
FALSE = 0

;Misc vars, flags, constants


HDdrv_no db 0 ;init to first hard drive
num_hdrvs db 0 ;hard drive count
log_drv_no db 0 ;physical based logical drv no (1=A:,2=B:, etc.)
MAX_LOG_NO = 24 ;maximum HD logical drive number
first_HD_log db 0 ;first logical HD number
know_first_HD_log db FALSE ;flag know first HD logical drive number
SysInventory db FALSE ;flag TRUE if system inventory performed

;text for display


header_text db 13,10,13,10,'LOG DRV BIOS# FAT TYPE HEAD CYL
SEC',13,10,13,10,'$'
line_buff db '
',13,10,'$'
cr_lf db 13,10,'$'

;reserved sector buffer for Int 13h, Read function


sec_buffer db 512 dup (?)

;reserved parameter block for IOCTL Get Device Parms function


parm_block db 128 dup (0) ;byte at offset +0 (special
;functions field must be zero)
;define structures for 3 tables
_HDTABLE STRUC
part_flags db 0
num_logic_drvs db 0
sequence_num db 0
_HDTABLE ENDS

;structure _hdtable partition flag equates


PRIM_PARTITION = 80h
PRIM_ASSIGNED = 40h
SEC_PRIM_PART = 20h
SEC_PRIM_ASSIGN = 10h

_HDPHYS STRUC
bios_HD_num db 0
fat_type db 0
head db 0
cylinder db 0
sector db 0
_HDPHYS ENDS

_HDindex STRUC
IDXlogdrive_num db 0
IDXbios_HD_num db 0
IDXfat_type db 0
IDXhead db 0
IDXcylinder db 0 ;cylinder# (low order 7 bits)
IDXsector db 0 ;sector# (bits 5-0); bits 7,6 (cylinder 2 high bits)
_HDindex ENDS

EVEN

;Create multiple structures of type _HDTABLE with default init. values


;for up to max number of HD DOS logical letters (C: - Z: =24)
possible.
HDtable _HDTABLE <>
SIZE_HDentry = $ - HDtable
HDtable2 _HDTABLE MAX_LOG_NO-1 DUP (<>)

EVEN

;Create multiple structures of type _HDPHYS with default init. values


HDphys _HDPHYS <>
SIZE_HDphys = $ - HDphys
HDphys2 _HDPHYS MAX_LOG_NO-1 DUP (<>)

EVEN

;Create multiple structures of type _HDINDEX with default init. values


HDindex _HDINDEX <>
SIZE_HDindex = $ - HDindex
HDindex2 _HDINDEX MAX_LOG_NO-1 DUP (<>)

; ----------------------------------------------
; MAIN: HIGH LEVEL DEMONSTRATION TEST CODE
; ----------------------------------------------

.CODE

START:
mov ax,@DATA
mov ds,ax
mov es,ax

;display header text line


mov dx,offset header_text
mov ah,9
int 21h
;init. operand logical drive number to drive A
mov [log_drv_no],1

;init. sys inventory flag


mov [SysInventory],FALSE

NEXT_DRIVE:
;For LOGICAL DOS DRIVE = A: TO Z:

;Perform IOCTL Get Device Parms to validate as hard drive


mov ax,440dh
mov bl,[log_drv_no]
mov cx,0860h
mov dx,offset parm_block
int 21h
jc next_drv ;error, skip this logical drv

;check parm block offset +1 for device type id


mov bx,dx
cmp byte ptr [bx][1],5 ;HD type device?
jne next_drv ;not Hard drive

;have logical HD, save first logical HD number


mov al,[log_drv_no]
cmp [know_first_HD_log],TRUE
je map_log_to_phy ;already know it
mov [know_first_HD_log],TRUE
mov [first_HD_log],al ;save first logical HD number

map_log_to_phy:
call HDMapLogToPhy ;DS:SI gets ptr to log drv's info
jz next_drv ;no entry in HDindex for this drive

;Have valid entry in HDindex table for this logical drive. Extract
data
;from table using returned ptr, convert, format it and display it.
call format_linebuff

NEXT_DRV:
;inc drive letter id
inc [log_drv_no]
cmp [log_drv_no],MAX_LOG_NO ;max is logical drive 'Z'
jbe next_drive ;do next logical drive

;test is done
mov dx,offset cr_lf
mov ah,9
int 21h

;term prog
mov ax,4c00h
int 21h

FORMAT_LINEBUFF proc
;Format logical drive's data for display
;On entry: DS:SI has ptr to logical drives's entry in table HDindex

;get, convert, and plug logical drive letter in display line buffer
cld
lodsb
add al,'A'-1
mov ah,':'
mov bp,offset line_buff+3
mov ds:[bp],ax
add bp,7

;get BIOS HD number, convert and plug in line buffer


lodsb
call val_to_hex_ascii
mov byte ptr ds:[bp][2],'H'
add bp,9

;get FAT type


lodsb
call val_to_hex_ascii
add bp,8

;get HEAD number


lodsb
call val_to_hex_ascii
add bp,5

;get CYLINDER number


lodsb
call val_to_hex_ascii
mov byte ptr ds:[bp][2],'H'
add bp,5

;get SECTOR number


lodsb
call val_to_hex_ascii
mov byte ptr ds:[bp][2],'H'

;display line buffer


mov dx,offset line_buff
mov ah,9
int 21h
ret
FORMAT_LINEBUFF endp

VAL_TO_HEX_ASCII proc
;On entry: AL contains byte value to convert to hex ascii.
; BP has ptr to buffer that will get ascii string
;Note: No leading zero supression
;On exit: DI has length of string excluding null terminating byte

xor di,di

hex_16s:
xor ah,ah
mov bl,16
div bl
call store_hex_char

hex_ones:
mov al,ah ;use remainder
call store_hex_char
ret
VAL_TO_HEX_ASCII endp

STORE_HEX_CHAR proc
add al,'0'
cmp al,'9'
jbe to_buffer
add al,'@'-'9'
to_buffer:
mov byte ptr ds:[bp][di],al
inc di
ret
STORE_HEX_CHAR endp

; ------------------------------------------------------
; LOW LEVEL FUNCTIONS: HDMapLogToPhy and HDSysInventory
; ------------------------------------------------------

HDMapLogToPhy proc
;On Entry: reg AL contains physical based logical drive number
;On Exit : ZR clr and DS:SI contains dword pointer to offset +0
; of logical drive's entry in HDIndex table, else ZR set
; indicating no valid data found for drive in HDindex.

push ax

;has system HD inventory been performed yet?


cmp [SysInventory],TRUE
je get_ptr_to_log_info ;yes

;perform system inventory


call HDSysInventory

get_ptr_to_log_info:
;get ptr to logical drive's entry in HDIndex table
pop ax

;Use [log_drv_no] - [first_HD_log] as zero based index into


;prepared HDIndex table
mov ah,[first_HD_log]
sub al,ah
xor ah,ah
mov dl,SIZE_HDindex
mul dl
mov si,offset HDindex
add si,ax ;SI gets offset

;Check if have valid data in HDindex for this logical drive. A zero
;value in first field (logical drive #) indicates no data. Comparison
;here sets or clrs ZR flag that can be tested by caller.
cmp byte ptr [si],0
RET

HDMapLogToPhy endp

; ----------------------------------------------
; FUNCTION: HDSysInventory
; ----------------------------------------------

HDSysInventory proc
;Perform system hard drive inventory, apply DOS logical drive
assignment
;rules to build final lookup table to be used by proc HDMapLogToPhy.

mov [SysInventory],TRUE ;set this flag

mov al,[log_drv_no] ;preserve caller's value


push ax

;Use BIOS Int 13h, fcn 15h (read DASD type) to determine total # hard
drives
;in system instead of fcn 8h (return drv parms) because although fcn 8
;does infact return count of hard drives beyond 2, it's undocumented.
mov [num_hdrvs],0ffh ;init count to -1
mov dl,80h

count_hdrvs:
inc [num_hdrvs]
mov ah,15h
push dx
int 13h
pop dx
inc dl ;next hard drv #
cmp ah,3 ;hard drive?
je count_hdrvs ;yes, check for next one

;init BX, SI to start of HDtable, HDphys


mov bx,offset HDtable
mov di,offset HDphys
PROCESS_HD:
;Process each physical hard drive and update HDtable with
;partition and logical drive info.
mov dl,[HDdrv_no]
or dl,80h
mov dh,0 ;head 0
mov cl,1 ;sector# (bits 5-0); bits 7,6 (cylinder 2 high
bits)
mov ch,0 ;cylinder# (low order 7 bits)

call read_sector
jc next_HD ;read failed, num_logic_drvs in HDtable
;entry for this HD remains 0

ck_first_partition_table:
;FOR partition entry = 1 to 4 (16 bytes each)
mov si,offset sec_buffer+1beh ;partition bias in first sector

process_part_table:
cmp byte ptr [si][4],0 ;ck TYPE part. Used?
jz DONE_PART_TABLE ;no, assume no entries follow

;have entry, find out what, eliminate DOS primary first


call ck_primary_part
jz mark_primary

;not primary, eliminate DOS extended type before flaging as second


primary
;(other operating systems partition)
cmp byte ptr [si][4],5
je process_extended

;not DOS extended, mark as second primary


or [bx].part_flags,SEC_PRIM_PART
inc [bx].num_logic_drvs
jmp short update_hdphys_tab

mark_primary:
or [bx].part_flags,PRIM_PARTITION
inc [bx].num_logic_drvs

update_hdphys_tab:
;update HDphys table with this logical drive's info
call update_HDphys

next_part_tab_entry:
add si,16
jmp short process_part_table

process_extended:
;Extended partition table can only have up two entries in it:
;one for the logical drive and a possible extended entry for
;next logical drive in this extended partition.
;Therefore we continue to process extended partition obtaining
;new first sectors for any additional logical drives.

;obtain head, cylinder and sector of start extended partition


mov dl,[HDdrv_no]
or dl,80h
mov dh,[si][1] ;head#
mov cx,[si][2] ;sector# (bits 5-0); bits 7,6 (cylinder 2 high
bits) and cylinder# (low order 7 bits)

call read_sector
jc next_HD ;read failed, do not process any more
;logical drives for this extended partition

;re-init to first entry of extended partition table


mov si,offset sec_buffer+1beh ;partition bias in first sector

process_ext_entry:
;end of extended table?
cmp byte ptr [si][4],0 ;ck TYPE part. Used?
Jz next_HD ;no, done ext table

;have entry, find out what, eliminate DOS logical drive type
call ck_primary_part
jz inc_log_count

;not logical drive, have another extended?


cmp byte ptr [si][4],5
je process_extended

inc_log_count:
inc [bx].num_logic_drvs

;update HDphys table with this logical drive's info


call update_HDphys

next_ext_entry:
add si,16 ;next ext partition table entry
jmp short process_ext_entry

NEXT_HD:
call next_HDentry
jb PROCESS_HD

DONE_PART_TABLE:
;Now Apply DOS Logical drive assignment rules.
mov al,[first_HD_log]
mov [log_drv_no],al
mov di,offset HDindex

PROCESS_A_Z:
;Process entries marked with primary attribute first.
;Check remaining entries in table for primaries to be assigned.
mov bx,offset HDtable
mov [HDdrv_no],0

PRIMARY_CHK:
;any logical drives left on this physical drive?
cmp [bx].num_logic_drvs,0
jz next_prim_ck ;no

test [bx].part_flags,PRIM_PARTITION
jz next_prim_ck
test [bx].part_flags,PRIM_ASSIGNED
jnz next_prim_ck

;have un-assigned primary, assign it


or [bx].part_flags,PRIM_ASSIGNED
call create_index_table_entry
call update_remain_and_seq_numbers
jmp short NEXT_LOG ;this log drive done

next_prim_ck:
call next_HDentry
jb primary_chk

;no more primaries, now process logical drives that were found in
;extended partitions
mov bx,offset HDtable
mov [HDdrv_no],0

LOGICAL_CHK:
;any logical drives left?
cmp [bx].num_logic_drvs,0
je next_log_ck

;yes, update HDtable entry for this log drive and display stats
call create_index_table_entry
call update_remain_and_seq_numbers
jmp short NEXT_LOG ;this log drive done

next_log_ck:
call next_HDentry
jb logical_chk

;no more extended partition logical drives, now process possible


;secondary primaries in order found
mov bx,offset HDtable
mov [HDdrv_no],0

SECOND_PRIM_CHK:
;any logical drives left on this physical drive?
cmp [bx].num_logic_drvs,0
jz next_sec_prim_ck ;no

test [bx].part_flags,SEC_PRIM_PART
jz next_sec_prim_ck
test [bx].part_flags,SEC_PRIM_ASSIGN
jnz next_sec_prim_ck

;have un-assigned secondary primary, assign it


or [bx].part_flags,SEC_PRIM_ASSIGN
call create_index_table_entry
call update_remain_and_seq_numbers
jmp short NEXT_LOG ;this log drive done

next_sec_prim_ck:
call next_HDentry
jb second_prim_chk

NEXT_LOG:
;next logical drive
inc [log_drv_no]
cmp [log_drv_no],MAX_LOG_NO
jbe PROCESS_A_Z

pop ax ;recover caller's value


mov [log_drv_no],al
RET

HDSysInventory endp

; ----------------------------------------------
; MISC SUPPORT PROCS
; ----------------------------------------------

READ_SECTOR proc
;On Entry: ax, cx, dx contains values:
; dl = bios hard disk number
; dh = head number
; cl = sector# (bits 5-0); bits 7,6 (cylinder 2 high bits)
; ch = cylinder# (low order 7 bits)
;On exit: CY set if could not read drive, else CY clr

push bx
mov bx,offset sec_buffer
mov ax,0201h ;read one sector
int 13h
pop bx
ret
READ_SECTOR endp

NEXT_HDENTRY proc
;On exit: bx ptr updated to next hdtable entry
; var HDdrv_no incremented
; CY set if have another entry to process

add bx,SIZE_HDentry ;point to next HD tab entry


inc [HDdrv_no] ;zero based
mov al,[HDdrv_no]
cmp al,[num_hdrvs] ;physical based
ret
NEXT_HDENTRY endp

CK_PRIMARY_PART proc
;On exit: ZR flag set if have DOS primary partition type
; AL has partition type

mov al,byte ptr [si][4]


cmp al,1
je exit_ck
cmp al,4
je exit_ck
cmp al,6
exit_ck:
ret
CK_PRIMARY_PART endp

UPDATE_HDPHYS proc
;On entry: al has partition fat type
;On Exit : ptr to HDphys is updated to next available table entry

mov [di].fat_type,al ;store fat type


mov al,[si][2] ;get cyl+sector byte
mov [di].sector,al
mov al,[si][3] ;get cylinder low 7 bits
mov [di].cylinder,al
mov al,[HDdrv_no] ;get current HD logical #
mov [di].bios_HD_num,al
add di,SIZE_HDphys ;point to next HDphys entry
ret
UPDATE_HDPHYS endp

CREATE_INDEX_TABLE_ENTRY proc
;create index table entry from HDtable and HDPhys table info
;first locate operand HD in table by indexing on [HDdrv_no]

push si
push di

mov si,offset HDphys-SIZE_HDphys


mov ah,[HDdrv_no]
find_HD_log_no:
add si,SIZE_HDphys
cld
lodsb
cmp al,ah
jne find_HD_log_no

;add in offset to this HD's operand log drive


dec si ;adjust source ptr
mov al,[bx].sequence_num
xor ah,ah
mov dl,SIZE_HDphys
mul dl
add si,ax

;move data to index table, di ptr to available table entry


mov al,[log_drv_no]
mov byte ptr [di],al ;store DOS logical drv no
inc di
mov al,byte ptr [si] ;get HD logical number
or al,80h ;convert to BIOS HD number
mov byte ptr [di],al ;and store it
inc di
inc si

;move rest of data


mov cx,SIZE_HDphys-1
cld
rep movsb

pop di
add di,SIZE_HDindex ;point to next IDX avail. entry
pop si
ret
CREATE_INDEX_TABLE_ENTRY endp

UPDATE_REMAIN_AND_SEQ_NUMBERS proc
;obtain logical sequence number, increment it and decrement
;remaining log drvs for this entry
;Return: al has log drv seq number (one based)

mov al,[bx].sequence_num
inc al ;make physical based
inc [bx].sequence_num
dec [bx].num_logic_drvs
ret
UPDATE_REMAIN_AND_SEQ_NUMBERS endp

END START

You might also like