Files
MS-DOS/v4.0/src/BIOS/MSHARD.ASM
T

428 lines
8.7 KiB
NASM

;***
; Title: Disk
; C: (C) Copyright 1988 by Microsoft corp.
; Date: 1/11/85
;
; There is a bug in some versions of IBM's AT ROM BIOS.
; Interrupts are not disabled during read operations.
;
; Use: This program should be chained in line with the disk
; interupt 13h, it intercepts read calls to the hard disk
; and handles them appropriately. For other functions it
; passes controll to OLD13, which should contain the
; address of the AT ROM disk routine. The entry point for
; this program is IBM_DISK_IO.
;
.286c ;Use 80286 non-protected mode
BIOSEG = 040h ;Segment for ROM BIOS Data
ROMSEG = 0F000h ;Segment of ROM
BAD_DISK = 01
HF_PORT = 01F0h
HF_REG_PORT = 03F6h
;* Offsets into Fixed disk parameter table
FDP_PRECOMP = 5
FDP_CONTROL = 8
DATA SEGMENT AT BIOSEG ;ROM BIOS data segment
ORG 42h
CMD_BLOCK DB 6 DUP (?)
;* Offsets into CMD_BLOCK for registers
PRE_COMP = 0 ;Write Pre-compensation
SEC_CNT = 1 ;Sector count
SEC_NUM = 2 ;Sector number
CYL_LOW = 3 ;Cylinder number, low part
CYL_HIGH = 4 ;Cylinder number, high part
DRV_HEAD = 5 ;Drive/Head (Bit 7 = ECC mode, Bit 5 = 512 byte sectors,
; Bit 4 = drive number, Bits 3-0 have head number)
CMD_REG = 6 ;Command register
ORG 074h
DISK_STATUS1 DB ?
HF_NUM DB ?
CONTROL_BYTE DB ?
DATA ENDS
;*** Define where the ROM routines are actually located
ROM SEGMENT AT ROMSEG
ORG 02E1Eh
ROMCOMMAND PROC FAR
ROMCOMMAND ENDP
ORG 02E7Fh
ROMWAIT PROC FAR
ROMWAIT ENDP
ORG 02EE2h
ROMWAIT_DRQ PROC FAR
ROMWAIT_DRQ ENDP
ORG 02EF8h
ROMCHECK_STATUS PROC FAR
ROMCHECK_STATUS ENDP
ORG 02F69h
ROMCHECK_DMA PROC FAR
ROMCHECK_DMA ENDP
ORG 02F8Eh
ROMGET_VEC PROC FAR
ROMGET_VEC ENDP
ORG 0FF65h
ROMFRET PROC FAR ;Far return at F000:FF65 in AT ROM.
ROMFRET ENDP
ROM ENDS
CODE SEGMENT BYTE PUBLIC 'code'
EXTRN OLD13:DWORD ;Link to AT bios int 13h
PUBLIC IBM_DISK_IO
ASSUME CS:CODE
ASSUME DS:DATA
;*** IBM_DISK_IO - main routine, fixes AT ROM bug
;
; ENTRY: (AH) = function, 02 or 0A for read.
; (DL) = drive number (80h or 81h).
; (DH) = head number.
; (CH) = cylinder number.
; (CL) = Sector number (high 2 bits has cylinder number).
; (AL) = number of sectors.
; (ES:BX) = address of read buffer.
; For more on register contents see ROM BIOS listing.
; Stack set up for return by an IRET.
;
; EXIT: (AH) = status of current operation.
; (CY) = 1 IF failed, 0 if successful.
; For other register contents see ROM BIOS listing.
;
; USES:
;
;
; WARNING: Uses OLD13 vector for non-read calls.
; Does direct calls to the AT ROM.
; Does segment arithmatic.
;
; EFFECTS: Performs DISK I/O operation.
;
IBM_DISK_IO PROC FAR
CMP DL, 80h
JB ATD1 ;Pass through floppy disk calls.
CMP AH, 02
JE ATD2 ;Intercept call 02 (read sectors).
CMP AH, 0Ah
JE ATD2 ;and call 0Ah (read long).
ATD1:
JMP OLD13 ;Use ROM INT 13h handler.
ATD2:
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH DS
PUSH ES
PUSH AX
MOV AX,BIOSEG ;Establish BIOS segment addressing.
MOV DS,AX
MOV DISK_STATUS1, 0 ;Initially no error code.
AND DL, 07fh ;Mask to hard disk number
CMP DL, HF_NUM
JB ATD3 ;Disk number in range
MOV DISK_STATUS1, BAD_DISK
JMP SHORT ATD4 ;Disk number out of range error, return
ATD3:
PUSH BX
MOV AX, ES ;Make ES:BX to Seg:000x form.
SHR BX, 4
ADD AX, BX
MOV ES, AX
POP BX
AND BX,000Fh
PUSH CS
CALL CHECK_DMA
JC ATD4 ;Abort if DMA across segment boundary
POP AX ;Restore AX register for SETCMD
PUSH AX
CALL SETCMD ;Set up command block for disk op
MOV DX, HF_REG_PORT
OUT DX, AL ;Write out command modifier
CALL DOCMD ;Carry out command
ATD4:
;; Old code - Carry cleared after set by logical or opearation
;; POP AX
;; MOV AH,DISK_STATUS1 ;On return AH has error code
;; STC
;; OR AH,AH
;; JNZ ATD5 ;Carry set if error
;; CLC
;;---------------------------------------------------
;; New Code - Let Logical or clear carry and then set carry if ah!=0
;; And save a couple bytes while were at it.
POP AX
MOV AH,DISK_STATUS1 ;On return AH has error code
OR AH,AH
JZ ATD5 ;Carry set if error
STC
ATD5:
POP ES
POP DS
POP DI
POP DX
POP CX
POP BX
RET 2 ;Far return, dropping flags
IBM_DISK_IO ENDP
;*** SETCMD - Set up CMD_BLOCK for the disk operation
;
; ENTRY: (DS) = BIOS Data segment.
; (ES:BX) in seg:000x form.
; Other registers as in INT 13h call
;
; EXIT: CMD_BLOCK set up for disk read call.
; CONTROL_BYTE set up for disk operation.
; (AL) = Control byte modifier
;
;
; Sets the fields of CMD_BLOCK using the register contents
; and the contents of the disk parameter block for the given drive.
;
; WARNING: (AX) destroyed.
; Does direct calls to the AT ROM.
;
SETCMD PROC NEAR
MOV CMD_BLOCK[SEC_CNT], AL
MOV CMD_BLOCK[CMD_REG], 020h ;Assume function 02
CMP AH, 2
JE SETC1 ;CMD_REG = 20h if function 02 (read)
MOV CMD_BLOCK[CMD_REG], 022h ;CMD_REG = 22h if function 0A (" long)
SETC1: ;No longer need value in AX
MOV AL, CL
AND AL, 03fh ;Mask to sector number
MOV CMD_BLOCK[SEC_NUM], AL
MOV CMD_BLOCK[CYL_LOW], CH
MOV AL, CL
SHR AL, 6 ;Get two high bits of cylender number
MOV CMD_BLOCK[CYL_HIGH], AL
MOV AX, DX
SHL AL, 4 ;Drive number
AND AH, 0Fh
OR AL, AH ;Head number
OR AL, 0A0h ;Set ECC and 512 bytes per sector
MOV CMD_BLOCK[DRV_HEAD], AL
PUSH ES ;GET_VEC destroys ES:BX
PUSH BX
PUSH CS
CALL GET_VEC
MOV AX, ES:FDP_PRECOMP[BX] ;Write pre-comp from disk parameters
SHR AX, 2
MOV CMD_BLOCK[PRE_COMP],AL ;Only use low part
MOV AL, ES:FDP_CONTROL[BX] ;Control byte modifier
POP BX
POP ES
MOV AH, CONTROL_BYTE
AND AH, 0C0h ;Keep disable retry bits
OR AH, AL
MOV CONTROL_BYTE, AH
RET
SETCMD ENDP
;*** DOCMD - Carry out READ operation to AT hard disk
;
; ENTRY: (ES:BX) = address for read in data.
; CMD_BLOCK set up for disk read.
;
; EXIT: Buffer at (ES:BX) contains data read.
; DISK_STATUS1 set to error code (0 if success).
;
;
;
; WARNING: (AX), (BL), (CX), (DX), (DI) destroyed.
; No check is made for DMA boundary overrun.
;
; EFFECTS: Programs disk controller.
; Performs disk input.
;
DOCMD PROC NEAR
MOV DI, BX ;(ES:DI) = data buffer addr.
PUSH CS
CALL COMMAND
JNZ DOC3
DOC1:
PUSH CS
CALL WAITT ;Wait for controller to complete read
JNZ DOC3
MOV CX, 100h ;256 words per sector
MOV DX, HF_PORT
CLD ;String op goes up
CLI ;Disable interrupts (BUG WAS FORGETTING THIS)
REPZ INSW ;Read in sector
STI
TEST CMD_BLOCK[CMD_REG], 02
JZ DOC2 ;No ECC bytes to read.
PUSH CS
CALL WAIT_DRQ
JC DOC3
MOV CX, 4 ;4 bytes of ECC
MOV DX, HF_PORT
CLI
REPZ INSB ;Read in ECC
STI
DOC2:
PUSH CS
CALL CHECK_STATUS
JNZ DOC3 ;Operation failed
DEC CMD_BLOCK[SEC_CNT]
JNZ DOC1 ;Loop while more sectors to read
DOC3:
RET
DOCMD ENDP
;*** GET_VEC - Get pointer to hard disk parameters.
;
; ENTRY: (DL) = Low bit has hard disk number (0 or 1).
;
; EXIT: (ES:BX) = address of disk parameters table.
;
; USES: AX for segment computation.
;
; Loads ES:BX from interrupt table in low memory, vector 46h (disk 0)
; or 70h (disk 1).
;
; WARNING: (AX) destroyed.
; This does a direct call to the AT ROM.
;
GET_VEC PROC NEAR
PUSH OFFSET ROMFRET
JMP ROMGET_VEC
GET_VEC ENDP
;*** COMMAND - Send contents of CMD_BLOCK to disk controller.
;
; ENTRY: Control_byte
; CMD_BLOCK - set up with values for hard disk controller.
;
; EXIT: DISK_STATUS1 = Error code.
; NZ if error, ZR for no error.
;
;
; WARNING: (AX), (CX), (DX) destroyed.
; Does a direct call to the AT ROM.
;
; EFFECTS: Programs disk controller.
;
COMMAND PROC NEAR
PUSH OFFSET ROMFRET
JMP ROMCOMMAND
COMMAND ENDP
;*** WAITT - Wait for disk interrupt
;
; ENTRY: Nothing.
;
; EXIT: DISK_STATUS1 = Error code.
; NZ if error, ZR if no error.
;
;
; WARNING: (AX), (BL), (CX) destroyed.
; Does a direct call to the AT ROM.
;
; EFFECTS: Calls int 15h, function 9000h.
;
WAITT PROC NEAR
PUSH OFFSET ROMFRET
JMP ROMWAIT
WAITT ENDP
;*** WAIT_DRQ - Wait for data request.
;
; ENTRY: Nothing.
;
; EXIT: DISK_STATUS1 = Error code.
; CY if error, NC if no error.
;
;
; WARNING: (AL), (CX), (DX) destroyed.
; Does a direct call to the AT ROM.
;
WAIT_DRQ PROC NEAR
PUSH OFFSET ROMFRET
JMP ROMWAIT_DRQ
WAIT_DRQ ENDP
;*** CHECK_STATUS - Check hard disk status.
;
; ENTRY: Nothing.
;
; EXIT: DISK_STATUS1 = Error code.
; NZ if error, ZR if no error.
;
;
; WARNING: (AX), (CX), (DX) destroyed.
; Does a direct call to the AT ROM.
;
CHECK_STATUS PROC NEAR
PUSH OFFSET ROMFRET
JMP ROMCHECK_STATUS
CHECK_STATUS ENDP
;*** CHECK_DMA - check for DMA overrun 64k segment.
;
; ENTRY: (ES:BX) = addr. of memory buffer in seg:000x form.
; CMD_BLOCK set up for operation.
;
; EXIT: DISK_STATUS1 - Error code.
; CY if error, NC if no error.
;
;
; WARNING: Does a direct call to the AT ROM.
;
CHECK_DMA PROC NEAR
PUSH OFFSET ROMFRET
JMP ROMCHECK_DMA
CHECK_DMA ENDP
CODE ENDS
END