📄 bambi.asm
字号:
; case.
jmp no_partial_on_front
skip_cache_em:
add curblk_l,1
adc curblk_h,0
add di,cache_block_bytes
loop skip_cache_em
jmp short done_cache_em
; pass read error condition back to caller.
got_fatal_error:
les bx,user_reqblk
mov es:[bx.reqstat],ax ; pass error code back to caller
mov es:word ptr [bx.count],0 ; no sectors complete
ret
; d_count is now less than a full cache block
; we are cache block aligned
do_last_partial:
cmp d_count,0 ; *IS* there a partial?
jz reading_done ; skip if not
call check_supercache_match
jc last_partial_moveit ; just move it from supercache if so
; last partial not in supercache. Try regular cache next.
call check_hit ; is last block in cache?
jz need_to_read_last_partial
; Got it in regular cache!
ifdef USE_VALID
mov ax,d_count ; ah=0, al=sectors we need
call make_sure_sectors_are_valid ; make sure they're valid
jc got_fatal_error ; BUG1 fatal exit if read error
endif
mov ax,d_count ; starting with zero, read d_count
les di,d_trans
mov bp,cache_element_index
call read_part_cache_block ; read it from cache
jmp short reading_done ; done! exit okay!
; We've gotta hit the disk. Maybe we'll do a readahead too.
need_to_read_last_partial:
call readahead_check ; should we readahead?
mov cx,1 ; just read this one block if we're
; ; not sequential from last time
jnz last_partial_no_readahead
mov cx,max_valid_buffers ; read/cache this many blocks if seq.
last_partial_no_readahead:
call get_curblks_into_cache ; get those suckers into cache
jnc last_partial_readok ; done if no read error
; read error. We'd better try reading just exactly what the
; user requested.
mov ah,byte ptr d_count ; get count
xor al,al ; start reading from front of block
les di,d_trans
call read_part_curblk_from_disk
jnc reading_done ; done if read ok!!!
jmp got_fatal_error ; fatal error if disk read error
last_partial_readok:
mov si,word ptr local_buf ; we know the data is in the
; front of the local_buf
; We will enter here when we're moving the data out of the
; supercache.
last_partial_moveit:
mov ax,d_count
mul sector_size_bytes
mov cx,ax ; copy this many
shr cx,1 ; convert to words
les di,d_trans
mov ds,lb_seg
assume ds:nothing
rep movsw
push cs
pop ds ; restore addressability
assume ds:zseg
reading_done:
mov ax,curblk_l
mov lastblk_l,ax ; copy curblk to lastblk
mov al,curblk_h
mov lastblk_h,al
readwrite_done:
les bx,user_reqblk
mov es:[bx.reqstat],100h ; normal completion
ret ; no error checking for now
cache_reads endp
;-----------------------------------------------------------------------
;
; subroutine to check to see if curblk is just past lastblk;
; this condition is used during a read of anything besides
; a first partial, to trigger readahead. Zero is set
; when (curblk-1) == lastblk
;
; ****Note: For now, we'll also return zero when curblk==lastblk.
; Depending on the exact exit path taken, lastblk may or may not
; be updated to point past the end of the previous read.
;
; trashes ax, cl
readahead_check proc near
assume cs:zseg,ds:zseg,es:nothing
mov ax,curblk_l
mov cl,curblk_h
sub ax,lastblk_l
sbb cl,lastblk_h
and al,0feh ; was result 0 or 1?
or al,ah
or al,cl ; set zero flag if so
ret
readahead_check endp
ifdef USE_VALID
;-----------------------------------------------------------------------
;
; make sure that the currently needed sectors of the current
; block are indeed valid. If not, we've gotta read the
; whole block and mark it valid.
;
; Entry: ah=first sector we need, al=number of sectors we need
; Exit: carry set if we had a read error
; ax == error code if carry set BUG1
;
; Trashes: all
make_sure_sectors_are_valid proc near
assume cs:zseg,ds:zseg,es:nothing
mov cx,ax ; get our counts into cx
mov ax,1
shl ax,cl ; get one bits for each of ours
dec ax
mov cl,ch ; now shift that for starting place
shl ax,cl
make_sure_sectors_are_valid endp ; fall into similar routine w/ mask
;-----------------------------------------------------------------------
;
; make sure that the sectors in the currently looked-up cache
; block whose mask is in ax are valid. Otherwise, we've got
; to force the whole damn cache block to be valid.
;
; Entry: ax == mask of sectors required from this block
; Exit: carry set if we had a read error
; ax == error code if carry set BUG1
;
; Trashes: all
make_sure_sectors_are_valid_mask proc near
assume cs:zseg,ds:zseg,es:nothing
log_it 0 ; tracker: bambi type zero
mov cx,valid_mask ; here is what's valid
not cx
and cx,ax ; were any of our 1 bits zero bits?
jnz make_cache_block_valid
clc ; return with no error
ret
make_cache_block_valid:
log_it 1 ; tracker: bambi type one
mov num_valid_buffers,0 ; invalidate supercache
les di,local_buf
mov ax,1 ; block count
push cx ; BUG1 -- save mask of needed sectors
call read_curblks_from_disk ; read it into buffer
pop cx ; BUG1 -- restore mask of needed secs
jc make_cache_readerror ; skip if read error!!!!
log_it 2 ; tracker: time stamp reading done
; Now we've got to copy only the NON-DIRTY sectors into
; the cache, so that we don't replace data that hasn't yet
; made it onto the disk.
mov cx,dirty_mask
not cx ; get NON-DIRTY bits
and cx,cache_mask
xor ah,ah ; ah=0 (sector zero)
; Here we will assume CX != 0. If all of the bits in
; that block were DIRTY, they would also have to be VALID
; and we'd never be here in the first place.
find_one_to_copy:
inc ah ; count it
shr cx,1
jnc find_one_to_copy ; bypass clean block
dec ah ; this is the sector number
xor al,al ; count=1+number of contig ones in cl
find_number_to_copy:
inc al
shr cx,1
jc find_number_to_copy ; loop while we find more ones
shl cx,1 ; put a zero bit back
push cx ; save mask
push ax ; save count
mov al,ah ; get starting sector
xor ah,ah
mul sector_size_bytes
les di,local_buf ; find location in disk buffer
add di,ax
pop ax ; restore count
push ax ; save count again
mov bp,cache_element_index
call write_part_cache_block ; write into cache
pop ax
pop cx ; restore continuing mask
log_it 3 ; tracker: xms written
add ah,al ; update sector number
or cx,cx
jnz find_one_to_copy
mov bx,cache_mask ; valid == all
mov valid_mask,bx
mov cx,dirty_mask
mov bp,cache_element_index
call set_dirtyindex ; mark it all valid
clc
ret ; return with carry set if error
; BUG1 -- BEGIN NEW CODE!!!!!
; -- the following error exit was totally messed up
; in the Win 3.1 version of this code, causing
; potential data loss in this case of bad adjacent blocks.
;
; the block we need is only partially valid, but trying
; the usual technique of making the whole thing valid
; won't work because there are bad sectors in the block.
; We must try to read exactly the missing sectors we
; need. If this succeeds, we'll stick them in the
; cache, otherwise, we'll bomb out with a fatal error.
make_cache_readerror:
; Here is the old, wrong code.
;BUG1 mov bp,cache_element_index
;BUG1 call invalidate_element
;BUG1 stc ; return error condition, ax == code
;BUG1 ret
push cx ; save mask of new sectors to read
xor ah,ah ; ah=0 (sector zero)
; Here we will assume cx != 0, because it is the mask of
; sectors we need which are not valid in the cache.
find_one_to_read:
inc ah ; count it
shr cx,1
jnc find_one_to_read ; bypass unneeded block
dec ah ; this is the sector number
xor al,al ; count=1+number of contig ones in cx
find_number_to_read:
inc al
shr cx,1
jc find_number_to_read ; loop while we find more ones
shl cx,1 ; put a zero bit back
push cx ; save mask
push ax ; save count
mov al,ah ; get starting sector
xor ah,ah
mul sector_size_bytes
les di,local_buf ; find location in disk buffer
add di,ax
pop ax ; restore count
; Now we have to read those sectors into the buffer.
push ax
xchg ah,al ; swap count and start
push es
push di
call read_part_curblk_from_disk ; read the sectors we need
pop di
pop es
jc make_sure_fatal_read_error ; abort if error
pop ax ; restore start sector and count
push ax ; save count again
mov bp,cache_element_index
call write_part_cache_block ; write into cache
pop ax
pop cx ; restore continuing mask
log_it 3 ; tracker: xms written
add ah,al ; update sector number
or cx,cx
jnz find_one_to_read
pop ax ; get mask of sectors we just cached
or valid_mask,ax
mov bx,valid_mask
mov cx,dirty_mask
mov bp,cache_element_index
call set_dirtyindex ; mark new sectors valid
clc
ret ; return no carry, no error
make_sure_fatal_read_error:
add sp,6 ; get rid of count, running mask, and
; ; overall mask of missing sectors
stc ; set error condition
ret ; and return with error code in ax
; BUG1 -- end of new code
make_sure_sectors_are_valid_mask endp
endif ; ifdef USE_VALID
;-----------------------------------------------------------------------
;
; Now let's do a write function, caching any data that's
; appropriate.
cache_write_data proc near
assume cs:zseg,ds:zseg,es:nothing
test flags_and_unit,40h ; should we delay writes?
jz write_without_delay
if 1
push es ;check if this is a
les si,accessing_swap_file_ptr ;swapfile access, if so
cmp byte ptr es:[si],0 ;dont cache it
pop es
jne write_without_delay
endif
jmp short do_delayed_writes
; Writes are not delayed. Just make sure it's all in the
; cache (except for first partial block with no hit), then
; pass it through to the driver and return the error.
write_without_delay:
mov num_valid_buffers,0 ; invalidate supercache
cmp byte ptr curblk_index,0 ; partial block at the front?
jz wnodel_no_first_partial
; count is min (cache_block_sectors - curblk_index, d_count)
mov ax,cache_block_sectors
sub ax,curblk_index ; how many left in block?
cmp ax,d_count ; do we want that many?
jb wnodel_need_em_all ; skip if so
mov ax,d_count ; only transfer what we need
wnodel_need_em_all:
push ax ; save the count
call check_hit ; see if we hit on curblk
pop ax ; restore count into ax!!!!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -