mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-11-26 07:35:47 +00:00
501 lines
17 KiB
NASM
501 lines
17 KiB
NASM
|
TITLE HRDDRV.SYS for the ALTOS ACS-86C.
|
|||
|
|
|||
|
; Hard Disk Drive for Version 2.x of MSDOS.
|
|||
|
|
|||
|
; Constants for commands in Altos ROM.
|
|||
|
|
|||
|
ROM_CONSTA EQU 01 ;Return status AL of console selected in CX.
|
|||
|
ROM_CONIN EQU 02 ;Get char. from console in CX to AL
|
|||
|
ROM_CONOUT EQU 03 ;Write char. in DL to console in CX.
|
|||
|
ROM_PMSG EQU 07 ;Write string ES:DX to console in CX.
|
|||
|
ROM_DISKIO EQU 08 ;Perform disk I/O from IOPB in ES:CX.
|
|||
|
ROM_INIT EQU 10 ;Returns boot console and top memory ES:DX.
|
|||
|
|
|||
|
|
|||
|
CODE SEGMENT
|
|||
|
ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE
|
|||
|
|
|||
|
ORG 0 ;Starts at an offset of zero.
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Device driver tables.
|
|||
|
|
|||
|
;-----------------------------------------------+
|
|||
|
; DWORD pointer to next device | 1 word offset.
|
|||
|
; (-1,-1 if last device) | 1 word segement.
|
|||
|
;-----------------------------------------------+
|
|||
|
; Device attribute WORD ; 1 word.
|
|||
|
; Bit 15 = 1 for chacter devices. ;
|
|||
|
; 0 for Block devices. ;
|
|||
|
; ;
|
|||
|
; Charcter devices. (Bit 15=1) ;
|
|||
|
; Bit 0 = 1 current sti device. ;
|
|||
|
; Bit 1 = 1 current sto device. ;
|
|||
|
; Bit 2 = 1 current NUL device. ;
|
|||
|
; Bit 3 = 1 current Clock device. ;
|
|||
|
; ;
|
|||
|
; Bit 13 = 1 for non IBM machines. ;
|
|||
|
; 0 for IBM machines only. ;
|
|||
|
; Bit 14 = 1 IOCTL control bit. ;
|
|||
|
;-----------------------------------------------+
|
|||
|
; Device strategy pointer. ; 1 word offset.
|
|||
|
;-----------------------------------------------+
|
|||
|
; Device interrupt pointer. ; 1 word offset.
|
|||
|
;-----------------------------------------------+
|
|||
|
; Device name field. ; 8 bytes.
|
|||
|
; Character devices are any valid name ;
|
|||
|
; left justified, in a space filled ;
|
|||
|
; field. ;
|
|||
|
; Block devices contain # of units in ;
|
|||
|
; the first byte. ;
|
|||
|
;-----------------------------------------------+
|
|||
|
|
|||
|
DSKDEV: ;Header for hard disk driver.
|
|||
|
DW -1,-1 ;Last device
|
|||
|
DW 2000H ;Is a block device
|
|||
|
DW STRATEGY
|
|||
|
DW DSK_INT
|
|||
|
MEMMAX DB 1 ;Number of Units
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Dispatch tables for each device.
|
|||
|
|
|||
|
DSK_TBL:DW DSK_INI ;0 - Initialize Driver.
|
|||
|
DW MEDIAC ;1 - Return current media code.
|
|||
|
DW GET_BPB ;2 - Get Bios Parameter Block.
|
|||
|
DW CMDERR ;3 - Reserved. (currently returns error)
|
|||
|
DW DSK_RED ;4 - Block read.
|
|||
|
DW BUS_EXIT ;5 - (Not used, return busy flag)
|
|||
|
DW EXIT ;6 - Return status. (Not used)
|
|||
|
DW EXIT ;7 - Flush input buffer. (Not used.)
|
|||
|
DW DSK_WRT ;8 - Block write.
|
|||
|
DW DSK_WRV ;9 - Block write with verify.
|
|||
|
DW EXIT ;10 - Return output status.
|
|||
|
DW EXIT ;11 - Flush output buffer. (Not used.)
|
|||
|
DW EXIT ;12 - IO Control.
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Strategy and Software Interrupt routines.
|
|||
|
|
|||
|
;Define offsets for io data packet
|
|||
|
|
|||
|
IODAT STRUC
|
|||
|
CMDLEN DB ? ;LENGTH OF THIS COMMAND
|
|||
|
UNIT DB ? ;SUB UNIT SPECIFIER
|
|||
|
CMD DB ? ;COMMAND CODE
|
|||
|
STATUS DW ? ;STATUS
|
|||
|
DB 8 DUP (?)
|
|||
|
MEDIA DB ? ;MEDIA DESCRIPTOR
|
|||
|
TRANS DD ? ;TRANSFER ADDRESS
|
|||
|
COUNT DW ? ;COUNT OF BLOCKS OR CHARACTERS
|
|||
|
START DW ? ;FIRST BLOCK TO TRANSFER
|
|||
|
IODAT ENDS
|
|||
|
|
|||
|
PTRSAV DD 0 ;Strategy pointer save.
|
|||
|
|
|||
|
;
|
|||
|
; Simplistic Strategy routine for non-multi-Tasking system.
|
|||
|
;
|
|||
|
; Currently just saves I/O packet pointers in PTRSAV for
|
|||
|
; later processing by the individual interrupt routines.
|
|||
|
;
|
|||
|
|
|||
|
STRATP PROC FAR
|
|||
|
|
|||
|
STRATEGY:
|
|||
|
MOV WORD PTR CS:[PTRSAV],BX
|
|||
|
MOV WORD PTR CS:[PTRSAV+2],ES
|
|||
|
RET
|
|||
|
|
|||
|
STRATP ENDP
|
|||
|
|
|||
|
|
|||
|
;
|
|||
|
; Ram memory driver interrupt routine for processing I/O packets.
|
|||
|
;
|
|||
|
|
|||
|
DSK_INT:
|
|||
|
PUSH SI ;Save SI from caller.
|
|||
|
MOV SI,OFFSET DSK_TBL
|
|||
|
|
|||
|
;
|
|||
|
; Common program for handling the simplistic I/O packet
|
|||
|
; processing scheme in MSDOS 2.0
|
|||
|
;
|
|||
|
|
|||
|
ENTRY: PUSH AX ;Save all nessacary registers.
|
|||
|
PUSH CX
|
|||
|
PUSH DX
|
|||
|
PUSH DI
|
|||
|
PUSH BP
|
|||
|
PUSH DS
|
|||
|
PUSH ES
|
|||
|
PUSH BX
|
|||
|
|
|||
|
LDS BX,CS:[PTRSAV] ;Retrieve pointer to I/O Packet.
|
|||
|
|
|||
|
MOV AL,[BX.UNIT] ;AL = Unit code.
|
|||
|
MOV AH,[BX.MEDIA] ;AH = Media descriptor.
|
|||
|
MOV CX,[BX.COUNT] ;CX = Contains byte/sector count.
|
|||
|
MOV DX,[BX.START] ;DX = Starting Logical sector.
|
|||
|
XCHG DI,AX ;Save Unit and Media Temporarily.
|
|||
|
MOV AL,[BX.CMD] ;Retrieve Command type. (1 => 11)
|
|||
|
XOR AH,AH ;Clear upper half of AX for calculation.
|
|||
|
ADD SI,AX ;Compute entry pointer in dispatch table.
|
|||
|
ADD SI,AX
|
|||
|
CMP AL,11 ;Verify that not more than 11 commands.
|
|||
|
JA CMDERR ;Ah, well, error out.
|
|||
|
XCHG AX,DI
|
|||
|
LES DI,[BX.TRANS] ;DI contains addess of Transfer address.
|
|||
|
;ES contains segment.
|
|||
|
PUSH CS
|
|||
|
POP DS ;Data segment same as Code segment.
|
|||
|
JMP [SI] ;Perform I/O packet command.
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Common error and exit points.
|
|||
|
|
|||
|
BUS_EXIT: ;Device busy exit.
|
|||
|
MOV AH,00000011B ;Set busy and done bits.
|
|||
|
JMP SHORT EXIT1
|
|||
|
|
|||
|
CMDERR: MOV AL,3 ;Set unknown command error #.
|
|||
|
|
|||
|
;
|
|||
|
; Common error processing routine.
|
|||
|
; AL contains actual error code.
|
|||
|
;
|
|||
|
; Error # 0 = Write Protect violation.
|
|||
|
; 1 = Unkown unit.
|
|||
|
; 2 = Drive not ready.
|
|||
|
; 3 = Unknown command in I/O packet.
|
|||
|
; 4 = CRC error.
|
|||
|
; 5 = Bad drive request structure length.
|
|||
|
; 6 = Seek error.
|
|||
|
; 7 = Unknown media discovered.
|
|||
|
; 8 = Sector not found.
|
|||
|
; 9 = Printer out of paper.
|
|||
|
; 10 = Write fault.
|
|||
|
; 11 = Read fault.
|
|||
|
; 12 = General failure.
|
|||
|
;
|
|||
|
|
|||
|
ERR_EXIT:
|
|||
|
MOV AH,10000001B ;Set error and done bits.
|
|||
|
STC ;Set carry bit also.
|
|||
|
JMP SHORT EXIT1 ;Quick way out.
|
|||
|
|
|||
|
EXITP PROC FAR ;Normal exit for device drivers.
|
|||
|
|
|||
|
EXIT: MOV AH,00000001B ;Set done bit for MSDOS.
|
|||
|
EXIT1: LDS BX,CS:[PTRSAV]
|
|||
|
MOV [BX.STATUS],AX ;Save operation compete and status.
|
|||
|
|
|||
|
POP BX ;Restore registers.
|
|||
|
POP ES
|
|||
|
POP DS
|
|||
|
POP BP
|
|||
|
POP DI
|
|||
|
POP DX
|
|||
|
POP CX
|
|||
|
POP AX
|
|||
|
POP SI
|
|||
|
RET ;RESTORE REGS AND RETURN
|
|||
|
EXITP ENDP
|
|||
|
|
|||
|
PAGE
|
|||
|
|
|||
|
subttl Hard Disk drive control.
|
|||
|
|
|||
|
;
|
|||
|
; Read command = 09 hex.
|
|||
|
; Write command = 02 hex.
|
|||
|
; Seek command = 10 hex.
|
|||
|
; Recal command = 20 hex.
|
|||
|
; Rezero command = 40 hex.
|
|||
|
; Reset command = 80 hex.
|
|||
|
;
|
|||
|
; Busy = 01 hex.
|
|||
|
; Operation Complete = 02 hex.
|
|||
|
; Bad Sector = 04 hex.
|
|||
|
; Record Not found = 08 hex.
|
|||
|
; CRC error = 10 hex.
|
|||
|
; (not used) = 20 hex.
|
|||
|
; Write fault = 40 hex.
|
|||
|
; Drive Ready = 80 hex.
|
|||
|
;
|
|||
|
|
|||
|
hd_read equ 09h
|
|||
|
hd_writ equ 02h
|
|||
|
hd_wmsk equ 5dh
|
|||
|
hd_rmsk equ 9ch
|
|||
|
page
|
|||
|
|
|||
|
SUBTTL Altos monitor ram and 8089 IOPB structures.
|
|||
|
|
|||
|
;
|
|||
|
; Structure to reference 8089 and ROM command table.
|
|||
|
;
|
|||
|
|
|||
|
SIOPB STRUC
|
|||
|
DB 4 DUP (?) ;Monitor Use Only
|
|||
|
OPCODE DB ? ;I/O operation code.
|
|||
|
DRIVE DB ? ;Logical drive spec.
|
|||
|
TRACK DW ? ;Logical track number.
|
|||
|
HEAD DB ? ;Logical head number.
|
|||
|
SECTOR DB ? ;Logical sector to start with.
|
|||
|
SCOUNT DB ? ;Number of logical sectors in buffer.
|
|||
|
RETCODE DB ? ;Error code after masking.
|
|||
|
RETMASK DB ? ;Error mask.
|
|||
|
RETRIES DB ? ;Number of retries before error exit.
|
|||
|
DMAOFF DW ? ;Buffer offset address.
|
|||
|
DMASEG DW ? ;Buffer segment.
|
|||
|
SECLENG DW ? ;Sector Length.
|
|||
|
DB 6 DUP (?) ;8089 use only.
|
|||
|
SIOPB ENDS
|
|||
|
|
|||
|
IOPB SIOPB <,0,0,0,0,0,0,0,0,0,0,0,0,>
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Common Drive parameter block definitions on Altos.
|
|||
|
|
|||
|
DBP STRUC
|
|||
|
|
|||
|
JMPNEAR DB 3 DUP (?) ;Jmp Near xxxx for boot.
|
|||
|
NAMEVER DB 8 DUP (?) ;Name / Version of OS.
|
|||
|
|
|||
|
;------- Start of Drive Parameter Block.
|
|||
|
|
|||
|
SECSIZE DW ? ;Sector size in bytes. (dpb)
|
|||
|
ALLOC DB ? ;Number of sectors per alloc. block. (dpb)
|
|||
|
RESSEC DW ? ;Reserved sectors. (dpb)
|
|||
|
FATS DB ? ;Number of FAT's. (dpb)
|
|||
|
MAXDIR DW ? ;Number of root directory entries. (dpb)
|
|||
|
SECTORS DW ? ;Number of sectors per diskette. (dpb)
|
|||
|
MEDIAID DB ? ;Media byte ID. (dpb)
|
|||
|
FATSEC DW ? ;Number of FAT Sectors. (dpb)
|
|||
|
|
|||
|
;------- End of Drive Parameter Block.
|
|||
|
|
|||
|
SECTRK DW ? ;Number of Sectors per track.
|
|||
|
HEADS DW ? ;Number of heads per cylinder.
|
|||
|
HIDDEN DW ? ;Number of hidden sectors.
|
|||
|
|
|||
|
DBP ENDS
|
|||
|
|
|||
|
HDDRIVE DBP <,,512,4,0,2,256,4000,0F5H,3,12,4,0>
|
|||
|
|
|||
|
|
|||
|
INI_TAB DW OFFSET HDDRIVE.SECSIZE
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Media check routine
|
|||
|
|
|||
|
;
|
|||
|
; Media check routine.
|
|||
|
; On entry:
|
|||
|
; AL = memory driver unit number.
|
|||
|
; AH = media byte
|
|||
|
; On exit:
|
|||
|
;
|
|||
|
; [MEDIA FLAG] = -1 (FF hex) if disk is changed.
|
|||
|
; [MEDIA FLAG] = 0 if don't know.
|
|||
|
; [MEDIA FLAG] = 1 if not changed.
|
|||
|
;
|
|||
|
|
|||
|
MEDIAC: LDS BX,CS:[PTRSAV]
|
|||
|
MOV BYTE PTR [BX.TRANS],1
|
|||
|
JMP EXIT
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Build and return Bios Parameter Block for a diskette.
|
|||
|
|
|||
|
;
|
|||
|
; Build Bios Parameter Blocks.
|
|||
|
;
|
|||
|
; On entry: ES:BX contains the address of a scratch sector buffer.
|
|||
|
; AL = Unit number.
|
|||
|
; AH = Current media byte.
|
|||
|
;
|
|||
|
; On exit: Return a DWORD pointer to the associated BPB
|
|||
|
; in the Request packet.
|
|||
|
;
|
|||
|
|
|||
|
GET_BPB:
|
|||
|
MOV SI,OFFSET HDDRIVE+11
|
|||
|
LDS BX,CS:[PTRSAV]
|
|||
|
MOV WORD PTR [BX.COUNT],SI
|
|||
|
MOV WORD PTR [BX.COUNT+2],CS
|
|||
|
JMP EXIT
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL MSDOS 2.x Disk I/O drivers.
|
|||
|
|
|||
|
;
|
|||
|
; Disk READ/WRITE functions.
|
|||
|
;
|
|||
|
; On entry:
|
|||
|
; AL = Disk I/O driver number
|
|||
|
; AH = Media byte.
|
|||
|
; ES = Disk transfer segment.
|
|||
|
; DI = Disk transfer offset in ES.
|
|||
|
; CX = Number of sectors to transfer
|
|||
|
; DX = Logical starting sector.
|
|||
|
;
|
|||
|
; On exit:
|
|||
|
; Normal exit through common exit routine.
|
|||
|
;
|
|||
|
; Abnormal exit through common error routine.
|
|||
|
;
|
|||
|
|
|||
|
DSK_RED:
|
|||
|
MOV AH,HD_READ
|
|||
|
JMP SHORT DSK_COM
|
|||
|
DSK_WRV:
|
|||
|
DSK_WRT:
|
|||
|
MOV AH,HD_WRIT
|
|||
|
DSK_COM:
|
|||
|
MOV SI,OFFSET HDDRIVE ;Keeps code size down.
|
|||
|
MOV [IOPB.DMASEG],ES
|
|||
|
MOV [IOPB.DMAOFF],DI
|
|||
|
MOV DI,[SI.SECSIZE]
|
|||
|
MOV [IOPB.SECLENG],DI
|
|||
|
MOV [IOPB.RETRIES],1
|
|||
|
MOV [IOPB.RETMASK],05DH ;Error return mask.
|
|||
|
MOV [IOPB.OPCODE],AH
|
|||
|
MOV [IOPB.DRIVE],4 ;Drive 4 is only available.
|
|||
|
ADD DX,[SI.HIDDEN] ;Account for invisible sectors.
|
|||
|
MOV BP,CX ;Save number of sectors to R/W
|
|||
|
DSK_IO1:
|
|||
|
PUSH DX ;Save starting sector.
|
|||
|
MOV AX,DX
|
|||
|
MOV DX,0 ;32 bit divide coming up.
|
|||
|
MOV CX,[SI.SECTRK]
|
|||
|
DIV CX ;Get track+head and start sector.
|
|||
|
MOV [IOPB.SECTOR],DL ;Starting sector.
|
|||
|
MOV BL,DL ;Save starting sector for later.
|
|||
|
MOV DX,0
|
|||
|
MOV CX,[SI.HEADS]
|
|||
|
DIV CX ;Compute head we are on.
|
|||
|
MOV [IOPB.HEAD],DL
|
|||
|
MOV [IOPB.TRACK],AX ;Track to read/write.
|
|||
|
MOV AX,[SI.SECTRK] ;Now see how many sectors
|
|||
|
INC AL ; we can burst read.
|
|||
|
SUB AL,BL ;BL is the starting sector.
|
|||
|
MOV AH,0
|
|||
|
POP DX ;Retrieve logical sector start.
|
|||
|
CMP AX,BP ;See if on last partial track+head.
|
|||
|
JG DSK_IO2 ;Yes, on last track+head.
|
|||
|
SUB BP,AX ;No, update number of sectors left.
|
|||
|
ADD DX,AX ;Update next starting sector.
|
|||
|
JMP SHORT DSK_IO3
|
|||
|
DSK_IO2:MOV AX,BP ;Only read enough of sector
|
|||
|
MOV BP,0 ;to finish buffer and clear # left.
|
|||
|
DSK_IO3:MOV [IOPB.SCOUNT],AL
|
|||
|
MOV DI,AX ;Save number sectors for later.
|
|||
|
MOV BX,ROM_DISKIO
|
|||
|
MOV CX,OFFSET IOPB
|
|||
|
PUSH CS
|
|||
|
POP ES
|
|||
|
CALL ROM_CALL ;Do disk operation.
|
|||
|
MOV AL,[IOPB.RETCODE] ;Get error code.
|
|||
|
OR AL,AL
|
|||
|
JNZ DERROR
|
|||
|
MOV AX,DI ;Retrieve number of sectors read.
|
|||
|
MOV CX,[SI.SECSIZE] ;Number of bytes per sector.
|
|||
|
PUSH DX
|
|||
|
MUL CX
|
|||
|
POP DX
|
|||
|
TEST AL,0FH ;Make sure no strange sizes.
|
|||
|
JNZ SERR1
|
|||
|
MOV CL,4
|
|||
|
SHR AX,CL ;Convert number of bytes to para.
|
|||
|
ADD AX,[IOPB.DMASEG]
|
|||
|
MOV [IOPB.DMASEG],AX
|
|||
|
OR BP,BP
|
|||
|
JNZ DSK_IO1 ;Still more to do.
|
|||
|
MOV AL,0
|
|||
|
JMP EXIT ;All done.
|
|||
|
SERR1: MOV AL,12
|
|||
|
JMP ERR_EXIT
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Disk Error processing.
|
|||
|
|
|||
|
;
|
|||
|
; Disk error routine.
|
|||
|
;
|
|||
|
|
|||
|
DERROR:
|
|||
|
LDS BX,CS:[PTRSAV]
|
|||
|
MOV [BX.COUNT],0
|
|||
|
PUSH CS
|
|||
|
POP DS
|
|||
|
|
|||
|
MOV BL,-1
|
|||
|
MOV AH,AL
|
|||
|
MOV BH,14 ;Lenght of table.
|
|||
|
MOV SI,OFFSET DERRTAB
|
|||
|
DERROR2:INC BL ;Increment to next error code.
|
|||
|
LODS BYTE PTR CS:[SI]
|
|||
|
CMP AH,AL ;See if error code matches disk status.
|
|||
|
JZ DERROR3 ;Got the right error, exit.
|
|||
|
DEC BH
|
|||
|
JNZ DERROR2 ;Keep checking table.
|
|||
|
MOV BL,12 ;Set general type of error.
|
|||
|
DERROR3:MOV AL,BL ;Now we've got the code.
|
|||
|
JMP ERR_EXIT
|
|||
|
|
|||
|
DERRTAB DB 00H ; 0. Write protect error
|
|||
|
DB 00H ; 1. Unknown unit.
|
|||
|
DB 00H ; 2. Not ready error.
|
|||
|
DB 00H ; 3. Unknown command.
|
|||
|
DB 10H ; 4. CRC error
|
|||
|
DB 00H ; 5. Bad drive request.
|
|||
|
DB 00H ; 6. Seek error
|
|||
|
DB 00H ; 7. Unknown media.
|
|||
|
DB 08H ; 8. Sector not found
|
|||
|
DB 00H ; 9. (Not used.)
|
|||
|
DB 40H ;10. Write fault.
|
|||
|
DB 04H ;11. Read fault.
|
|||
|
DB 01H ;12. General type of failure.
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Common ROM call routine.
|
|||
|
|
|||
|
;
|
|||
|
; Save all registers except CX, BX and AX.
|
|||
|
|
|||
|
ROMRTN DD 0FE000000H ;Main ROM entry point.
|
|||
|
|
|||
|
ROM_CALL:
|
|||
|
PUSH DI
|
|||
|
PUSH SI
|
|||
|
PUSH BP
|
|||
|
PUSH DX
|
|||
|
PUSH ES
|
|||
|
CALL CS:DWORD PTR [ROMRTN]
|
|||
|
POP ES
|
|||
|
POP DX
|
|||
|
POP BP
|
|||
|
POP SI
|
|||
|
POP DI
|
|||
|
RET
|
|||
|
|
|||
|
|
|||
|
PAGE
|
|||
|
SUBTTL Hard Disk Drive initalization routine.
|
|||
|
|
|||
|
DSK_INI:
|
|||
|
LDS BX,CS:[PTRSAV]
|
|||
|
MOV BYTE PTR [BX.MEDIA],1
|
|||
|
MOV WORD PTR [BX.TRANS],OFFSET DSK_INI
|
|||
|
MOV WORD PTR [BX.TRANS+2],CS
|
|||
|
MOV WORD PTR [BX.COUNT],OFFSET INI_TAB
|
|||
|
MOV WORD PTR [BX.COUNT+2],CS
|
|||
|
JMP EXIT
|
|||
|
|
|||
|
CODE ENDS
|
|||
|
|
|||
|
END
|
|||
|
|