;*** ; Title: Disk ; By: Michael Hanson ; C: Copyright (C) 1985-1987 by Microsoft corp. ; Date: 1/11/85 ; ; There is a bug in some versions of IBM's AT ROM BIOS ; interupts 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: POP AX MOV AH,DISK_STATUS1 ;On return AH has error code STC OR AH,AH JNZ ATD5 ;Carry set if error CLC 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 WAIT ;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 ;*** WAIT - 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. ; WAIT PROC NEAR PUSH OFFSET ROMFRET JMP ROMWAIT WAIT 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