mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-11-29 17:15:47 +00:00
509 lines
14 KiB
NASM
509 lines
14 KiB
NASM
;
|
|
; buffer management for MSDOS
|
|
;
|
|
|
|
INCLUDE DOSSEG.ASM
|
|
|
|
CODE SEGMENT BYTE PUBLIC 'CODE'
|
|
ASSUME SS:DOSGROUP,CS:DOSGROUP
|
|
|
|
.xlist
|
|
.xcref
|
|
INCLUDE DOSSYM.ASM
|
|
INCLUDE DEVSYM.ASM
|
|
.cref
|
|
.list
|
|
|
|
i_need BuffHead,DWORD
|
|
i_need PreRead,WORD
|
|
i_need LastBuffer,DWORD
|
|
i_need CurBuf,DWORD
|
|
i_need WPErr,BYTE
|
|
|
|
SUBTTL SETVISIT,SKIPVISIT -- MANAGE BUFFER SCANS
|
|
PAGE
|
|
procedure SETVISIT,near
|
|
ASSUME DS:NOTHING,ES:NOTHING
|
|
|
|
; Inputs:
|
|
; None
|
|
; Function:
|
|
; Set up a scan of I/O buffers
|
|
; Outputs:
|
|
; All visit flags = 0
|
|
; NOTE: This pre-scan is needed because a hard disk error
|
|
; may cause a scan to stop in the middle leaving some
|
|
; visit flags set, and some not set.
|
|
; DS:DI Points to [BUFFHEAD]
|
|
; No other registers altered
|
|
|
|
LDS DI,[BUFFHEAD]
|
|
PUSH AX
|
|
XOR AX,AX
|
|
SETLOOP:
|
|
MOV [DI.VISIT],AL
|
|
LDS DI,[DI.NEXTBUF]
|
|
CMP DI,-1
|
|
JNZ SETLOOP
|
|
LDS DI,[BUFFHEAD]
|
|
POP AX
|
|
return
|
|
|
|
entry SKIPVISIT
|
|
ASSUME DS:NOTHING,ES:NOTHING
|
|
|
|
; Inputs:
|
|
; DS:DI Points to a buffer
|
|
; Function:
|
|
; Skip visited buffers
|
|
; Outputs:
|
|
; DS:DI Points to next unvisited buffer
|
|
; Zero is set if skip to LAST buffer
|
|
; No other registers altered
|
|
|
|
CMP DI,-1
|
|
retz
|
|
CMP [DI.VISIT],1
|
|
retnz
|
|
LDS DI,[DI.NEXTBUF]
|
|
JMP SHORT SKIPVISIT
|
|
return
|
|
SetVisit ENDP
|
|
|
|
|
|
SUBTTL SCANPLACE, PLACEBUF -- PUT A BUFFER BACK IN THE POOL
|
|
PAGE
|
|
procedure ScanPlace,near
|
|
ASSUME DS:NOTHING,ES:NOTHING
|
|
|
|
; Inputs:
|
|
; Same as PLACEBUF
|
|
; Function:
|
|
; Save scan location and call PLACEBUF
|
|
; Outputs:
|
|
; DS:DI Points to saved scan location
|
|
; SI destroyed, other registers unchanged
|
|
|
|
PUSH ES
|
|
LES SI,[DI.NEXTBUF] ; Save scan location
|
|
CALL PLACEBUF
|
|
PUSH ES
|
|
POP DS ; Restore scan location
|
|
MOV DI,SI
|
|
POP ES
|
|
return
|
|
ScanPlace ENDP
|
|
|
|
NRETJ: JMP SHORT NRET
|
|
|
|
procedure PLACEBUF,NEAR
|
|
ASSUME DS:NOTHING,ES:NOTHING
|
|
|
|
; Input:
|
|
; DS:DI points to buffer
|
|
; Function:
|
|
; Remove buffer from queue and re-insert it in proper place.
|
|
; If buffer doesn't go at end, and isn't free, decrement
|
|
; priorities.
|
|
; NO registers altered
|
|
;
|
|
; DS:SI -- Curbuf, current buffer in list
|
|
; ES:DI -- Buf, buffer passed as argument
|
|
; BP:CX -- Pointsave, saved Buf.nextbuf
|
|
; DX:BX -- Lastbuf, previous buffer in list
|
|
; AL -- Inserted, Buf has been inserted
|
|
; AH -- Removed, Buf has been removed
|
|
|
|
IF IBM
|
|
IF NOT IBM
|
|
invoke save_world
|
|
XOR AX,AX ; Inserted = Removed = FALSE
|
|
LES CX,[DI.NEXTBUF]
|
|
MOV BP,ES ; Pointsave = Buf.nextbuf
|
|
MOV SI,DS
|
|
MOV ES,SI ; Buf is ES:DI
|
|
LDS SI,[BUFFHEAD] ; Curbuf = HEAD
|
|
CALL POINTCOMP ; Buf == HEAD?
|
|
JNZ TNEWHEAD
|
|
CMP CX,-1 ; Buf is LAST?
|
|
JZ NRETJ ; Only one buffer, nothing to do
|
|
MOV WORD PTR [BUFFHEAD],CX
|
|
MOV WORD PTR [BUFFHEAD+2],BP ; HEAD = Pointsave
|
|
INC AH ; Removed = TRUE
|
|
MOV DS,BP
|
|
MOV SI,CX ; Curbuf = HEAD
|
|
TNEWHEAD:
|
|
MOV BL,ES:[DI.BUFPRI]
|
|
CMP BL,[SI.BUFPRI]
|
|
JGE BUFLOOP
|
|
NEWHEAD: ; If Buf.pri < HEAD.pri
|
|
MOV WORD PTR ES:[DI.NEXTBUF],SI
|
|
MOV WORD PTR ES:[DI.NEXTBUF+2],DS ; Buf.nextbuf = HEAD
|
|
MOV WORD PTR [BUFFHEAD],DI
|
|
MOV WORD PTR [BUFFHEAD+2],ES ; HEAD = Buf
|
|
INC AL ; Inserted = TRUE
|
|
OR AH,AH
|
|
JNZ NRET ; If Removed == TRUE
|
|
BUFLOOP:
|
|
PUSH DS
|
|
PUSH SI
|
|
LDS SI,[SI.NEXTBUF]
|
|
CALL POINTCOMP
|
|
POP SI
|
|
POP DS
|
|
JNZ TESTINS
|
|
MOV WORD PTR [SI.NEXTBUF],CX ; If Curbuf.nextbuf == buf
|
|
MOV WORD PTR [SI.NEXTBUF+2],BP ; Curbuf.nextbuf = Pointsave
|
|
INC AH ; Removed = TRUE
|
|
OR AL,AL
|
|
JNZ SHUFFLE ; If Inserted == TRUE
|
|
TESTINS:
|
|
OR AL,AL
|
|
JNZ LOOKBUF
|
|
PUSH CX ; If NOT Inserted
|
|
MOV CL,ES:[DI.BUFPRI]
|
|
CMP CL,[SI.BUFPRI]
|
|
POP CX
|
|
JGE LOOKBUF
|
|
PUSH DS ; If Buf.pri < Curbuf.pri
|
|
MOV DS,DX
|
|
MOV WORD PTR [BX.NEXTBUF],DI
|
|
MOV WORD PTR [BX.NEXTBUF+2],ES ; Lastbuf.nextbuf = Buf
|
|
POP DS
|
|
MOV WORD PTR ES:[DI.NEXTBUF],SI
|
|
MOV WORD PTR ES:[DI.NEXTBUF+2],DS ; Buf.nextbuf = Curbuf
|
|
INC AL ; Inserted = TRUE
|
|
OR AH,AH
|
|
JNZ SHUFFLE ; If Removed == TRUE
|
|
LOOKBUF:
|
|
MOV BX,SI
|
|
MOV DX,DS ; Lastbuf = Curbuf
|
|
CMP WORD PTR [SI.NEXTBUF],-1
|
|
JZ ISLAST
|
|
LDS SI,[SI.NEXTBUF] ; Curbuf = Curbuf.nextbuf
|
|
JMP SHORT BUFLOOP
|
|
ISLAST: ; If Curbuf is LAST
|
|
MOV WORD PTR [SI.NEXTBUF],DI
|
|
MOV WORD PTR [SI.NEXTBUF+2],ES ; Curbuf.nextbuf = Buf
|
|
MOV WORD PTR ES:[DI.NEXTBUF],-1
|
|
MOV WORD PTR ES:[DI.NEXTBUF+2],-1 ; Buf is LAST
|
|
NRET:
|
|
invoke restore_world
|
|
return
|
|
|
|
SHUFFLE:
|
|
LDS DI,[BUFFHEAD]
|
|
DECLOOP:
|
|
CMP [DI.BUFPRI],FREEPRI
|
|
JZ NODEC
|
|
DEC [DI.BUFPRI]
|
|
NODEC:
|
|
LDS DI,[DI.NEXTBUF]
|
|
CMP DI,-1
|
|
JNZ DECLOOP
|
|
JMP SHORT NRET
|
|
ENDIF
|
|
ENDIF
|
|
|
|
invoke save_world
|
|
LES CX,[DI.NEXTBUF]
|
|
CMP CX,-1 ; Buf is LAST?
|
|
JZ NRET ; Buffer already last
|
|
MOV BP,ES ; Pointsave = Buf.nextbuf
|
|
PUSH DS
|
|
POP ES ; Buf is ES:DI
|
|
LDS SI,[BUFFHEAD] ; Curbuf = HEAD
|
|
CALL POINTCOMP ; Buf == HEAD?
|
|
JNZ BUFLOOP
|
|
MOV WORD PTR [BUFFHEAD],CX
|
|
MOV WORD PTR [BUFFHEAD+2],BP ; HEAD = Pointsave
|
|
JMP SHORT LOOKEND
|
|
|
|
BUFLOOP:
|
|
PUSH DS
|
|
PUSH SI
|
|
LDS SI,[SI.NEXTBUF]
|
|
CALL POINTCOMP
|
|
JZ GOTTHEBUF
|
|
POP AX
|
|
POP AX
|
|
JMP SHORT BUFLOOP
|
|
|
|
GOTTHEBUF:
|
|
POP SI
|
|
POP DS
|
|
MOV WORD PTR [SI.NEXTBUF],CX ; If Curbuf.nextbuf == buf
|
|
MOV WORD PTR [SI.NEXTBUF+2],BP ; Curbuf.nextbuf = Pointsave
|
|
LOOKEND:
|
|
PUSH DS
|
|
PUSH SI
|
|
LDS SI,[SI.NEXTBUF]
|
|
CMP SI,-1
|
|
JZ GOTHEEND
|
|
POP AX
|
|
POP AX
|
|
JMP SHORT LOOKEND
|
|
|
|
GOTHEEND:
|
|
POP SI
|
|
POP DS
|
|
MOV WORD PTR [SI.NEXTBUF],DI
|
|
MOV WORD PTR [SI.NEXTBUF+2],ES ; Curbuf.nextbuf = Buf
|
|
MOV WORD PTR ES:[DI.NEXTBUF],-1
|
|
MOV WORD PTR ES:[DI.NEXTBUF+2],-1 ; Buf is LAST
|
|
NRET:
|
|
invoke restore_world
|
|
return
|
|
|
|
PLACEBUF ENDP
|
|
|
|
procedure PLACEHEAD,NEAR
|
|
ASSUME DS:NOTHING,ES:NOTHING
|
|
|
|
; SAME AS PLACEBUF except places buffer at head
|
|
|
|
invoke save_world
|
|
PUSH DS
|
|
POP ES
|
|
LDS SI,[BUFFHEAD]
|
|
MOV WORD PTR [BUFFHEAD],DI
|
|
MOV WORD PTR [BUFFHEAD+2],ES
|
|
MOV WORD PTR ES:[DI.NEXTBUF],SI
|
|
MOV WORD PTR ES:[DI.NEXTBUF+2],DS
|
|
LOOKEND2:
|
|
PUSH DS
|
|
PUSH SI
|
|
LDS SI,[SI.NEXTBUF]
|
|
CALL POINTCOMP
|
|
JZ GOTHEEND2
|
|
POP AX
|
|
POP AX
|
|
JMP SHORT LOOKEND2
|
|
|
|
GOTHEEND2:
|
|
POP SI
|
|
POP DS
|
|
MOV WORD PTR [SI.NEXTBUF],-1
|
|
MOV WORD PTR [SI.NEXTBUF+2],-1 ; Buf is LAST
|
|
JMP SHORT NRET
|
|
|
|
PLACEHEAD ENDP
|
|
|
|
SUBTTL POINTCOMP -- 20 BIT POINTER COMPARE
|
|
PAGE
|
|
procedure PointComp,NEAR
|
|
ASSUME DS:NOTHING,ES:NOTHING
|
|
|
|
; Compare DS:SI to ES:DI (or DS:DI to ES:SI) for equality
|
|
; DO NOT USE FOR < or >
|
|
; No Registers altered
|
|
|
|
CMP SI,DI
|
|
retnz
|
|
PUSH CX
|
|
PUSH DX
|
|
MOV CX,DS
|
|
MOV DX,ES
|
|
CMP CX,DX
|
|
POP DX
|
|
POP CX
|
|
return
|
|
PointComp ENDP
|
|
|
|
SUBTTL GETBUFFR -- GET A SECTOR INTO A BUFFER
|
|
PAGE
|
|
procedure GETBUFFR,NEAR
|
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|
|
|
; Input:
|
|
; AH = Priority buffer is to have
|
|
; AL = 0 means sector must be pre-read
|
|
; ELSE no pre-read
|
|
; DX = Desired physical sector number
|
|
; ES:BP = Pointer to drive parameters
|
|
; Function:
|
|
; Get the specified sector into one of the I/O buffers
|
|
; And shuffle the queue
|
|
; Output:
|
|
; [CURBUF] Points to the Buffer for the sector
|
|
; DX,ES:BP unchanged, all other registers destroyed
|
|
|
|
XOR SI,SI
|
|
entry GETBUFFRB
|
|
MOV [PREREAD],AX
|
|
MOV AL,ES:[BP.dpb_drive]
|
|
LDS DI,[LASTBUFFER]
|
|
ASSUME DS:NOTHING
|
|
CMP DI,-1 ; Recency pointer valid?
|
|
JZ SKBUF ; No
|
|
CMP DX,[DI.BUFSECNO]
|
|
JNZ SKBUF ; Wrong sector
|
|
CMP AL,[DI.BUFDRV]
|
|
JNZ SKBUF ; Wrong Drive
|
|
JMP SHORT JUSTBUF ; Just asked for same buffer
|
|
SKBUF:
|
|
LDS DI,[BUFFHEAD]
|
|
NXTBFF:
|
|
CMP DX,[DI.BUFSECNO]
|
|
JNZ BUMP
|
|
CMP AL,[DI.BUFDRV]
|
|
JNZ BUMP
|
|
JMP SHORT SETINF
|
|
BUMP:
|
|
LDS DI,[DI.NEXTBUF]
|
|
CMP DI,-1
|
|
JNZ NXTBFF
|
|
LDS DI,[BUFFHEAD]
|
|
PUSH SI
|
|
PUSH DX
|
|
PUSH BP
|
|
PUSH ES
|
|
CALL BUFWRITE ; Write out the dirty buffer
|
|
POP ES
|
|
POP BP
|
|
POP DX
|
|
POP SI
|
|
RDSEC: ; Read in the new sector
|
|
TEST BYTE PTR [PREREAD],-1
|
|
JNZ SETBUF
|
|
LEA BX,[DI.BufInSiz] ; Point at buffer
|
|
MOV CX,1
|
|
PUSH SI
|
|
PUSH DI
|
|
PUSH DX
|
|
OR SI,SI
|
|
JZ NORMSEC
|
|
invoke FATSECRD
|
|
JMP SHORT GOTTHESEC ; Buffer is marked free if read barfs
|
|
NORMSEC:
|
|
invoke DREAD ; Buffer is marked free if read barfs
|
|
GOTTHESEC:
|
|
POP DX
|
|
POP DI
|
|
POP SI
|
|
SETBUF:
|
|
MOV [DI.BUFSECNO],DX
|
|
MOV WORD PTR [DI.BUFDRVDP],BP
|
|
MOV WORD PTR [DI.BUFDRVDP+2],ES
|
|
XOR AH,AH
|
|
MOV AL,ES:[BP.dpb_drive]
|
|
MOV WORD PTR [DI.BUFDRV],AX
|
|
SETINF:
|
|
MOV AX,1 ; Default to not a FAT sector
|
|
OR SI,SI
|
|
JZ SETSTUFFOK
|
|
MOV AL,ES:[BP.dpb_FAT_count]
|
|
MOV AH,ES:[BP.dpb_FAT_size]
|
|
SETSTUFFOK:
|
|
MOV WORD PTR [DI.BUFWRTCNT],AX
|
|
CALL PLACEBUF
|
|
JUSTBUF:
|
|
MOV WORD PTR [CURBUF+2],DS
|
|
MOV WORD PTR [LASTBUFFER+2],DS
|
|
PUSH SS
|
|
POP DS
|
|
ASSUME DS:DOSGROUP
|
|
MOV WORD PTR [CURBUF],DI
|
|
MOV WORD PTR [LASTBUFFER],DI
|
|
return
|
|
GETBUFFR ENDP
|
|
|
|
|
|
SUBTTL FLUSHBUF -- WRITE OUT DIRTY BUFFERS
|
|
PAGE
|
|
procedure FlushBuf,NEAR
|
|
ASSUME DS:DOSGROUP,ES:NOTHING
|
|
|
|
; Input:
|
|
; DS = DOSGROUP
|
|
; AL = Physical unit number
|
|
; = -1 for all units
|
|
; Function:
|
|
; Write out all dirty buffers for unit, and flag them as clean
|
|
; DS Preserved, all others destroyed (ES too)
|
|
|
|
LDS DI,[BUFFHEAD]
|
|
ASSUME DS:NOTHING
|
|
MOV AH,-1
|
|
NXTBUFF:
|
|
CMP [DI.BUFDRV],AH
|
|
JZ SKIPBFF ; Skip free buffers
|
|
CMP AH,AL
|
|
JZ DOBUFFER ; Do all dirty buffers
|
|
CMP AL,[DI.BUFDRV]
|
|
JNZ SKIPBFF ; Buffer not for this unit
|
|
DOBUFFER:
|
|
CMP BYTE PTR [DI.BUFDIRTY],0
|
|
JZ SKIPBFF ; Buffer not dirty
|
|
PUSH AX
|
|
PUSH WORD PTR [DI.BUFDRV]
|
|
CALL BUFWRITE
|
|
POP AX
|
|
XOR AH,AH ; Buffer is clean
|
|
CMP AL,BYTE PTR [WPERR]
|
|
JNZ NOZAP
|
|
MOV AL,0FFH ; Invalidate buffer, it is inconsistent
|
|
NOZAP:
|
|
MOV WORD PTR [DI.BUFDRV],AX
|
|
POP AX ; Search info
|
|
SKIPBFF:
|
|
LDS DI,[DI.NEXTBUF]
|
|
CMP DI,-1
|
|
JNZ NXTBUFF
|
|
PUSH SS
|
|
POP DS
|
|
return
|
|
FlushBuf ENDP
|
|
|
|
|
|
SUBTTL BUFWRITE -- WRITE OUT A BUFFER IF DIRTY
|
|
PAGE
|
|
procedure BufWrite,NEAR
|
|
ASSUME DS:NOTHING,ES:NOTHING
|
|
|
|
; Input:
|
|
; DS:DI Points to the buffer
|
|
; Function:
|
|
; Write out all the buffer if dirty.
|
|
; Output:
|
|
; Buffer marked free
|
|
; DS:DI Preserved, ALL others destroyed (ES too)
|
|
|
|
MOV AX,00FFH
|
|
XCHG AX,WORD PTR [DI.BUFDRV] ; Free, in case write barfs
|
|
CMP AL,0FFH
|
|
retz ; Buffer is free.
|
|
OR AH,AH
|
|
retz ; Buffer is clean.
|
|
CMP AL,BYTE PTR [WPERR]
|
|
retz ; If in WP error zap buffer
|
|
LES BP,[DI.BUFDRVDP]
|
|
LEA BX,[DI.BufInSiz] ; Point at buffer
|
|
MOV DX,[DI.BUFSECNO]
|
|
MOV CX,WORD PTR [DI.BUFWRTCNT]
|
|
MOV AL,CH ; [DI.BUFWRTINC]
|
|
XOR CH,CH
|
|
MOV AH,CH
|
|
PUSH DI
|
|
WRTAGAIN:
|
|
PUSH CX
|
|
PUSH AX
|
|
MOV CX,1
|
|
PUSH BX
|
|
PUSH DX
|
|
invoke DWRITE ; Write out the dirty buffer
|
|
POP DX
|
|
POP BX
|
|
POP AX
|
|
POP CX
|
|
ADD DX,AX
|
|
LOOP WRTAGAIN
|
|
POP DI
|
|
return
|
|
BufWrite ENDP
|
|
|
|
do_ext
|
|
|
|
CODE ENDS
|
|
END
|