📄 bambi.asm
字号:
not di ;2, 2bytes invert mask so we can get high bits for ax
and cx,di ;2, 2bytes mask just covers the high bits
or ax,cx ;2 2bytes or the high bits into ax--ax is done
;= 21 clocks total (386),19 bytes
mov curblk_l,ax ; store the cache block number of
mov curblk_h,dl ; the 1st sector in a temp. variable
pop ax ; get low bits (modulo)
mov ah,byte ptr cache_block_sectors
dec ah ; generate a mask for secs/blk
and al,ah ; extract the partial block size
mov byte ptr curblk_index,al ; save index within cache block
cmp es:[bx.reqfunc],devrd ; reading?
jnz do_writes ; assume all other functions are writes
call cache_reads ; use a subroutine for the read loop
jmp short common_exit
do_writes:
call cache_write_data ; write it, cache if appropriate
common_exit:
go_back_to_dos:
pop si
pop di
pop bx
pop es
pop cx ; restore 1st tier of saved regs
pop dx
pop bp
cmp in_device_call,0
jne handle_reentrancy_exit_near
mov ss,save_stack_ss ;restore stack
mov sp,save_stack_sp
dont_restore_stack:
dec in_bambi ; free device_driver resource
dec in_device_call ;keep track of reentrancy
cmp commit_all_when_ok,0 ;now is a good time to determine if
jne must_commit_all ;some asynch event (ctrl+alt+delete)
;requires us to commit all
continue_returntodos:
pop ds ; restore caller's ds
assume ds:nothing
ret ; back to DOS (or last hooker)
must_commit_all:
call write_behind_cache
jmp short continue_returntodos
handle_reentrancy_exit_near:
jmp handle_reentrancy_exit
our_int endp
;-----------------------------------------------------------------------
;
; This routine is used when a media_change or an IOCTL forces
; us to invalidate our information about a given drive so that
; we are forced to re-read it.
;
reset_drive_stuff proc near
assume cs:zseg,ds:zseg,es:nothing
mov num_valid_buffers,0 ; invalidate supercache
push ax ;flush the cache and invalidate
push bx
push cx
push dx
push bp
push si
push di
push es
call commit_all_dirty
call flush_queue
pop es
pop di
pop si
pop bp
pop dx
pop cx
pop bx
pop ax
ret
reset_drive_stuff endp
;-----------------------------------------------------------------------
;
; Come here when we have a read operation on a cached drive.
; The block number and index within the first block have already
; been setup by the common entry code.
;
; The basic idea is that we break the read down into:
;
; First partial (non-cache-block aligned sectors on front)
; Full cache blocks
; Last partial (cache-block aligned, but we don't need it all)
xno_partial_on_front: jmp no_partial_on_front ; make short branch reach
cache_reads proc near
assume cs:zseg,ds:zseg,es:nothing
cmp byte ptr curblk_index,0 ; partial block at the front?
jz xno_partial_on_front ; skip if not
call check_supercache_match ; if we're lucky, the data we want
; is already in our RAM buffer and
; we won't even have to hit XMS
jnc no_supercache_in_partial ; Skip if we weren't lucky
; the block we need part of is already in the cache, copy to
; user's buffer. Note: si has already been setup (pointing
; to the target block in the supercache) and must not be trashed.
call first_partial_setup ; get sector count, set es:di for move
push ax ; save # sectors
mov ax,curblk_index ; get offset within block
mul sector_size_bytes
add si,ax ; point to correct source in supercache
pop ax
mul sector_size_bytes
mov cx,ax
shr cx,1 ; convert to words
mov ds,lb_seg
assume ds:nothing
; ds:si -> desired sector in supercache (our local RAM buffer)
; es:di -> user's transfer address
; cx = length of this transfer in words
; ax = length of this transfer in bytes
rep movsw ; move to user's buffer
push cs
pop ds
assume ds:zseg ; restore addressability
jmp short next_read_block ; update transfer, curblk, and continue
; We're still trying to satisfy our first partial, but it wasn't
; in the supercache. Our next best bet is our REAL cache.
no_supercache_in_partial:
call check_hit ; see if we hit on curblk
jnz partial_was_a_hit ; skip if that block is present
; the block we need isn't in cache! We've got to hit the disk,
; and while we're at it, we'll stick it into the cache for
; future use.
mov cx,1 ; just get one block
call get_curblks_into_cache ; get the curblk into local buf
; ; and cache it!
jnc frst_prt_rdok ; done if no disk read error
; we couldn't read the whole block. Now we'd better try to
; read just the part the user wanted directly into his buffer
; before we decide to bomb out and report an error.
call first_partial_setup ; get es:di -> dma addr, ax=count
push ax ; save count
mov ah,al ; get count into ah
mov al,byte ptr curblk_index ; get sector within block
call read_part_curblk_from_disk
pop dx ; restore count into dx to preserve
; error code in ax
jc xgot_fatal_error ; bomb out if fatal disk error
; lucky us! the read error was in another part of the
; block, or, the retry was sufficient to get the data.
mov ax,dx ; get count just xferred
mul sector_size_bytes ; get amount to bump xfer addr by
jmp short next_read_block
xgot_fatal_pop2: ; BUG1 - adjust stack & exit if error
add sp,4 ; BUG1 - pop 2 entries off stack
xgot_fatal_error: jmp got_fatal_error ; make short branch reach
; We've got the first partial read and cached. Now pass it
; back to the caller.
frst_prt_rdok:
call first_partial_setup ; setup for partial block
mul sector_size_bytes ; get byte count for transfer
mov cx,ax
shr cx,1 ; convert to words
push ax ; preserve the byte count in ax
mov ax,curblk_index ; get starting index
mul sector_size_bytes
lds si,local_buf
assume ds:nothing
add si,ax
rep movsw ; move the sectors
pop ax
push cs
pop ds
assume ds:zseg ; restore addressability
jmp short next_read_block
x_do_last_partial: jmp do_last_partial ; bridge for short jumps
; the block we need part of is already in the cache, copy to
; user's buffer.
partial_was_a_hit:
call first_partial_setup
push ax ; save # sectors
mov ah,byte ptr curblk_index ; get al blocks, starting here
ifdef USE_VALID
push ax
call make_sure_sectors_are_valid ; if valid_bits not set,
; ; this routine will read the
; ; whole block and make sure
; ; it's all valid.
jc xgot_fatal_pop2 ; BUG1 exit if error reading
pop ax
endif
mov bp,cache_element_index
les di,d_trans
call read_part_cache_block ; read from cache into user buffer
pop ax ; restore sector count
mul sector_size_bytes
;//////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////////////
; This is the main READ loop. We come back here after successfully
; completing the first partial or any full blocks. AX has the number
; of bytes just transferred, and will be added to the transfer address.
; curblk is also incremented.
next_read_block:
add word ptr d_trans,ax ; update transfer address
add curblk_l,1 ; move to next block
adc curblk_h,0
; Now we're block aligned. Complete any remaining full blocks first.
no_partial_on_front:
mov ax,cache_block_sectors
cmp ax,d_count ; do we need a full block?
ja x_do_last_partial
sub d_count,ax ; count it down
call check_supercache_match ; did we match in supercache?
jnc no_full_block_supercache_hit
; copy the block from supercache
les di,d_trans ; get user buffer
mov cx,cache_block_words ; move one full cache block
mov ds,lb_seg ; si set by check_supercache_match
assume ds:nothing
rep movsw ; move from supercache
push cs
pop ds
assume ds:zseg ; restore addressability
mov ax,cache_block_bytes ; size for updating pointer
jmp short next_read_block
no_full_block_supercache_hit:
; No supercache match on full cache block. Our next best bet
; is the REAL cache.
call check_hit ; is curblk in cache?
jz full_nohit ; brif not
ifdef USE_VALID
mov ax,cache_mask ; make sure it is valid
call make_sure_sectors_are_valid_mask
jc zgot_fatal_error ; BUG1 -- exit if read error!
endif
les di,d_trans ; get user buffer
mov bp,cache_element_index
call read_full_cache_block ; read the whole cached block
mov ax,cache_block_bytes ; size for updating pointer
jmp next_read_block
zgot_fatal_error: ; BUG1 -- error exit bridge
jmp got_fatal_error ; BUG1
; block not in cache. Figure out how many contiguous nohits
; there are in the data we need, and read them all, then
; transfer them all into the cache at once.
full_nohit:
mov ax,curblk_l
mov dl,curblk_h ; get last block number
xor cx,cx ; init block needed count
mov bx,d_count ; we need this many more sectors
count_nohit_loop:
inc cx ; count blocks needed
sub bx,cache_block_sectors ; do we need another full block?
jb we_know_how_many_nohits
add ax,1 ; point to next block
adc dl,0
push ax
push bx
push cx
push dx
call check_hit_in_regs ; do we need to read next block?
pop dx
pop cx
pop bx
pop ax
jz count_nohit_loop ; just keep looping while no hits
we_know_how_many_nohits:
; now cx tells us how many blocks we need to read from disk
; bx is the number of remaining sectors after the contig nohits
; Okay, then. Let's jam directly on the user's buffer.
cant_fit_more_in_localbuf:
les di,d_trans ; get user buffer
push cx ; save number of blks for caching loop
mov ax,cx ; get count of blocks
call read_curblks_from_disk ; read that sucker
pop cx
jc got_fatal_error ; error out! We NEED those blocks
; ; to succeed this call!
; adjust d_count to reflect multiple blocks transferred
mov ax,cx ; we know this is at least one
dec ax
mul cache_block_sectors
sub d_count,ax
; Now we've got to copy all of that shit into the cache
les di,d_trans ; point to buffer
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 skip_cache_em
cache_em:
push cx
push di
xor cx,cx ; none of it is dirty!!!
ifdef USE_VALID
mov bx,cache_mask ; all valid
endif
call create_cache_block ; **** create the block^
pop di
push di
call write_full_cache_block
add curblk_l,1
adc curblk_h,0
pop di
pop cx
add di,cache_block_bytes
loop cache_em
done_cache_em:
mov word ptr d_trans,di ; update d_trans
; **** Note: We're branching all of the way back here so
; we can test for the case where we've done with all
; of the full blocks. A potential speed optimization
; would be to duplicate the test here, and not bother
; looking up the next block if there is another one.
; In that case, we already know it is a hit. The
; block number would have to be saved above in this
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -