428 lines
8.7 KiB
NASM
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
|