350 lines
14 KiB
NASM
350 lines
14 KiB
NASM
; rawread.asm
|
|
;
|
|
; this program reads a DOS cluster using only BIOS disk calls. All
|
|
; of the tasks usually done by DOS, e.g. FAT lookup, cluster to
|
|
; logical sector translation, logical to physical translation, are
|
|
; all done by this program instead. The idea is to be able to create
|
|
; a program that can access DOS disks from a bootable floppy without
|
|
; having to have DOS.
|
|
;
|
|
; well, that's what it used to do. Now it's supposed to do something
|
|
; completely different. Its job is to scan the entire surface of the
|
|
; hard drive, looking for the specified string. If that string is
|
|
; found, it is to print the full path and directory entry, including
|
|
; the file date and time.
|
|
;
|
|
; but wait! There's more. Now what we have is a number of raw
|
|
; routines which could prove useful for manipulating a DOS file
|
|
; structure outside of the DOS environment. The main routine still
|
|
; should be kept (if renamed), since the order in which these things
|
|
; are done is important (e.g. later calls depend on data set up by
|
|
; earlier calls).
|
|
;
|
|
; get filename
|
|
; parse filename into subdirs
|
|
; locate root dir and cluster size
|
|
; follow subdir routing to filename
|
|
; report file size, date & time
|
|
;
|
|
.MODEL small
|
|
.STACK 0200h
|
|
.586P
|
|
|
|
.DATA
|
|
PartEntry STRUC
|
|
Bootable db ? ;80h = bootable, 00h = nonbootable
|
|
BeginHead db ? ;beginning head
|
|
BeginSector db ? ;beginning sector
|
|
BeginCylinder db ? ;beginning cylinder
|
|
FileSystem db ? ;name of file system
|
|
EndHead db ? ;ending head
|
|
EndSector db ? ;ending sector
|
|
EndCylinder db ? ;ending cylinder
|
|
StartSector dd ? ;starting sector (relative to beg. of disk)
|
|
PartSectors dd ? ;number of sectors in partition
|
|
PartEntry ENDS
|
|
|
|
BootSector STRUC
|
|
Jump db ? ;E9 xx xx or EB xx 90
|
|
JumpTarget dw ? ;E9 xx xx or EB xx 90
|
|
OemName db '????????' ;OEM name & version
|
|
;Start of BIOS parameter block
|
|
BytesPerSec dw ? ;bytes per sector
|
|
SecPerClust db ? ;sectors per cluster
|
|
ResSectors dw ? ;number of reserved sectors
|
|
FATs db ? ;number of file allocation tables
|
|
RootDirEnts dw ? ;number of root-dir entries
|
|
Sectors dw ? ;total number of sectors
|
|
Media db ? ;media descriptor byte
|
|
FATsecs dw ? ;number of sectors per FAT
|
|
SecPerTrack dw ? ;sectors per track
|
|
Heads dw ? ;number of heads
|
|
HiddenSecs dd ? ;number of hidden sectors
|
|
HugeSectors dd ? ;num sectors if Sectors==0
|
|
;End of BIOS parameter block
|
|
BootSector ENDS
|
|
|
|
DirEntry STRUC
|
|
FileName db '????????' ;name
|
|
Extension db '???' ;extension
|
|
Attributes db ? ;attributes
|
|
Reserved db 10 dup (?) ;reserved
|
|
Time dw ? ;time stamp
|
|
Date dw ? ;date stamp
|
|
StartCluster dw ? ;starting cluster
|
|
FileSize dd ? ;file size
|
|
DirEntry ENDS
|
|
|
|
BootFileName db "CONFIG SYS" ;the boot loader for this OS
|
|
MBR DB 0200h DUP (?)
|
|
buff DB 0200h * 40h DUP (?)
|
|
ClustOffs dd ?
|
|
|
|
CR EQU 0DH
|
|
LF EQU 0AH
|
|
|
|
|
|
.CODE
|
|
main PROC
|
|
STARTUPCODE ;initialize stuff
|
|
call FetchMBR C ;fetch the master boot record
|
|
jc @@exit
|
|
mov cx,4 ;search up to four partitions
|
|
add bx,01aeh ;point to partition table (-10h)
|
|
@@FindBootable:
|
|
add bx,10h ;point to next entry
|
|
cmp BYTE ptr [bx],80h ;is it a bootable partition?
|
|
loopnz @@FindBootable
|
|
call FetchSector C, \
|
|
WORD ptr [(PartEntry PTR bx).BeginHead], \
|
|
WORD ptr [(PartEntry PTR bx).BeginSector], \
|
|
WORD ptr [(PartEntry PTR bx).BeginCylinder], \
|
|
OFFSET MBR, ds ;SEG MBR
|
|
;
|
|
; here's the point at which our OS loader would begin, with the
|
|
; BootSector structure in memory.
|
|
;
|
|
mov bx, OFFSET MBR
|
|
call CalcClustOff C, \
|
|
WORD ptr [(BootSector PTR bx).ResSectors], \
|
|
WORD ptr [(BootSector PTR bx).FATsecs], \
|
|
WORD ptr [(BootSector PTR bx).FATs], \
|
|
WORD ptr [(BootSector PTR bx).RootDirEnts], \
|
|
WORD ptr [(BootSector PTR bx).BytesPerSec], \
|
|
WORD ptr [(BootSector PTR bx).SecPerClust]
|
|
mov WORD ptr [ClustOffs],ax
|
|
mov WORD ptr [ClustOffs+2],dx
|
|
call CalcClust2 C, \
|
|
WORD ptr [(BootSector PTR bx).ResSectors], \
|
|
WORD ptr [(BootSector PTR bx).FATsecs], \
|
|
WORD ptr [(BootSector PTR bx).FATs]
|
|
; now dx:ax contains the logical sector for cluster 2
|
|
call LsectToGeom C, \
|
|
ax, dx, \
|
|
WORD ptr [(BootSector PTR bx).HiddenSecs] , \
|
|
WORD ptr [((BootSector PTR bx).HiddenSecs)+2],\
|
|
[(BootSector PTR bx).Heads], \
|
|
[(BootSector PTR bx).SecPerTrack]
|
|
|
|
mov dl,80h
|
|
mov bx,offset buff
|
|
mov al,[(BootSector PTR MBR).SecPerClust]
|
|
mov ah,2h ; get ready to read
|
|
int 13h
|
|
; now find our desired filename within buffer (which has the root dir)
|
|
|
|
call FindFile C, \
|
|
bx, 200h * 40h, offset BootFileName
|
|
xor dh,dh
|
|
mov dl,[(BootSector PTR MBR).SecPerClust]
|
|
mov si,ax
|
|
mov ax,[(DirEntry PTR si).StartCluster]
|
|
mul dx
|
|
add ax,WORD ptr [ClustOffs]
|
|
adc dx,WORD ptr [ClustOffs+2]
|
|
; now dx:ax contains logical sector number for start of file
|
|
|
|
call LsectToGeom C, \
|
|
ax, dx, \
|
|
WORD ptr [(BootSector PTR MBR).HiddenSecs] , \
|
|
WORD ptr [((BootSector PTR MBR).HiddenSecs)+2],\
|
|
[(BootSector PTR MBR).Heads], \
|
|
[(BootSector PTR MBR).SecPerTrack]
|
|
mov dl,80h
|
|
mov ax,204h ; read in 2k worth of data
|
|
int 13h
|
|
|
|
@@exit:
|
|
EXITCODE ;exit to DOS
|
|
ENDP main
|
|
|
|
;
|
|
; FetchMBR - fetches the Master Boot Record from the first physical
|
|
; hard disk and stores it in the location MBR.
|
|
;
|
|
; INPUT: none
|
|
; OUTPUT: AX is error code if CY set, ES:BX ==> MBR
|
|
; DESTROYED: none
|
|
;
|
|
FetchMBR PROC C
|
|
USES cx, dx ;save registers we'll use
|
|
mov dx,80h ;first physical disk
|
|
mov cx,1 ;head 1, sector 0
|
|
mov bx,ds ;
|
|
mov es,bx ;point to boot record buffer
|
|
mov bx,OFFSET MBR ;read into boot record
|
|
mov ax,0201h ;read one sector
|
|
int 13h ;BIOS read
|
|
ret ;return to main
|
|
FetchMBR ENDP
|
|
|
|
;
|
|
; FetchSector - fetches the physical sector described by the passed
|
|
; parameters and stores it in the named buffer
|
|
;
|
|
; INPUT: head, sector, cylinder, buffer
|
|
; OUTPUT: AX is error code if CY set, ES:BX ==> Boot
|
|
; DESTROYED: none
|
|
;
|
|
FetchSector PROC C head:BYTE, sector:BYTE, cylinder:BYTE, buffer:DWORD
|
|
USES cx, dx ;save registers we'll use
|
|
mov ch, [cylinder] ;
|
|
mov cl, [sector] ;
|
|
mov dh, [head] ;
|
|
mov dl, 80h ;first physical hard drive
|
|
les bx, [buffer] ;
|
|
mov ax,0201h ;read one sector
|
|
int 13h ;BIOS read
|
|
ret ;return to main
|
|
FetchSector ENDP
|
|
|
|
;
|
|
; GeomToLsect - converts to logical sector number from the physical
|
|
; geometry (head, cylinder, track). See LsectToGeom.
|
|
;
|
|
; INPUT: cx, dx are set with cylinder/track, and head respectively
|
|
; HiddenSecs, Heads, SecPerTrack
|
|
; OUTPUT: lsect
|
|
; DESTROYED: none
|
|
;
|
|
GeomToLsect PROC C lsect:DWORD, dHiddenSecs:DWORD, \
|
|
dHeads:WORD, dSecPerTrack:WORD, buffer:DWORD
|
|
USES ax ;save registers we'll use
|
|
mov ax, WORD ptr [lsect] ;load lsect into DX:AX
|
|
mov dx, WORD ptr [lsect+2] ;
|
|
stc ;add one additional
|
|
adc ax, WORD ptr [dHiddenSecs] ;add starting sector
|
|
adc dx, WORD ptr [dHiddenSecs+2] ;
|
|
div [dSecPerTrack] ;
|
|
mov cl,dl ;store sector in cl
|
|
xor dx,dx ;
|
|
div [dHeads] ;
|
|
mov dh,dl ;store head in dh
|
|
mov ch,al ;store low 8 bits of cylinder in ch
|
|
shr ax,1 ;
|
|
shr ax,1 ;
|
|
and al,0c0h ;pass through two hi bits only
|
|
or cl,ah ;mov bits into location
|
|
ret ;
|
|
GeomToLsect ENDP
|
|
|
|
;
|
|
; LsectToGeom - converts from logical sector number to the physical
|
|
; geometry (head, cylinder, track) in the form required
|
|
; by the BIOS (Int 13h) disk read and write calls.
|
|
;
|
|
; INPUT: lsect, HiddenSecs, Heads, SecPerTrack
|
|
; OUTPUT: cx, dx are set with cylinder/track, and head respectively
|
|
; DESTROYED: none
|
|
;
|
|
LsectToGeom PROC C lsect:DWORD, lHiddenSecs:DWORD, \
|
|
lHeads:WORD, lSecPerTrack:WORD, buffer:DWORD
|
|
USES ax ;save registers we'll use
|
|
mov ax, WORD ptr [lsect] ;load lsect into DX:AX
|
|
mov dx, WORD ptr [lsect+2] ;
|
|
stc ;add one additional
|
|
adc ax, WORD ptr [lHiddenSecs] ;add starting sector
|
|
adc dx, WORD ptr [lHiddenSecs+2] ;
|
|
div [lSecPerTrack] ;
|
|
mov cl,dl ;store sector in cl
|
|
xor dx,dx ;
|
|
div [lHeads] ;
|
|
mov dh,dl ;store head in dh
|
|
mov ch,al ;store low 8 bits of cylinder in ch
|
|
shr ax,1 ;
|
|
shr ax,1 ;
|
|
and al,0c0h ;pass through two hi bits only
|
|
or cl,ah ;mov bits into location
|
|
ret ;
|
|
LsectToGeom ENDP
|
|
|
|
;
|
|
; CalcClust2 - calculates the starting logical sector number of
|
|
; cluster 2, (the beginning of data space for
|
|
; partitions).
|
|
;
|
|
; INPUT: ResSectors, FATsecs, FATs
|
|
; OUTPUT: dx:ax contains the starting logical sector number
|
|
; DESTROYED: none
|
|
;
|
|
CalcClust2 PROC C cResSectors:WORD, cFATsecs:WORD, cFATs:BYTE
|
|
xor dx,dx ;
|
|
mov ax,[cFATsecs] ;
|
|
mul [cFATs] ;
|
|
add ax,[cResSectors] ;
|
|
adc dx,0 ;
|
|
ret
|
|
CalcClust2 ENDP
|
|
|
|
;
|
|
; CalcClustOff - calculates the starting logical sector number of
|
|
; cluster 0, which isn't really a cluster, but the
|
|
; number returned is useful for calculations converting
|
|
; cluster number to logical sector
|
|
;
|
|
; INPUT: ResSectors, FATsecs, FATs
|
|
; OUTPUT: dx:ax contains the starting logical sector number
|
|
; DESTROYED: none
|
|
;
|
|
CalcClustOff PROC C dResSectors:WORD, dFATsecs:WORD, dFATs:BYTE, \
|
|
dRootDirEnts:WORD, dBytesPerSec:WORD, dSecPerClust:BYTE
|
|
LOCAL clustLo:WORD, clustHi:WORD
|
|
xor dh,dh
|
|
mov ax,[dFatSecs]
|
|
mov dl,[dFATs]
|
|
mul dx
|
|
add ax,[dResSectors]
|
|
adc dx,0
|
|
; call CalcClust2 C, [dResSectors], [dFATsecs], [dFATs]
|
|
; now dx:ax = FATs * FATsecs + ResSectors
|
|
mov [clustLo],ax
|
|
mov [clustHi],dx
|
|
mov dx,20h ; bytes per dir entry
|
|
mov ax,[dRootDirEnts] ;
|
|
mul dx ; multiply 'em out
|
|
div [dBytesPerSec] ; and divide by bytes/sec
|
|
add [clustLo],ax ;
|
|
adc [clustHi],dx ; create the aggregate
|
|
mov al,[dSecPerClust] ;
|
|
xor ah,ah ;
|
|
shl ax,1 ; AX = SecPerClust * 2
|
|
sub [clustLo],ax ;
|
|
sbb [clustHi],0 ; propagate carry flag
|
|
mov ax,[clustLo] ;
|
|
mov dx,[clustHi] ;
|
|
ret
|
|
CalcClustOff ENDP
|
|
|
|
;
|
|
; FindFile - given a memory buffer containing the directory data
|
|
; and a static file name for which to search, this routine
|
|
; finds the file and returns a pointer to its directory
|
|
; entry in ds:si
|
|
;
|
|
; INPUT: dirbuffer, filespec
|
|
; OUTPUT: ax contains pointer to directory entry (or NULL)
|
|
; DESTROYED: none
|
|
;
|
|
FindFile PROC C dirbuffer:WORD, limit:WORD, filespec:WORD
|
|
USES cx, dx, di, si, es
|
|
mov cx,ds ;
|
|
mov es,cx ; es and ds point to same segment
|
|
cld ; always count forward
|
|
mov ax,[dirbuffer] ; load 'em up
|
|
add [limit],ax
|
|
mov dx,[filespec] ;
|
|
keepsearching:
|
|
mov cx,11 ; size of dos filename (8.3)
|
|
mov si,dx ;
|
|
mov di,ax ;
|
|
repe cmpsb ; compare 'em
|
|
jz foundit ;
|
|
add ax,20h ; size of directory entry
|
|
cmp ax,[limit]
|
|
jb keepsearching
|
|
xor ax,ax
|
|
|
|
foundit:
|
|
ret
|
|
FindFile ENDP
|
|
END |