MS-DOS/v2.0/source/FAT.ASM
2018-09-21 17:53:34 -07:00

362 lines
9.9 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; FAT operations 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
TITLE FAT - FAT maintenance routines
NAME FAT
i_need CURBUF,DWORD
i_need CLUSSPLIT,BYTE
i_need CLUSSAVE,WORD
i_need CLUSSEC,WORD
i_need THISDRV,BYTE
i_need DEVCALL,BYTE
i_need CALLMED,BYTE
i_need CALLRBYT,BYTE
i_need BUFFHEAD,DWORD
i_need CALLXAD,DWORD
i_need CALLBPB,DWORD
SUBTTL UNPACK -- UNPACK FAT ENTRIES
PAGE
ASSUME SS:DOSGROUP
procedure UNPACK,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Cluster number
; ES:BP = Base of drive parameters
; Outputs:
; DI = Contents of FAT for given cluster
; Zero set means DI=0 (free cluster)
; SI Destroyed, No other registers affected. Fatal error if cluster too big.
CMP BX,ES:[BP.dpb_max_cluster]
JA HURTFAT
CALL MAPCLUSTER
ASSUME DS:NOTHING
MOV DI,[DI]
JNC HAVCLUS
PUSH CX
MOV CL,4
SHR DI,CL
POP CX
STC
HAVCLUS:
AND DI,0FFFH
PUSH SS
POP DS
return
HURTFAT:
PUSH AX
MOV AH,80H ; Signal Bad FAT to INT int_fatal_abort handler
MOV DI,0FFFH ; In case INT int_fatal_abort returns (it shouldn't)
invoke FATAL
POP AX ; Try to ignore bad FAT
return
UNPACK ENDP
SUBTTL PACK -- PACK FAT ENTRIES
PAGE
procedure PACK,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Cluster number
; DX = Data
; ES:BP = Pointer to drive DPB
; Outputs:
; The data is stored in the FAT at the given cluster.
; SI,DX,DI all destroyed
; No other registers affected
CALL MAPCLUSTER
ASSUME DS:NOTHING
MOV SI,[DI]
JNC ALIGNED
PUSH CX
MOV CL,4
SHL DX,CL
POP CX
AND SI,0FH
JMP SHORT PACKIN
ALIGNED:
AND SI,0F000H
PACKIN:
OR SI,DX
MOV [DI],SI
LDS SI,[CURBUF]
MOV [SI.BUFDIRTY],1
CMP BYTE PTR [CLUSSPLIT],0
PUSH SS
POP DS
ASSUME DS:DOSGROUP
retz
PUSH AX
PUSH BX
PUSH CX
MOV AX,[CLUSSAVE]
MOV DS,WORD PTR [CURBUF+2]
ASSUME DS:NOTHING
ADD SI,BUFINSIZ
MOV [SI],AH
PUSH SS
POP DS
ASSUME DS:DOSGROUP
PUSH AX
MOV DX,[CLUSSEC]
MOV SI,1
XOR AL,AL
invoke GETBUFFRB
LDS DI,[CURBUF]
ASSUME DS:NOTHING
MOV [DI.BUFDIRTY],1
ADD DI,BUFINSIZ
DEC DI
ADD DI,ES:[BP.dpb_sector_size]
POP AX
MOV [DI],AL
PUSH SS
POP DS
POP CX
POP BX
POP AX
return
PACK ENDP
SUBTTL MAPCLUSTER - BUFFER A FAT SECTOR
PAGE
procedure MAPCLUSTER,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; ES:BP Points to DPB
; BX Is cluster number
; Function:
; Get a pointer to the cluster
; Outputs:
; DS:DI Points to contents of FAT for given cluster
; DS:SI Points to start of buffer
; Carry set if cluster data is in high 12 bits of word
; No other registers effected
MOV BYTE PTR [CLUSSPLIT],0
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AX,BX
SHR AX,1
ADD AX,BX
XOR DX,DX
MOV CX,ES:[BP.dpb_sector_size]
DIV CX ; AX is FAT sector # DX is sector index
ADD AX,ES:[BP.dpb_first_FAT]
DEC CX
PUSH AX
PUSH DX
PUSH CX
MOV DX,AX
XOR AL,AL
MOV SI,1
invoke GETBUFFRB
LDS SI,[CURBUF]
ASSUME DS:NOTHING
LEA DI,[SI.BufInSiz]
POP CX
POP AX
POP DX
ADD DI,AX
CMP AX,CX
JNZ MAPRET
MOV AL,[DI]
PUSH SS
POP DS
ASSUME DS:DOSGROUP
INC BYTE PTR [CLUSSPLIT]
MOV BYTE PTR [CLUSSAVE],AL
MOV [CLUSSEC],DX
INC DX
XOR AL,AL
MOV SI,1
invoke GETBUFFRB
LDS SI,[CURBUF]
ASSUME DS:NOTHING
LEA DI,[SI.BufInSiz]
MOV AL,[DI]
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV BYTE PTR [CLUSSAVE+1],AL
MOV DI,OFFSET DOSGROUP:CLUSSAVE
MAPRET:
POP DX
POP CX
POP BX
MOV AX,BX
SHR AX,1
POP AX
return
MAPCLUSTER ENDP
SUBTTL FATREAD -- CHECK DRIVE GET FAT
PAGE
ASSUME DS:DOSGROUP,ES:NOTHING
procedure FAT_operation,NEAR
FATERR:
AND DI,STECODE ; Put error code in DI
MOV AH,2 ; While trying to read FAT
MOV AL,BYTE PTR [THISDRV] ; Tell which drive
invoke FATAL1
entry FATREAD
ASSUME DS:DOSGROUP,ES:NOTHING
; Function:
; If disk may have been changed, FAT is read in and buffers are
; flagged invalid. If not, no action is taken.
; Outputs:
; ES:BP = Base of drive parameters
; All other registers destroyed
MOV AL,BYTE PTR [THISDRV]
invoke GETBP
MOV AL,DMEDHL
MOV AH,ES:[BP.dpb_UNIT]
MOV WORD PTR [DEVCALL],AX
MOV BYTE PTR [DEVCALL.REQFUNC],DEVMDCH
MOV [DEVCALL.REQSTAT],0
MOV AL,ES:[BP.dpb_media]
MOV BYTE PTR [CALLMED],AL
PUSH ES
PUSH DS
MOV BX,OFFSET DOSGROUP:DEVCALL
LDS SI,ES:[BP.dpb_driver_addr] ; DS:SI Points to device header
ASSUME DS:NOTHING
POP ES ; ES:BX Points to call header
invoke DEVIOCALL2
PUSH SS
POP DS
ASSUME DS:DOSGROUP
POP ES ; Restore ES:BP
MOV DI,[DEVCALL.REQSTAT]
TEST DI,STERR
JNZ FATERR
XOR AH,AH
XCHG AH,ES:[BP.dpb_first_access] ; Reset dpb_first_access
MOV AL,BYTE PTR [THISDRV] ; Use physical unit number
OR AH,BYTE PTR [CALLRBYT]
JS NEWDSK ; new disk or first access?
JZ CHKBUFFDIRT
return ; If Media not changed
CHKBUFFDIRT:
INC AH ; Here if ?Media..Check buffers
LDS DI,[BUFFHEAD]
ASSUME DS:NOTHING
NBUFFER: ; Look for dirty buffers
CMP AX,WORD PTR [DI.BUFDRV]
retz ; There is a dirty buffer, assume Media OK
LDS DI,[DI.NEXTBUF]
CMP DI,-1
JNZ NBUFFER
; If no dirty buffers, assume Media changed
NEWDSK:
invoke SETVISIT
NXBUFFER:
MOV [DI.VISIT],1
CMP AL,[DI.BUFDRV] ; For this drive?
JNZ SKPBUFF
MOV WORD PTR [DI.BUFDRV],00FFH ; Free up buffer
invoke SCANPLACE
SKPBUFF:
invoke SKIPVISIT
JNZ NXBUFFER
LDS DI,ES:[BP.dpb_driver_addr]
TEST [DI.SDEVATT],ISFATBYDEV
JNZ GETFREEBUF
context DS
MOV BX,2
CALL UNPACK ; Read the first FAT sector into CURBUF
LDS DI,[CURBUF]
JMP SHORT GOTGETBUF
GETFREEBUF:
ASSUME DS:NOTHING
PUSH ES ; Get a free buffer for BIOS to use
PUSH BP
LDS DI,[BUFFHEAD]
invoke BUFWRITE
POP BP
POP ES
GOTGETBUF:
ADD DI,BUFINSIZ
MOV WORD PTR [CALLXAD+2],DS
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV WORD PTR [CALLXAD],DI
MOV AL,DBPBHL
MOV AH,BYTE PTR ES:[BP.dpb_UNIT]
MOV WORD PTR [DEVCALL],AX
MOV BYTE PTR [DEVCALL.REQFUNC],DEVBPB
MOV [DEVCALL.REQSTAT],0
MOV AL,BYTE PTR ES:[BP.dpb_media]
MOV [CALLMED],AL
PUSH ES
PUSH DS
PUSH WORD PTR ES:[BP.dpb_driver_addr+2]
PUSH WORD PTR ES:[BP.dpb_driver_addr]
MOV BX,OFFSET DOSGROUP:DEVCALL
POP SI
POP DS ; DS:SI Points to device header
ASSUME DS:NOTHING
POP ES ; ES:BX Points to call header
invoke DEVIOCALL2
POP ES ; Restore ES:BP
PUSH SS
POP DS
ASSUME DS:DOSGROUP
MOV DI,[DEVCALL.REQSTAT]
TEST DI,STERR
JNZ FATERRJ
MOV AL,BYTE PTR ES:[BP.dpb_media]
LDS SI,[CALLBPB]
ASSUME DS:NOTHING
CMP AL,BYTE PTR [SI.BPMEDIA]
JZ DPBOK
invoke $SETDPB
LDS DI,[CALLXAD] ; Get back buffer pointer
MOV AL,BYTE PTR ES:[BP.dpb_FAT_count]
MOV AH,BYTE PTR ES:[BP.dpb_FAT_size]
MOV WORD PTR [DI.BUFWRTCNT-BUFINSIZ],AX ;Correct buffer info
DPBOK:
context ds
MOV AX,-1
TEST ES:[BP.dpb_current_dir],AX
retz ; If root, leave as root
MOV ES:[BP.dpb_current_dir],AX ; Path may be bad, mark invalid
return
FATERRJ: JMP FATERR
FAT_operation ENDP
do_ext
CODE ENDS
END