mirror of
https://github.com/SEPPDROID/DR-DOS-OpenDOS.git
synced 2025-10-22 16:04:20 +00:00
2619 lines
70 KiB
NASM
2619 lines
70 KiB
NASM
; File : $DISK.ASM$
|
|
;
|
|
; Description :
|
|
;
|
|
; Original Author :
|
|
;
|
|
; Last Edited By : $Author: RGROSS$
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
; Copyright Unpublished Work of Novell, Inc. All Rights Reserved.
|
|
;
|
|
; THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL,
|
|
; PROPRIETARY AND TRADE SECRET INFORMATION OF NOVELL, INC.
|
|
; ACCESS TO THIS WORK IS RESTRICTED TO (I) NOVELL, INC. EMPLOYEES
|
|
; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
|
|
; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN NOVELL, INC. WHO
|
|
; HAVE ENTERED INTO APPROPRIATE LICENSE AGREEMENTS. NO PART OF THIS
|
|
; WORK MAY BE USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED,
|
|
; REVISED, MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, EXPANDED,
|
|
; COLLECTED, COMPILED, LINKED, RECAST, TRANSFORMED OR ADAPTED
|
|
; WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR
|
|
; EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
|
|
; THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; *** Current Edit History ***
|
|
; *** End of Current Edit History ***
|
|
;
|
|
; $Log: $
|
|
; DISK.ASM 1.1 93/11/18 17:20:12 RGROSS
|
|
;
|
|
; DISK.ASM 1.41 93/11/18 17:20:25 IJACK
|
|
;
|
|
; DISK.ASM 1.40 93/11/10 00:28:12 IJACK
|
|
; Format changes so you can format your hard disk
|
|
; DISK.ASM 1.39 93/11/08 21:47:25 IJACK
|
|
; Add hidden sectors to ioctl format etc of hard disks
|
|
; DISK.ASM 1.38 93/11/02 16:09:29 IJACK
|
|
; Always zero BPB_HIDDEN_SECTORS on floppies - problem with PCW free disk which
|
|
; has garbage in those fields.
|
|
; DISK.ASM 1.37 93/10/18 17:33:18 IJACK
|
|
; format c: fix
|
|
; DISK.ASM 1.36 93/10/11 18:37:24 IJACK
|
|
; media-change checks serial-numbers for 3.5" disks
|
|
; DISK.ASM 1.35 93/10/06 22:09:16 IJACK
|
|
; vec_save extrn replaced by orgInt13 extrn
|
|
; DISK.ASM 1.34 93/09/03 20:13:32 IJACK
|
|
; Fix bug in disk formatting
|
|
; DISK.ASM 1.33 93/09/01 17:40:31 IJACK
|
|
; update UDSC_TIMER after media check forced by drive change
|
|
; (DBASE IV slow installation problem)
|
|
; DISK.ASM 1.32 93/08/12 15:33:07 IJACK
|
|
; Handle DMA error from multi-track read (ancient PC-XT hard disk)
|
|
; DISK.ASM 1.31 93/08/03 15:29:01 IJACK
|
|
; use serial numbers for media change detection
|
|
; DISK.ASM 1.30 93/08/02 18:44:50 IJACK
|
|
; don't trust the changeline if switching drives
|
|
; DISK.ASM 1.29 93/08/02 18:38:19 IJACK
|
|
;
|
|
; DISK.ASM 1.28 93/08/02 14:47:38 IJACK
|
|
;
|
|
; DISK.ASM 1.27 93/07/29 21:00:24 IJACK
|
|
; get rid of genpb_ptr and genpb_minor
|
|
; DISK.ASM 1.26 93/07/26 21:18:25 IJACK
|
|
; Correctly return UDSC_ root from Int 2F/0803
|
|
; DISK.ASM 1.25 93/07/26 18:07:21 IJACK
|
|
; Switch ms-windows to full screen when prompting for disk
|
|
; DISK.ASM 1.24 93/07/23 17:34:27 IJACK
|
|
; fix floppy/driver.sys support
|
|
; DISK.ASM 1.23 93/07/22 20:37:42 IJACK
|
|
;
|
|
; DISK.ASM 1.22 93/07/22 19:43:46 IJACK
|
|
; switch over to REQUEST.EQU
|
|
; change floppy drive order, add get/set serial number
|
|
; DISK.ASM 1.21 93/07/19 18:57:21 IJACK
|
|
; Add header
|
|
;
|
|
; ENDLOG
|
|
|
|
include BIOSGRPS.EQU
|
|
include DRMACROS.EQU ; standard DR macros
|
|
include IBMROS.EQU ; ROM BIOS equates
|
|
include REQUEST.EQU ; request header equates
|
|
include BPB.EQU ; BIOS parameter block equates
|
|
include UDSC.EQU ; unit descriptor equates
|
|
include DRIVER.EQU ; device driver equates
|
|
|
|
|
|
int_____DISK_INT macro
|
|
call Int13
|
|
endm
|
|
|
|
FASTSETTLE equ FALSE ; disable "head settle == 0 ms"
|
|
|
|
RETRY_MAX equ 3 ; do 3 retries if we get an error
|
|
MAX_SPT equ 40 ; maximum sectors per track
|
|
|
|
SECSIZE equ 512
|
|
IDOFF equ SECSIZE-2 ; last word in boot sector is ID
|
|
PTOFF equ IDOFF-40h ; 4*16 bytes for partition def's
|
|
|
|
DOS20_ID equ 1 ; DOS 2.0 partition, < 4086 clusters
|
|
DOS30_ID equ 4 ; DOS 3.0 partition, < 65536 sectors
|
|
DOSEX_ID equ 5 ; DOS 3.3 extended partition
|
|
DOS331_ID equ 6 ; COMPAQ DOS 3.31 partition > 32 Mb
|
|
|
|
; Now for the secure partition types
|
|
SEC_ID equ 0C0h ; New DR secure partition types
|
|
SEC_ID2 equ 0D0h ; Old DR secure partition types
|
|
|
|
page
|
|
CGROUP group CODE, RCODE, ICODE, RESBIOS, IDATA
|
|
|
|
CG equ offset CGROUP
|
|
|
|
Assume CS:CGROUP, DS:CGROUP, ES:Nothing, SS:Nothing
|
|
|
|
IVECT segment at 0000h
|
|
|
|
org 0013h*4
|
|
i13off dw ?
|
|
i13seg dw ?
|
|
|
|
org 001Eh*4
|
|
i1eptr dd ?
|
|
|
|
org 002Fh*4
|
|
i2Foff dw ?
|
|
i2Fseg dw ?
|
|
|
|
org 0472h
|
|
reset_flag dw ?
|
|
|
|
org 0504h
|
|
dual_byte db ? ; multiple drive byte at 50:4
|
|
|
|
IVECT ends
|
|
|
|
ROS segment at 0F000h
|
|
org 0FFF0h
|
|
reset proc far
|
|
reset endp
|
|
ROS ends
|
|
|
|
CODE segment 'CODE'
|
|
|
|
extrn endbios:word ; for device driver INIT function
|
|
extrn read_system_ticks:near ; get system tick count in CX/DX
|
|
extrn Int13Trap:near
|
|
extrn Int2FTrap:near
|
|
extrn orgInt13:dword
|
|
extrn i13pointer:dword
|
|
extrn i13off_save:word
|
|
extrn i13seg_save:word
|
|
|
|
extrn NumDiskUnits:byte
|
|
extrn DeblockSeg:word
|
|
extrn local_parms:byte
|
|
extrn parms_spt:byte
|
|
extrn parms_gpl:byte
|
|
extrn local_buffer:byte
|
|
extrn local_pt:word
|
|
extrn local_id:word
|
|
extrn layout_table:word
|
|
extrn bpbs:word
|
|
extrn bpb160:byte
|
|
extrn bpb360:byte
|
|
extrn bpb720:byte
|
|
extrn NBPBS:abs
|
|
extrn bpbtbl:word
|
|
extrn req_off:word
|
|
extrn req_seg:word
|
|
|
|
|
|
udsc_root label dword
|
|
dw -1,-1
|
|
|
|
orig_int1e_off dw 522h
|
|
orig_int1e_seg dw 0
|
|
|
|
new_int1e_off dw 522h
|
|
new_int1e_seg dw 0
|
|
|
|
|
|
Public i13_AX
|
|
i13_AX label word
|
|
i13_size db ? ; number of sectors to xfer
|
|
i13_op db ? ; Int13 Operation
|
|
i13_dma_ptr label dword
|
|
i13_dma_off dw ?
|
|
i13_dma_seg dw ?
|
|
|
|
activeRosUnit db ? ; currently active ROS unit
|
|
|
|
include biosmsgs.def ; Include TFT Header File
|
|
|
|
|
|
ifdef JAPAN
|
|
extrn disk_msgA_jpn :byte
|
|
extrn disk_msgB_jpn :byte
|
|
endif
|
|
|
|
;disk_msgA db 13,10,'Insert disk for drive '
|
|
;disk_msgB db ': any press any key when ready ', 0
|
|
|
|
page
|
|
Assume DS:nothing, SS:nothing, ES:nothing
|
|
|
|
CODE ends
|
|
|
|
RCODE segment 'RCODE'
|
|
|
|
extrn DataSegment:word
|
|
|
|
even
|
|
Int13 proc near
|
|
clc
|
|
push bp
|
|
int DISK_INT
|
|
pop bp
|
|
ret
|
|
Int13 endp
|
|
|
|
ros_errors db 03h, 80h, 08h, 10h, 40h, 04h, 06h, 00h
|
|
dos_errors db 00h, 02h, 04h, 04h, 06h, 08h, 0Fh, 0Ch
|
|
NUMROSERR equ dos_errors - ros_errors
|
|
|
|
; The following code is required in order to cope with
|
|
; application programs invoking Int 13h directly. It
|
|
; handles applications that format floppies or access the
|
|
; disk via Int 13h after a floppy disk change.
|
|
|
|
Assume CS:CGROUP, DS:Nothing, ES:Nothing, SS:Nothing
|
|
|
|
|
|
Public Int13Unsure
|
|
;----------
|
|
Int13Unsure proc far
|
|
;----------
|
|
sti
|
|
cld
|
|
push ds
|
|
mov ds,cs:DataSegment
|
|
Assume DS:CGROUP
|
|
call i13_unsure ; no longer sure of this drive
|
|
pop ds
|
|
ret
|
|
Int13Unsure endp
|
|
|
|
Public Int13Deblock
|
|
|
|
;-----------
|
|
Int13Deblock proc far
|
|
;-----------
|
|
; handle user programs formatting the disk
|
|
sti
|
|
cld
|
|
push ds
|
|
mov ds,cs:DataSegment
|
|
Assume DS:CGROUP
|
|
|
|
pushx <es, bx, cx, si, di> ; save work registers
|
|
mov i13_dma_off,bx
|
|
mov i13_dma_seg,es
|
|
i13_deblock10:
|
|
pushx <cx, dx>
|
|
mov cl,4
|
|
mov ax,i13_dma_seg ; get transfer address
|
|
shl ax,cl ; get A4..A15 from segment
|
|
add ax,i13_dma_off ; combine with A0..A15 from offset
|
|
not ax ; AX = # of bytes left in 64K bank
|
|
xor dx,dx
|
|
mov cx,SECSIZE
|
|
div cx ; convert this to physical sectors
|
|
mov dl,i13_size ; see if we can xfer amount wanted
|
|
cmp al,dl ; capable of more than requested?
|
|
jb i13_deblock20 ; skip if we can do it all
|
|
xchg ax,dx ; we can do them all
|
|
i13_deblock20:
|
|
les bx,i13_dma_ptr ; do the xfer to here
|
|
popx <dx, cx>
|
|
mov ah,i13_op ; get read/write/verify operation
|
|
test al,al ; if zero length possible
|
|
jz i13_deblock30 ; then deblock
|
|
mov di,es ; get transfer address
|
|
cmp di,DeblockSeg ; is this in high memory ?
|
|
jb i13_deblock50 ; then force through deblock buffer
|
|
i13_deblock30:
|
|
push ds ; if deblocking then we'd better
|
|
pop es ; point at local buffer we
|
|
mov bx,CG:local_buffer ; will be using for actual I/O
|
|
cmp i13_op,ROS_WRITE
|
|
jne i13_deblock40 ; skip data copy if not writing to disk
|
|
push ds
|
|
push cx
|
|
mov di,bx ; ES:DI -> local buffer
|
|
lds si,i13_dma_ptr ; DS:SI -> data to write
|
|
mov cx,SECSIZE/2
|
|
rep movsw ; copy to deblocking buffer
|
|
pop cx
|
|
pop ds
|
|
i13_deblock40:
|
|
mov al,1 ; do a single sector via buffer
|
|
clc
|
|
pushf ; fake an Int
|
|
call i13pointer ; to the track handler
|
|
jc i13_deblock90 ; stop on error
|
|
mov al,1 ; restore AL for buggy bios's
|
|
cmp i13_op,ROS_READ ; if we are reading then we'll
|
|
jne i13_deblock60 ; have to copy data out of
|
|
push cx ; the deblocking buffer
|
|
les di,i13_dma_ptr ; ES:DI -> dest for data
|
|
mov si,CG:local_buffer ; point at local buffer which
|
|
mov cx,SECSIZE/2 ; contains actual data
|
|
rep movsw ; copy from deblocking buffer
|
|
pop cx
|
|
jmps i13_deblock60
|
|
|
|
i13_deblock50:
|
|
push ax ; save # sectors in xfer
|
|
clc
|
|
pushf ; fake an Int
|
|
call i13pointer ; do the operation
|
|
pop bx
|
|
mov al,bl ; restore AL for buggy bios's
|
|
jc i13_deblock90 ; stop on error
|
|
i13_deblock60: ; we succeeded in doing AL sectors
|
|
sub i13_size,al ; forget about those we have done
|
|
jbe i13_deblock90 ; and do more if there are any
|
|
push ax
|
|
mov ah,SECSIZE/16
|
|
mul ah ; AX = paras to inc DMA address
|
|
add i13_dma_seg,ax ; up DMA address by this amount
|
|
pop ax
|
|
call i13_point_unit ; ES:DI -> UDSC_
|
|
jc i13_deblock90 ; exit if we can't find it
|
|
mov bx,cx ; get sector/cylinder in BX
|
|
and bx,0003Fh ; BX = sector
|
|
and cx,0FFC0h ; CX = mandled cylinder bits
|
|
add bl,al ; work out new sector
|
|
i13_deblock70:
|
|
mov ax,es:UDSC_BPB+BPB_SPT[di]
|
|
cmp bx,ax ; still on the same track ?
|
|
jbe i13_deblock80 ; easy if no overflow onto next track
|
|
sub bx,ax ; subtract a tracks worth
|
|
inc dh ; and move onto next head
|
|
mov al,dh ; isolate head from cylinder
|
|
and ax,003Fh ; bits 10/11
|
|
cmp ax,es:UDSC_BPB+BPB_HEADS[di]
|
|
jb i13_deblock70 ; onto next track yet ?
|
|
and dh,0C0h ; back to head zero
|
|
add ch,1 ; onto next track (bits 0-7)
|
|
jnc i13_deblock70 ; overflow to bits 8-9 ?
|
|
add cl,040h ; yes, "inc" bits 8/9 of cylinder
|
|
jnc i13_deblock70 ; overflow to bits 10-11 ?
|
|
add dh,040h ; yes, "inc" bits 10/11 of cylinder
|
|
jmps i13_deblock70
|
|
|
|
i13_deblock80:
|
|
or cx,bx ; recombine sector/cylinder
|
|
jmp i13_deblock10 ; and do some more
|
|
|
|
i13_deblock90:
|
|
popx <di, si, cx, bx, es> ; restore work registers
|
|
pop ds ; recover user DS
|
|
ret 2 ; return to user with result
|
|
|
|
i13_point_unit proc near
|
|
;-------------
|
|
; On Entry:
|
|
; DL = ROS unit
|
|
; On Exit:
|
|
; ES:DI -> UDSC_ for that unit
|
|
; All other regs preserved
|
|
;
|
|
les di,udsc_root ; ES:DI -> 1st es:UDSC_
|
|
i13_point_unit10:
|
|
cmp dl,es:UDSC_RUNIT[di] ; find the physical unit
|
|
je i13_point_unit20
|
|
les di,es:UDSC_NEXT[di]
|
|
cmp di,0FFFFh ; else try the next es:UDSC_
|
|
jne i13_point_unit10
|
|
mov ah,09h ; return DMA error to caller as we
|
|
stc ; don't know about this unit
|
|
i13_point_unit20:
|
|
ret
|
|
i13_point_unit endp
|
|
|
|
Int13Deblock endp
|
|
|
|
i13_unsure proc near
|
|
;---------
|
|
; mark physical drive DL as unsure
|
|
;
|
|
pushx <ds, si>
|
|
lds si,udsc_root
|
|
i13_unsure10:
|
|
cmp dl,ds:UDSC_RUNIT[si] ; does it match ROS drive?
|
|
jne i13_unsure20 ; skip if not
|
|
or ds:UDSC_FLAGS[si],UDF_UNSURE
|
|
i13_unsure20: ; next drive
|
|
lds si,ds:UDSC_NEXT[si]
|
|
cmp si,0FFFFh
|
|
jne i13_unsure10
|
|
popx <si, ds> ; restore registers
|
|
ret
|
|
|
|
i13_unsure endp
|
|
|
|
Assume DS:Nothing, SS:Nothing, ES:Nothing
|
|
|
|
Public Int2FHandler
|
|
|
|
Int2FHandler proc far
|
|
;-----------
|
|
; On Entry we have offset/seg of next in chain on the stack
|
|
; (ie. we can pass on by a RETF)
|
|
;
|
|
cmp ah,8 ; DRIVER.SYS support
|
|
je i2F_driver
|
|
cmp ah,13h ; int13 intercept
|
|
jne i2F_iret
|
|
;
|
|
; Int 13 interception support
|
|
; ---------------------------
|
|
;
|
|
; On Entry:
|
|
; DS:DX -> New Int 13 vector
|
|
; ES:BX -> Int 13 vector restored by Int 19
|
|
;
|
|
; On Exit:
|
|
; DS:DX -> Old Int 13 vector
|
|
; ES:BX -> Old Int 13 vector restored by Int 19
|
|
;
|
|
i2F_i13_intercept:
|
|
mov ax,ds
|
|
mov ds,cs:DataSegment
|
|
Assume DS:CGROUP
|
|
xchg dx,ds:i13off_save
|
|
xchg ax,ds:i13seg_save
|
|
push ax
|
|
xchg bx,ds:word ptr orgInt13
|
|
mov ax,es
|
|
xchg ax,ds:word ptr orgInt13+2
|
|
mov es,ax
|
|
pop ds
|
|
Assume DS:Nothing
|
|
i2F_iret:
|
|
iret
|
|
|
|
|
|
;
|
|
; DRIVER.SYS support
|
|
; -------------------
|
|
;
|
|
; On Entry:
|
|
; AX=0800, installation check
|
|
; AX=0801, add new block device at DS:SI
|
|
; AX=0802, execute driver request at ES:BX
|
|
; AX=0803, return address of first es:UDSC_
|
|
;
|
|
i2F_driver:
|
|
cmp al,1
|
|
jb i2F_driver_check
|
|
je i2F_driver_add
|
|
cmp al,3
|
|
jb i2F_driver_req
|
|
je i2F_driver_point
|
|
iret
|
|
|
|
i2F_driver_check:
|
|
;
|
|
; Installation check
|
|
;
|
|
mov al,0ffh ; say we are installed
|
|
iret
|
|
|
|
i2F_driver_add:
|
|
;
|
|
; Add new block device DS:DI
|
|
;
|
|
push ds
|
|
push es
|
|
push ds
|
|
pop es ; ES:DI -> unit
|
|
mov ds,cs:DataSegment
|
|
call add_unit
|
|
pop es
|
|
pop ds
|
|
iret
|
|
|
|
i2F_driver_point:
|
|
;
|
|
; return DS:DI -> first UDSC_
|
|
;
|
|
mov ds,cs:DataSegment ; DS -> our data
|
|
lds di,ds:udsc_root
|
|
iret
|
|
;
|
|
; Execute DRIVER.SYS request ES:BX
|
|
;
|
|
i2F_driver_req:
|
|
push ds
|
|
mov ds,cs:DataSegment
|
|
Assume DS:CGROUP
|
|
mov ds:req_off,bx ; fill in request pointer
|
|
mov ds:req_seg,es ; as if it was local
|
|
pop ds
|
|
Assume DS:Nothing
|
|
push cs:driverTable ; fiddle the table address
|
|
jmp DriverFunction ; then go to normal handler
|
|
|
|
extrn DriverFunction:near
|
|
extrn IntDiskTable:word ; = DiskTable
|
|
|
|
driverTable dw CG:IntDiskTable ; push address of table on
|
|
; stack as DriverFunction
|
|
; examines it
|
|
|
|
Int2FHandler endp
|
|
|
|
Assume DS:CGROUP, SS:Nothing, ES:Nothing
|
|
|
|
Public DiskTable
|
|
|
|
DiskTable label word
|
|
db 24 ; Last supported function
|
|
dw CG:dd_init ; 0-initialize driver
|
|
dw CG:dd_medchk ; 1-media change check
|
|
dw CG:dd_build_bpb ; 2-build BIOS Parameter Block
|
|
dw CG:dd_error ; 3-IOCTL string input
|
|
dw CG:dd_input ; 4-input
|
|
dw CG:dd_error ; 5-nondestructive input (char only)
|
|
dw CG:dd_error ; 6-input status (char only)
|
|
dw CG:dd_error ; 7-input flush
|
|
dw CG:dd_output ; 8-output
|
|
dw CG:dd_output_vfy ; 9-output with verify
|
|
dw CG:dd_error ; 10-output status (char only)
|
|
dw CG:dd_error ; 11-output flush (char only)
|
|
dw CG:dd_error ; 12-IOCTL string output
|
|
dw CG:dd_open ; 13-device open
|
|
dw CG:dd_close ; 14-device close
|
|
dw CG:dd_remchk ; 15-removable media check
|
|
dw CG:dd_error ; 16-n/a
|
|
dw CG:dd_error ; 17-n/a
|
|
dw CG:dd_error ; 18-n/a
|
|
dw CG:dd_genioctl ; 19-generic IOCTL
|
|
dw CG:dd_error ; 20-n/a
|
|
dw CG:dd_error ; 21-n/a
|
|
dw CG:dd_error ; 22-n/a
|
|
dw CG:dd_getdev ; 23-get logical drive
|
|
dw CG:dd_setdev ; 24-set logical drive
|
|
|
|
driver proc near
|
|
|
|
point_unit: ; get unit descriptor for work drive
|
|
;----------
|
|
; On Entry:
|
|
; ES:BX -> Request Header
|
|
; On Exit:
|
|
; AL = logical drive
|
|
; ES:DI -> es:UDSC_
|
|
; (All other registers preserved)
|
|
;
|
|
mov al,es:RH_UNIT[bx] ; get the unit number (0=A:, 1=B:, etc)
|
|
les di,udsc_root ; ES:DI -> 1st es:UDSC_
|
|
point_unit10:
|
|
cmp al,es:UDSC_DRIVE[di] ; stop if the logical drive matches
|
|
je point_unit20
|
|
les di,es:UDSC_NEXT[di]
|
|
cmp di,0FFFFh ; else try the next es:UDSC_
|
|
jne point_unit10
|
|
pop ax ; don't return to the caller
|
|
mov ax,RHS_ERROR+1 ; return "invalid unit" error
|
|
point_unit20:
|
|
ret
|
|
|
|
add_unit: ; add a new unit to the list
|
|
;--------
|
|
; On Entry:
|
|
; ES:DI -> UDSC to add
|
|
; On Exit:
|
|
; ES:DI preserved
|
|
;
|
|
mov al,es:UDSC_DRIVE[di] ; get the logical unit
|
|
cmp al,MAXPART ; is it too many ?
|
|
jae add_unit40
|
|
push ds
|
|
mov es:word ptr UDSC_NEXT[di],0FFFFh
|
|
; make sure it's terminated
|
|
and es:UDSC_FLAGS[di],UDF_HARD+UDF_CHGLINE
|
|
lea si,udsc_root ; DS:SI -> [first UDSC_]
|
|
add_unit10:
|
|
cmp ds:word ptr UDSC_NEXT[si],0FFFFh
|
|
je add_unit30
|
|
lds si,ds:UDSC_NEXT[si] ; DS:SI -> UDSC_ we already have
|
|
mov al,es:UDSC_RUNIT[di]
|
|
cmp al,ds:UDSC_RUNIT[si] ; do the logical units match ?
|
|
jne add_unit10
|
|
mov ax,ds:UDSC_FLAGS[si] ; inherit some flags
|
|
push ax
|
|
and ax,UDF_HARD+UDF_CHGLINE
|
|
mov es:UDSC_FLAGS[di],ax ; hard disk/changeline inherited
|
|
pop ax
|
|
test ax,UDF_HARD
|
|
jnz add_unit10 ; skip owner stuff on hard drive
|
|
test ax,UDF_VFLOPPY ; is this a multiple drive anyway ?
|
|
jnz add_unit20
|
|
or ax,UDF_OWNER+UDF_VFLOPPY
|
|
mov ds:UDSC_FLAGS[si],ax ; no, 1st person becomes owner
|
|
add_unit20:
|
|
or es:UDSC_FLAGS[di],UDF_VFLOPPY
|
|
jmps add_unit10 ; go and try the next
|
|
add_unit30:
|
|
mov ds:word ptr UDSC_NEXT[si],di
|
|
mov ds:word ptr UDSC_NEXT+2[si],es
|
|
pop ds
|
|
add_unit40:
|
|
ret
|
|
|
|
dd_error: ; 3-IOCTL string input
|
|
;--------
|
|
mov ax,RHS_ERROR+3 ; "invalid command" error
|
|
ret
|
|
|
|
dd_medchk: ; 1-media change check
|
|
;---------
|
|
; entry: ES:BX -> request header
|
|
; exit: RH1_RETURN = 0, 1 or FF
|
|
; 00 = media may have changed
|
|
; 01 = media hasn't changed
|
|
; FF = media has been changed
|
|
|
|
call point_unit ; get unit descriptor
|
|
test es:UDSC_FLAGS[di],UDF_HARD
|
|
jnz medchk2 ; "hasn't changed" if hard disk
|
|
call ask_for_disk ; make sure we've got correct floppy
|
|
mov ax,es:UDSC_FLAGS[di] ; get flags
|
|
test ax,UDF_UNSURE ; has format/diskcopy occurred?
|
|
jnz medchk6 ; may have changed to different format
|
|
test ax,UDF_CHGLINE
|
|
jz medchk3 ; skip ROS call if no change line
|
|
mov dl,es:UDSC_RUNIT[di]
|
|
mov al,dl ; don't trust changeline if we are
|
|
xchg al,activeRosUnit ; changing floppies
|
|
cmp al,dl ; return may have changed
|
|
jne medchk3
|
|
mov ah,ROS_DSKCHG ; get disk change status function
|
|
int_____DISK_INT ; AH=0: DC low, AH=6: DC active
|
|
jc medchk5 ; disk change not active?
|
|
medchk2:
|
|
mov al,01h ; disk hasn't changed
|
|
jmps medchk_ret
|
|
|
|
|
|
medchk3: ; no changeline support, use timer
|
|
call read_system_ticks ; get system tick count in CX/DX
|
|
mov ax,dx
|
|
xchg ax,es:UDSC_TIMER[di] ; get previous time and update
|
|
sub dx,ax
|
|
mov ax,cx
|
|
xchg ax,es:UDSC_TIMER+2[di]
|
|
sbb cx,ax ; CX/DX = # ticks since last access
|
|
jne medchk5 ; media could have changed if > 64k
|
|
cmp dx,18*3 ; more than three seconds expired?
|
|
jb medchk2 ; "not changed" if access too recent
|
|
medchk5:
|
|
mov cx,1 ; read track 0, sector 1 (boot sector)
|
|
call login_read ; to check the builtin BPB
|
|
jc medchk6 ; may have changed if read error
|
|
mov al,local_buffer+11+BPB_FATID
|
|
cmp al,0F0h ; check if we find a BPB
|
|
jb medchk6 ; may have changed if not good BPB
|
|
cmp al,es:UDSC_BPB+BPB_FATID[di]
|
|
jne medchk8 ; has media byte changed ?
|
|
mov si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11+2
|
|
lodsb ; get extended boot
|
|
sub al,29h ; do we have an extended boot ?
|
|
je medchk7 ; no, test against our dummy value
|
|
push cs
|
|
pop ds ; DS:SI -> our dummy value
|
|
mov si,offset CGROUP:dummyMediaID
|
|
medchk7:
|
|
push di
|
|
lea di,UDSC_SERIAL[di]
|
|
mov cx,2
|
|
repe cmpsw ; is serial number unchanged ?
|
|
pop di
|
|
je medchk6 ; then return may have changed
|
|
medchk8:
|
|
lea ax,UDSC_LABEL[di] ; ES:AX -> ASCII label
|
|
lds bx,REQUEST[bp]
|
|
mov ds:word ptr RH1_VOLID[bx],ax
|
|
mov ds:word ptr RH1_VOLID+2[bx],es
|
|
mov al,0FFH ; return disk changed
|
|
jmps medchk_ret
|
|
|
|
medchk6:
|
|
mov al,00h ; disk may have changed
|
|
|
|
medchk_ret:
|
|
and es:UDSC_FLAGS[di],not UDF_UNSURE
|
|
les bx,REQUEST[bp]
|
|
mov es:RH1_RETURN[bx],al ; set return value
|
|
sub ax,ax
|
|
ret
|
|
|
|
|
|
page
|
|
dd_build_bpb: ; 2-build BIOS Parameter Block
|
|
;------------
|
|
call point_unit ; get unit descriptor
|
|
test es:UDSC_FLAGS[di],UDF_HARD
|
|
jnz bldbpb1 ; BPB doesn't change for hard disks
|
|
call login_media ; try to determine media type (BPB)
|
|
jc bldbpb_err
|
|
bldbpb1:
|
|
mov es:UDSC_OPNCNT[di],0 ; no files open at this time
|
|
and es:UDSC_FLAGS[di],not UDF_UNSURE
|
|
; media is sure
|
|
lea si,UDSC_BPB[di]
|
|
mov ax,es
|
|
les bx,REQUEST[bp]
|
|
mov es:RH2_BPBOFF[bx],si ; return the current BPB
|
|
mov es:RH2_BPBSEG[bx],ax
|
|
|
|
xor ax,ax
|
|
ret
|
|
|
|
bldbpb_err:
|
|
jmp xlat_error ; return error code
|
|
; ret
|
|
|
|
|
|
|
|
login_media: ; determine BPB for new floppy disk
|
|
;-----------
|
|
push ds
|
|
mov cx,1 ; read track 0, sector 1 (boot)
|
|
call login_read ; to determine media type
|
|
jc login_media_err ; abort if physical error
|
|
cmp local_buffer+11+BPB_FATID,0F0h
|
|
jb login_media10 ; fail unless FATID sensible
|
|
lodsw ; get JMP instruction from boot sector
|
|
xchg ax,bx ; save in BX
|
|
lodsb ; get next 3rd byte in AX
|
|
add si,8 ; skip JMP, OEM name, SI -> BPB
|
|
cmp bl,0E9h ; does it start with a JMP ?
|
|
je login_media40
|
|
cmp bl,069h
|
|
je login_media40
|
|
cmp bl,0EBh ; how about a JMPS ?
|
|
jne login_media10
|
|
cmp al,090h ; then we need a NOP
|
|
je login_media40
|
|
login_media10:
|
|
mov cx,2 ; read track 0, sector 2 (FAT)
|
|
call login_read ; try to read the sector
|
|
jc login_media_err ; abort if physical error
|
|
cmp word ptr 1[si],-1 ; bytes 1, 2 must be 0FFh, 0FFh
|
|
jne login_media30 ; default media if bad FAT
|
|
lodsb ; else get FAT ID byte
|
|
mov si,CG:bpb160 ; look through builtin BPB table
|
|
mov cx,NBPBS ; # of builtin BPBs
|
|
login_media20:
|
|
cmp al,BPB_FATID[si] ; does it match one we know?
|
|
je login_media40 ; yes, use builtin BPB
|
|
add si,BPB_LENGTH ; else move to next BPB
|
|
loop login_media20 ; repeat for all BPBs
|
|
login_media30: ; can't find that FAT ID
|
|
lea si,UDSC_DEVBPB[di] ; use the default type
|
|
push es
|
|
pop ds ; use BPB at DS:SI ->
|
|
login_media40:
|
|
push di
|
|
lea di,UDSC_BPB[di] ; ES:DI -> unit descriptor (UDSC)
|
|
mov cx,UDSC_BPB_LENGTH ; size of a BPB (less reserved stuff)
|
|
rep movsb ; copy into unit descriptor
|
|
pop di
|
|
mov es:UDSC_BPB+BPB_SECSIZ[di],SECSIZE
|
|
; mov cx,0
|
|
mov es:word ptr (UDSC_BPB+BPB_HIDDEN)[di],cx
|
|
mov es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di],cx
|
|
cmp si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11
|
|
jne login_media50 ; is the BPB from the boot sector ?
|
|
; mov ax,ds ; if so then check for media id
|
|
; cmp ax,cs:DataSegment ; seg check redundant as UDSC_DEVBPB
|
|
; jne login_media50 ; is followed by 7 bytes of zero
|
|
lodsw ; skip 2 bytes
|
|
lodsb ; now get possible boot signature
|
|
cmp al,29h ; is it an extended boot sector ?
|
|
je login_media60 ; yes, use it
|
|
login_media50:
|
|
push cs
|
|
pop ds ; DS:SI -> our dummy value
|
|
mov si,offset CGROUP:dummyMediaID
|
|
login_media60:
|
|
call UpdateMediaID ; update UDSC_ with media info
|
|
clc
|
|
login_media_err:
|
|
pop ds
|
|
ret
|
|
|
|
dummyMediaID dd 0 ; serial number 0
|
|
db 'NO NAME '
|
|
db 'FAT12 '
|
|
|
|
UpdateMediaID:
|
|
;-------------
|
|
; On Entry:
|
|
; DS:SI -> extended boot record info
|
|
; ES:DI -> UDSC_ to update
|
|
; On Exit:
|
|
; ES:DI preserved
|
|
;
|
|
push di
|
|
xor ax,ax ; AX = a handy zero
|
|
lea di,UDSC_SERIAL[di]
|
|
movsw
|
|
movsw ; copy serial number
|
|
pop di
|
|
push di
|
|
lea di,UDSC_LABEL[di]
|
|
mov cx,11
|
|
rep movsb ; copy the volume label
|
|
stosb ; zero terminate it
|
|
pop di
|
|
push di
|
|
lea di,UDSC_FSTYPE[di]
|
|
movsw
|
|
movsw
|
|
movsw
|
|
movsw ; copy the file system type
|
|
stosb ; zero terminate it
|
|
pop di
|
|
ret
|
|
|
|
|
|
login_read:
|
|
; entry: CH, CL = cylinder/sector to read
|
|
; exit: CY = 1, AH = status if error
|
|
; else local_buffer filled in
|
|
|
|
mov dl,es:UDSC_RUNIT[di] ; DL = ROS drive
|
|
mov dh,0 ; DH = head number
|
|
|
|
login_read_dx: ; read on drive DL, head DH
|
|
;------------- ; (entry for hard disk login)
|
|
mov P_RETRY[bp],RETRY_MAX ; initialize retry count
|
|
logrd1:
|
|
push es
|
|
mov ax,ROS_READ*256 + 1 ; read one sector from ROS
|
|
push ds
|
|
pop es ; ES = DS = local segment
|
|
mov bx,CG:local_buffer
|
|
int_____DISK_INT ; call the ROM BIOS
|
|
pop es
|
|
jnc logrd3 ; skip if no disk error
|
|
push ax
|
|
; mov ah,ROS_RESET
|
|
xor ax,ax
|
|
int_____DISK_INT ; reset the drive
|
|
pop ax
|
|
dec P_RETRY[bp]
|
|
jnz logrd1 ; loop back if more retries
|
|
logrd2:
|
|
stc
|
|
logrd3:
|
|
mov si,CG:local_buffer
|
|
ret
|
|
|
|
page
|
|
dd_output: ; 8-output
|
|
;---------
|
|
mov P_ROSCMD[bp],ROS_WRITE ; write to floppy/hard disk
|
|
jmps io_common
|
|
|
|
dd_output_vfy: ; 9-output with verify
|
|
;-------------
|
|
mov P_ROSCMD[bp],ROS_VERIFY ; write & verify floppy/hard disk
|
|
jmps io_common
|
|
|
|
dd_input: ; 4-input
|
|
;--------
|
|
mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
|
|
; jmps io_common
|
|
|
|
io_common: ; common code for the above three
|
|
call point_unit ; get unit descriptor
|
|
call ask_for_disk ; make sure we've got correct floppy
|
|
call setup_rw ; setup for read/write operation
|
|
jc io_ret ; return if bad parameters
|
|
io_loop:
|
|
call track_rw ; read as much as possible on track
|
|
jc xlat_error ; return if physical disk error
|
|
cmp P_COUNT[bp],0 ; test if any more stuff to read
|
|
jne io_loop ; yes, loop back for more
|
|
|
|
mov al,es:UDSC_RUNIT[di] ; remember the drive that is active
|
|
mov activeRosUnit,al
|
|
test es:UDSC_FLAGS[di],UDF_HARD+UDF_CHGLINE
|
|
jnz io_exit ; skip timer read for hard/changeline
|
|
|
|
call read_system_ticks ; get system tick count in CX/DX
|
|
mov es:UDSC_TIMER[di],dx
|
|
mov es:UDSC_TIMER+2[di],cx ; save time of successful access
|
|
io_exit:
|
|
xor ax,ax ; all done, no error encountered
|
|
io_ret:
|
|
ret
|
|
|
|
xlat_error: ; translate ROS error to DOS error
|
|
;----------
|
|
; entry: AH = ROS disk error code, CY = 1
|
|
; exit: AX = status to be returned to BDOS
|
|
|
|
pushx <es, di> ; save some registers
|
|
mov al,ah ; AL = ROS error code
|
|
push cs
|
|
pop es
|
|
mov di,CG:ros_errors ; ES:DI -> ROS error code table
|
|
mov cx,NUMROSERR
|
|
repne scasb ; scan for match
|
|
mov ax,RHS_ERROR ; get basic error indication
|
|
or al,cs:(CG:dos_errors-CG:ros_errors-1)[di]
|
|
; combine with type of error
|
|
popx <di, es>
|
|
stc
|
|
ret
|
|
|
|
|
|
|
|
setup_rw: ; prepare for INPUT, OUTPUT or OUTPUT_VFY
|
|
;--------
|
|
; On Entry:
|
|
; ES:DI -> UDSC
|
|
; On Exit:
|
|
; if CY == 0:
|
|
; P_CYL, P_HEAD, P_SECTOR,
|
|
; P_DMAOFF, P_DMASEG, P_COUNT initialized
|
|
; if CY == 1: invalid parameters detected
|
|
; ES:DI preserved
|
|
|
|
push ds
|
|
lds bx,REQUEST[bp]
|
|
mov ax,ds:RH4_BUFOFF[bx] ; get offset of transfer buffer
|
|
mov P_DMAOFF[bp],ax ; set transfer offset
|
|
mov ax,ds:RH4_BUFSEG[bx] ; get segment of transfer buffer
|
|
mov P_DMASEG[bp],ax ; set transfer segment
|
|
mov ax,ds:RH4_COUNT[bx] ; get sector count from request header
|
|
mov P_COUNT[bp],ax ; save it locally for later
|
|
mov ax,ds:RH4_SECTOR[bx] ; get low 16 bit of sector #
|
|
sub dx,dx ; assume value is 16 bit only
|
|
cmp ds:RH_LEN[bx],22 ; check if small request
|
|
je setrw2 ; if so forget the rest
|
|
cmp ds:RH_LEN[bx],24 ; check if large request
|
|
jne setrw1
|
|
mov dx,ds:RH4_SECTOR+2[bx] ; yes, get 32-bit record number
|
|
jmps setrw2
|
|
setrw1:
|
|
cmp ds:RH_LEN[bx],30
|
|
jne setrw2
|
|
cmp ax,-1 ; magic number indicating it's
|
|
jne setrw2 ; a 32-bit record number
|
|
mov ax,ds:RH4_BIGSECTORLO[bx]
|
|
mov dx,ds:RH4_BIGSECTORHI[bx]
|
|
setrw2:
|
|
pop ds
|
|
|
|
mov cx,P_COUNT[bp] ; get requested count
|
|
jcxz setrw3 ; invalid count
|
|
dec cx ; CX = count - 1
|
|
cmp es:word ptr (UDSC_BPB+BPB_TOTSEC)[di],0
|
|
jne setrw4 ; skip if < 65536 sectors on disk
|
|
add ax,cx
|
|
adc dx,0 ; AX/DX = # of last sector for I/O
|
|
jc setrw3 ; error if > 32 bits
|
|
cmp dx,es:word ptr (UDSC_BPB+BPB_SIZE+2)[di]
|
|
ja setrw3 ; skip if too large
|
|
jb setrw5 ; O.K. if small enough
|
|
cmp ax,es:word ptr (UDSC_BPB+BPB_SIZE)[di]
|
|
jb setrw5 ; fail if too large
|
|
setrw3:
|
|
mov ax,RHS_ERROR+8 ; return "sector not found"
|
|
stc
|
|
ret
|
|
|
|
setrw4: ; less than 65536 records
|
|
add ax,cx ; compute end of transfer
|
|
jc setrw3 ; skip if overflow
|
|
cmp ax,es:UDSC_BPB+BPB_TOTSEC[di]
|
|
jae setrw3 ; skip if too large
|
|
setrw5:
|
|
sub ax,cx
|
|
sbb dx,0 ; add partition address for hard disk
|
|
add ax,es:word ptr (UDSC_BPB+BPB_HIDDEN)[di]
|
|
adc dx,es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di]
|
|
push ax ; AX/DX = 32 bit starting record address
|
|
push dx ; save starting record
|
|
mov ax,es:UDSC_BPB+BPB_SPT[di]
|
|
mul es:UDSC_BPB+BPB_HEADS[di]; get sectors per track * heads
|
|
mov cx,ax ; CX = sectors per cylinder
|
|
pop dx ; recover 32 bit start block
|
|
pop ax
|
|
div cx ; AX = cylinder #, DX = head/sec offset
|
|
mov P_CYL[bp],ax ; save physical cylinder number
|
|
xor ax,ax ; make remainder 32 bit so
|
|
xchg ax,dx ; DX:AX = (head # * SPT) + sector #
|
|
div es:UDSC_BPB+BPB_SPT[di] ; divide by sectors per track
|
|
mov P_SECTOR[bp],dl ; DX = sector #, AX = head #
|
|
mov P_HEAD[bp],al ; save physical sector/head for later
|
|
|
|
clc ; tell them we like the parameters
|
|
ret ; we've figured out starting address
|
|
|
|
track_rw:
|
|
;--------
|
|
; entry: P_CYL = cylinder for start of transfer
|
|
; P_HEAD = head # for start of transfer
|
|
; P_SECTOR = sector # for start of transfer
|
|
; P_COUNT = remaining sector count
|
|
; P_DMAOFF = transfer offset
|
|
; P_DMASEG = transfer segment
|
|
; ES:DI -> UDSC structure
|
|
; exit: CY = 0 if no error, P_COUNT = remaining sectors
|
|
; CY = 1 if error, AH = ROS error code
|
|
|
|
call track_setup ; compute size of transfer
|
|
if FASTSETTLE
|
|
call new_settle ; set new head settle delay
|
|
endif
|
|
cmp P_DIRECT[bp],0 ; DMA boundary problem?
|
|
jne trkrw10 ; no, direct transfer performed
|
|
cmp P_ROSCMD[bp],ROS_READ
|
|
je trkrw10 ; skip if not writing to disk
|
|
pushx <ds, es, di>
|
|
mov cx,SECSIZE/2 ; CX = # of word per sector
|
|
push ds
|
|
pop es ; ES:DI -> destination
|
|
mov di,CG:local_buffer
|
|
lds si,P_DMA[bp] ; DS:SI -> source
|
|
rep movsw ; copy from deblocking buffer
|
|
popx <di, es, ds>
|
|
trkrw10:
|
|
mov P_RETRY[bp],RETRY_MAX ; perform up to three retries
|
|
trkrw20: ; loop back here for retries
|
|
mov cx,P_CYL[bp] ; get cylinder #
|
|
xchg cl,ch ; CH = bits 0..7, CL = bits 8..11
|
|
ror cl,1
|
|
ror cl,1 ; cylinder bits 8..9 in bits 6..7
|
|
mov dh,cl ; cylinder bits 10.11 in bits 0..1
|
|
and cl,11000000b ; isolate cylinder bits 8..9
|
|
add cl,P_SECTOR[bp] ; bits 0..5 are sector number
|
|
inc cx ; make it one-relative for ROS
|
|
ror dh,1
|
|
ror dh,1 ; cylinder bits 10..11 in bits 6..7
|
|
and dh,11000000b ; isolate cylinder bits 10..11
|
|
add dh,P_HEAD[bp] ; add physical head number
|
|
mov dl,es:UDSC_RUNIT[di] ; get ROS unit #
|
|
|
|
push es
|
|
mov ax,ds
|
|
mov es,ax
|
|
mov bx,CG:local_buffer ; point at our local buffer
|
|
cmp P_DIRECT[bp],0 ; DMA boundary problem?
|
|
je trkrw30 ; no, direct transfer performed
|
|
les bx,P_DMA[bp] ; ES:BX -> transfer address
|
|
trkrw30:
|
|
mov ax,P_MCNT[bp] ; AL = physical sector count
|
|
mov ah,P_ROSCMD[bp] ; AH = ROS read command
|
|
cmp ah,ROS_VERIFY ; write with verify?
|
|
jne trkrw40 ; skip if ROS_READ or ROS_WRITE
|
|
mov ah,ROS_WRITE ; else first perform normal write
|
|
int_____DISK_INT ; call ROS to write to disk
|
|
jc trkrw50 ; skip if any errors occurred
|
|
mov ax,P_MCNT[bp] ; else get sector count
|
|
mov ah,ROS_VERIFY ; verify disk sectors
|
|
trkrw40: ; AH = function, AL = count
|
|
int_____DISK_INT ; read/write/verify via ROM BIOS
|
|
trkrw50: ; CY = 1, AH = error code
|
|
pop es
|
|
jnc trkrw70 ; skip if no errors occurred
|
|
call disk_reset ; reset the hardware
|
|
cmp ah,11h ; ECC corrected data?
|
|
je trkrw60 ; first sector known to be good
|
|
cmp ah,03h ; write protect error
|
|
je trkrw_error ; don't recover, report to user
|
|
dec P_RETRY[bp] ; count # of errors so far
|
|
jnz trkrw20 ; retries done, declare it permanent
|
|
trkrw_error: ; disk error occurred
|
|
if FASTSETTLE
|
|
call old_settle ; restore head settle delay
|
|
endif
|
|
stc ; CY = 1 indicates error, AH = code
|
|
ret
|
|
|
|
trkrw60: ; ECC error, only 1st sector OK
|
|
mov P_MCNT[bp],1 ; say we have done one sector
|
|
trkrw70: ; read/write/verify succeeded
|
|
cmp P_DIRECT[bp],0 ; DMA boundary problem?
|
|
jne trkrw80 ; no, direct transfer performed
|
|
cmp P_ROSCMD[bp],ROS_READ
|
|
jne trkrw80 ; skip if not reading from disk
|
|
pushx <di, ds, es>
|
|
mov cx,SECSIZE/2 ; CX = # of word per sector
|
|
mov si,CG:local_buffer
|
|
les di,P_DMA[bp] ; DS:SI -> source, ES:DI -> destination
|
|
rep movsw ; copy from deblocking buffer
|
|
popx <es, ds, di>
|
|
trkrw80:
|
|
mov ax,P_MCNT[bp] ; get physical transfer length
|
|
sub P_COUNT[bp],ax ; subtract from total transfer length
|
|
jz trkrw90 ; exit if none left
|
|
add P_SECTOR[bp],al ; update current sector
|
|
mov ah,SECSIZE/16
|
|
mul ah ; AX = paras to inc DMA address
|
|
add P_DMASEG[bp],ax ; update DMA segment
|
|
xor ax,ax
|
|
mov al,P_SECTOR[bp] ; get current sector
|
|
cmp ax,es:UDSC_BPB+BPB_SPT[di]
|
|
jb trkrw90 ; skip if on same track
|
|
mov P_SECTOR[bp],0 ; else start at beginning of new track
|
|
inc P_HEAD[bp] ; move to the next head
|
|
mov al,P_HEAD[bp] ; get current head
|
|
cmp ax,es:UDSC_BPB+BPB_HEADS[di]
|
|
jb trkrw90 ; did we go over end of cylinder?
|
|
mov P_HEAD[bp],0 ; start with first head...
|
|
inc P_CYL[bp] ; ... on the next cylinder
|
|
trkrw90:
|
|
if FASTSETTLE
|
|
call old_settle ; restore head settle delay
|
|
endif
|
|
clc ; indicate no errors
|
|
ret
|
|
|
|
|
|
|
|
disk_reset:
|
|
;----------
|
|
; entry: DL = ROS drive code
|
|
|
|
push ax ; save the error status
|
|
; mov ah,ROS_RESET ; try a restore
|
|
xor ax,ax
|
|
int_____DISK_INT ; might sort things out
|
|
pop ax ; restore error status
|
|
ret
|
|
|
|
|
|
track_setup: ; prepare for I/O on disk track
|
|
;-----------
|
|
; entry: P_CYL = cylinder for start of transfer
|
|
; P_HEAD = head # for start of transfer
|
|
; P_SECTOR = sector # for start of transfer
|
|
; P_COUNT = remaining sector count
|
|
; P_DMAOFF = transfer offset
|
|
; P_DMASEG = transfer segment
|
|
; ES:DI -> UDSC structure
|
|
; exit: P_DIRECT = 1 if no deblocking
|
|
; P_MCNT = # of sectors possible in one ROS call
|
|
|
|
|
|
mov ax,P_DMASEG[bp] ; get transfer address
|
|
cmp ax,DeblockSeg ; is this in high memory ?
|
|
jae trksu20 ; then force through deblock buffer
|
|
mov ax,P_COUNT[bp] ; assume we can transfer all
|
|
mov P_MCNT[bp],ax ; that's requested this time
|
|
mov P_DIRECT[bp],1 ; directly to destination
|
|
test es:UDSC_RUNIT[di],80h ; is it a hard disk transfer ?
|
|
jnz trksu30 ; yes, transfer the lot
|
|
; floppy transfer, break up into tracks
|
|
mov dx,es:UDSC_BPB+BPB_SPT[di]
|
|
; DX = sectors per track
|
|
sub dl,P_SECTOR[bp] ; subtract starting sector
|
|
cmp dx,ax ; more than we want?
|
|
jae trksu10 ; no, use this count
|
|
mov P_MCNT[bp],dx ; set count for this pass
|
|
trksu10:
|
|
mov ax,P_DMASEG[bp] ; get transfer address
|
|
mov cl,4
|
|
shl ax,cl ; get A4..A15 from segment
|
|
add ax,P_DMAOFF[bp] ; combine with A0..A15 from offset
|
|
not ax ; AX = # of bytes left in 64K bank
|
|
sub dx,dx
|
|
mov cx,SECSIZE
|
|
div cx ; convert this to physical sectors
|
|
cmp ax,P_MCNT[bp] ; capable of more than requested?
|
|
jae trksu30 ; skip if we can do it all
|
|
mov P_MCNT[bp],ax ; else update possible transfer length
|
|
test ax,ax ; can we transfer anything at all?
|
|
jnz trksu30 ; yes, perform the transfer
|
|
trksu20:
|
|
mov P_MCNT[bp],1 ; single sector transfer via buffer
|
|
mov P_DIRECT[bp],0 ; if DIRECT = 0, deblocked transfer
|
|
trksu30:
|
|
ret
|
|
|
|
|
|
|
|
|
|
if FASTSETTLE
|
|
new_settle:
|
|
;----------
|
|
test es:UDSC_FLAGS[di],UDF_HARD ; fix head settle on floppies
|
|
jnz new_settle9
|
|
cmp P_ROSCMD[bp],ROS_READ
|
|
jne new_settle9
|
|
push ax
|
|
pushx <bx, ds>
|
|
sub ax,ax
|
|
mov ds,ax
|
|
Assume DS:IVECT
|
|
lds bx,i1eptr
|
|
xchg al,9[bx]
|
|
Assume DS:CGROUP
|
|
popx <ds, bx>
|
|
mov P_SETTLE[bp],al
|
|
pop ax
|
|
new_settle9:
|
|
ret
|
|
|
|
old_settle:
|
|
;----------
|
|
test es:UDSC_FLAGS[di],UDF_HARD ; fix head settle on floppies
|
|
jnz old_settle9
|
|
cmp P_ROSCMD[bp],ROS_READ
|
|
jne old_settle9
|
|
pushx <ax, bx, ds>
|
|
mov al,P_SETTLE[bp]
|
|
sub bx,bx
|
|
mov ds,bx
|
|
Assume DS:IVECT
|
|
lds bx,i1eptr
|
|
mov 9[bx],al
|
|
Assume DS:CGROUP
|
|
popx <ds, bx, ax>
|
|
old_settle9:
|
|
ret
|
|
endif
|
|
|
|
|
|
dd_open: ; 13-device open
|
|
;-------
|
|
call point_unit ; get unit descriptor
|
|
inc es:UDSC_OPNCNT[di] ; increment open count
|
|
sub ax,ax
|
|
ret
|
|
|
|
|
|
dd_close: ; 14-device close
|
|
;--------
|
|
call point_unit ; get unit descriptor
|
|
dec es:UDSC_OPNCNT[di] ; decrement open count
|
|
sub ax,ax
|
|
ret
|
|
|
|
|
|
dd_remchk: ; 15-removable media check
|
|
;---------
|
|
call point_unit ; get unit descriptor
|
|
sub ax,ax ; assume floppy disk
|
|
test es:UDSC_FLAGS[di],UDF_HARD
|
|
jz remchk1 ; skip if it really is a floppy
|
|
mov ax,RHS_BUSY ; else return "busy" for hard disk
|
|
remchk1:
|
|
ret
|
|
|
|
dd_genioctl: ; 19-generic IOCTL
|
|
;-----------
|
|
mov cx,es:RH19_CATEGORY[bx] ; get major & minor function
|
|
xchg cl,ch ; swap them around
|
|
call point_unit ; get unit descriptor
|
|
|
|
cmp ch,8 ; is it the right major category?
|
|
jne ioctl20 ; no, return an error
|
|
|
|
or es:UDSC_FLAGS[di],UDF_UNSURE
|
|
; media unsure after IOCTL
|
|
|
|
mov si,offset CGROUP:genioctlTable
|
|
ioctl10:
|
|
lods cs:byte ptr [si] ; get category
|
|
mov ch,al ; keep in CH
|
|
lods cs:word ptr [si] ; AX = function address
|
|
cmp cl,ch ; is it the category we want ?
|
|
je ioctl30 ; yes, go do it
|
|
test ch,ch ; is it the end of the list ?
|
|
jnz ioctl10 ; no, do another one
|
|
ioctl20:
|
|
mov ax,RHS_ERROR+3 ; "unknown command"
|
|
ret
|
|
ioctl30:
|
|
jmp ax ; go do our routine
|
|
|
|
genioctlTable label byte
|
|
db RQ19_SET ; set device parameters
|
|
dw offset CGROUP:ioctl_set
|
|
db RQ19_GET ; get device parameters
|
|
dw offset CGROUP:ioctl_get
|
|
db RQ19_WRITE ; write track
|
|
dw offset CGROUP:ioctl_write
|
|
db RQ19_READ ; read track
|
|
dw offset CGROUP:ioctl_read
|
|
db RQ19_FORMAT ; format & verify track
|
|
dw offset CGROUP:ioctl_format
|
|
db RQ19_VERIFY ; verify track
|
|
dw offset CGROUP:ioctl_verify
|
|
db RQ19_GETMEDIA ; get media id
|
|
dw offset CGROUP:ioctl_getmedia
|
|
db RQ19_SETMEDIA ; set media id
|
|
dw offset CGROUP:ioctl_setmedia
|
|
db 0 ; terminate the list
|
|
|
|
point_ioctl_packet:
|
|
;------------------
|
|
; On Entry:
|
|
; None
|
|
; On Exit:
|
|
; DS:BX -> ioctl request packet
|
|
; All other regs preserved
|
|
;
|
|
lds bx,REQUEST[bp]
|
|
lds bx,ds:RH19_GENPB[bx] ; ES:BX -> request packet
|
|
ret
|
|
|
|
|
|
ioctl_get:
|
|
;---------
|
|
push ds
|
|
call point_ioctl_packet ; DS:BX -> ioctl packet
|
|
mov al,es:UDSC_TYPE[di] ; get drive type
|
|
mov ds:1[bx],al ; return drive type (0/1/2/5/7)
|
|
|
|
mov ax,es:UDSC_FLAGS[di] ; get device attributes
|
|
and ax,UDF_HARD+UDF_CHGLINE ; isolate hard disk + change line bits
|
|
mov ds:2[bx],ax ; return device attributes
|
|
|
|
mov ax,es:UDSC_NCYL[di] ; get # of cylinders
|
|
mov ds:4[bx],ax ; return # of cylinders
|
|
|
|
sub ax,ax ; for now always say "default"
|
|
mov ds:6[bx],al ; return media type
|
|
|
|
test ds:byte ptr [bx],1 ; return default BPB?
|
|
pop ds
|
|
lea si,UDSC_DEVBPB[di] ; assume we want device BPB
|
|
jz get1 ; skip if yes
|
|
test es:UDSC_FLAGS[di],UDF_HARD
|
|
jnz get1 ; BPB doesn't change for hard disks
|
|
call ask_for_disk ; make sure we've got correct floppy
|
|
call login_media ; determine floppy disk type
|
|
jc get_err ; abort if can't login disk
|
|
lea si,es:UDSC_BPB[di] ; get current BPB
|
|
get1:
|
|
push ds
|
|
push es
|
|
push di
|
|
push es
|
|
call point_ioctl_packet ; DS:BX -> ioctl packet
|
|
push ds
|
|
pop es
|
|
lea di,7[bx] ; ES:DI -> BPB in parameter block
|
|
pop ds ; DS:SI -> BPB to copy
|
|
mov cx,UDSC_BPB_LENGTH
|
|
rep movsb ; copy the BPB across to user
|
|
pop di
|
|
pop es
|
|
pop ds
|
|
xor ax,ax ; return success
|
|
ret
|
|
get_err:
|
|
jmp xlat_error ; return error code
|
|
; ret
|
|
|
|
ioctl_set: ; set device parameters
|
|
;---------
|
|
|
|
push ds
|
|
push es
|
|
call point_ioctl_packet ; DS:BX -> ioctl packet
|
|
test ds:byte ptr [bx],2 ; ignore all but track layout?
|
|
jnz set2 ; yes, skip BPB stuff
|
|
|
|
mov al,ds:1[bx] ; get new drive type (0/1/2/5/7)
|
|
mov es:UDSC_TYPE[di],al ; set drive type
|
|
|
|
and es:UDSC_FLAGS[di],not (UDF_HARD+UDF_CHGLINE)
|
|
mov ax,ds:2[bx] ; get new device attributes
|
|
and ax,UDF_HARD+UDF_CHGLINE ; isolate hard disk + change line bits
|
|
or es:UDSC_FLAGS[di],ax ; combine the settings
|
|
|
|
mov ax,ds:4[bx] ; get new # of cylinders
|
|
mov es:UDSC_NCYL[di],ax ; set # of cylinders
|
|
|
|
lea ax,UDSC_BPB[di] ; AX -> media BPB in es:UDSC_
|
|
test ds:byte ptr [bx],1 ; fix BPB for "build BPB" call?
|
|
jnz set1 ; skip if new media BPB only
|
|
lea ax,UDSC_DEVBPB[di] ; AX -> device BPB in es:UDSC_
|
|
set1:
|
|
lea si,7[bx] ; DS:SI -> new BPB from user
|
|
xchg ax,di ; ES:DI -> BPB in es:UDSC_
|
|
mov cx,UDSC_BPB_LENGTH
|
|
rep movsb ; copy BPB into UDSC as new default
|
|
xchg ax,di ; ES:DI -> UDSC_ again
|
|
|
|
set2: ; now set track layout
|
|
lea si,BPB_LENGTH+7[bx] ; DS:SI -> new user layout
|
|
mov es,cs:DataSegment
|
|
mov di,CG:layout_table ; ES:DI -> BIOS layout table
|
|
lodsw ; get sector count
|
|
test ax,ax ; make sure this is good value
|
|
jz set6
|
|
cmp ax,MAX_SPT ; make sure this is good value
|
|
ja set6 ; so we don't overflow table
|
|
xchg ax,cx ; CX = sector count
|
|
set3: ; loop here for every sector
|
|
inc di
|
|
inc di
|
|
lodsw ; get sector number
|
|
stosb ; write sector number
|
|
lodsw ; get sector size (0080, 0100, 0200, 0400)
|
|
shl ax,1 ; double it (0100, 0200, 0400, 0800)
|
|
set4:
|
|
shr ah,1 ; halve the sector size until = 128
|
|
jc set5 ; we've shifted out bottom bit
|
|
inc al ; count the # of bits
|
|
jnz set4 ; (this should always jump)
|
|
set5:
|
|
stosb ; store LOG2 (sector size/128)
|
|
loop set3 ; repeat for all sectors
|
|
set6:
|
|
pop es
|
|
pop ds
|
|
xor ax,ax
|
|
ret
|
|
|
|
ioctl_read:
|
|
;----------
|
|
|
|
mov P_ROSCMD[bp],ROS_READ ; read physical track
|
|
jmps ioctl_rw_common ; use common code
|
|
|
|
ioctl_write:
|
|
;-----------
|
|
|
|
mov P_ROSCMD[bp],ROS_WRITE ; write physical track
|
|
; jmps ioctl_rw_common ; use common code
|
|
|
|
ioctl_rw_common:
|
|
call ask_for_disk ; make sure we've got correct floppy
|
|
push ds
|
|
call point_ioctl_packet ; DS:BX -> ioctl packet
|
|
mov al,ds:5[bx] ; get logical sector (0..SPT-1)
|
|
mov P_SECTOR[bp],al
|
|
mov ax,ds:7[bx] ; get sector count
|
|
mov P_COUNT[bp],ax
|
|
mov ax,ds:9[bx] ; get transfer address
|
|
mov P_DMAOFF[bp],ax
|
|
mov ax,ds:11[bx]
|
|
mov P_DMASEG[bp],ax
|
|
mov ax,ds:1[bx] ; get head number
|
|
mov P_HEAD[bp],al
|
|
mov ax,ds:3[bx] ; get cylinder number
|
|
mov P_CYL[bp],ax
|
|
pop ds
|
|
rw_loop:
|
|
call track_rw ; read as much as possible on track
|
|
jc rw_err ; return if physical disk error
|
|
cmp P_COUNT[bp],0 ; test if any more stuff to read
|
|
jne rw_loop ; yes, loop back for more
|
|
sub ax,ax ; all done, no error encountered
|
|
ret ; return O.K. code
|
|
rw_err:
|
|
jmp xlat_error ; translate ROS code to DOS error
|
|
; ret
|
|
|
|
ioctl_verify:
|
|
;------------
|
|
ioctl_format:
|
|
;------------
|
|
call ask_for_disk ; make sure we've got correct floppy
|
|
mov P_RETRY[bp],RETRY_MAX ; perform up to three retries
|
|
format_retry:
|
|
call set_format ; attempt data rate setup
|
|
push ds
|
|
call point_ioctl_packet ; DS:BX -> ioctl packet
|
|
test ds:byte ptr [bx],1 ; are we testing parameters only ?
|
|
jz format10
|
|
mov ds:[bx],al ; return AL
|
|
pop ds
|
|
xor ax,ax ; we succeeded
|
|
ret
|
|
|
|
format10:
|
|
mov ax,es:UDSC_BPB+BPB_SPT[di]
|
|
test ds:byte ptr [bx],2 ; is it undocumented "do 2 tracks" bit?
|
|
jz format20
|
|
add ax,ax ; yes, double the count
|
|
format20:
|
|
mov P_COUNT[bp],ax ; save it locally for later
|
|
mov dh,ds:1[bx] ; get head #
|
|
mov cx,ds:3[bx] ; get cylinder #
|
|
ror ch,1
|
|
ror ch,1
|
|
xchg cl,ch
|
|
or cl,1 ; start with sector 1
|
|
mov dl,es:UDSC_RUNIT[di] ; get ROS drive #
|
|
lds bx,REQUEST[bp] ; DS:BX -> Request Header
|
|
mov bx,ds:RH19_CATEGORY[bx] ; get major & minor function
|
|
pop ds
|
|
|
|
push es
|
|
xor ax,ax
|
|
mov es,ax
|
|
mov ax,new_int1e_off ; point floppy paramters at local
|
|
xchg ax,es:[4*1Eh]
|
|
mov orig_int1e_off,ax ; save old value
|
|
mov ax,new_int1e_seg
|
|
xchg ax,es:[4*1Eh+2]
|
|
mov orig_int1e_seg,ax
|
|
pop es
|
|
|
|
format30:
|
|
cmp bh,RQ19_FORMAT ; skip if verify only
|
|
jne format40
|
|
test es:UDSC_FLAGS[di],UDF_HARD
|
|
jnz format40 ; hard disks are always verify
|
|
|
|
mov ax,P_COUNT[bp]
|
|
mov ah,ROS_FORMAT
|
|
push es
|
|
push bx
|
|
push ds
|
|
pop es
|
|
mov bx,CG:layout_table ; ES:BX -> parameter table
|
|
int_____DISK_INT
|
|
pop bx
|
|
pop es
|
|
jc format50
|
|
format40: ; no error on format, try verify
|
|
mov ax,P_COUNT[bp]
|
|
mov ah,ROS_VERIFY
|
|
push es
|
|
push bx
|
|
xor bx,bx
|
|
mov es,bx
|
|
int_____DISK_INT
|
|
pop bx
|
|
pop es
|
|
jc format50
|
|
xor ax,ax ; return success
|
|
format50:
|
|
push es
|
|
push di
|
|
push ax
|
|
mov ax,0
|
|
mov es,ax
|
|
mov di,78h
|
|
mov ax,orig_int1e_off
|
|
stosw
|
|
mov ax,orig_int1e_seg
|
|
stosw
|
|
pop ax
|
|
pop di
|
|
pop es
|
|
jnc format60 ; if no error's just exit
|
|
call xlat_error ; translate to DOS error
|
|
dec P_RETRY[bp] ; any more retries ?
|
|
jz format60 ; no, just exit with error
|
|
; mov ah,ROS_RESET
|
|
xor ax,ax
|
|
int_____DISK_INT ; reset the drive
|
|
jmp format_retry ; now give it another go
|
|
format60:
|
|
ret
|
|
|
|
|
|
; The following table indicates which combinations of drive
|
|
; types, sectors per track and tracks per disk are O.K. and
|
|
; which value in AL is required for those combinations for
|
|
; INT 13h, AH = 17h ("set DASD type for format").
|
|
|
|
; +---------------------- 0 = 360Kb, 1 = 1.2Mb, 2 = 720Kb
|
|
; | +------------------ # of sectors/track (9, 15, 18)
|
|
; | | +--------------- # of tracks per disk (40 or 80)
|
|
; | | | +----------- 1 = 360 Kb in 360 Kb
|
|
; | | | | 2 = 360 Kb in 1.2 Mb
|
|
; | | | | 3 = 1.2 Mb in 1.2 Mb
|
|
; | | | | 4 = 720 Kb in 720 Kb
|
|
; | | | | +-------- gap length for format
|
|
; | | | | |
|
|
; V V V V V
|
|
|
|
ok_fmt_table db 0, 9, 40, 1, 50h ; 360 Kb
|
|
db 1, 9, 40, 2, 50h ; 360 Kb in 1.2 Mb
|
|
db 1, 15, 80, 3, 54h ; 1.2 Mb in 1.2 Mb
|
|
db 2, 9, 80, 4, 50h ; 720 Kb in 720 Kb
|
|
db -1 ; end of table
|
|
|
|
set_format:
|
|
;----------
|
|
; On Entry:
|
|
; ES:DI -> UDSC_
|
|
; On Exit:
|
|
; AL = 0 on success, else value to return in parameter block
|
|
; ES:DI preserved
|
|
;
|
|
push ds
|
|
call point_ioctl_packet ; DS:BX -> ioctl packet
|
|
mov dh,ds:1[bx] ; get the head number
|
|
mov cx,ds:3[bx] ; get the cylinder number
|
|
pop ds
|
|
|
|
mov si,CG:layout_table ; SI -> track layout table
|
|
mov ax,MAX_SPT ; AX = # of sectors per track
|
|
set_format10:
|
|
mov 0[si],cl ; set cylinder number
|
|
mov 1[si],dh ; set head number
|
|
add si,4 ; next sector entry
|
|
dec ax ; count down # of sectors
|
|
jnz set_format10 ; repeat until all done
|
|
|
|
call get_ncyl ; return # of tracks
|
|
dec ax ; AX = max. cylinder #
|
|
ror ah,1
|
|
ror ah,1 ; move bits 8,9 into 6,7
|
|
xchg al,ah
|
|
mov cx,es:UDSC_BPB+BPB_SPT[di]
|
|
; get desired sectors/track
|
|
or cx,ax ; CL, CH = max. cylinder/max. sector #
|
|
cmp cx,2708h ; check for 40 track, 8 sectors/track
|
|
jne set_format20 ; we convert 160, 320 to 180, 360
|
|
inc cx ; make it 9 sectors per track
|
|
set_format20:
|
|
mov dl,es:UDSC_RUNIT[di] ; get ROS unit number
|
|
pushx <es, di>
|
|
mov ah,ROS_SETMEDIA ; set type for format
|
|
int_____DISK_INT ; check if combination is legal
|
|
mov new_int1e_off,di
|
|
mov new_int1e_seg,es ; ES:DI -> new parameters if legal
|
|
popx <di, es>
|
|
jc set_format40 ; did we succeed ?
|
|
set_format30:
|
|
xor ax,ax ; success, return no errors
|
|
ret
|
|
|
|
set_format40:
|
|
; ROM BIOS has given an error, if the function isn't supported drop
|
|
; thru' and try the older method's
|
|
;
|
|
mov al,2 ; assume ROS doesn't support it
|
|
cmp ah,0Ch ; media combination not supported ?
|
|
je set_format80 ; return AL=2
|
|
inc ax ; AL = 3
|
|
cmp ah,80h ; drive not ready ?
|
|
je set_format80 ; return AL=3
|
|
|
|
; Lets look for a match in our tables
|
|
|
|
call get_ncyl ; AX = number of cylinders
|
|
mov cx,es:UDSC_BPB+BPB_SPT[di]
|
|
; CL = sectors per track
|
|
mov ch,al ; CH = tracks per disk
|
|
cmp cx,2808h ; 40 tracks, 8 sectors?
|
|
jne set_format50
|
|
inc cx ; force it to 9 sectors/track
|
|
set_format50:
|
|
mov si,CG:ok_fmt_table-4
|
|
set_format60:
|
|
add si,4 ; next table entry
|
|
lods cs:byte ptr [si] ; get drive type
|
|
cmp al,0FFh ; end of device/media list?
|
|
je set_format70 ; yes, can't handle this combination
|
|
cmp al,es:UDSC_TYPE[di] ; does the drive type match?
|
|
jne set_format60 ; try next one if wrong drive
|
|
cmp cx,cs:[si] ; do tracks/sectors match?
|
|
jne set_format60 ; no, try next one
|
|
|
|
mov parms_spt,cl ; set sectors/track
|
|
mov al,cs:3[si] ; get required gap length from table
|
|
mov parms_gpl,al ; set gap length for format
|
|
mov ax,CG:local_parms
|
|
mov new_int1e_off,ax ; use local parameters for formatting
|
|
mov new_int1e_seg,ds ; set new interrupt vector address
|
|
mov dl,es:UDSC_RUNIT[di]
|
|
mov al,cs:2[si] ; get media/drive combination
|
|
mov ah,ROS_SETTYPE ; set the drive type
|
|
int_____DISK_INT
|
|
jnc set_format30 ; return if no errors
|
|
cmp es:UDSC_TYPE[di],0 ; is this a 360 K drive?
|
|
je set_format30 ; go ahead, might be old ROS
|
|
cmp es:UDSC_TYPE[di],2 ; is this a 720 K drive?
|
|
je set_format30 ; go ahead, might be old ROS
|
|
set_format70:
|
|
mov al,1 ; return not supported
|
|
set_format80:
|
|
ret
|
|
|
|
|
|
get_ncyl:
|
|
;--------
|
|
mov ax,es:UDSC_BPB+BPB_TOTSEC[di]
|
|
xor dx,dx ; get sectors on disk
|
|
test ax,ax ; zero means we use 32 bit value
|
|
jnz get_ncyl10
|
|
mov ax,es:word ptr (UDSC_BPB+BPB_SIZE)[di]
|
|
mov dx,es:word ptr (UDSC_BPB+BPB_SIZE+2)[di]
|
|
get_ncyl10:
|
|
div es:UDSC_BPB+BPB_SPT[di] ; AX = # of cylinders * heads
|
|
call get_ncyl20 ; round up
|
|
div es:UDSC_BPB+BPB_HEADS[di]; AX = # of cylinders
|
|
get_ncyl20:
|
|
test dx,dx ; do we have overflow ?
|
|
jz get_ncyl30
|
|
inc ax ; round up
|
|
xor dx,dx ; make it a 32 bit value
|
|
get_ncyl30:
|
|
ret
|
|
|
|
|
|
ioctl_getmedia:
|
|
;--------------
|
|
mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
|
|
call rw_media ; read the boot sector
|
|
jc getmedia10
|
|
push es
|
|
push di
|
|
push ds
|
|
call point_ioctl_packet ; DS:BX -> ioctl packet
|
|
push ds
|
|
pop es
|
|
lea di,2[bx] ; ES:DI -> skip info word
|
|
pop ds ; DS:SI -> boot sector media id
|
|
mov cx,4+11+8
|
|
rep movsb ; copy the boot sector image
|
|
pop di
|
|
pop es
|
|
xor ax,ax
|
|
getmedia10:
|
|
ret
|
|
|
|
|
|
ioctl_setmedia:
|
|
;--------------
|
|
mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
|
|
call rw_media ; read the boot sector
|
|
jc setmedia10
|
|
push ds
|
|
push si
|
|
push es
|
|
push di
|
|
push ds
|
|
push si
|
|
call point_ioctl_packet ; DS:BX -> ioctl packet
|
|
lea si,2[bx] ; DS:SI -> skip info word
|
|
pop di
|
|
pop es ; ES:DI -> boot sector image
|
|
mov cx,4+11+8
|
|
rep movsb ; update the boot sector image
|
|
pop di
|
|
pop es
|
|
pop si
|
|
pop ds
|
|
mov P_ROSCMD[bp],ROS_WRITE ; write to floppy/hard disk
|
|
jmp rw_media ; write the boot sector
|
|
setmedia10:
|
|
ret
|
|
|
|
rw_media:
|
|
;--------
|
|
; On Entry:
|
|
; ES:DI -> UDSC
|
|
; On Exit:
|
|
; ES:DI preserved
|
|
; CY clear, SI -> boot record info
|
|
; CY set on error, AX = error code
|
|
;
|
|
; setup parameters to read/write boot sector to/from local buffer
|
|
;
|
|
call ask_for_disk ; make sure we've got correct floppy
|
|
mov P_DMAOFF[bp],CG:local_buffer
|
|
mov P_DMASEG[bp],ds ; set transfer address
|
|
mov P_COUNT[bp],1 ; read 1 sector
|
|
mov ax,es:UDSC_BPB+BPB_SPT[di]
|
|
mul es:UDSC_BPB+BPB_HEADS[di]; get sectors per track * heads
|
|
xchg ax,cx ; CX = sectors per cylinder
|
|
mov ax,es:word ptr (UDSC_BPB+BPB_HIDDEN)[di]
|
|
mov dx,es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di]
|
|
div cx ; AX = cylinder #, DX = head/sec offset
|
|
mov P_CYL[bp],ax ; save physical cylinder number
|
|
xor ax,ax ; make remainder 32 bit so
|
|
xchg ax,dx ; DX:AX = (head # * SPT) + sector #
|
|
div es:UDSC_BPB+BPB_SPT[di] ; divide by sectors per track
|
|
mov P_SECTOR[bp],dl ; DX = sector #, AX = head #
|
|
mov P_HEAD[bp],al ; save physical sector/head for later
|
|
call rw_loop ; read the boot sector
|
|
jc rw_media20
|
|
cmp local_buffer+11+BPB_FATID,0F0h
|
|
jb rw_media10
|
|
mov si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11+2
|
|
lodsb ; get extended boot
|
|
sub al,29h ; do we have an extended boot ?
|
|
je rw_media20 ; no, well we can't write a new one
|
|
rw_media10:
|
|
mov ax,RHS_ERROR+3 ; "unknown command"
|
|
rw_media20:
|
|
ret
|
|
|
|
|
|
dd_getdev: ; 23-get logical drive
|
|
;---------
|
|
; get logical drive that corresponds to the physical drive
|
|
call point_unit ; get unit descriptor
|
|
call get_owner ; DL = owning drive (zero not owned)
|
|
jmps dd_setdev10 ; return the owner
|
|
|
|
|
|
dd_setdev: ; 24-set logical drive
|
|
;---------
|
|
; set logical drive that corresponds to the physical drive
|
|
;
|
|
call point_unit ; get unit descriptor
|
|
call set_owner ; set new owner
|
|
dd_setdev10:
|
|
les bx,REQUEST[bp]
|
|
mov es:RH_UNIT[bx],dl ; return current logical drive
|
|
xor ax,ax
|
|
ret
|
|
|
|
get_owner:
|
|
;---------
|
|
; On Entry:
|
|
; ES:DI -> UDSC_
|
|
; On Exit:
|
|
; DL = owning drive (zero = no owner)
|
|
;
|
|
xor dx,dx ; assume one unit per physical drive
|
|
mov ax,es:UDSC_FLAGS[di]
|
|
test ax,UDF_HARD
|
|
jnz get_owner40
|
|
test ax,UDF_VFLOPPY
|
|
jz get_owner40
|
|
push ds
|
|
mov ds,dx ; DS -> low memory
|
|
Assume DS:IVECT
|
|
mov dl,dual_byte
|
|
pop ds
|
|
Assume DS:CGROUP
|
|
mov al,es:UDSC_RUNIT[di] ; lets look for this ROS drive
|
|
test al,al ; is it physical unit zero ?
|
|
jz get_owner30 ; yes, return dual_byte
|
|
push ds ; no, search our internal info
|
|
lds si,udsc_root
|
|
Assume DS:Nothing
|
|
get_owner10:
|
|
cmp al,ds:UDSC_RUNIT[si] ; do we use the same drive ?
|
|
jne get_owner20
|
|
test ds:UDSC_FLAGS[si],UDF_OWNER
|
|
jz get_owner20 ; do we own it ?
|
|
mov dl,ds:UDSC_DRIVE[si] ; get the logical drive owner
|
|
get_owner20:
|
|
lds si,ds:UDSC_NEXT[si]
|
|
cmp si,0FFFFh ; try the next drive
|
|
jne get_owner10
|
|
pop ds
|
|
Assume DS:CGROUP
|
|
get_owner30:
|
|
inc dx ; make drive one based
|
|
get_owner40:
|
|
ret
|
|
|
|
set_owner:
|
|
;---------
|
|
; On Entry:
|
|
; ES:DI -> UDSC_
|
|
; On Exit:
|
|
; ES:DI preserved
|
|
; DL = owning drive (zero = no owner)
|
|
;
|
|
xor dx,dx ; assume one unit per physical drive
|
|
mov ax,es:UDSC_FLAGS[di]
|
|
test ax,UDF_HARD
|
|
jnz set_owner40
|
|
test ax,UDF_VFLOPPY
|
|
jz set_owner40
|
|
mov al,es:UDSC_DRIVE[di]
|
|
mov ah,es:UDSC_RUNIT[di] ; get ROS unit
|
|
test ah,ah ; is it unit zero ?
|
|
jnz set_owner10
|
|
push ds
|
|
mov ds,dx ; DS -> low memory
|
|
Assume DS:IVECT
|
|
mov dual_byte,al ; set dual drive support byte
|
|
pop ds
|
|
Assume DS:CGROUP
|
|
set_owner10:
|
|
push ds
|
|
lds si,udsc_root
|
|
Assume DS:Nothing
|
|
set_owner20:
|
|
cmp ah,ds:UDSC_RUNIT[si] ; does this unit use the same drive ?
|
|
jne set_owner30
|
|
or ds:UDSC_FLAGS[si],UDF_UNSURE+UDF_OWNER
|
|
cmp al,ds:UDSC_DRIVE[di]
|
|
je set_owner30
|
|
and ds:UDSC_FLAGS[si],not UDF_OWNER
|
|
set_owner30:
|
|
lds si,ds:UDSC_NEXT[si]
|
|
cmp si,0FFFFh ; end of the line ?
|
|
jne set_owner20
|
|
pop ds
|
|
Assume DS:CGROUP
|
|
xchg ax,dx ; DL = owning drive
|
|
inc dx ; make it one based
|
|
set_owner40:
|
|
ret
|
|
|
|
|
|
ask_for_disk: ; make sure the right disk is in the floppy drive
|
|
;------------
|
|
call get_owner ; DL = owning drive
|
|
dec dx ; make DL zero based
|
|
js askfdsk30 ; stop if not a logical drive
|
|
mov dh,es:UDSC_DRIVE[di] ; DH = new drive, DL = old drive
|
|
cmp dl,dh ; do we own the drive ?
|
|
je askfdsk30 ; yes, stop now
|
|
push dx ; save for broadcast
|
|
mov dl,dh ; new owner in DL
|
|
call set_owner ; we are now the owner
|
|
push es
|
|
push di
|
|
push cs
|
|
call FullScreen
|
|
pop di
|
|
pop es
|
|
pop dx
|
|
mov ax,4A00h ; should we prompt ?
|
|
xor cx,cx
|
|
int 2Fh ; lets ask
|
|
inc cx ; CX = FFFF ?
|
|
jcxz askfdsk30 ; then skip prompt
|
|
ifdef JAPAN
|
|
mov ax,5001h ; get adaptor mode
|
|
int VIDEO_INT ; ..
|
|
cmp bx,81 ; japanese mode ?
|
|
mov si,CG:disk_msgA_jpn ; get message to print for Japanese
|
|
je askfdsk10 ; yes
|
|
endif
|
|
mov si,CG:disk_msgA ; get message to print
|
|
askfdsk10:
|
|
call WriteASCIIZ ; output the string
|
|
mov al,es:UDSC_DRIVE[di] ; get drive letter for new drive
|
|
add al,'A'
|
|
dec si ; point to NUL
|
|
call WriteNext ; output char, stop at NUL
|
|
ifdef JAPAN
|
|
mov ax,5001h ; get adaptor mode
|
|
int VIDEO_INT ; ..
|
|
cmp bx,81 ; japanese mode ?
|
|
mov si,CG:disk_msgB_jpn ; get message to print for Japanese
|
|
je askfdsk20 ; yes
|
|
endif
|
|
mov si,CG:disk_msgB ; get message to print
|
|
askfdsk20:
|
|
call WriteASCIIZ ; output the string
|
|
mov ah,0 ; wait for any key to be pressed
|
|
int KEYBOARD_INT ; read one key from keyboard
|
|
askfdsk30:
|
|
ret ; we've got the right drive
|
|
|
|
WriteNext:
|
|
int 29h ; output via fastconsole entry
|
|
WriteASCIIZ:
|
|
lods cs:byte ptr [si] ; get next char
|
|
test al,al
|
|
jnz WriteNext ; stop at NUL
|
|
ret
|
|
|
|
FullScreen:
|
|
xor di,di
|
|
mov es,di
|
|
mov ax,1684h ; get the entry point
|
|
mov bx,21 ; for DOSMGR
|
|
int 2Fh
|
|
mov bx,es
|
|
or bx,di ; anyone there ?
|
|
jz FullScreen10
|
|
mov ax,1 ; yes, go full screen please
|
|
push es ; fake a JMPF to ES:DI
|
|
push di
|
|
FullScreen10:
|
|
retf
|
|
|
|
|
|
driver endp
|
|
|
|
|
|
RCODE ends ; end of device driver code
|
|
|
|
page
|
|
|
|
ICODE segment 'ICODE' ; initialization code
|
|
|
|
Assume CS:CGROUP, DS:CGROUP, ES:Nothing, SS:Nothing
|
|
|
|
dd_init: ; 0-initialize driver
|
|
;-------
|
|
|
|
call hard_init ; setup hard disk units
|
|
call floppy_init ; setup floppy units
|
|
|
|
les bx,REQUEST[bp]
|
|
mov al,nunits ; get # of units installed
|
|
mov es:RH0_NUNITS[bx],al ; return value to the BDOS
|
|
mov NumDiskUnits,al ; also set it in device header
|
|
|
|
mov ax,endbios ; get pointer to last resident byte
|
|
mov es:RH0_RESIDENT[bx],ax ; set end of device driver
|
|
mov es:RH0_RESIDENT+2[bx],ds
|
|
|
|
mov ax,CG:bpbtbl
|
|
mov es:RH0_BPBOFF[bx],ax ; set BPB table array
|
|
mov es:RH0_BPBSEG[bx],ds
|
|
|
|
sub ax,ax ; initialization succeeded
|
|
ret ; (BIOS init always does...)
|
|
|
|
|
|
floppy_init:
|
|
;-----------
|
|
mov nunits,0 ; floppies start at drive A:
|
|
mov ah,ROS_RESET ; reset the disk system
|
|
xor dx,dx ; for NEAT hard disk boot bug
|
|
int_____DISK_INT
|
|
int EQUIPMENT_INT ; determine equipment status
|
|
mov cl,6
|
|
shr ax,cl ; shift down floppy bits
|
|
and ax,03h ; mask for floppy
|
|
inc ax ; correct 0 based code
|
|
mov nfloppy,al
|
|
|
|
cmp al,1 ; if there is only one floppy
|
|
jne equip_check_des ; then use 2 designators
|
|
inc ax ; this fakes a B: drive
|
|
equip_check_des:
|
|
mov cx,ax ; CX = # of units to set up
|
|
xor dx,dx ; DL = physical drive
|
|
equip_loop:
|
|
push cx
|
|
|
|
call new_unit ; ES:DI -> UDSC
|
|
mov es:UDSC_RUNIT[di],dl ; set physical drive (ROS code)
|
|
|
|
call floppy_type ; determine type, build default BPB
|
|
|
|
cmp nfloppy,1 ; do we only have single drive?
|
|
je equip_single ; yes, use same physical drive for all
|
|
inc dx ; else use new drive for each unit
|
|
equip_single: ; we only have one physical drive
|
|
|
|
call add_unit ; add ES:DI to list of UDSC_'s
|
|
|
|
pop cx
|
|
loop equip_loop ; repeat for all logical floppies
|
|
|
|
pushx <ds, es>
|
|
|
|
push ds ; DS -> i13_trap segment
|
|
|
|
mov di,ds
|
|
mov es,di
|
|
sub si,si
|
|
mov ds,si
|
|
lds si,78h[si]
|
|
mov di,CG:local_parms ; copy parameters to template
|
|
mov cx,11
|
|
rep movsb
|
|
|
|
pop es ; now ES -> i13_trap segment
|
|
Assume ES:CGROUP
|
|
sub ax,ax
|
|
mov ds,ax ; DS -> interrupt vectors
|
|
Assume DS:IVECT
|
|
mov ax,CG:Int2FTrap ; hook Int 2F
|
|
mov i2Foff,ax
|
|
mov i2Fseg,es
|
|
mov ax,CG:Int13Trap ; hook Int 13
|
|
xchg ax,i13off
|
|
mov es:i13off_save,ax
|
|
mov ax,es
|
|
xchg ax,i13seg
|
|
mov es:i13seg_save,ax
|
|
|
|
mov di,500h ; dual drive byte & friends live here
|
|
mov cx,20h/2 ; zero some bytes at 50h:0
|
|
sub ax,ax ; get a quick zero
|
|
mov es,ax ; ES:DI -> 0:500h
|
|
rep stosw ; setup dual drive byte & friends
|
|
|
|
Assume DS:CGROUP, ES:Nothing
|
|
popx <es, ds>
|
|
|
|
ret
|
|
|
|
|
|
floppy_type:
|
|
;-----------
|
|
; entry: DI -> unit descriptor
|
|
|
|
mov UDSC_TYPE[di],0 ; assume 360K 5.25" floppy
|
|
mov UDSC_NCYL[di],40 ; 40 tracks only
|
|
mov ah,ROS_GETTYPE ; "Read DASD type"
|
|
int_____DISK_INT ; find out if disk change line available
|
|
jc equip_no_chgline ; skip if function not supported
|
|
cmp ah,2 ; floppy with disk change line?
|
|
jne equip_no_chgline ; no, must be old 360K
|
|
or es:UDSC_FLAGS[di],UDF_CHGLINE
|
|
mov es:UDSC_TYPE[di],1 ; assume 1.2Mb floppy
|
|
mov es:UDSC_NCYL[di],80 ; 80 tracks
|
|
equip_no_chgline:
|
|
pushx <es, di, dx> ; save our registers
|
|
mov ah,ROS_PARAM ; read drive parameters
|
|
int_____DISK_INT ; find out floppy type
|
|
popx <dx, di, es>
|
|
jc equip_no_type ; skip if PC,XT,jr,AT before 10 Jan 84
|
|
dec bx ; make values 0 based
|
|
jns equip_type ; (CMOS invalid - type = 0)
|
|
xor bx,bx ; assume 360K
|
|
cmp ch,4fh ; is it 80 track ?
|
|
jne equip_no_type ; if not forget it
|
|
mov bl,1 ; BL = 1 (ie. 1.2M)
|
|
cmp cl,15 ; 15 spt ?
|
|
je equip_type
|
|
inc bx ; BL = 2 (ie. 720k)
|
|
cmp cl,9 ; 9 spt ?
|
|
je equip_type
|
|
inc bx ; BL = 3 (ie. 1.4M)
|
|
cmp cl,18 ; 18 spt ?
|
|
je equip_type
|
|
inc bx
|
|
inc bx ; BL = 5 (ie. 2.8M)
|
|
cmp cl,36 ; 36 spt ?
|
|
jne equip_no_type ; don't recognise anything
|
|
equip_type:
|
|
cmp bl,3 ; is it 1.44 Mb 3.5" type?
|
|
jb equip_type_ok ; skip if 360K, 1.2Mb, 720K (0, 1, 2)
|
|
mov bl,7 ; use reserved "Other" type
|
|
je equip_type_ok
|
|
inc bx ; else make it 2.88 Mb type 9
|
|
inc bx
|
|
equip_type_ok:
|
|
mov es:UDSC_TYPE[di],bl ; set the default drive type for format
|
|
equip_no_type:
|
|
|
|
mov al,es:UDSC_TYPE[di] ; AL = 0, 1, 2 or 7 (360/1.2/720/1.44)
|
|
cbw ; make it a word
|
|
xchg ax,si ; SI = drive type
|
|
shl si,1 ; SI = drive type * 2
|
|
mov si,bpbs[si] ; get default BPB for drive
|
|
cmp si,CG:bpb360 ; is this is a 360 K drive?
|
|
jne equip_360 ; skip if any other type
|
|
mov bpbtbl[bx],CG:bpb720 ; use larger default BPB
|
|
equip_360:
|
|
mov cx,UDSC_BPB_LENGTH ; CX = size of BPB
|
|
pushx <es, di, si, cx>
|
|
lea di,es:UDSC_BPB[di]
|
|
mov ax,ds
|
|
mov es,ax ; ES = DS
|
|
rep movsb ; make default BPB current BPB in UDSC
|
|
popx <cx, si, di, es>
|
|
pushx <es, di>
|
|
lea di,es:UDSC_DEVBPB[di]
|
|
rep movsb ; copy default BPB device BPB in UDSC
|
|
popx <di, es>
|
|
ret
|
|
|
|
|
|
page
|
|
|
|
LOG_PRIM equ 01h ; log in primary partitions
|
|
LOG_EXTD equ 02h ; log in extended partitions
|
|
|
|
log_flag dw LOG_PRIM ; scan for primary only initially
|
|
|
|
hard_init: ; setup all hard disk units
|
|
;---------
|
|
; mov log_flag,LOG_PRIM ; log in primary only initially
|
|
call hardi0 ; C: & D:
|
|
mov log_flag,LOG_EXTD ; log in extended only
|
|
; call hardi0
|
|
; ret
|
|
|
|
hardi0:
|
|
mov ah,ROS_PARAM ; get hard disk parameters
|
|
mov dl,80h
|
|
int_____DISK_INT ; get # of hard disks we have
|
|
jc hardi9 ; skip if hard disks not supported
|
|
test dl,dl ; test if any hard disks found
|
|
jz hardi9 ; skip if there weren't any
|
|
mov al,dl
|
|
cbw
|
|
xchg ax,cx ; CX = # of hard disks
|
|
mov dl,80h ; start with first hard disk
|
|
hardi1:
|
|
pushx <cx, dx> ; save drive count, physical drive
|
|
call login_hdisk ; find all partitions on hard disk
|
|
popx <dx, cx> ; restore physical drive, drive count
|
|
inc dx ; next physical hard disk
|
|
loop hardi1 ; next physical hard disk
|
|
hardi9: ; all hard disks done
|
|
ret
|
|
|
|
|
|
login_hdisk: ; find all partitions on a hard disk
|
|
;-----------
|
|
; entry: DL = 80h, 81h for 1st/2nd hard disk
|
|
|
|
push log_flag ; save state for next drive
|
|
|
|
mov p_unit,dl ; save physical drive
|
|
mov cx,0001h ; track 0, sector 1
|
|
mov dh,0 ; partition tables start on head 0
|
|
log_h1:
|
|
mov dl,p_unit ; get physical unit
|
|
call login_read_dx
|
|
jnc log_h1a
|
|
jmp log_h9 ; give up if disk error
|
|
log_h1a:
|
|
push cx
|
|
push dx
|
|
|
|
mov ah,ROS_PARAM
|
|
int_____DISK_INT ; return disk drive parameters
|
|
inc dh ; DH = number of heads
|
|
mov nhead,dh ; set # of heads on drive
|
|
and cl,3Fh ; isolate sector count
|
|
mov nsect,cl ; set sectors per track
|
|
|
|
pop dx
|
|
pop cx
|
|
|
|
;; cmp local_id,0AA55h
|
|
;; jne log_h9 ; give up if not initialized
|
|
|
|
test log_flag,LOG_PRIM ; scanning for primary?
|
|
jz log_h5 ; no, ignore all primary partitions
|
|
|
|
mov si,CG:local_pt ; point to partition table
|
|
log_h2:
|
|
;** SECURE PARTITIONS **
|
|
mov al,init_runit
|
|
test al,al ; booting from a hard disk ?
|
|
;** SECURE PARTITIONS **
|
|
mov al,4[si] ; get system ID
|
|
;** SECURE PARTITIONS **
|
|
jns log_h2a ; booting from a hard disk ?
|
|
mov ah,al ; yes, allow secure partitions
|
|
and ah,0F0h
|
|
cmp ah,SEC_ID
|
|
je log_h02
|
|
cmp ah,SEC_ID2
|
|
jne log_h2a
|
|
log_h02:
|
|
sub al,ah ; turn into a sensible partition ID
|
|
log_h2a:
|
|
;** SECURE PARTITIONS **
|
|
cmp al,DOS20_ID ; is this a DOS 2.x partition?
|
|
je log_h3 ; yes, try to log it in
|
|
cmp al,DOS30_ID ; is this a DOS 3.0/3.1/3.2 partition?
|
|
je log_h3 ; yes, try to log it in
|
|
cmp al,DOS331_ID ; is this a DOS 3.31/4.0 partition?
|
|
jne log_h4 ; skip if not a good partition
|
|
log_h3:
|
|
push si ; save partition table index
|
|
pushx <cx, dx> ; save partition table address
|
|
call login_primary ; login primary partition
|
|
popx <dx, cx> ; get partition table address
|
|
call login_read_dx ; re-read partition table
|
|
pop si ; get partition table index
|
|
jc log_h9 ; give up if error
|
|
log_h4:
|
|
add si,16 ; next partition table entry
|
|
cmp si,CG:local_id ; all partitions checked?
|
|
jb log_h2 ; loop back if more
|
|
|
|
log_h5: ; primary partitions done
|
|
test log_flag,LOG_EXTD ; scanning for extended?
|
|
jz log_h9 ; skip if no extended scan
|
|
|
|
or log_flag,LOG_PRIM ; scan for both types now
|
|
mov si,CG:local_pt ; SI -> partition table
|
|
; RG-01
|
|
log_h6:
|
|
;** SECURE PARTITIONS **
|
|
mov al,init_runit
|
|
test al,al ; booting from a hard disk ?
|
|
;** SECURE PARTITIONS **
|
|
mov al,4[si] ; get system ID
|
|
;** SECURE PARTITIONS **
|
|
jns log_h6a ; booting from a hard disk ?
|
|
mov ah,al ; yes, allow secure partitions
|
|
and ah,0F0h
|
|
cmp ah,SEC_ID
|
|
je log_sec2
|
|
cmp ah,SEC_ID2
|
|
jne log_h6a
|
|
log_sec2:
|
|
sub al,ah
|
|
log_h6a:
|
|
;** SECURE PARTITIONS **
|
|
cmp al,DOSEX_ID ; DOS 3.3 extended partition found?
|
|
jne log_h7
|
|
log_h6b:
|
|
mov dh,1[si] ; get head # for next table
|
|
mov cx,2[si] ; get cylinder, sector for next table
|
|
jmp log_h1 ; read & scan next partition table
|
|
|
|
log_h7: ; entry not an extended partition
|
|
add si,16 ; next partition table entry
|
|
cmp si,CG:local_buffer+IDOFF; all partitions checked?
|
|
jb log_h6 ; loop back if more
|
|
|
|
log_h9: ; drive login done
|
|
pop log_flag ; restore state for next drive
|
|
ret
|
|
|
|
|
|
login_primary:
|
|
;-------------
|
|
; entry: SI -> partition table entry
|
|
|
|
mov ax,12[si] ; get size of partition (low)
|
|
mov part_size,ax
|
|
mov ax,14[si] ; get size of partition (high)
|
|
mov part_size+2,ax
|
|
mov cl,2
|
|
mov bx,5[si] ; get last head/sector
|
|
and bx,1100000011000000b ; isolate cylinder bits 10..11,8..9
|
|
rol bl,cl ; bits 10..11 from head into position
|
|
or bh,bl ; or in bits 8..9
|
|
rol bh,cl ; bits 8..11 into place
|
|
mov bl,7[si] ; get cylinder bits 0..7
|
|
mov dh,1[si] ; get head of DOS partition
|
|
mov cx,2[si] ; get cylinder, sector of DOS partition
|
|
pushx <bx,cx,dx>
|
|
call login_read_dx ; try to read the partition boot
|
|
popx <dx,cx,bx>
|
|
jc login_p9 ; skip if partition not readable
|
|
; CX, DX = disk addr of 1st sector
|
|
; SI -> boot sector
|
|
; PART_SIZE = 32 bit partition address
|
|
cmp nunits,MAXPART ; do we already have the maximum?
|
|
jb log_p0 ; skip if space for more units
|
|
login_p9:
|
|
ret ; else ignore this partition
|
|
|
|
log_p0:
|
|
call new_unit ; ES:DI -> new UDSC
|
|
mov es:UDSC_FLAGS[di],UDF_HARD
|
|
mov es:UDSC_RUNIT[di],dl ; set physical drive (ROS code)
|
|
mov es:UDSC_TYPE[di],5 ; set type = hard disk
|
|
|
|
mov al,dh ; copy head byte
|
|
and al,11000000b ; cylinder # bits 10..11 are in 6..7
|
|
rol al,1 ; shift bits to bottom of word
|
|
rol al,1
|
|
mov ah,cl ; cylinder # bits 8..9 are in 6..7
|
|
and ah,11000000b ; strip off non-cylinder # bits
|
|
or ah,al ; combine the bits
|
|
rol ah,1 ; shift the bits into place
|
|
rol ah,1
|
|
mov al,ch ; cylinder # bits 0..7
|
|
sub bx,ax ; bx = # cylinders
|
|
inc bx ; make it inclusive
|
|
mov es:UDSC_NCYL[di],bx ; and save it
|
|
push ax ; save # CYLINDERS
|
|
mov al,nsect
|
|
and dh,00111111b ; DH = head offset
|
|
mul dh ; AX = HEAD_OFF * NSECT
|
|
xchg ax,bx ; keep in BX
|
|
mov al,nsect
|
|
mul nhead ; AX = HEADS * NSECT
|
|
pop dx ; recover # CYLINDERS
|
|
mul dx ; DX:AX = CYLINDERS * HEADS * NSECT
|
|
add ax,bx
|
|
adc dx,0 ; DX:AX = (CYL*HEADS + HEAD_OFF)*NSECT
|
|
|
|
and cx,00111111b ; isolate bottom 6 bits (sector #)
|
|
dec cx ; sector numbers are one-relative
|
|
add ax,cx ; add in non-partition sectors
|
|
adc dx,0 ; (usually 2.x partition table)
|
|
|
|
lea bx,UDSC_BPB[di] ; BX -> BPB to build
|
|
add si,11 ; skip JMP + OEM name in boot sector
|
|
|
|
mov es:word ptr BPB_HIDDEN[bx],ax ; set the partition address
|
|
mov word ptr BPB_HIDDEN+2[bx],dx ; (32 bit sector offset)
|
|
mov ax,part_size
|
|
mov dx,part_size+2
|
|
mov word ptr BPB_SIZE[bx],ax ; set partition size in sectors
|
|
mov word ptr BPB_SIZE+2[bx],dx
|
|
|
|
mov BPB_TOTSEC[bx],ax ; set partition size for < 32 Mb
|
|
; we'll zero this later if > 32 Mb
|
|
push es
|
|
push di
|
|
push ax
|
|
push dx
|
|
push si
|
|
call hd_bpb ; build BPB from scratch
|
|
pop si
|
|
pop dx
|
|
pop ax
|
|
pop di
|
|
pop es
|
|
|
|
cmp byte ptr -11[si],0E9h ; look for a jmp
|
|
jz log_p1a
|
|
cmp word ptr -11[si],0EB90h ; look for a nop!jmps
|
|
jz log_p1a
|
|
cmp byte ptr -11[si],0EBh ; look for a jmps
|
|
jnz log_p1 ; at the start of the boot sector.
|
|
cmp byte ptr -9[si],90h ; EJH 7-1-91
|
|
jnz log_p1
|
|
log_p1a:
|
|
|
|
test BPB_SECSIZ[si],SECSIZE-1; not a multiple of 512 byte?
|
|
jnz log_p1
|
|
cmp BPB_FATID[si],0F8h ; is this a good hard disk?
|
|
jne log_p1
|
|
cmp BPB_NFATS[si],2 ; too many FATs?
|
|
ja log_p1
|
|
cmp BPB_NFATS[si],1 ; no FATs at all?
|
|
jae log_p2 ; continue if BPB is valid
|
|
; elsa build new BPB
|
|
log_p1: ; any of the above: BPB invalid
|
|
; (propably FDISKed, not FORMATted yet)
|
|
jmps log_p9
|
|
|
|
log_p2: ; valid BPB for partition, AX/DX = size
|
|
push ax
|
|
mov al,BPB_ALLOCSIZ[si] ; copy a few parameters from the
|
|
mov BPB_ALLOCSIZ[bx],al ; Boot Sector BPB to our new BPB
|
|
mov ax,BPB_DIRMAX[si] ; EJH 7-1-91
|
|
mov BPB_DIRMAX[bx],ax
|
|
mov ax,BPB_FATSEC[si]
|
|
mov BPB_FATSEC[bx],ax
|
|
mov ax,BPB_SECSIZ[si]
|
|
mov BPB_SECSIZ[bx],ax
|
|
mov ax,BPB_FATADD[si]
|
|
mov BPB_FATADD[bx],ax
|
|
mov al,BPB_NFATS[si]
|
|
mov BPB_NFATS[bx],al
|
|
pop ax
|
|
|
|
cmp BPB_TOTSEC[bx],0 ; is it an 32 bit sector partition ?
|
|
jne log_p3 ; no, carry on
|
|
test dx,dx ; would it fit in 16 bit sector sizes ?
|
|
jnz log_p3 ; yes, then make BPB_TOTSEC
|
|
mov BPB_TOTSEC[bx],ax ; a valid 16 bit value too
|
|
log_p3: ; valid BPB for partition, AX/DX = size
|
|
cmp BPB_SECSIZ[bx],SECSIZE
|
|
jbe log_p9 ; skip if no large sectors
|
|
shr BPB_SECSIZ[bx],1 ; halve the sector size
|
|
shl BPB_ALLOCSIZ[bx],1 ; double the cluster size
|
|
shl BPB_FATSEC[bx],1 ; double the FAT size
|
|
shl BPB_FATADD[bx],1 ; double the FAT address
|
|
shl BPB_TOTSEC[bx],1 ; double # of sectors
|
|
jnc log_p3 ; skip if still < 65536 sectors
|
|
mov BPB_TOTSEC[bx],0 ; else indicate large partition
|
|
jmps log_p3 ; try again
|
|
; we've adjusted the sector size
|
|
log_p9:
|
|
pushx <ds, di>
|
|
push es
|
|
pop ds
|
|
lea si,UDSC_BPB[di] ; DS:SI -> new BPB
|
|
lea di,UDSC_DEVBPB[di] ; ES:DI -> fixed BPB
|
|
mov cx,UDSC_BPB_LENGTH
|
|
rep movsb ; make this the fixed BPB
|
|
popx <di, ds>
|
|
call add_unit ; register this DDSC_
|
|
inc nhard ; yet another hard disk
|
|
ret
|
|
|
|
hd_bpb:
|
|
;------
|
|
mov BPB_SECSIZ[bx],SECSIZE ; set standard sector size
|
|
mov BPB_FATADD[bx],1 ; one reserved (boot) sector
|
|
mov BPB_NFATS[bx],2 ; two FAT copies
|
|
mov BPB_DIRMAX[bx],512 ; assume 512 entry root directory
|
|
; BPB_TOTSEC set up already
|
|
mov BPB_FATID[bx],0F8h ; standard hard disk ID
|
|
mov al,nsect
|
|
mov ah,0
|
|
mov BPB_SPT[bx],ax ; set sectors/track
|
|
mov al,nhead
|
|
mov BPB_HEADS[bx],ax ; set # of heads
|
|
; determine FAT size:
|
|
mov BPB_ALLOCSIZ[bx],2*2 ; assume 2 K clusters
|
|
mov ax,word ptr BPB_SIZE[bx]; AX/DX = 32 bit sector count
|
|
mov dx,word ptr BPB_SIZE+2[bx]
|
|
test dx,dx ; have we got huge partition (type 6)?
|
|
jnz hd_bpb10 ; yes, it's 16-bit
|
|
cmp ax,7FCEh ; more than 16 Mb?
|
|
jae hd_bpb20 ; yes, use 16 bit FAT
|
|
mov cx,4*2 ; else we've got old 12-bit FAT
|
|
mov BPB_ALLOCSIZ[bx],cl ; we use 4 K clusters
|
|
add ax,cx ; adjust DX:AX for rounding
|
|
dec ax ; when we work out num clusters
|
|
div cx ; AX = # of clusters
|
|
mov cx,ax
|
|
add ax,ax ; * 2
|
|
add ax,cx ; * 3
|
|
shr ax,1 ; AX = num clus * 3/2 = bytes
|
|
adc ax,512-1 ; allow for rounding
|
|
xor dx,dx
|
|
mov cx,512
|
|
div cx ; AX = # fat sectors
|
|
mov BPB_FATSEC[bx],ax ; remember FAT size
|
|
ret
|
|
|
|
hd_bpb10:
|
|
mov BPB_TOTSEC[bx],0 ; zero this if BPB_SIZE is required
|
|
cmp dx,2 ; less than 2*65536 sectors (64 Mb)?
|
|
jb hd_bpb20 ; yes, leave cluster size the same
|
|
mov BPB_ALLOCSIZ[bx],4*2 ; use 4 K clusters if 64-128 Mb
|
|
cmp dx,4 ; less than 4*65536 sectors (128 Mb)?
|
|
jb hd_bpb20 ; yes, leave cluster size the same
|
|
mov BPB_ALLOCSIZ[bx],8*2 ; use 8 K clusters if 128-512 Mb
|
|
cmp dx,16 ; less than 16*65536 sectors (512 Mb)?
|
|
jb hd_bpb20 ; yes, leave cluster size the same
|
|
mov BPB_ALLOCSIZ[bx],16*2 ; use 16 K clusters if 512-1024 Mb
|
|
cmp dx,32 ; less than 32*65536 sectors (1 Gb)?
|
|
jb hd_bpb20 ; yes, leave cluster size the same
|
|
mov BPB_ALLOCSIZ[bx],32*2 ; use 32 K clusters if 1-2 Gb
|
|
|
|
hd_bpb20: ; cluster size determined
|
|
sub ax,1+(512*32/SECSIZE) ; subtract reserved+root directory
|
|
sbb dx,0 ; (note: 32 bytes per entry)
|
|
xor cx,cx
|
|
mov ch,BPB_ALLOCSIZ[bx] ; CX = (256 * # of clusters on drive)
|
|
dec cx
|
|
add ax,cx ; add in for rounding error
|
|
adc dx,0
|
|
inc cx
|
|
div cx ; AX = # of fat sectors
|
|
mov BPB_FATSEC[bx],ax ; remember FAT size
|
|
mov es:UDSC_FSTYPE+4[di],'6'; change "FAT12" to "FAT16"
|
|
ret
|
|
|
|
|
|
|
|
new_unit:
|
|
push ds
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push si
|
|
mov es,cs:DataSegment
|
|
mov di,endbios ; get next unit descriptor
|
|
mov cx,UDSC_LENGTH
|
|
add endbios,cx ; grow the BIOS size
|
|
xor ax,ax
|
|
push di
|
|
rep stosb ; zero the UDSC
|
|
pop di
|
|
xor bx,bx
|
|
mov bl,nunits ; BX = unit we are working on
|
|
mov es:UDSC_DRIVE[di],bl ; make that our logical unit
|
|
shl bx,1 ; make it a BPB index
|
|
lea ax,es:UDSC_DEVBPB[di] ; get storage area for device BPB
|
|
mov bpbtbl[bx],ax ; update entry in BPB table
|
|
shr bx,1 ; get the latest drive
|
|
inc bx ; onto next unit
|
|
cmp bl,2 ; 3rd floppy ?
|
|
jne new_unit10
|
|
add bl,nhard ; yes, skip past hard disks
|
|
new_unit10:
|
|
mov nunits,bl ; store ready for next time
|
|
mov es:UDSC_RUNIT[di],0FFh ; set physical drive (ROS code)
|
|
push cs
|
|
pop ds ; DS:SI -> our dummy value
|
|
mov si,offset CGROUP:dummyMediaID
|
|
call UpdateMediaID ; update UDSC_ with media info
|
|
pop si
|
|
pop dx
|
|
pop cx
|
|
pop bx
|
|
pop ax
|
|
pop ds
|
|
ret
|
|
|
|
|
|
ICODE ends
|
|
|
|
RESBIOS segment 'RESBIOS'
|
|
; NOTE: we extend the resident BIOS size by the amount of
|
|
; memory required by the disk driver.
|
|
db MAXPART*UDSC_LENGTH dup (?)
|
|
RESBIOS ends
|
|
|
|
IDATA segment
|
|
p_unit db ? ; 80h, 81h for hard disks
|
|
nsect db ? ; # of sectors per track
|
|
nhead db ? ; # of heads on disk
|
|
part_size dw 2 dup (?) ; temporary save address for size
|
|
nunits db 2 ; start with driver C:
|
|
nhard db 0 ; # of hard disk partitions
|
|
nfloppy db 0 ; # of floppy drives
|
|
|
|
Public init_runit
|
|
init_runit db 0 ; poked with ROS Unit at boot
|
|
|
|
IDATA ends
|
|
|
|
end
|