windows-nt/Source/XPSP1/NT/base/ntsetup/mpk/iolib/i13disk.asm

941 lines
23 KiB
NASM
Raw Normal View History

2020-09-26 03:20:57 -05:00
DOSSEG
.MODEL LARGE
include disk.inc
;
; Disk record structure specific to int13-visible disks.
;
INT13_DISK_INFO STRUC
;
; First part is a DiskInfo structure
;
DiskInfo db SIZE DISK_INFO DUP (?)
;
; Int13 unit number and drive geometry for drive.
;
Int13DiskUnit db ?
Int13SectorsPerTrack db ?
Int13Heads dw ?
Int13Cylinders dw ?
Int13xSectorCountl dw ?
Int13xSectorCounth dw ?
INT13_DISK_INFO ENDS
.DATA?
extrn DiskList:dword
;
; Table of drives for which xint13 is disabled
; 128 units at 1 bit each = 128 bits = 16 bytes = 8 words
;
; We support this solely by returning a zero
; extended sector count from pGetExtendedInt13SectorCount;
; this forces everyone else into regular int13 mode.
;
xInt13DisableTable db 16 dup (?)
.CODE
ASSUME ds:NOTHING
extrn _malloc:far
.386
;++
;
; UINT
; _far
; InitializeInt13DiskList(
; IN UINT FirstDiskId
; );
;
; Routine Description:
;
; This routine determines the number of int13 disk units and
; gathers information about each, which is saved in a structure.
; The structures are stored in a linked list whose head is
; the DiskList global variable.
;
; Arguments:
;
; FirstDiskId - supplies the id to be used for the first disk.
;
; Return Value:
;
; non-0 - success
; 0 - failure
;
;--
FirstDiskId equ word ptr [bp+6]
public InitializeInt13DiskList
InitializeInt13DiskList proc far
push bp
mov bp,sp
push ds
push es
push bx
push si
push di
mov ah,8
mov dl,80h
int 13h
jnc @f
xor dl,dl
@@: or dl,80h
xor dh,dh
mov di,dx ; di = int13 disk limit
mov si,80h ; si = current int13 disk
nextdisk:
cmp si,di
je ildoneok ; no more disks
push ds
push DGROUP
pop ds ; crt needs ds to address _DATA
push SIZE INT13_DISK_INFO
call _malloc
add sp,2
pop ds
mov cx,ax
or cx,dx
jz ildone ; ax already 0 for error return
push ax
push dx ; save disk record pointer
push si ; save current int13 unit #
push di ; save int13 unit # limit
mov dx,si ; dl = int13 unit #
mov ah,8
int 13h
pop di ; di = int13 disk limit
pop bx ; bl = int13 unit #, bh = 0
pop ds
pop si ; ds:si -> new disk record
jnc @f
mov ax,0
jmp short ildone
;
; Store int13 unit number in disk record.
; Also generate a disk id.
;
@@: mov ax,bx
sub ax,80h
add ax,FirstDiskId
mov [si].DiskInfo.DiskInfoDiskId,ax
mov [si].DiskInfo.DiskInfoDiskOpen,bh ; bh=0, set disk not open
mov [si].Int13DiskUnit,bl
;
; Max head is in in dh, convert to count in dx
;
shr dx,8
inc dx
mov [si].Int13Heads,dx
;
; Deal with sectors per track in cl
;
mov al,cl
and al,3fh
mov [si].Int13SectorsPerTrack,al
;
; Deal with cylinder count wierdness
;
xchg ch,cl
shr ch,6
inc cx
mov [si].Int13Cylinders,cx
;
; Fetch extended int13 count. Comes back as 0 if xint13
; not supported for the drive.
;
push bx
call far ptr pGetExtendedInt13SectorCount
pop cx ; cl = int13 unit#, ch = 0
mov [si].Int13xSectorCountl,ax
mov [si].Int13xSectorCounth,dx
;
; Now link the disk record into the linked list.
;
mov dx,di ; dx = int13 unit # limit
mov ax,DGROUP
mov es,ax
mov di,OFFSET DGROUP:DiskList ; es:di = &DiskList
mov ax,es:[di]
mov [si].DiskInfo.DiskInfoNextl,ax
mov ax,es:[di+2]
mov [si].DiskInfo.DiskInfoNexth,ax
mov es:[di],si
mov ax,ds
mov es:[di+2],ax
mov di,dx ; di = int13 unit # limit
mov si,cx ; si = int13 unit #
inc si
jmp nextdisk
ildoneok:
mov ax,si
sub ax,80h ; ax = int13 disk count
ildone:
pop di
pop si
pop bx
pop es
pop ds
leave
retf
InitializeInt13DiskList endp
;++
;
; BOOL
; _far
; OpenInt13Disk(
; IN FPINT13_DISK_INFO DiskRecord
; );
;
; Routine Description:
;
; This routine "opens" an int13 disk.
; Housekeeping such as locking, etc, is performed.
;
; It is assumed that a disk can be opened only once at a time,
; but the caller is responsible for enforcing this.
;
; Arguments:
;
; DiskRecord - supplies a far pointer to the disk record struct
; for the disk to be opened.
;
; Return Value:
;
; non-0 - success
; 0 - failure
;
;--
DiskRecord equ dword ptr [bp+6]
public OpenInt13Disk
OpenInt13Disk proc far
;
; BUGBUG perform locking for OSR2
;
mov ax,1
retf
OpenInt13Disk endp
;++
;
; VOID
; _far
; CloseInt13Disk(
; IN FPINT13_DISK_INFO DiskRecord
; );
;
; Routine Description:
;
; This routine "closes" an int13 disk previously opened with
; OpenInt13Disk. Housekeeping such as locking, etc, is performed.
;
; Arguments:
;
; DiskRecord - supplies a far pointer to the disk record struct
; for the disk to be closed.
;
; Return Value:
;
; None.
;
;--
DiskRecord equ dword ptr [bp+6]
public CloseInt13Disk
CloseInt13Disk proc far
;
; BUGBUG perform unlocking for OSR2
;
retf
CloseInt13Disk endp
;
; BOOL
; _far
; pInt13Read(
; IN FPINT13_DISK_INFO DiskRecord,
; IN ULONG StartSector,
; IN BYTE SectorCount,
; OUT FPVOID Buffer
; );
;
; BOOL
; _far
; pInt13Read(
; IN FPINT13_DISK_INFO DiskRecord,
; IN ULONG StartSector,
; IN BYTE SectorCount,
; IN FPVOID Buffer
; );
;
DiskRecord equ dword ptr [bp+6]
StartSectorl equ word ptr [bp+10]
StartSectorh equ word ptr [bp+12]
SectorCount equ byte ptr [bp+14]
Buffer equ dword ptr [bp+16]
public pInt13Read
pInt13Read label far
mov ah,2
jmp short pInt13IO
public pInt13Write
pInt13Write label far
mov ah,3
pInt13IO proc far
push bp
mov bp,sp
push ds
push es
push bx
push si
push di
push ax
lds si,DiskRecord
;
; Calculate sectors per cylinder, which is a max of 63*256 = 16128,
; which fits in a word register. But we do a full 32-bit multiply,
; because the heads count could be 256 (which doesn't fit in al).
;
mov al,[si].Int13SectorsPerTrack
cbw ; ax = sectors per track
mul [si].Int13Heads ; ax = sectors per cylinder
mov bx,ax ; bx = sectors per cylinder
mov dx,StartSectorh
mov ax,StartSectorl ; dx:ax = start sector
div bx ; ax = cyl, dx = sector in cyl
;
; Set up the cylinder in cx in int13 format:
;
; ch = bits 0-7 of the cylinder
; bits 6,7 of cl = bits 8,9 of the cylinder
;
mov cx,ax
xchg cl,ch
shl cl,6
;
; Now calculate the head and sector. The head is max 255
; and the sector is max 62, meaning we can do a 16-bit divide.
;
mov ax,dx ; ax = sector within cylinder
div [si].Int13SectorsPerTrack ; al = head, ah = sector
;
; Pack everything into int13 format.
;
inc ah ; sector is 1-based (1-63)
or cl,ah
mov dh,al ; dh = head
mov dl,[si].Int13DiskUnit
les bx,Buffer
pop ax ; ah = operation (2 or 3)
mov al,SectorCount
int 13h
setnc al
cbw
pop di
pop si
pop bx
pop es
pop ds
leave
retf
pInt13IO endp
;
; BOOL
; _far
; pXInt13Read(
; IN FPINT13_DISK_INFO DiskRecord,
; IN ULONG StartSector,
; IN BYTE SectorCount,
; OUT FPVOID Buffer
; );
;
; BOOL
; _far
; pXInt13Read(
; IN FPINT13_DISK_INFO DiskRecord,
; IN ULONG StartSector,
; IN BYTE SectorCount,
; IN FPVOID Buffer
; );
;
DiskRecord equ dword ptr [bp+6]
StartSector equ dword ptr [bp+10]
SectorCount equ byte ptr [bp+14]
Buffer equ dword ptr [bp+16]
public pXInt13Read
pXInt13Read label far
mov ah,42h
jmp short pXInt13IO
public pXInt13Write
pXInt13Write label far
mov ax,4300h ; need to clear bit 0 (verify flag)
pXInt13IO proc far
push bp
mov bp,sp
push ds
push es
push bx
push si
push di
lds si,DiskRecord ; ds:si -> disk record
mov dl,[si].Int13DiskUnit
push 0 ; high dword of sector # is 0
push 0
push StartSector
push Buffer
mov bl,SectorCount ; sector count
xor bh,bh ; make sure high byte is 0
push bx
push 16 ; packet size
push ss
pop ds
mov si,sp ; ds:si -> param packet on stack
int 13h ; ax already set up from above
setnc al
cbw ; ax: 0=failure, 1=success
add sp,16 ; get rid of param packet on stack
pop di
pop si
pop bx
pop es
pop ds
leave
retf
pXInt13IO endp
;++
;
; BOOL
; _far
; Int13DiskIo(
; IN FPINT13_DISK_INFO DiskRecord
; IN ULONG StartSector,
; IN BYTE SectorCount,
; IN OUT FPVOID Buffer,
; IN BOOL Write
; );
;
; Routine Description:
;
; This routine performs disk i/o using int13 services, automatically
; using extended int13 services if available for the drive.
;
; This routine DOES ensure that i/o will not cross a track boundary
; to ensure maximum compatibility with various BIOSes out there.
;
; Arguments:
;
; DiskRecord - supplies pointer to the disk record structure for the
; disk to be read from or written to.
;
; StartSector - supplies the physical start sector where the transfer
; is to start.
;
; SectorCount - supplies the number of sectors to be transfered.
;
; Buffer - supplies the target buffer for reads or the data for write.
;
; Write - non-0 means write operation, 0 means read operation.
;
; Return Value:
;
; non-0 - success
; 0 - failure
;
;--
DiskRecord equ dword ptr [bp+6]
StartSector equ dword ptr [bp+10]
StartSectorl equ word ptr [bp+10]
StartSectorh equ word ptr [bp+12]
SectorCount equ byte ptr [bp+14]
Buffer equ dword ptr [bp+16]
Bufferl equ word ptr [bp+18]
Bufferh equ word ptr [bp+18]
Write equ word ptr [bp+20]
IoRoutine equ dword ptr [bp-4]
IoRoutinel equ word ptr [bp-4]
IoRoutineh equ word ptr [bp-2]
public Int13DiskIo
Int13DiskIo proc far
push bp
mov bp,sp
sub sp,4
push ds
push es
push bx
push si
push di
;
; Address the disk record structure to determine
; which set of int13 services to use (standard or extended).
; We'll use extended if they are supported for the drive.
; Even in that case, however, we'll do i/o a track at a time
; to ensure maximum compatibility.
;
lds si,DiskRecord
mov ax,Write
cmp [si].Int13xSectorCountl,0
jnz io_xint13
cmp [si].Int13xSectorCounth,0
jnz io_xint13
cmp ax,1
je @f
mov dx,SEG pInt13Read
mov ax,OFFSET pInt13Read
jmp short store_io
@@: mov dx,SEG pInt13Write
mov ax,OFFSET pInt13Write
jmp short store_io
io_xint13:
cmp ax,1
je @f
mov dx,SEG pXInt13Read
mov ax,OFFSET pXInt13Read
jmp short store_io
@@: mov dx,SEG pXInt13Write
mov ax,OFFSET pXInt13Write
store_io:
mov IoRoutinel,ax
mov IoRoutineh,dx
;
; Figure out how many sectors are left in the first track.
; Note that this calculation can overflow, since the sector
; can be very large (like in the xint13 case) and thus the
; absolute track number can easily be > 64k. To get around this
; we calculate the cylinder and remainder first, and then
; degenerate the remainder into track and sector.
;
; Max sectors per cylinder = 63*256, which fits in a word register.
;
mov al,[si].Int13SectorsPerTrack
cbw
mul [si].Int13Heads ; ax = sectors per cylinder
mov cx,ax ; cx = sectors per cylinder
mov dx,StartSectorh
mov ax,StartSectorl ; dx:ax = lba start sector
div cx ; dx = sector within cylinder
mov ax,dx ; ax = sector within cylinder
div [si].Int13SectorsPerTrack ; ah = sector in track
mov al,[si].Int13SectorsPerTrack
sub al,ah ; al = sectors left in track
cbw ; ah = 0
nexttrack:
cmp al,SectorCount ; see if we need that many
jbe @f
mov al,SectorCount
@@: push Buffer
push ax ; al = count, ah = 0
mov di,ax ; save sector count
push StartSector
push ds
push si
call IoRoutine
add sp,14
cmp ax,0
jz iodone ; ax already 0 for error exit
mov ax,di ; al = #sectors we just read, ah = 0
add StartSectorl,ax ; adjust start sector
adc StartSectorh,0
sub SectorCount,al ; adjust sector count
jz iodone ; ax already non-0 for success return
;
; To avoid segment wraps, we'll do arithmetic on the segment
; instead of the offset. The maximum number of sectors per track
; is 3fh. Each sector is 200h bytes, which expressed as the offset
; to the next segment is 20h = 2^5. Thus shifting the sector count
; left by 5 yields a result between 20h and 7e0h, which we add
; to the segment of the transfer address.
;
; Note that at this point ah = 0.
;
shl ax,5
add Bufferh,ax
mov al,[si].Int13SectorsPerTrack
cbw ; ax = whole track for next read
jmp short nexttrack
iodone:
pop di
pop si
pop bx
pop es
pop ds
leave
retf
Int13DiskIo endp
;++
;
; ULONG
; _far
; pGetExtendedInt13SectorCount(
; IN BYTE Int13Unit
; );
;
; Routine Description:
;
; This routine determines the number of sectors available on an int13
; disk via extended int13 services.
;
; Arguments:
;
; Int13Unit - supplies the int13 unit # for the disk.
;
; Return Value:
;
; 0 - extended int13 services not available for drive.
; non-0 - number of sectors available for i/o via xint13 on the drive.
;
;--
Int13Unit equ byte ptr [bp+6]
pGetExtendedInt13SectorCount proc far
push bp
mov bp,sp
sub sp,26
push ds
push es
push bx
push si
push di
;
; See if xint13 is disabled for this unit.
;
push DGROUP
pop ds
mov si,OFFSET DGROUP:xInt13DisableTable
mov al,Int13Unit
and al,7fh
cbw ; ah = 0
mov bx,ax ; bh = 0
and al,7 ; al = bit offset within byte
shr bl,3 ; bx = offset to byte
bt [si+bx],al ; see if disabled bit set
jc notpresent ; bit set, don't use xint13
;
; check extensions present
;
mov ah,41h
mov bx,55aah
mov dl,Int13Unit
int 13h
jc notpresent
cmp bx,0aa55h
jne notpresent
test cx,1
jz notpresent
;
; now we think the extensions are present, go get
; extended geometry. Note that there are plenty of
; broken BIOSes out there that will return success to this
; call even though they don't really support extended int13.
; So we zero out the buffer ourselves first. If the BIOS
; doesn't fill the buffer the extended sector count will
; be returned as zero, which is what we want.
;
mov ax,ss
mov ds,ax
mov es,ax
lea di,[bp-24] ; don't bother with first word (size)
xor ax,ax
mov cx,12 ; 24 bytes
cld
rep stosw
lea si,[bp-26]
mov word ptr [si],26 ; set up size of info buffer
mov ah,48h
mov dl,Int13Unit
int 13h
jc notpresent
;
; OK, everything worked, return sector count.
;
mov ax,[bp-10]
mov dx,[bp-8]
jmp short xdone
notpresent:
xor ax,ax
mov dx,ax
xdone:
pop di
pop si
pop bx
pop es
pop ds
leave
ret
pGetExtendedInt13SectorCount endp
;++
;
; VOID
; _far
; DisableExtendedInt13(
; IN BYTE Int13Unit OPTIONAL
; );
;
; Routine Description:
;
; This routine disables use of extended int13 services on a particular
; int13 disk unit, or for all int13 disk units. This works by forcing
; the extended sector count to 0, which in a chain reaction ensures
; that no one will ever invoke an xint13 service for that unit.
;
; This routine MUST be called before InitializeDiskList or it will
; have no effect!
;
; Arguments:
;
; Int13Unit - supplies the int13 unit # on which to disable xint13.
; (The high bit is assumed set and ignored.) If this value
; is 0, xint13 is disabled for all drives.
;
; Return Value:
;
; None.
;
;--
Int13Unit equ byte ptr [bp+6]
public _DisableExtendedInt13
_DisableExtendedInt13 proc far
push bp
mov bp,sp
push es
push bx
push di
;
; Address the xint13 disabled list table.
;
push DGROUP
pop es
mov di,OFFSET DGROUP:xInt13DisableTable
;
; See if we're supposed to disable for all disks.
;
mov al,Int13Unit
cmp al,0
jz allunits
;
; One unit only, take care of it here.
;
and al,7fh
cbw ; ah = 0
mov bx,ax ; bh = 0
and al,7 ; al = bit offset within byte
shr bl,3 ; bx = offset to byte
bts es:[di+bx],al
jmp dxidone
allunits:
;
; Set all bits in the table to 1
;
cbw ; ax = 0
dec ax ; ax = ff
mov cx,8 ; 8 words = 16 bytes = 128 bits
cld
rep stosw
dxidone:
pop di
pop bx
pop es
leave
ret
_DisableExtendedInt13 endp
;++
;
; VOID
; _far
; GetInt13DiskInfo(
; IN FPINT13_DISK_INFO DiskRecord,
; OUT FPBYTE Int13UnitNumber,
; OUT FPBYTE SectorsPerTrack,
; OUT FPUSHORT Heads,
; OUT FPUSHORT Cylinders,
; OUT FPULONG ExtendedSectorCount
; );
;
; Routine Description:
;
; These routines fetches information about a disk.
;
; Arguments:
;
; Return Value:
;
; None.
;
;--
DiskRecord equ dword ptr [bp+6]
Int13UnitNumber equ dword ptr [bp+10]
SectorsPerTrack equ dword ptr [bp+14]
Heads equ dword ptr [bp+18]
Cylinders equ dword ptr [bp+22]
ExtendedSecCnt equ dword ptr [bp+26]
public GetInt13DiskInfo
GetInt13DiskInfo proc far
push bp
mov bp,sp
push ds
push es
push si
push di
lds si,DiskRecord
add si,Int13DiskUnit
cld
les di,Int13UnitNumber
movsb
.errnz (Int13SectorsPerTrack - Int13DiskUnit) - 1
les di,SectorsPerTrack
movsb
.errnz (Int13Heads - Int13SectorsPerTrack) - 1
les di,Heads
movsw
.errnz (Int13Cylinders - Int13Heads) - 2
les di,Cylinders
movsw
.errnz (Int13xSectorCountl - Int13Cylinders) - 2
les di,ExtendedSecCnt
movsw
movsw
pop di
pop si
pop es
pop ds
leave
retf
GetInt13DiskInfo endp
end