📄 bambi.asm
字号:
page 58,132
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
;debug = 1 ; enables some debug code
;tracker = 0ffffh ; enables special TRACKER events
debug = 0
tracker = 0
; BAMBI global register conventions:
;
; The machine registers are generally considered extremely
; volatile in this program and should not generally be
; considered to be preserved when calling a subroutine,
; unless specifically stated otherwise.
;
; DS: generally points to CS: in order to access the data
; stored there without overrides.
;
; BAMBI design assumptions:
;
; The number of sectors per cache block CANNOT be > 16.
;
; Write caching of a given drive implies that it is read cached.
;
; Purpose of this module:
;
; This is the main resident device driver interface for Bambi.
; It contains the main caching logic flow and utilizes external
; modules for keeping track of caching data structure and accessing
; secondary RAM storage.
;
; This module provides one main entry point, which is our_strat/
; our_int. This is what DOS calls through to access the block
; device drivers. It also contains entry points which are used
; by the dirty_write function in a companion module.
.xlist
include msequ.inc ; get device request packet definitions
include devsym.inc ; get device driver structure definitions
include bambi.inc
include bootform.inc
include bpb.inc
.list
public our_int ; DOS branches here for ALL block
public our_strat ; device driver calls for devices which
; are present when we're first initialized
; We publish a few special entry points and variables for use
; by the dirtywrt.asm module.
public lookup_device
public read_full_cache_block
public set_start_sector
public call_dd_common
public loc_req_seg ; allow bambinit to initialize our pointers
public lb_seg
public our_count
public our_trans_off
public our_trans_seg
public our_starth
public our_startl
public our_start
public loc_reqblk
public num_valid_buffers
public rblk_op
public media_id
public media_ids
public packet_size
public packet_sizes
public next_bad_entry_ptr
public num_bad_blocks
zseg segment public 'code'
assume cs:zseg,ds:nothing,es:nothing
;
; data from rdata.asm
;
extrn last_buffer :word
extrn max_valid_buffers :word
extrn dos_3x :word
extrn hit_l :word
extrn hit_h :word
extrn nohit_l :word
extrn nohit_h :word
extrn in_bambi :byte
extrn selected_drive :byte
extrn real_dd_headers :dword
extrn real_cache_units :byte
extrn secsize_and_align_info :word
extrn cache_block_bytes :word
extrn cache_block_words :word
;
; routines from queueman.asm
;
extrn flush_queue :near
extrn set_dirtyindex :near
extrn fast_lookup :near
extrn invalidate_element :near
extrn queue_element :near
;
; routines from cacheman.asm
;
extrn cache_to_buffer :near
extrn buffer_to_cache :near
extrn commit_all_dirty :near
;
; data from int2f.asm
;
extrn accessing_swap_file_ptr :dword
;
; data from queueman.asm
;
extrn queuelength :word
;
; data from hooks.asm
;
extrn resident_stack :word
extrn temp_res_stack :word
extrn save_stack_ss :word
extrn save_stack_sp :word
extrn commit_all_when_ok :byte
extrn write_behind_cache :near
;
; routines from popup.asm
;
extrn warning_pop_up :near
;
; data from bambinit.asm
;
extrn ending_address :word
extrn number_of_cache_elements:word ;WARNING transient!
extrn initqueue :near
; local variables
;
; Please note: Many of these variables are only valid for
; the operation being performed by the mainline
; routine. dirty_write must handle its own
; configuration constants on the fly.
;
; put our dword pointers first so they're all
; aligned without wasting space
far_call_address dd 0
d_trans dd 0
dd_header dd 0
user_reqblk dd 0
MAXRENTER equ 5 ;arbitrary number of reentracy allowed
user_save_reqblk dd MAXRENTER dup(0)
; quick reference points for our block buffer and request block
; the segments fields are declared external so bambinit.asm
; can initialize them.
loc_reqblk label dword
dw our_reqblk
loc_req_seg dw 0 ; init'd by bambinit, always == cs
local_buf label dword
dw 0
lb_seg dw 0 ; this will generally be a
; different segment from cs
; put word variables next
blockids dw 16 dup (?)
d_count dw 0
curblk_l dw 0
curblk_h db 0,0 ; may be accessed as word
lastblk_l dw 0
lastblk_h db 0,0 ; may be accessed as word
curblk_index dw 0 ; high byte may be assumed to be zero
cache_element_index dw 0
num_valid_buffers dw 0 ; num. valid buffers in 'super-cache'
bufferblk_l dw 0 ; low word of base block of super-cache
bufferblk_h dw 0 ; high word + drive number
cache_align_factor dw 0 ; must be < cache_block_sectors
cache_block_shift dw 2 ; log2(blocksize/sectorsize)
sector_size_bytes dw 512
cache_block_sectors dw 4
dirty_mask dw 0 ; mask for last looked up element
ifdef USE_VALID
valid_mask dw 0 ; mask for last looked up element
endif
cache_mask dw 0 ; this is the full mask
; ; for the selected block/sector size
; the following data structure is used when we wish to
; wish to issue a device driver call other than the one
; originally passed to us from DOS. It can benefit from
; word alignment.
our_reqblk label byte
packet_size db 30 ; length
rblk_cache_unit db 2 ; cache unit
rblk_op db devrd ; read command
devstatus dw 0 ; status
db 13-5 dup (0) ; other stuff (???)
media_id db 0f0h ; media id byte
our_trans_off dw 0 ; transfer offset
our_trans_seg dw 0 ; transfer segment
our_count dw 0 ; count
our_start dw 0ffffh ; start (ignored)
dw 0,0
our_startl dw 0 ; start low
our_starth dw 0
in_device_call dw -1
media_ids db 26 dup(0f0h) ;save media_id for dirty writes
packet_sizes db 26 dup(30h) ;save packet sizes for dirty writes
MAXBADS equ 32
next_bad_entry_ptr dw 0 ; first entry will be 0
num_bad_blocks dw 0
bad_blocks dw MAXBADS dup(0)
bad_drives dw MAXBADS dup(-1)
; now the byte variables
original_unit db -1
flags_and_unit db 0
cache_unit db 0
; enter a BAMBI record in TRACKER, subtype as argument to macro
; this macro is defined to be a null macro of TRACKER is set
; false, so that every single LOG event needn't have IF TRACKER
; conditionals on it.
log_it macro rectype
if tracker
push ax
mov al,rectype
call tracker_log
pop ax
endif
endm
if tracker
; We may want to save some special BAMBI events in
; the TRACKER log. If this feature is enabled, we'll
; call through a FAR variable into TRACKER.
public save_it_off ; allow external initialization for
public save_it_seg ; TRACKER save entry point
save_it label dword
save_it_off dw offset far_ret
save_it_seg dw 0 ; will be init'd to cs if tracker not present
far_ret:
retf
code_bambi = 6 ; this is our special TRACKER record type
event struc ; this is the TRACKER event structure
rectype db ?
level db ?
regax dw ?
regbx dw ?
regcx dw ?
regdx dw ?
reges dw ?
time dd ? ; time stamp
event ends
xbuf event <code_bambi,0> ; this is our local event structure
;-----------------------------------------------------------------------
;
; enter a bambi-type tracker log
;
; entry: al == event subtype
; ds == cs
;
; exit: no registers affected
tracker_log proc near
assume cs:zseg,ds:zseg,es:nothing
push si
mov si,offset xbuf
mov ds:[si].regax,ax
call save_it
pop si
ret
tracker_log endp
endif
;-----------------------------------------------------------------------
;
; call into the device driver using the user's original
; request packet.
;
; Entry: ds == cs
;
; Trashed: es, bx, ax, si, far_call_addr
; (plus anything affected by bad d.d.'s)
call_dd_ureqblk proc near
assume cs:zseg,ds:zseg,es:nothing
les bx,user_reqblk ;es:bx points to request packet
call_dd_ureqblk endp ; note: fall through to call_dd
;-----------------------------------------------------------------------
;
; call through to the device driver
; plug in the mapped unit code to the request block
;
; Entry: ds == cs, es:[bx] -> request block
;
; Trashed: ax, si, far_call_addr
; (plus anything affected by bad d.d.'s)
call_dd proc near
assume cs:zseg,ds:zseg,es:nothing
mov al,cache_unit ; get remapped cache unit
mov es:byte ptr [bx].requnit,al
push ds ; save caller's ds
lds si,dd_header ; get actual device's header
assume ds:nothing
; fall into call_dd_common
call_dd endp
;-----------------------------------------------------------------------
;
; This is a special entry point used by dirtywrt for calling
; out to the device driver. When this routine is JMP'd to,
; the original ds is already saved on the stack after the
; actual return address.
;
; Entry: ds:[si] -> device driver header
; es:[bx] -> request packet
;
; Exit: ds restored from stack
;
; Trashed: ax, "far_call_address", and anything munched by
; bad device drivers.
call_dd_common proc near
assume cs:zseg,ds:nothing,es:nothing
mov devstatus,0
mov ax,word ptr [si].SDEVSTRAT ; get strategy entry
mov word ptr far_call_address[2],ds
mov word ptr far_call_address[0],ax
push es ; save packet for unit restore
push bx
call DWORD PTR[far_call_address]
mov ax,word ptr [si].SDEVINT ; get interrupt entry
mov word ptr far_call_address[0],ax
call DWORD PTR[far_call_address]
pop bx ; get packet
pop es
; We have to make sure the UNIT code is returned to the
; caller unchanged if we're calling through on DOS's
; packet. In the case of our own packet, original_unit
; may not have any meaning, but in this case, we're sure
; we're not going to care about what's left in that
; field in the packet.
;
; This is made more complicated by the fact that the SET_LOGICAL
; device function returns a value in that field, so in this
; particular case, we can't restore the original field.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -