]>
wirehaze git hosting - MS-DOS.git/blob - v4.0/src/DOS/FAT.ASM
1 ; SCCSID = @(#)fat.asm 1.3 85/08/15
2 ; SCCSID = @(#)fat.asm 1.3 85/08/15
3 TITLE FAT
- FAT maintenance routines
5 ; Low level local device routines for performing disk change sequence,
6 ; setting cluster validity, and manipulating the FAT
18 ; AN000 version Jan. 1988
19 ; A001 PTM -- disk changed for look ahead buffers
23 ; get the appropriate segment definitions
28 CODE SEGMENT BYTE PUBLIC 'CODE'
29 ASSUME
SS:DOSGROUP
,CS:DOSGROUP
42 i_need CLUSSEC
,DWORD ;F.C. >32mb ;AN000;
59 i_need VOLCHNG_FLAG
,BYTE
60 i_need HIGH_SECTOR
,WORD
61 i_need BUF_HASH_COUNT
,WORD
62 i_need BUF_HASH_PTR
,DWORD
63 i_need FIRST_BUFF_ADDR
,WORD
64 i_need SC_CACHE_COUNT
,WORD ;AN001;
65 i_need CURSC_DRIVE
,BYTE ;AN001;
68 Break <IsEOF
- check the quantity
in BX for EOF
>
71 ; IsEOF - check the fat value in BX for eof.
73 ; Inputs: ES:BP point to DPB
76 ; Registers modified: none
78 ASSUME
SS:DOSGROUP
,CS:DOSGROUP
,DS:NOTHING
,ES:NOTHING
79 Assert ISDPB
,<ES,BP>,"IsEOF"
80 CMP ES:[BP.dpb_max_cluster
],4096-10 ; is this 16 bit fat?
81 JAE EOF16
; yes, check for eof there
83 ;Modified to accept 0FF0h as an eof. This is to handle the diskfull case
84 ;of any media that has "F0"(Other) as a MediaByte.
85 ;Hopely, this does not create any side effect for those who may use any value
86 ;other than "FF8-FFF" as an Eof for their own file.
89 CMP BX,0FF8h ; do the 12 bit compare
93 CMP BX,0FFF8h ; 16 bit compare
97 Break <UNPACK
-- UNPACK FAT ENTRIES
>
100 ; BX = Cluster number (may be full 16-bit quantity)
101 ; ES:BP = Base of drive parameters
103 ; DI = Contents of FAT for given cluster (may be full 16-bit quantity)
104 ; Zero set means DI=0 (free cluster)
105 ; Carry set means error (currently user FAILed to I 24)
106 ; SI Destroyed, No other registers affected. Fatal error if cluster too big.
108 procedure UNPACK
,NEAR
109 DOSAssume
CS,<DS>,"UnPack"
112 Assert ISDPB
,<ES,BP>,"Unpack"
113 CMP BX,ES:[BP.dpb_max_cluster
]
119 JNZ High12
; MZ if high 12 bits, go get 'em
120 MOV SI,ES:[BP.dpb_max_cluster
] ; MZ is this 16-bit fat?
122 JB Unpack12
; MZ No, go 'AND' off bits
123 OR DI,DI ; MZ set zero condition code, clears carry
124 JMP SHORT DoContext
; MZ go do context
132 AND DI,0FFFH ; Clears carry
139 MOV ES:[BP.dpb_free_cnt
],-1 ; Err in FAT must force recomp of freespace
141 MOV AH,allowed_fail
+ 80h
142 MOV Allowed
,allowed_fail
144 ; Signal Bad FAT to INT int_fatal_abort handler. We have an invalid cluster.
146 MOV DI,0FFFH ; In case INT int_fatal_abort returns (it shouldn't)
150 JNZ OKU_RET
; Try to ignore bad FAT
157 Break <PACK
-- PACK FAT ENTRIES
>
160 ; BX = Cluster number
162 ; ES:BP = Pointer to drive DPB
164 ; The data is stored in the FAT at the given cluster.
165 ; SI,DX,DI all destroyed
166 ; Carry set means error (currently user FAILed to I 24)
167 ; No other registers affected
170 DOSAssume
CS,<DS>,"Pack"
173 Assert ISDPB
,<ES,BP>,"Pack"
178 JZ Aligned
; byte (not nibble) aligned
179 PUSH CX ; move data to upper 12 bits
183 AND SI,0FH ; leave in original low 4 bits
186 CMP ES:[BP.dpb_max_cluster
],4096-10 ; MZ 16 bit fats?
187 JAE Pack16
; MZ yes, go clobber original data
188 AND SI,0F000H ; MZ leave in upper 4 bits of original
189 AND DX,0FFFh ; MZ store only 12 bits
190 JMP SHORT PackIn
; MZ go store
192 XOR SI,SI ; MZ no original data
197 TEST [SI.buf_flags
],buf_dirty
;LB. if already dirty ;AN000;
198 JNZ yesdirty
;LB. don't increment dirty count ;AN000;
199 invoke INC_DIRTY_COUNT
;LB. ;AN000;
200 OR [SI.buf_flags
],buf_dirty
;LB. ;AN000;
201 yesdirty: ;LB. ;AN000;
202 CMP BYTE PTR [CLUSSPLIT
],0
209 MOV DS,WORD PTR [CURBUF
+2]
215 MOV DX,WORD PTR [CLUSSEC
+2] ;F.C. >32mb ;AN000;
216 MOV WORD PTR [HIGH_SECTOR
],DX ;F.C. >32mb ;AN000;
218 MOV DX,WORD PTR [CLUSSEC
]
226 TEST [DI.buf_flags
],buf_dirty
;LB. if already dirty ;AN000;
227 JNZ yesdirty2
;LB. don't increment dirty count ;AN000;
228 invoke INC_DIRTY_COUNT
;LB. ;AN000;
229 OR [DI.buf_flags
],buf_dirty
233 ADD DI,ES:[BP.dpb_sector_size
]
246 Break <MAPCLUSTER
- BUFFER A FAT SECTOR
>
249 ; ES:BP Points to DPB
250 ; BX Is cluster number
252 ; Get a pointer to the cluster
254 ; DS:DI Points to contents of FAT for given cluster
255 ; DS:SI Points to start of buffer
256 ; Zero Not set if cluster data is in high 12 bits of word
257 ; Zero set if cluster data is in low 12 or 16 bits
258 ; Carry set if failed.
261 procedure MAPCLUSTER
,NEAR
262 DOSAssume
CS,<DS>,"MapCluster"
265 Assert ISDPB
,<ES,BP>,"MapCluster"
266 MOV BYTE PTR [CLUSSPLIT
],0
267 SaveReg
<AX,BX,CX,DX>
270 CMP ES:[BP.dpb_max_cluster
],CX ; MZ 16 bit fat?
271 JAE Map16
; MZ yes, do 16 bit algorithm
273 Map16: ; MZ skip prev => AX=2*BX
274 XOR DI,DI ; >32mb fat ;AN000;
275 ADD AX,BX ; AX = 1.5*fat = byte offset in fat
276 ADC DI,0 ; >32mb fat ;AN000;
278 MOV CX,ES:[BP.dpb_sector_size
]
281 ; Gross hack: 99% of all disks have 512 bytes per sector. We test for this
282 ; case and apply a really fast algorithm to get the desired results
284 ; Divide method takes 158 (XOR and DIV)
285 ; Fast method takes 20
287 ; This saves a bunch.
289 CMP CX,512 ; 4 Is this 512 byte sector?
290 JZ Nodiv
;F.C. >32mb ;AN000;
291 JMP DoDiv
; 4/16 No, go do divide
292 Nodiv: ;F.C. >32mb ;AN000;
293 MOV DX,AX ; 2 get set for remainder
294 AND DX,512-1 ; 4 Form remainder
297 CBW ; 2 Fast divide by 512
298 OR DI,DI ;>32mb >64k ? ;AN000;
299 JZ g64k
;>32mb no ;AN000;
300 OR AX,80H
;>32mb ;AN000;
304 DIV CX ; 155 AX is FAT sector # DX is sector index
307 ADD AX,ES:[BP.dpb_first_FAT
]
308 DEC CX ; CX is sector size - 1
311 MOV [HIGH_SECTOR
],0 ;F.C. >32mb low sector #
315 RestoreReg
<CX,AX,DX> ; CX is sec siz-1, AX is offset in sec
325 INC BYTE PTR [CLUSSPLIT
]
326 MOV BYTE PTR [CLUSSAVE
],AL
327 MOV WORD PTR [CLUSSEC
],DX
328 MOV WORD PTR [CLUSSEC
+2],0 ;F.C. >32mb ;AN000;
330 MOV [HIGH_SECTOR
],0 ;F.C. >32mb FAT sector <32mb ;AN000;
340 MOV BYTE PTR [CLUSSAVE
+1],AL
341 MOV DI,OFFSET DOSGROUP
:CLUSSAVE
343 RestoreReg
<DX,CX,BX>
344 XOR AX,AX ; MZ allow shift to clear carry
345 CMP ES:[BP.dpb_max_cluster
],4096-10 ; MZ is this 16-bit fat?
346 JAE MapSet
; MZ no, set flags
349 TEST AL,1 ; set zero flag if not on boundary
354 RestoreReg
<DX,CX,BX,AX>
359 DIV CX ; 155 AX is FAT sector # DX is sector index
360 JMP DivDone
;15 total=35
365 Break <FATREAD_SFT
/FATREAD_CDS
-- CHECK DRIVE GET FAT
>
368 ; ES:DI points to an SFT for the drive of intrest (local only,
369 ; giving a NET SFT will produce system crashing results).
372 ; Can be used by an SFT routine (like CLOSE) to invalidate buffers
374 ; In other respects, same as FATREAD_CDS.
375 ; (note ES:DI destroyed!)
377 ; Carry set if error (currently user FAILed to I 24)
378 ; NOTE: This routine may cause FATREAD_CDS to "miss" a disk change
379 ; as far as invalidating curdir_ID is concerned.
380 ; Since getting a true disk changed on this call is a screw up
381 ; anyway, that's the way it goes.
383 procedure FATREAD_SFT
,NEAR
384 DOSAssume
CS,<DS>,"FATRead_SFT"
387 LES BP,ES:[DI.sf_devptr
]
388 Assert ISDPB
,<ES,BP>,"FatReadSFT"
389 MOV AL,ES:[BP.dpb_drive
]
391 invoke GOTDPB
;Set THISDPB
398 ; ES:DI points to an CDS for the drive of intrest (local only,
399 ; giving a NET or NUL CDS will produce system crashing results).
401 ; If disk may have been changed, media is determined and buffers are
402 ; flagged invalid. If not, no action is taken.
404 ; ES:BP = Drive parameter block
407 ; Carry set if error (currently user FAILed to I 24)
408 ; DS preserved , all other registers destroyed
410 procedure FATREAD_CDS
,NEAR
411 DOSAssume
CS,<DS>,"FATRead_CDS"
416 LES BP,ES:[DI.curdir_devptr
]
417 Assert ISDPB
,<ES,BP>,"FatReadCDS"
418 MOV AL,ES:[BP.dpb_drive
]
420 invoke GOTDPB
;Set THISDPB
422 POP DI ;Get back CDS pointer
425 JNZ NO_CHANGE
;Media NOT changed
426 ; Media changed. We now need to find all CDS structures which use this
427 ; DPB and invalidate their ID pointers.
433 XOR CH,CH ; CX is number of structures
434 LDS SI,ES:[DI.curdir_devptr
] ; Find all CDS with this devptr
436 LES DI,[CDSADDR
] ; Start here
438 TEST ES:[DI.curdir_flags
],curdir_isnet
439 JNZ NEXTCDS
; Leave NET guys alone!!
442 LES DI,ES:[DI.curdir_devptr
]
446 JNZ NEXTCDS
; CDS not for this drive
447 TEST ES:[DI.curdir_ID
],AX
448 JZ NEXTCDS
; If root, leave root
449 MOV ES:[DI.curdir_ID
],AX ; else invalid
451 ADD DI,SIZE curdir_list
; Point to next CDS
454 DOSAssume
CS,<DS>,"FAT/NextCDS"
461 Break <Fat_Operation
- miscellaneous fat stuff
>
463 procedure FAT_operation
,NEAR
465 DOSAssume
CS,<DS>,"FATERR"
466 MOV ES:[BP.dpb_free_cnt
],-1 ; Err in FAT must force recomp of freespace
467 AND DI,STECODE
; Put error code in DI
468 MOV [ALLOWED
],allowed_FAIL
+ allowed_RETRY
469 MOV AH,2 + allowed_FAIL
+ allowed_RETRY
; While trying to read FAT
470 MOV AL,BYTE PTR [THISDRV
] ; Tell which drive
474 JNZ FAT_GOT_DPB
; User said retry
481 MOV AH,ES:[BP.dpb_UNIT
]
482 MOV WORD PTR [DEVCALL
],AX
483 MOV BYTE PTR [DEVCALL
.REQFUNC
],DEVMDCH
484 MOV [DEVCALL
.REQSTAT
],0
485 MOV AL,ES:[BP.dpb_media
]
486 MOV BYTE PTR [CALLMED
],AL
489 MOV BX,OFFSET DOSGROUP
:DEVCALL
490 LDS SI,ES:[BP.dpb_driver_addr
] ; DS:SI Points to device header
492 POP ES ; ES:BX Points to call header
495 POP ES ; Restore ES:BP
496 MOV DI,[DEVCALL
.REQSTAT
]
500 XCHG AH,ES:[BP.dpb_first_access
] ; Reset dpb_first_access
501 MOV AL,BYTE PTR [THISDRV
] ; Use physical unit number
502 ; See if we had changed volume id by creating one on the diskette
503 cmp [VOLCHNG_FLAG
],AL
505 mov [VOLCHNG_FLAG
],-1
506 jmp GOGETBPB
; Need to get device driver to read in
509 OR AH,BYTE PTR [CALLRBYT
]
510 JNS CHECK_ZR
; ns = 0 or 1
514 JZ CHKBUFFDIRT
; jump if I don't know
516 return
; If Media not changed (NZ)
522 LES BP,ES:[BP.dpb_driver_addr
] ; Get device pointer
523 TEST ES:[BP.SDEVATT
],DEVOPCL
; Did it set vol id?
526 JZ FAIL_OPJ2
; Nope, FAIL
527 PUSH DS ; Save buffer pointer for ignore
530 MOV [ALLOWED
],allowed_FAIL
+ allowed_RETRY
532 LES DI,[CALLVIDM
] ; Get volume ID pointer
533 MOV WORD PTR [EXTERRPT
+2],ES
535 MOV WORD PTR [EXTERRPT
],DI
536 MOV AX,error_I24_wrong_disk
537 MOV [READOP
],1 ; Write
539 POP DI ; Get back buffer for ignore
545 JMP FAT_GOT_DPB
; Retry
548 DOSAssume
CS,<DS>,"FAT/ChkBuffDirt"
551 XOR DX,DX ;LB. ;AN000;
552 LDS DI,[BUF_HASH_PTR
] ;LB. scan from 1st entry ;AN000;
553 MOV CX,[BUF_HASH_COUNT
] ;LB. get Hash entry count ;AN000;
556 CMP [DI.Dirty_Count
],0 ;LB. if not dirty ;AN000;
557 JZ GETNEXT
;LB. get next hash entry ;AN000;
558 PUSH DS ;LB. save hash entry addr ;AN000;
560 invoke Map_Entry
;LB. ;AN000;
561 NBUFFER: ; Look for dirty buffers
563 JNZ LFNXT
; Not for this unit
564 TEST [DI.buf_flags
],buf_dirty
566 POP DI ;LB. restore regs ;AN000;
570 return
; There is a dirty buffer, assume Media OK (NZ)
579 mov DI,[DI.buf_next
] ;; 1/19/88
580 CMP DI,[FIRST_BUFF_ADDR
] ;; 1/19/88
582 POP DI ;LB. restore regs ;AN000;
585 ADD DI,size BUFFER_HASH_ENTRY
;LB. next entry ;AN000;
586 LOOP scan_dirty
;LB. scan next entry ;AN000;
587 ; If no dirty buffers, assume Media changed
589 MOV ES:[BP.dpb_free_cnt
],-1 ; Media changed, must re-compute
590 ; NOTE: It is TECHNICALLY more correct
592 XOR DX,DX ;LB. ;AN000;
593 MOV [HIGH_SECTOR
],DX ;LB. scan from 1st entry ;AN000;
594 MOV CX,[BUF_HASH_COUNT
] ;LB. get Hash entry count ;AN000;
597 invoke GETCURHEAD
;LB. get Hash entry buffer header ;AN000;
598 ; to do this AFTER the check for
601 CMP AL,[DI.buf_ID
] ; For this drive?
602 JZ OLDDRV2
;LB. yes ;AN000;
603 mov DI,[DI.buf_next
] ;LB. get next buffer 1/19/88 ;AN000;
604 JMP SHORT SKPBUFF
;LB. ;AN000;
606 TEST [DI.buf_flags
],buf_dirty
608 JMP Disk_Chng_Err
; Disk changed but dirty buffers
610 MOV WORD PTR [DI.buf_ID
],(buf_visit
SHL 8) OR 0FFH ; Free up buffer
613 CMP DI,[FIRST_BUFF_ADDR
] ;LB. end of chain 1/19/88 ;AN000;
614 JNZ NXBUFFER
;LB. no ;AN000;
616 LOOP NxtHash
;LB. ;AN000;
617 CMP [SC_CACHE_COUNT
],0 ;LB. look ahead buffers ? ;AN001;
618 JZ GOGETBPB
;LB. no ;AN001;
619 CMP AL,[CURSC_DRIVE
] ;LB. same as changed drive ;AN001;
620 JNZ GOGETBPB
;LB. no ;AN001;
621 MOV [CURSC_DRIVE
],-1 ;LB. invalidate look ahead buffers ;AN000;
623 LDS DI,ES:[BP.dpb_driver_addr
]
624 TEST [DI.SDEVATT
],ISFATBYDEV
628 CALL UNPACK
; Read the first FAT sector into CURBUF
637 PUSH ES ; Get a free buffer for BIOS to use
640 XOR DX,DX ;LB. fake to get 1st ;AN000;
641 MOV [HIGH_SECTOR
],DX ;LB. buffer addr ;AN000;
642 invoke GETCURHEAD
;LB. ;AN000;
650 MOV WORD PTR [CALLXAD
+2],DS
652 MOV WORD PTR [CALLXAD
],DI
654 MOV AH,BYTE PTR ES:[BP.dpb_UNIT
]
655 MOV WORD PTR [DEVCALL
],AX
656 MOV BYTE PTR [DEVCALL
.REQFUNC
],DEVBPB
657 MOV [DEVCALL
.REQSTAT
],0
658 MOV AL,BYTE PTR ES:[BP.dpb_media
]
662 PUSH WORD PTR ES:[BP.dpb_driver_addr
+2]
663 PUSH WORD PTR ES:[BP.dpb_driver_addr
]
664 MOV BX,OFFSET DOSGROUP
:DEVCALL
666 POP DS ; DS:SI Points to device header
668 POP ES ; ES:BX Points to call header
670 POP ES ; Restore ES:BP
672 MOV DI,[DEVCALL
.REQSTAT
]
675 MOV AL,BYTE PTR ES:[BP.dpb_media
]
678 MOV ES:[BP].DPB_next_free
,0 ; recycle scanning pointer
680 LDS DI,[CALLXAD
] ; Get back buffer pointer
681 MOV AL,BYTE PTR ES:[BP.dpb_FAT_count
]
682 MOV [DI.buf_wrtcnt
-BUFINSIZ
],AL ;>32mb ;AN000;
683 MOV AX,ES:[BP.dpb_FAT_size
] ;>32mb ;AC000;
684 MOV [DI.buf_wrtcntinc
-BUFINSIZ
],AX ;>32mb Correct buffer info ;AC000;
687 XOR AL,AL ;Media changed (Z), Carry clear
692 EndProc FAT_operation