mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-11-29 17:15:47 +00:00
362 lines
9.9 KiB
NASM
362 lines
9.9 KiB
NASM
;
|
||
; 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
|
||
|