⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bambi.asm

📁 Dos6.0
💻 ASM
📖 第 1 页 / 共 5 页
字号:
	
	cmp     es:[bx].reqfunc,19
	jae     no_restore_unit         ; skip unit restore if so

	mov     al,cs:original_unit
	mov     byte ptr es:[bx].requnit,al

no_restore_unit:
	pop     ds
	ret                             

call_dd_common  endp

;-----------------------------------------------------------------------
;
;       our strategy entry point

our_strat       proc    far
	assume  cs:zseg,ds:nothing,es:nothing

	inc     cs:in_device_call               ;keep track of reentrancy
	jnz     reentering                      ;zero means first entry
finish_strategy:
	mov     cs:word ptr user_reqblk,bx
	mov     cs:word ptr user_reqblk+2,es
	ret

reentering:
	;
	; we need to save off the packet pointer for the re-entered
	; call so it will still be valid when its execution continues.
	; we use our semaphore as an index into a table which will 
	; hold the saved packet
	
	push    di                              ;must preserve all regs
	push    es
	push    bx

	mov     di,cs:in_device_call            ;treat as index into table
	shl     di,1                            ;dword table
	shl     di,1
	les     bx,user_reqblk                  ;get re-entered packed
	mov     word ptr cs:user_save_reqblk[di],bx     ;save it in our table
	mov     word ptr cs:user_save_reqblk[di+2],es

	pop     bx
	pop     es
	pop     di
	jmp     short finish_strategy   

our_strat       endp


handle_reentrancy_exit:
	pop     word ptr far_call_address[2]
	pop     word ptr far_call_address
	pop     word ptr dd_header[2]
	pop     word ptr dd_header
	pop     word ptr cache_unit
	pop     word ptr flags_and_unit
	pop     word ptr original_unit

	;
	; we need to save off the packet pointer for the re-entered
	; call so it will still be valid when its execution continues.
	; we use our semaphore as an index into a table which will 
	; hold the saved packet
	
	push    di                              ;must preserve all regs
	push    es
	push    bx

	mov     di,cs:in_device_call            ;treat as index into table
	shl     di,1                            ;dword table
	shl     di,1

	mov     bx,word ptr user_save_reqblk[di]
	mov     es,word ptr user_save_reqblk[di+2]
	mov     word ptr user_reqblk,bx
	mov     word ptr user_reqblk[2],es

	pop     bx
	pop     es
	pop     di

	jmp     dont_restore_stack

handle_reentrancy_enter:
	push    word ptr original_unit
	push    word ptr flags_and_unit
	push    word ptr cache_unit
	push    word ptr dd_header
	push    word ptr dd_header[2]
	push    word ptr far_call_address
	push    word ptr far_call_address[2]
	jmp     short skip_stack_swap


;-----------------------------------------------------------------------
;
;       This is it!  This is when DOS is trying to call a device
;         driver.  We intercept the call, and decide if it is something
;         that can be:
;
;               A) saved away into the cache
;            or B) gotten from the cache
;            or C) some combination of A & B
;
;       Entry:  our parameter block was saved in user_reqblk by
;               a call to the previous routine
;
;       Exit:   We'll try to satisfy the request and make sure we
;               fill in the status word of the request block before returning.
;
;       Trashed: We should preserve ALL registers, but we trash ax, bx & es
;                BUGBUG -- will ANYBODY ever care about ax, bx & es here?
;                          we leave es:[bx] pointing at the original req pkt.
;                Flags including direction

our_int proc    far
	assume  cs:zseg,ds:nothing,es:nothing

	push    ds              ; save caller's ds
	push    cs
	pop     ds
	assume  ds:zseg         ; make our data quickly addressable

	inc     in_bambi        ; make sure we aren't reentered

;       if there are no hw stacks, we may be the straw that breaks
;       the stack, so we have to switch to our own stack to ensure
;       no stack overflow problems

	cmp     in_device_call,0
	jne     handle_reentrancy_enter

	mov     save_stack_ss,ss        ;save the current stack 
	mov     save_stack_sp,sp        ;context
	
	push    cs                      ;and switch to our own
	pop     ss                      ;internal stack
	mov     sp,offset resident_stack

skip_stack_swap:

	push    bp                      ; we ALWAYS need these registers saved
	push    dx
	push    cx
	push    es
	push    bx
	push    di
	push    si


;       We must find the device header and unit number for the
;       drive number in the request block.  The unit number code
;       also has a couple of flag bits in it which indicate what
;       level of caching is enabled for this drive.

	les     bx,user_reqblk          ;es:bx points to request packet
	mov     al,byte ptr es:[bx].requnit 

	mov     original_unit,al        ; save original unit code
	call    lookup_device           ; remap unit code, get dev header
	xor     al,0c0h                 ; flip the 'active' bits
	mov     flags_and_unit,al       ; save flags and unit
	and     al,3fh                  ; mask off high bits 
	mov     cache_unit,al

	mov     word ptr dd_header,dx   ; save actual device header
	mov     word ptr dd_header[2],bp

;       done setting up packet structure, its off to the races!
						
	cmp     queuelength,0   ;even if caching is enabled for a drive
	je      just_pass_thru  ;the queue size could be zero, so
				;be sure there is a non-zero cache present

	test    flags_and_unit,0c0h     ; any caching enabled?
	jnz     this_drive_is_cached    ; if any caching, enter main module

just_pass_thru:
	push    si
	call    call_dd                 ; call through to device driver
	pop     si

return_to_caller:
	jmp     go_back_to_dos


;       The code below will branch back up here if the operation is
;         a media check for a cached drive.  We must note the return
;         code before returning in this case so that we can invalidate
;         the cache on a media change.

do_media_check:
	push    si
	call    call_dd
	pop     si
	cmp     BYTE PTR es:[bx].14,1
	je      return_to_caller

;;;the following code notifies windows that the media for
;;;this drive has changed.  While mutlitasking dos boxes,
;;;windows has to maintain the CDS state but can get 
;;;confused when the media changes. This notification will
;;;ensure that windows keeps track of disk changes correctly
;;;code courtesy of aaronr
	xor     di,di
	mov     es,di
	mov     bx,15h                  ;dosmgr device id
	mov     ax,1684h                ;get device api entry point
	int     2fh
	mov     ax,es
	or      ax,di
	jz      nobodytonotify
	push    bp
	mov     bp,sp
	push    es
	push    di
	mov     ax,5h                   ;media change detected
	mov     bl,original_unit        ;zero based drive number
	call    dword ptr [bp-4]        ;change detected on a=0,b=1...
	;
	;Carry is clear if media change processed. Carry set if invalid
	;  drive passed in BL (drive is not in use, is out of range, is
	;  a network drive).
	;
	pop     ax                      
	pop     ax
	pop     bp
nobodytonotify:

	call    reset_drive_stuff

	xor     bh,bh                   ;cause the bpb to be re-read next access
	mov     bl,original_unit
	shl     bx,1
	mov     word ptr secsize_and_align_info[bx],0ffffh
	mov     selected_drive,-1

	jmp     go_back_to_dos

handle_get_bpb:
	call    reset_drive_stuff
	jmp     short not_get_bpb       

;       We now know we're operating on a cached drive.  We have to
;       look at the function number to decide what to do next.

this_drive_is_cached:
	cmp     es:[bx].reqfunc,devrd   ; read, write, writev == go do it
	je      cache_this_readwrite
	cmp     es:[bx].reqfunc,devwrt
	je      cache_this_readwrite
	cmp     es:[bx].reqfunc,devwrtv
	je      cache_this_readwrite
	cmp     es:[bx].reqfunc,1
	je      do_media_check          ; watch return code from media check
	cmp     es:[bx].reqfunc,2
	je      handle_get_bpb
not_get_bpb:

	cmp     es:[bx].reqfunc,genioctl ; certain genioctls require
	jnz     just_pass_thru          ; that we invalidate our cache

	mov     ax,word ptr es:[bx].majorfunction
	cmp     ax,6008h                ;dont trap get bpb
	je      just_pass_thru_short
	cmp     ax,6608h                
	jae     just_pass_thru_short
	call    reset_drive_stuff
just_pass_thru_short:
	jmp     just_pass_thru  

;       We've now qualified this operation substantially.  We know that
;       the request was a read, write, or write w/verify on a drive that
;       we are caching.  Furthermore, the cache is not zero-length and
;       it isn't a Win 3.1 swap file access.

cache_this_readwrite:

	mov     al,es:[bx].0dh                  ; use correct media id
	mov     media_id,al

	mov     al,es:[bx]                      ; use correct packet size
	mov     packet_size,al

	cld                     ; allow our internals to assume direction

;       have we changed drives from last time?

	mov     al,original_unit        ; no need to recalculate constants
	cmp     al,selected_drive       ; on repeated accesses to the same
	jz      constants_already_valid ; drive

;       setup the relevant constants for this drive

	mov     selected_drive,al
	call    get_drive_info

	mov     byte ptr cache_align_factor,ch  ; save cache align factor
	mov     byte ptr cache_block_shift,cl   ; save shift factor

	push    bx
	xor     bh,bh
	mov     bl,original_unit
	mov     al,media_id
	mov     byte ptr media_ids[bx],al
	mov     al,packet_size
	mov     byte ptr packet_sizes[bx],al
	pop     bx

	mov     ax,cache_block_bytes            ; get sector size
	shr     ax,cl
	mov     sector_size_bytes,ax

	mov     al,1
	shl     al,cl
	mov     byte ptr cache_block_sectors,al ; get number of secs / cache block

;       Now we have to generate a mask with one bit per sectors/blk

	mov     cl,al
	mov     ax,1
	shl     ax,cl
	dec     ax                      ; get one bit per sector in this block
	mov     cache_mask,ax           ; and save the mask

constants_already_valid:
;
;       When we come here, we know that variables like sector_size_bytes
;       and cache_block_sectors are set correctly to their values for the
;       drive for this operation.  The caller's registers have mostly been
;       saved on the stack.  It is time to go to work.

	mov     ax,es:[bx.count]        ; copy count & transfer address to
	mov     d_count,ax              ; local temporary variables

	mov     ax,es:word ptr [bx.trans]
	mov     word ptr d_trans,ax
	mov     ax,es:word ptr [bx.trans+2]
	mov     word ptr d_trans+2,ax

	mov     ax,es:[bx.start]        ; get 16-bit block number
	xor     dx,dx

;       We must look at our device header (original copy) to see
;         if we should support 32 bit sector numbers.

	push    es
	push    bx
	les     bx,dd_header
	test    es:byte ptr [bx.4],2    ; 32-bit capable device?
	pop     bx
	pop     es
	jz      use_16_bit_blocknum

	cmp     dos_3x,0
	je      notdos3x
	cmp     byte ptr es:[bx],24     ;compaq's 24 byte packet?
	jne     use_16_bit_blocknum

	mov     dx,es:[bx.start.2]      ;get second part of 32-bit offset
	jmp     short use_16_bit_blocknum

notdos3x:

	cmp     ax,-1                   ; for 32 bit block numbers, the
	jnz     use_16_bit_blocknum     ;  low 16 should be -1

	mov     dx,es:[bx.start_h]      ; get high part
	mov     ax,es:[bx.start_l]      ; get 32-bit block number

use_16_bit_blocknum:
;       We now have dx:ax == the starting sector for this I/O.  Let's
;       figure out which cache block contains that sector, and what the
;       sector offset within that cache block is

;       cmp     es:byte ptr [bx.1],1            ; drive b:
;       jnz     no_bkpt
;       cmp     ax,0b10h
;       jb      no_bkpt
;
;       int     3
;
;no_bkpt:
	add     ax,cache_align_factor   ; adjustment factor attempts to align
	adc     dx,0                    ;  cache blocks with FAT clusters

	mov     cx,cache_block_shift
	push    ax                      ; save the low bits

;       The following is a fast 32-bit shift right.     It will be used
;       elsewhere in this program without the timing documentation.
;       WARNING: assumes CL <=16!

	mov     di,0FFFFh ;2 clks 3bytes   set up to make a mask
	ror     dx,cl   ;3,       2bytes   low bits of dx set to final bit position
	shr     ax,cl   ;3,       2bytes   low bits of ax set to final bit position
	shr     di,cl   ;3,       2bytes   the mask should just cover low bits in dx
	mov     cx,dx   ;2,       2bytes   save off dx (we still need high bits)
	and     dx,di   ;2,       2bytes   mask off the high bits of dx--dx is is done

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -