📄 newint13.asm
字号:
;========================================================
COMMENT #
NEWINT13.ASM
Copyright (c) 1991 - Microsoft Corp.
All rights reserved.
Microsoft Confidential
=================================================
New interrupt 13h handler and support functions
which check for DMA boundary errors and if detected
will break the read into 3 pieces to eliminate
error.
=================================================
johnhe - 06/06/89
END COMMENT #
; =======================================================
FIRST_HARD_DISK EQU 80h
INCLUDE model.inc
.DATA
EXTRN DiskChange:BYTE
.CODE
; =======================================================
; DWORD address of original int 13h handler. Initialize
; by InitNew13() and then used by RestoreOld13() to
; to restore the vector before the program exits back
; to DOS.
; =======================================================
public OldInt13
OldInt13 dd (?)
OldAX dw (?)
SplitBuffer dd (?)
; =======================================================
; Sets int vector 13h to point to the NewInt13 function
; which does a check for DMA errors and corrects the
; error. Saves the original vector for later restoration.
;
; void InitNew13( char far *Buffer );
;
; ARGUMENTS: Buffer - Far ptr to min 1024 byte buffer
; to be used for if a disk read
; needs to be split to avoid a
; DMA boundary error
; RETURNS: void
; =======================================================
InitNew13 PROC USES DS ES, Buffer:DWORD
mov AX,3513h ; Get int vector 13h
int 21h
mov WORD PTR CS:OldInt13,BX ; Save the offset
mov WORD PTR CS:OldInt13[2],ES ; Save the segment
mov AX,2513h ; Set vector 13h
mov DX,offset NewInt13 ; Load new vector offset
push CS ; Load new vector segment
pop DS
int 21h ; DOS call
SaveBuffer:
lds BX,Buffer; ; DS:SI --> 1024 byte buffer
TestForSegmentBound:
mov AX,DS ; Put buffer segment in AX
shl AX,1 ; Convert segment to 20 bit address
shl AX,1 ; while ingoring the high 4 bits
shl AX,1
shl AX,1
add AX,BX ; Add offset to 20 bit address
add AX,512 ; Add sector size to 20 bit address
jnc GotBuffer ; If no carry then no segment overrun
add BX,512 ; Else move to next segment
GotBuffer:
mov WORD PTR CS:SplitBuffer,BX
mov WORD PTR CS:SplitBuffer[2],DS
ret
InitNew13 ENDP
; =======================================================
; Replaces the int 13h vector with the original pointer.
; =======================================================
RestoreOld13 PROC USES DS
mov AX,2513h ; Set vector 13h
mov DX,WORD PTR CS:OldInt13[2] ; Load old segment
mov DS,DX
mov DX,WORD PTR CS:OldInt13 ; Load old offset
int 21h
ret
RestoreOld13 ENDP
; =======================================================
; New int 13h handler which will correct DMA errors if
; they are detected on reads or writes.
; =======================================================
public NewInt13
NewInt13:
push AX ; Save original request
cmp DL, FIRST_HARD_DISK ; Only do disk change check
jae FakeIntCall ; if drive in AL < 80h
push DS ; First see if we need to fake
mov AX,@DATA ; a changeline.
mov DS,AX
xor AX,AX
cmp AL,BYTE PTR DS:DiskChange
mov BYTE PTR DS:DiskChange,AL
pop DS
pop AX ; Restore AX but keep original
push AX
je FakeIntCall
mov AX,0600h
stc
jmp SHORT TestError
FakeIntCall:
pushf ; Simulate an int request
call DWORD PTR CS:[OldInt13] ; of the old int 13h handler
jc TestError ; Error so check for DMA error
IntExit:
pop CS:OldAX
retf 02 ; Far return and pop flags
TestError:
cmp AH,9 ; Check for DMA bound error
je ServiceError
stc ; Reset error condition
jmp SHORT IntExit
ServiceError:
pop AX ; Get original function call in AX
cmp AL,0 ; Make sure of valid number sectors
je RestoreError
cmp AH,2 ; Check was it a read operation
je SplitOperation ; If yes try splitting the read
cmp AH,3 ; Check was it a write operation
je SplitOperation ; If yes try splitting the write
RestoreError:
mov AX,900h ; Retore original error code
stc ; Restore the original err condition
retf 02 ; Far return and pop the flags
SplitOperation:
call NEAR PTR Int13Error ; Try to avoid the DMA boundary
retf 02 ; Return to caller
; =======================================================
; Breaks a disk read or write into individual sectors
; using another memory location which is not on a DMA
; boundary. Returns BIOS int 13h error code if carry set
; else AX == 0. Preserves all registers execpt AX
; =======================================================
Int13Error PROC NEAR
push BX ; Save registers we need to use
push CX
push DI
push SI
push DS
push ES
lds SI,CS:SplitBuffer ; Put error buffer offset in SI
cmp AH,02 ; See if this is a read
jne IsWrite ; If not read must be a write
IsRead:
call ReadSecs ; Call proc to read in the sectors
jmp SHORT CleanUp ; Finished
IsWrite:
call WriteSecs ; Call proc to write the sectors
CleanUp:
pop ES ; Restore all caller's registers
pop DS ; excpet AX and flags
pop SI
pop DI
pop CX
pop BX
ret
Int13Error ENDP
; =======================================================
; Uses the BIOS int 13h call to read the number of sectors
; in AL into the buffer in DS:SI and then moves them to
; to the buffer in ES:BX. Reads and moves one sector at
; a time. AX, BX, CX, DX, ES must be setup on on entry
; for a normal BIOS read and DS:SI must point to a
; buffer at least 512 bytes long which is not on a
; DMA boundary.
; =======================================================
ReadSecs PROC NEAR
mov DI,BX ; ES:DI == start of caller's buffer
mov BX,SI ; Point BX to new buffer
ReadLoop:
push AX ; Save remaining sectors to do
mov AL,1 ; Set number of sector to 1
push ES ; Save caller's buffer segment
push DS ; Set ES to new buffer
pop ES
pushf ; Simulate and int call
call DWORD PTR CS:[OldInt13] ; of the old int 13h handler
pop ES ; Retore caller's buffer segment
ErrorTest:
jnc CopyFromBuf ; No error so copy sector to user buf
add SP,2 ; Adjust stack for pushed AX
stc ; Signal we got an error
jmp SHORT ReadReturn ; Finished
CopyFromBuf:
push SI ; Save ptr to start of new buffer
push CX ; Save next sector number
mov CX,(512/2) ; Set count of words in buffer
cld ; Set direction to forward
rep movsw ; Move 1 sector to new buffer
pop CX ; Restore next sector number
pop SI ; Restore ptr to start of buffer
pop AX ; Restore remaining sectors
inc CL ; Increment to next sector
dec AL ; One less sector to do
jnz ReadLoop ; Loop until AL == 0
xor AX,AX ; No error code also clears carry
jmp SHORT ReadReturn ; Finished
ReadReturn:
ret
ReadSecs ENDP
; =======================================================
; Uses the BIOS int 13h call to write the number of sectors
; in AL by moving them to a new buffer one sector at a
; time and then writing them one at a time.
; AX, BX, CX, DX, ES must be setup on on entry
; for a normal BIOS read and DS:SI must point to a
; buffer at least 512 bytes long which is not on a
; DMA boundary.
; =======================================================
WriteSecs PROC NEAR
push ES ; Set DS:SI to caller's buffer
push DS ; and ES:DI to new buffer
pop ES
pop DS
mov DI,SI
mov SI,BX
mov BX,DI ; Point BX to new buffer
WriteLoop:
push CX ; Save next sector number
CopyToBuf:
mov DI,BX ; Set ptr to new buffer
mov CX,(512/2) ; Set count of words in buffer
cld ; Set direction to forward
rep movsw ; Move 1 sector to new buffer
pop CX ; Restore next sector number
WriteTheSector:
push AX ; Save remaining sectors to do
mov AL,1 ; Set number of sector to 1
pushf ; Simulate and int call
call DWORD PTR CS:[OldInt13] ; of the old int 13h handler
ErrorTest:
jc WriteError ; Got an error so return
pop AX ; Restore remaining sectors
inc CL ; Increment to next sector
dec AL ; One less sector to do
jnz WriteLoop ; Loop until AL == 0
xor AX,AX ; No error code also clears carry
jmp SHORT WriteReturn ; Finished
WriteError:
add SP,2 ; Adjust stack for pushed AX
stc ; Signal we got an error
WriteReturn:
ret
WriteSecs ENDP
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -