📄 buffers.a86
字号:
jnz alloc_cl10 ; skip if it is
push ds
lds bx,ss:current_ddsc
mov ax,ds:DDSC_BLOCK[bx] ; else continue from last allocated block
pop ds
alloc_cl10:
mov bx,lastcl ; highest block number on current disk
cmp ax,bx ; is it within disk size?
jb alloc_cl20 ; skip if it is
sub ax,ax ; start at the beginning
alloc_cl20:
mov si,ax ; remember start of search
test ax,ax ; is this the 1st block?
jnz alloc_cl30 ; no
inc ax ; start at beginning
alloc_cl30: ; main loop:
inc ax ; skip to block after current
push ax ! push si ; quick save
call getblk ; get the content of this block
pop si ! pop ax
jz alloc_cl50 ; return if free
cmp ax,bx ; are we at the end yet?
jb alloc_cl30 ; no, try next block
xor ax,ax ; wrap to start of disk
mov bx,si ; remember starting position last time
test bx,bx ; have we been all the way round ?
jnz alloc_cl20 ; no, lets search from start
push ds
lds bx,ss:current_ddsc
mov ds:DDSC_FREE[bx],ax ; we definitely have none left
pop ds
ret ; return (0);
alloc_cl50:
push ds ; block # AX is available
lds bx,ss:current_ddsc
mov ds:DDSC_BLOCK[bx],ax ; remember for next time
pop ds
push ax
mov bx,dosfat ; mark this block as end of file
call fixfat ; for convenience
pop ax
test ax,ax ; update ZF from AX
ret ; return block number
if DELWATCH
; Update a FAT entry with a new value
change_fat_entry:
;----------------
; On Entry:
; AX = block number to change
; DX = new value
; On Exit:
; None
;
mov bx,dx
; jmps fixfat
endif
; entry: AX = block number to change
; BX = new value
; exit: DS,ES = sysdat
;------
fixfat:
;------
push bx ; save new value
push ax
call update_ddsc_free ; make sure DDSC_FREE is correct
pop ax
cmp dosfat,FAT16 ; check if 16-bit FAT
jne fixfat30 ; skip if 12 bit FAT
call fatptr ; ES:BX -> FAT word to modify
pop ax ; restore new value
xor dx,dx ; get a zero (no change of space)
test ax,ax ; are we setting to 0 or non-zero?
xchg ax,es:[bx] ; set the word in the buffer
jnz fixfat10 ; skip if releasing block
test ax,ax ; check if word was 0 before
jz fixfat20 ; skip if setting 0 to 0
inc dx ; DX = 0001h, one free cluster more
jmps fixfat15
fixfat10: ; allocating or fixing block
test ax,ax ; check if word was 0 before
jnz fixfat20 ; skip if setting non-0 to non-0
dec dx ; one free cluster less now
fixfat15: ; DX = change in free space (-1,1)
les si,current_ddsc
add es:DDSC_FREE[si],dx ; update free space count
fixfat20:
les si,bcb_root ; ES:SI -> buffer control block
or es:BCB_FLAGS[si],BF_DIRTY
; mark the buffer as dirty
push ds ! pop es ; ES back to local DS
ret
; We're dealing with a 12-bit FAT...
fixfat30: ; changing 12-bit FAT entry
call fatptr ; get address of block AX in ES:BX
pop cx ; get new value
mov dx,es:[bx] ; get old value
jz fixfat40 ; skip if even word
mov ax,0FFF0h ; set mask for new value
add cx,cx ; else shift new value into top bits
add cx,cx
add cx,cx
add cx,cx
jmps fixfat50 ; set the new word
fixfat40:
mov ax,00FFFh ; set mask for new value
and cx,ax
fixfat50: ; AX = mask, CX = new, DX = old
mov si,0 ; assume space doesn't change
jnz fixfat60 ; skip if new value is zero
test dx,ax ; test if old value was zero as well
jz fixfat70 ; yes, no change in free space
inc si ; else one more block available
jmps fixfat70
fixfat60: ; new value is non-zero
test dx,ax ; is old value non-zero as well?
jnz fixfat70 ; yes, no change in free space
dec si ; else one block less free now
fixfat70:
not ax ; flip the mask bits around
and dx,ax ; zero out old value
or dx,cx ; combine old & new value
mov es:[bx],dx ; update the FAT
xchg ax,si ; AX = free space change (-1, 0 , 1)
les si,current_ddsc
add es:DDSC_FREE[si],ax ; update free space count
les si,bcb_root ; get buffer control block
or es:BCB_FLAGS[si],BF_DIRTY
; mark the buffer as dirty
cmp split_fat,0 ; is 12-bit entry split across sectors
je fixfat80 ; need some magic if so
; handle a split FAT update
mov dx,fatrec ; lower sector number
inc dx ; get the upper sector
call locate_fat ; find the buffer
or es:BCB_FLAGS[si],BF_DIRTY
; mark buffer as write pending
mov al,fatbyth ; get the high byte
mov es:BCB_DATA[si],al ; store the high byte at the beginning
mov dx,fatrec ; get the previous sector
call locate_fat ; read into memory
or es:BCB_FLAGS[si],BF_DIRTY
; mark buffer as write pending
mov bx,psecsiz
dec bx ; BX = sector size - 1
mov al,fatbytl ; get the low byte
mov es:BCB_DATA[si+bx],al
fixfat80:
push ds ! pop es ; ES back to local DS
ret
; On Entry:
; AX = cluster number
; On Exit:
; AX preserved
; ES:BX -> address of word
; BCBSEG = segment of FAT FCB
; ZF = 1 if word on even address
; SPLIT_FAT = 0FFh if xing sector boundary
;
; CX = entries left in sector (if FAT16 - performance optimisation)
;
Public fatptr
fatptr:
;------
push ax ; save block number
mov bx,ax
sub dx,dx ; AX/DX = cluster #
cmp dosfat,FAT16 ; is it 16 bit FAT?
je fatptr10
shr ax,1 ; shift for 1 1/2 byte, else 2 byte
fatptr10:
add ax,bx ; AX = offset into FAT
adc dx,0 ; AX/DX = 32 bit offset
mov cx,psecsiz ; CX = sector size
div cx ; AX = sector offset
dec cx ; CX = sector size - 1
push dx ; DX = offset within FAT sector
push cx
add ax,fatadd ; make it absolute sector address
mov fatrec,ax ; save FAT sector for FIXFAT
xchg ax,dx ; DX = FAT sector
call locate_fat ; locate the sector
pop cx ; CX = sector size - 1
pop bx ; restore offset within FAT sector
pop ax ; restore cluster #
sub cx,bx ; CX = bytes left in sector - 1
lea bx,BCB_DATA[si+bx] ; ES:BX -> buffer data
cmp dosfat,FAT16 ; is it 16 bit media
jne fatptr20 ; skip if 12 bit media
shr cx,1 ; CX = extra entries left in sector
cmp ax,ax ; always set ZF = 1
ret ; return ES:BX -> word in FAT
fatptr20: ; it's a 12 bit FAT, is it a split FAT?
mov split_fat,0 ; assume no boundary crossing
jcxz fatptr30 ; end of sector, it's a split FAT
test al,1 ; ZF = 1 if even cluster
ret ; return ES:BX -> word in FAT buffer
fatptr30: ; block split across two sectors
push ax
mov split_fat,0FFh ; yes, the difficult case
mov al,es:[bx] ; get the low byte from 1st sector
mov fatbytl,al ; save it for later
mov dx,fatrec ; get the FAT record is
inc dx ; get 2nd sector
call locate_fat ; read the 2nd sector
sub bx,bx
lea bx,BCB_DATA[si+bx] ; ES:BX -> buffer data
mov al,es:[bx] ; get 1st byte from next sector
mov fatbyth,al ; save the high byte
push ds ; ES = local DS
pop es
mov bx,offset fatbytl ; ES:BX -> <fatbytl,fatbyh>
pop ax
test al,1 ; set non-zero condition, odd word
ret
if DOS5
; entry: DX = sector number to read
; exit: ES:SI = BCB
locate_fat:
;----------
mov ah,0 ; set sector address overflow = 0
mov cx,0ff00h+BF_ISFAT ; request a FAT buffer w/ preread
locate_buffer:
;-------------
; On Entry:
; AH:DX = sector to locate
; adrive = driver
; CH = 0FFh if preread required
; CL = buffer type
; On Exit:
; ES:SI -> BCB_
;
mov al,adrive ; get our drive number
les si,bcb_root ; get it from the right buffer list
locate10:
cmp dx,es:BCB_REC[si] ; does our sector address match?
jne locate20 ; skip if it doesn't
cmp ah,es:BCB_REC2[si] ; does record address overflow match?
jne locate20 ; skip if not
cmp al,es:BCB_DRV[si] ; does the drive match?
je locate30 ; found if it all matches
locate20: ; MRU buffer doesn't match
mov si,es:BCB_NEXT[si] ; try the next
cmp si,word ptr bcb_root ; while there are more buffers
jne locate10
push ax ! push cx ! push dx ; save all registers
mov si,es:BCB_PREV[si] ; recycle least recently used buffer
call flush_buffer ; write buffer to disk
pop dx ! pop cx ! pop ax ; restore all registers
mov es:BCB_DRV[si],al ; fill in the BCB: drive
mov es:BCB_REC[si],dx ; record low,middle
mov es:BCB_REC2[si],ah ; record high
mov es:BCB_FLAGS[si],cl ; mark as clean, ISFAT,ISDIR or ISDAT
test ch,ch ; is preread required?
jz locate30 ; skip if it isn't
call fill_buffer ; read it from disk
locate30:
cmp si,word ptr bcb_root ; are we already at the head ?
jne locate40 ; if not move ourself there
ret
locate40:
mov bx,es:BCB_NEXT[si] ; BX = next buffer
mov di,es:BCB_PREV[si] ; DI = previous buffer
mov es:BCB_NEXT[di],bx ; unlink buffer from the
mov es:BCB_PREV[bx],di ; chain
mov bx,si
xchg bx,word ptr bcb_root ; become the new head, BX = old head
mov es:BCB_NEXT[si],bx ; old chain follow us
mov di,si
xchg di,es:BCB_PREV[bx] ; back link to our buffer, DI = LRU buffer
mov es:BCB_PREV[si],di ; link ourselves to LRU buffer
mov es:BCB_NEXT[di],si ; forward link to our buffer
ret
; Flush all dirty FAT buffers for drive AL
; entry: AL = drive to flush (0-15)
; exit: CY = 0 if no error
; ax,bx,cx,dx,es preserved
flush_fat:
;---------
; entry: AL = drive for FAT flush
mov ah,BF_ISFAT ; flush all dirty FAT buffers
jmps flush_drive ; shared code for all flushes
;----------
update_dir:
;----------
call flush_dirbuf ; flush local dirbuf to buffers
;---------
flush_dir:
;---------
mov ah,BF_ISDIR ; write out dirty directories
jmps flush_adrive ; update the disk
;----------
update_dat:
;----------
mov ah,BF_ISDAT ; write out dirty data
jmps flush_adrive ; update the disk
;----------
update_fat: ;write out modified FAT buffers
;----------
mov ah,BF_ISFAT ; flush all dirty FAT buffers
; jmp flush_adrive ; update the disk if dirty
flush_adrive:
;------------
mov al,adrive ; AL = currently selected drive
; jmp flush_drive
; Write out all dirty data buffers for a given drive
; entry: AL = drive to be flushed
; AH = mask of buffer types to be flushed
; exit: AX,DX preserved
; Note: sector buffers will be written in the
; sequence in which they appear on disk (low to high)
flush_drive:
;-----------
push es
push si
flush_drive10:
les si,bcb_root ; start with the first buffer
mov bx,0FFFFh ; assume no buffer found
flush_drive20:
test es:BCB_FLAGS[si],BF_DIRTY
; has buffer been written to?
jz flush_drive40 ; no, do the next one
test es:BCB_FLAGS[si],ah ; is it one of these buffers?
jz flush_drive40 ; no, do the next one
cmp al,es:BCB_DRV[si] ; does the drive match?
jne flush_drive40 ; skip if wrong drive
; we've found a buffer to flush
cmp bx,0FFFFh ; first buffer ever found in list?
jz flush_drive30 ; yes, save as new best candidate
; else check if < previous lowest addr
mov dx,es:BCB_REC[si]
sub dx,ds:BCB_REC[bx]
mov dl,es:BCB_REC2[si] ; compare the disk addresss
sbb dl,ds:BCB_REC2[bx]
jnb flush_drive40 ; CY = 0 if new BCB higher
flush_drive30: ; else ES = best BCB so far
mov bx,si ; save it for later
flush_drive40:
mov si,es:BCB_NEXT[si] ; get next buffer address
cmp si,ss:word ptr bcb_root
jne flush_drive20
cmp bx,0FFFFh ; did we find a dirty buffer?
jz flush_drive50 ; no, all buffers cleaned
mov si,bx ; ES:SI -> BCB to flush
call flush_buffer ; write sector to disk
jmps flush_drive10 ; check if more dirty buffers
flush_drive50:
pop si
pop es
ret
else
; entry: DX = sector number to read
; exit: ES:SI = BCB
locate_fat:
;----------
mov ah,0 ; set sector address overflow = 0
mov cx,0ff00h+BF_ISFAT ; request a FAT buffer w/ preread
locate_buffer:
;-------------
; On Entry:
; AH:DX = sector to locate
; adrive = driver
; CH = 0FFh if preread required
; CL = buffer type
; On Exit:
; ES:SI -> BCB_
;
mov al,adrive ; get our drive number
les si,bcb_root ; get it from the right buffer list
mov bx,0FFFFh ; no previous buffers yet
locate1:
cmp dx,es:BCB_REC[si] ; does our sector address match?
jne locate2 ; skip if it doesn't
cmp ah,es:BCB_REC2[si] ; does record address overflow match?
jne locate2 ; skip if not
cmp al,es:BCB_DRV[si] ; does the drive match?
je locate6 ; found if it all matches
locate2: ; MRU buffer doesn't match
cmp es:BCB_LINK_OFF[si],0FFFFh
je locate3 ; are there more buffers?
push es ! pop ds
mov bx,si ; remember previous buffer
les si,es:BCB_NEXT[si] ; move on to next buffer
jmps locate1
locate3: ; we found the LRU buffer
push ax ! push cx ! push dx ; save all registers
call pick_cheapest ; determine cheapest buffer
; ES:SI -> cheapest buffer
; DS:BX -> previous link
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -