bambi.asm
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:95k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. page    58,132
  2. ;/*
  3. ; *                      Microsoft Confidential
  4. ; *                      Copyright (C) Microsoft Corporation 1991
  5. ; *                      All Rights Reserved.
  6. ; */
  7. ;debug  =       1       ; enables some debug code
  8. ;tracker        =       0ffffh  ; enables special TRACKER events
  9. debug = 0
  10. tracker = 0
  11. ;    BAMBI global register conventions:
  12. ;
  13. ;       The machine registers are generally considered extremely
  14. ;       volatile in this program and should not generally be
  15. ;       considered to be preserved when calling a subroutine,
  16. ;       unless specifically stated otherwise.
  17. ;
  18. ;       DS: generally points to CS: in order to access the data
  19. ;       stored there without overrides.
  20. ;
  21. ;    BAMBI design assumptions:
  22. ;
  23. ;       The number of sectors per cache block CANNOT be > 16.
  24. ;
  25. ;       Write caching of a given drive implies that it is read cached.
  26. ;
  27. ;    Purpose of this module:
  28. ;
  29. ;       This is the main resident device driver interface for Bambi.
  30. ;       It contains the main caching logic flow and utilizes external
  31. ;       modules for keeping track of caching data structure and accessing
  32. ;       secondary RAM storage.
  33. ;
  34. ;       This module provides one main entry point, which is our_strat/
  35. ;       our_int.  This is what DOS calls through to access the block
  36. ;       device drivers.  It also contains entry points which are used
  37. ;       by the dirty_write function in a companion module.
  38. .xlist
  39. include msequ.inc       ; get device request packet definitions
  40. include devsym.inc      ; get device driver structure definitions
  41. include bambi.inc
  42. include bootform.inc
  43. include bpb.inc
  44. .list
  45. public  our_int                 ; DOS branches here for ALL block
  46. public  our_strat               ;  device driver calls for devices which
  47. ;  are present when we're first initialized
  48. ;       We publish a few special entry points and variables for use
  49. ;       by the dirtywrt.asm module.
  50. public  lookup_device
  51. public  read_full_cache_block
  52. public  set_start_sector
  53. public  call_dd_common
  54. public  loc_req_seg             ; allow bambinit to initialize our pointers
  55. public  lb_seg
  56. public  our_count
  57. public  our_trans_off
  58. public  our_trans_seg
  59. public  our_starth
  60. public  our_startl
  61. public  our_start
  62. public  loc_reqblk
  63. public  num_valid_buffers
  64. public  rblk_op
  65. public  media_id
  66. public  media_ids 
  67. public  packet_size
  68. public  packet_sizes
  69. public  next_bad_entry_ptr 
  70. public  num_bad_blocks  
  71. zseg    segment public 'code'
  72. assume  cs:zseg,ds:nothing,es:nothing
  73. ;
  74. ;       data from rdata.asm
  75. ;
  76. extrn   last_buffer             :word
  77. extrn   max_valid_buffers       :word
  78. extrn   dos_3x                  :word
  79. extrn   hit_l                   :word
  80. extrn   hit_h                   :word
  81. extrn   nohit_l                 :word
  82. extrn   nohit_h                 :word
  83. extrn   in_bambi                :byte
  84. extrn   selected_drive          :byte
  85. extrn   real_dd_headers         :dword
  86. extrn   real_cache_units        :byte
  87. extrn   secsize_and_align_info  :word
  88. extrn   cache_block_bytes       :word
  89. extrn   cache_block_words       :word
  90. ;
  91. ;       routines from queueman.asm
  92. ;
  93. extrn   flush_queue             :near
  94. extrn   set_dirtyindex          :near
  95. extrn   fast_lookup             :near
  96. extrn   invalidate_element      :near
  97. extrn   queue_element           :near
  98. ;
  99. ;       routines from cacheman.asm
  100. ;
  101. extrn   cache_to_buffer         :near
  102. extrn   buffer_to_cache         :near
  103. extrn   commit_all_dirty        :near
  104. ;
  105. ;       data from int2f.asm
  106. ;
  107. extrn   accessing_swap_file_ptr :dword
  108. ;
  109. ;       data from queueman.asm
  110. ;
  111. extrn   queuelength             :word
  112. ;
  113. ;       data from hooks.asm
  114. ;
  115. extrn   resident_stack          :word
  116. extrn   temp_res_stack          :word
  117. extrn   save_stack_ss           :word
  118. extrn   save_stack_sp           :word
  119. extrn   commit_all_when_ok      :byte
  120. extrn   write_behind_cache      :near
  121. ;
  122. ;       routines from popup.asm
  123. ;
  124. extrn   warning_pop_up          :near
  125. ;
  126. ;       data from bambinit.asm
  127. ;
  128. extrn   ending_address          :word
  129. extrn   number_of_cache_elements:word   ;WARNING transient!
  130. extrn   initqueue               :near
  131. ;       local variables
  132. ;
  133. ;       Please note:  Many of these variables are only valid for
  134. ;                     the operation being performed by the mainline
  135. ;                     routine.  dirty_write must handle its own
  136. ;                     configuration constants on the fly.
  137. ;
  138. ;       put our dword pointers first so they're all
  139. ;       aligned without wasting space
  140. far_call_address        dd      0
  141. d_trans                 dd      0
  142. dd_header               dd      0
  143. user_reqblk             dd      0
  144. MAXRENTER       equ     5               ;arbitrary number of reentracy allowed
  145. user_save_reqblk        dd      MAXRENTER       dup(0)
  146. ;       quick reference points for our block buffer and request block
  147. ;          the segments fields are declared external so bambinit.asm
  148. ;          can initialize them.
  149. loc_reqblk              label   dword
  150. dw      our_reqblk
  151. loc_req_seg             dw      0       ; init'd by bambinit, always == cs
  152. local_buf               label   dword
  153. dw      0
  154. lb_seg                  dw      0       ; this will generally be a
  155. ;  different segment from cs
  156. ;       put word variables next
  157. blockids                dw      16 dup (?)
  158. d_count                 dw      0
  159. curblk_l                dw      0
  160. curblk_h                db      0,0     ; may be accessed as word
  161. lastblk_l               dw      0
  162. lastblk_h               db      0,0     ; may be accessed as word
  163. curblk_index            dw      0       ; high byte may be assumed to be zero
  164. cache_element_index     dw      0
  165. num_valid_buffers       dw      0       ; num. valid buffers in 'super-cache'
  166. bufferblk_l             dw      0       ; low word of base block of super-cache
  167. bufferblk_h             dw      0       ; high word + drive number
  168. cache_align_factor      dw      0       ; must be < cache_block_sectors
  169. cache_block_shift       dw      2       ; log2(blocksize/sectorsize)
  170. sector_size_bytes       dw      512
  171. cache_block_sectors     dw      4
  172. dirty_mask              dw      0       ; mask for last looked up element
  173. ifdef   USE_VALID
  174. valid_mask              dw      0       ; mask for last looked up element
  175. endif
  176. cache_mask              dw      0       ; this is the full mask
  177. ;                                       ; for the selected block/sector size
  178. ;       the following data structure is used when we wish to
  179. ;       wish to issue a device driver call other than the one
  180. ;       originally passed to us from DOS.  It can benefit from
  181. ;       word alignment.
  182. our_reqblk      label   byte
  183. packet_size     db      30      ; length
  184. rblk_cache_unit db      2       ; cache unit
  185. rblk_op         db      devrd   ; read command
  186. devstatus       dw      0       ; status
  187. db      13-5 dup (0) ; other stuff (???)
  188. media_id        db      0f0h    ; media id byte
  189. our_trans_off   dw      0       ; transfer offset
  190. our_trans_seg   dw      0       ; transfer segment
  191. our_count       dw      0       ; count
  192. our_start       dw      0ffffh  ; start (ignored)
  193. dw      0,0
  194. our_startl      dw      0       ; start low
  195. our_starth      dw      0
  196. in_device_call  dw      -1
  197. media_ids       db      26      dup(0f0h) ;save media_id for dirty writes
  198. packet_sizes    db      26      dup(30h)  ;save packet sizes for dirty writes
  199. MAXBADS         equ     32
  200. next_bad_entry_ptr dw   0       ; first entry will be 0
  201. num_bad_blocks  dw      0
  202. bad_blocks      dw      MAXBADS dup(0)
  203. bad_drives      dw      MAXBADS dup(-1)
  204. ;       now the byte variables
  205. original_unit           db      -1
  206. flags_and_unit          db      0
  207. cache_unit              db      0
  208. ;       enter a BAMBI record in TRACKER, subtype as argument to macro
  209. ;         this macro is defined to be a null macro of TRACKER is set
  210. ;         false, so that every single LOG event needn't have IF TRACKER
  211. ;         conditionals on it.
  212. log_it  macro   rectype
  213. if      tracker
  214. push    ax
  215. mov     al,rectype
  216. call    tracker_log
  217. pop     ax
  218. endif
  219. endm
  220. if      tracker
  221. ;       We may want to save some special BAMBI events in
  222. ;       the TRACKER log.  If this feature is enabled, we'll
  223. ;       call through a FAR variable into TRACKER.
  224. public  save_it_off     ; allow external initialization for
  225. public  save_it_seg     ;  TRACKER save entry point
  226. save_it         label   dword
  227. save_it_off     dw      offset far_ret
  228. save_it_seg     dw      0       ; will be init'd to cs if tracker not present
  229. far_ret:
  230. retf
  231. code_bambi      =       6       ; this is our special TRACKER record type
  232. event           struc           ; this is the TRACKER event structure
  233. rectype         db      ?
  234. level           db      ?
  235. regax           dw      ?
  236. regbx           dw      ?
  237. regcx           dw      ?
  238. regdx           dw      ?
  239. reges           dw      ?
  240. time            dd      ?       ; time stamp
  241. event           ends
  242. xbuf    event   <code_bambi,0>  ; this is our local event structure
  243. ;-----------------------------------------------------------------------
  244. ;
  245. ;       enter a bambi-type tracker log
  246. ;
  247. ;       entry: al == event subtype
  248. ;              ds == cs
  249. ;
  250. ;       exit:  no registers affected
  251. tracker_log     proc    near
  252. assume  cs:zseg,ds:zseg,es:nothing
  253. push    si
  254. mov     si,offset xbuf
  255. mov     ds:[si].regax,ax
  256. call    save_it
  257. pop     si
  258. ret
  259. tracker_log     endp
  260. endif
  261. ;-----------------------------------------------------------------------
  262. ;
  263. ;       call into the device driver using the user's original
  264. ;         request packet.
  265. ;
  266. ;       Entry: ds == cs
  267. ;
  268. ;       Trashed: es, bx, ax, si, far_call_addr
  269. ;                (plus anything affected by bad d.d.'s)
  270. call_dd_ureqblk proc    near
  271. assume  cs:zseg,ds:zseg,es:nothing
  272. les     bx,user_reqblk          ;es:bx points to request packet
  273. call_dd_ureqblk endp                    ; note:  fall through to call_dd
  274. ;-----------------------------------------------------------------------
  275. ;
  276. ;       call through to the device driver
  277. ;         plug in the mapped unit code to the request block
  278. ;
  279. ;       Entry: ds == cs, es:[bx] -> request block
  280. ;
  281. ;       Trashed: ax, si, far_call_addr
  282. ;                (plus anything affected by bad d.d.'s)
  283. call_dd proc    near
  284. assume  cs:zseg,ds:zseg,es:nothing
  285. mov     al,cache_unit           ; get remapped cache unit
  286. mov     es:byte ptr [bx].requnit,al
  287. push    ds                      ; save caller's ds
  288. lds     si,dd_header            ; get actual device's header
  289. assume  ds:nothing
  290. ; fall into call_dd_common
  291. call_dd endp
  292. ;-----------------------------------------------------------------------
  293. ;
  294. ;       This is a special entry point used by dirtywrt for calling
  295. ;       out to the device driver.  When this routine is JMP'd to,
  296. ;       the original ds is already saved on the stack after the
  297. ;       actual return address.
  298. ;
  299. ;       Entry:  ds:[si] -> device driver header
  300. ;               es:[bx] -> request packet
  301. ;
  302. ;       Exit:   ds restored from stack
  303. ;
  304. ;       Trashed: ax, "far_call_address", and anything munched by
  305. ;                 bad device drivers.
  306. call_dd_common  proc    near
  307. assume  cs:zseg,ds:nothing,es:nothing
  308. mov     devstatus,0
  309. mov     ax,word ptr [si].SDEVSTRAT ; get strategy entry
  310. mov     word ptr far_call_address[2],ds
  311. mov     word ptr far_call_address[0],ax
  312. push    es                      ; save packet for unit restore
  313. push    bx
  314. call    DWORD PTR[far_call_address]
  315. mov     ax,word ptr [si].SDEVINT ; get interrupt entry
  316. mov     word ptr far_call_address[0],ax
  317. call    DWORD PTR[far_call_address]
  318. pop     bx                      ; get packet
  319. pop     es
  320. ;       We have to make sure the UNIT code is returned to the
  321. ;         caller unchanged if we're calling through on DOS's
  322. ;         packet.  In the case of our own packet, original_unit
  323. ;         may not have any meaning, but in this case, we're sure
  324. ;         we're not going to care about what's left in that
  325. ;         field in the packet.
  326. ;
  327. ;       This is made more complicated by the fact that the SET_LOGICAL
  328. ;         device function returns a value in that field, so in this
  329. ;         particular case, we can't restore the original field.
  330. cmp     es:[bx].reqfunc,19
  331. jae     no_restore_unit         ; skip unit restore if so
  332. mov     al,cs:original_unit
  333. mov     byte ptr es:[bx].requnit,al
  334. no_restore_unit:
  335. pop     ds
  336. ret                             
  337. call_dd_common  endp
  338. ;-----------------------------------------------------------------------
  339. ;
  340. ;       our strategy entry point
  341. our_strat       proc    far
  342. assume  cs:zseg,ds:nothing,es:nothing
  343. inc     cs:in_device_call               ;keep track of reentrancy
  344. jnz     reentering                      ;zero means first entry
  345. finish_strategy:
  346. mov     cs:word ptr user_reqblk,bx
  347. mov     cs:word ptr user_reqblk+2,es
  348. ret
  349. reentering:
  350. ;
  351. ; we need to save off the packet pointer for the re-entered
  352. ; call so it will still be valid when its execution continues.
  353. ; we use our semaphore as an index into a table which will 
  354. ; hold the saved packet
  355. push    di                              ;must preserve all regs
  356. push    es
  357. push    bx
  358. mov     di,cs:in_device_call            ;treat as index into table
  359. shl     di,1                            ;dword table
  360. shl     di,1
  361. les     bx,user_reqblk                  ;get re-entered packed
  362. mov     word ptr cs:user_save_reqblk[di],bx     ;save it in our table
  363. mov     word ptr cs:user_save_reqblk[di+2],es
  364. pop     bx
  365. pop     es
  366. pop     di
  367. jmp     short finish_strategy   
  368. our_strat       endp
  369. handle_reentrancy_exit:
  370. pop     word ptr far_call_address[2]
  371. pop     word ptr far_call_address
  372. pop     word ptr dd_header[2]
  373. pop     word ptr dd_header
  374. pop     word ptr cache_unit
  375. pop     word ptr flags_and_unit
  376. pop     word ptr original_unit
  377. ;
  378. ; we need to save off the packet pointer for the re-entered
  379. ; call so it will still be valid when its execution continues.
  380. ; we use our semaphore as an index into a table which will 
  381. ; hold the saved packet
  382. push    di                              ;must preserve all regs
  383. push    es
  384. push    bx
  385. mov     di,cs:in_device_call            ;treat as index into table
  386. shl     di,1                            ;dword table
  387. shl     di,1
  388. mov     bx,word ptr user_save_reqblk[di]
  389. mov     es,word ptr user_save_reqblk[di+2]
  390. mov     word ptr user_reqblk,bx
  391. mov     word ptr user_reqblk[2],es
  392. pop     bx
  393. pop     es
  394. pop     di
  395. jmp     dont_restore_stack
  396. handle_reentrancy_enter:
  397. push    word ptr original_unit
  398. push    word ptr flags_and_unit
  399. push    word ptr cache_unit
  400. push    word ptr dd_header
  401. push    word ptr dd_header[2]
  402. push    word ptr far_call_address
  403. push    word ptr far_call_address[2]
  404. jmp     short skip_stack_swap
  405. ;-----------------------------------------------------------------------
  406. ;
  407. ;       This is it!  This is when DOS is trying to call a device
  408. ;         driver.  We intercept the call, and decide if it is something
  409. ;         that can be:
  410. ;
  411. ;               A) saved away into the cache
  412. ;            or B) gotten from the cache
  413. ;            or C) some combination of A & B
  414. ;
  415. ;       Entry:  our parameter block was saved in user_reqblk by
  416. ;               a call to the previous routine
  417. ;
  418. ;       Exit:   We'll try to satisfy the request and make sure we
  419. ;               fill in the status word of the request block before returning.
  420. ;
  421. ;       Trashed: We should preserve ALL registers, but we trash ax, bx & es
  422. ;                BUGBUG -- will ANYBODY ever care about ax, bx & es here?
  423. ;                          we leave es:[bx] pointing at the original req pkt.
  424. ;                Flags including direction
  425. our_int proc    far
  426. assume  cs:zseg,ds:nothing,es:nothing
  427. push    ds              ; save caller's ds
  428. push    cs
  429. pop     ds
  430. assume  ds:zseg         ; make our data quickly addressable
  431. inc     in_bambi        ; make sure we aren't reentered
  432. ;       if there are no hw stacks, we may be the straw that breaks
  433. ;       the stack, so we have to switch to our own stack to ensure
  434. ;       no stack overflow problems
  435. cmp     in_device_call,0
  436. jne     handle_reentrancy_enter
  437. mov     save_stack_ss,ss        ;save the current stack 
  438. mov     save_stack_sp,sp        ;context
  439. push    cs                      ;and switch to our own
  440. pop     ss                      ;internal stack
  441. mov     sp,offset resident_stack
  442. skip_stack_swap:
  443. push    bp                      ; we ALWAYS need these registers saved
  444. push    dx
  445. push    cx
  446. push    es
  447. push    bx
  448. push    di
  449. push    si
  450. ;       We must find the device header and unit number for the
  451. ;       drive number in the request block.  The unit number code
  452. ;       also has a couple of flag bits in it which indicate what
  453. ;       level of caching is enabled for this drive.
  454. les     bx,user_reqblk          ;es:bx points to request packet
  455. mov     al,byte ptr es:[bx].requnit 
  456. mov     original_unit,al        ; save original unit code
  457. call    lookup_device           ; remap unit code, get dev header
  458. xor     al,0c0h                 ; flip the 'active' bits
  459. mov     flags_and_unit,al       ; save flags and unit
  460. and     al,3fh                  ; mask off high bits 
  461. mov     cache_unit,al
  462. mov     word ptr dd_header,dx   ; save actual device header
  463. mov     word ptr dd_header[2],bp
  464. ;       done setting up packet structure, its off to the races!
  465. cmp     queuelength,0   ;even if caching is enabled for a drive
  466. je      just_pass_thru  ;the queue size could be zero, so
  467. ;be sure there is a non-zero cache present
  468. test    flags_and_unit,0c0h     ; any caching enabled?
  469. jnz     this_drive_is_cached    ; if any caching, enter main module
  470. just_pass_thru:
  471. push    si
  472. call    call_dd                 ; call through to device driver
  473. pop     si
  474. return_to_caller:
  475. jmp     go_back_to_dos
  476. ;       The code below will branch back up here if the operation is
  477. ;         a media check for a cached drive.  We must note the return
  478. ;         code before returning in this case so that we can invalidate
  479. ;         the cache on a media change.
  480. do_media_check:
  481. push    si
  482. call    call_dd
  483. pop     si
  484. cmp     BYTE PTR es:[bx].14,1
  485. je      return_to_caller
  486. ;;;the following code notifies windows that the media for
  487. ;;;this drive has changed.  While mutlitasking dos boxes,
  488. ;;;windows has to maintain the CDS state but can get 
  489. ;;;confused when the media changes. This notification will
  490. ;;;ensure that windows keeps track of disk changes correctly
  491. ;;;code courtesy of aaronr
  492. xor     di,di
  493. mov     es,di
  494. mov     bx,15h                  ;dosmgr device id
  495. mov     ax,1684h                ;get device api entry point
  496. int     2fh
  497. mov     ax,es
  498. or      ax,di
  499. jz      nobodytonotify
  500. push    bp
  501. mov     bp,sp
  502. push    es
  503. push    di
  504. mov     ax,5h                   ;media change detected
  505. mov     bl,original_unit        ;zero based drive number
  506. call    dword ptr [bp-4]        ;change detected on a=0,b=1...
  507. ;
  508. ;Carry is clear if media change processed. Carry set if invalid
  509. ;  drive passed in BL (drive is not in use, is out of range, is
  510. ;  a network drive).
  511. ;
  512. pop     ax                      
  513. pop     ax
  514. pop     bp
  515. nobodytonotify:
  516. call    reset_drive_stuff
  517. xor     bh,bh                   ;cause the bpb to be re-read next access
  518. mov     bl,original_unit
  519. shl     bx,1
  520. mov     word ptr secsize_and_align_info[bx],0ffffh
  521. mov     selected_drive,-1
  522. jmp     go_back_to_dos
  523. handle_get_bpb:
  524. call    reset_drive_stuff
  525. jmp     short not_get_bpb       
  526. ;       We now know we're operating on a cached drive.  We have to
  527. ;       look at the function number to decide what to do next.
  528. this_drive_is_cached:
  529. cmp     es:[bx].reqfunc,devrd   ; read, write, writev == go do it
  530. je      cache_this_readwrite
  531. cmp     es:[bx].reqfunc,devwrt
  532. je      cache_this_readwrite
  533. cmp     es:[bx].reqfunc,devwrtv
  534. je      cache_this_readwrite
  535. cmp     es:[bx].reqfunc,1
  536. je      do_media_check          ; watch return code from media check
  537. cmp     es:[bx].reqfunc,2
  538. je      handle_get_bpb
  539. not_get_bpb:
  540. cmp     es:[bx].reqfunc,genioctl ; certain genioctls require
  541. jnz     just_pass_thru          ; that we invalidate our cache
  542. mov     ax,word ptr es:[bx].majorfunction
  543. cmp     ax,6008h                ;dont trap get bpb
  544. je      just_pass_thru_short
  545. cmp     ax,6608h                
  546. jae     just_pass_thru_short
  547. call    reset_drive_stuff
  548. just_pass_thru_short:
  549. jmp     just_pass_thru  
  550. ;       We've now qualified this operation substantially.  We know that
  551. ;       the request was a read, write, or write w/verify on a drive that
  552. ;       we are caching.  Furthermore, the cache is not zero-length and
  553. ;       it isn't a Win 3.1 swap file access.
  554. cache_this_readwrite:
  555. mov     al,es:[bx].0dh                  ; use correct media id
  556. mov     media_id,al
  557. mov     al,es:[bx]                      ; use correct packet size
  558. mov     packet_size,al
  559. cld                     ; allow our internals to assume direction
  560. ;       have we changed drives from last time?
  561. mov     al,original_unit        ; no need to recalculate constants
  562. cmp     al,selected_drive       ; on repeated accesses to the same
  563. jz      constants_already_valid ; drive
  564. ;       setup the relevant constants for this drive
  565. mov     selected_drive,al
  566. call    get_drive_info
  567. mov     byte ptr cache_align_factor,ch  ; save cache align factor
  568. mov     byte ptr cache_block_shift,cl   ; save shift factor
  569. push    bx
  570. xor     bh,bh
  571. mov     bl,original_unit
  572. mov     al,media_id
  573. mov     byte ptr media_ids[bx],al
  574. mov     al,packet_size
  575. mov     byte ptr packet_sizes[bx],al
  576. pop     bx
  577. mov     ax,cache_block_bytes            ; get sector size
  578. shr     ax,cl
  579. mov     sector_size_bytes,ax
  580. mov     al,1
  581. shl     al,cl
  582. mov     byte ptr cache_block_sectors,al ; get number of secs / cache block
  583. ;       Now we have to generate a mask with one bit per sectors/blk
  584. mov     cl,al
  585. mov     ax,1
  586. shl     ax,cl
  587. dec     ax                      ; get one bit per sector in this block
  588. mov     cache_mask,ax           ; and save the mask
  589. constants_already_valid:
  590. ;
  591. ;       When we come here, we know that variables like sector_size_bytes
  592. ;       and cache_block_sectors are set correctly to their values for the
  593. ;       drive for this operation.  The caller's registers have mostly been
  594. ;       saved on the stack.  It is time to go to work.
  595. mov     ax,es:[bx.count]        ; copy count & transfer address to
  596. mov     d_count,ax              ; local temporary variables
  597. mov     ax,es:word ptr [bx.trans]
  598. mov     word ptr d_trans,ax
  599. mov     ax,es:word ptr [bx.trans+2]
  600. mov     word ptr d_trans+2,ax
  601. mov     ax,es:[bx.start]        ; get 16-bit block number
  602. xor     dx,dx
  603. ;       We must look at our device header (original copy) to see
  604. ;         if we should support 32 bit sector numbers.
  605. push    es
  606. push    bx
  607. les     bx,dd_header
  608. test    es:byte ptr [bx.4],2    ; 32-bit capable device?
  609. pop     bx
  610. pop     es
  611. jz      use_16_bit_blocknum
  612. cmp     dos_3x,0
  613. je      notdos3x
  614. cmp     byte ptr es:[bx],24     ;compaq's 24 byte packet?
  615. jne     use_16_bit_blocknum
  616. mov     dx,es:[bx.start.2]      ;get second part of 32-bit offset
  617. jmp     short use_16_bit_blocknum
  618. notdos3x:
  619. cmp     ax,-1                   ; for 32 bit block numbers, the
  620. jnz     use_16_bit_blocknum     ;  low 16 should be -1
  621. mov     dx,es:[bx.start_h]      ; get high part
  622. mov     ax,es:[bx.start_l]      ; get 32-bit block number
  623. use_16_bit_blocknum:
  624. ;       We now have dx:ax == the starting sector for this I/O.  Let's
  625. ;       figure out which cache block contains that sector, and what the
  626. ;       sector offset within that cache block is
  627. ;       cmp     es:byte ptr [bx.1],1            ; drive b:
  628. ;       jnz     no_bkpt
  629. ;       cmp     ax,0b10h
  630. ;       jb      no_bkpt
  631. ;
  632. ;       int     3
  633. ;
  634. ;no_bkpt:
  635. add     ax,cache_align_factor   ; adjustment factor attempts to align
  636. adc     dx,0                    ;  cache blocks with FAT clusters
  637. mov     cx,cache_block_shift
  638. push    ax                      ; save the low bits
  639. ;       The following is a fast 32-bit shift right.     It will be used
  640. ;       elsewhere in this program without the timing documentation.
  641. ;       WARNING: assumes CL <=16!
  642. mov     di,0FFFFh ;2 clks 3bytes   set up to make a mask
  643. ror     dx,cl   ;3,       2bytes   low bits of dx set to final bit position
  644. shr     ax,cl   ;3,       2bytes   low bits of ax set to final bit position
  645. shr     di,cl   ;3,       2bytes   the mask should just cover low bits in dx
  646. mov     cx,dx   ;2,       2bytes   save off dx (we still need high bits)
  647. and     dx,di   ;2,       2bytes   mask off the high bits of dx--dx is is done
  648. not     di      ;2,       2bytes   invert mask so we can get high bits for ax
  649. and     cx,di   ;2,       2bytes   mask just covers the high bits
  650. or      ax,cx   ;2        2bytes   or the high bits into ax--ax is done
  651. ;= 21 clocks total (386),19 bytes
  652. mov     curblk_l,ax             ; store the cache block number of
  653. mov     curblk_h,dl             ;  the 1st sector in a temp. variable
  654. pop     ax                      ; get low bits (modulo)
  655. mov     ah,byte ptr cache_block_sectors
  656. dec     ah                      ; generate a mask for secs/blk
  657. and     al,ah                   ; extract the partial block size
  658. mov     byte ptr curblk_index,al ; save index within cache block
  659. cmp     es:[bx.reqfunc],devrd   ; reading?
  660. jnz     do_writes               ; assume all other functions are writes
  661. call    cache_reads             ; use a subroutine for the read loop
  662. jmp     short common_exit
  663. do_writes:
  664. call    cache_write_data        ;  write it, cache if appropriate
  665. common_exit:
  666. go_back_to_dos:
  667. pop     si
  668. pop     di
  669. pop     bx
  670. pop     es
  671. pop     cx                      ; restore 1st tier of saved regs
  672. pop     dx
  673. pop     bp
  674. cmp     in_device_call,0
  675. jne     handle_reentrancy_exit_near
  676. mov     ss,save_stack_ss        ;restore stack
  677. mov     sp,save_stack_sp
  678. dont_restore_stack:
  679. dec     in_bambi                ; free device_driver resource
  680. dec     in_device_call          ;keep track of reentrancy
  681. cmp     commit_all_when_ok,0    ;now is a good time to determine if
  682. jne     must_commit_all         ;some asynch event (ctrl+alt+delete)
  683. ;requires us to commit all 
  684. continue_returntodos:
  685. pop     ds                      ; restore caller's ds
  686. assume  ds:nothing
  687. ret                             ; back to DOS (or last hooker)
  688. must_commit_all:
  689. call    write_behind_cache
  690. jmp     short continue_returntodos
  691. handle_reentrancy_exit_near:
  692. jmp     handle_reentrancy_exit
  693. our_int endp
  694. ;-----------------------------------------------------------------------
  695. ;
  696. ;       This routine is used when a media_change or an IOCTL forces
  697. ;       us to invalidate our information about a given drive so that
  698. ;       we are forced to re-read it.
  699. ;
  700. reset_drive_stuff       proc    near
  701. assume  cs:zseg,ds:zseg,es:nothing
  702. mov     num_valid_buffers,0     ; invalidate supercache
  703. push    ax                      ;flush the cache and invalidate
  704. push    bx
  705. push    cx
  706. push    dx
  707. push    bp
  708. push    si
  709. push    di
  710. push    es
  711. call    commit_all_dirty
  712. call    flush_queue
  713. pop     es
  714. pop     di
  715. pop     si
  716. pop     bp
  717. pop     dx
  718. pop     cx
  719. pop     bx
  720. pop     ax
  721. ret
  722. reset_drive_stuff       endp
  723. ;-----------------------------------------------------------------------
  724. ;
  725. ;       Come here when we have a read operation on a cached drive.
  726. ;       The block number and index within the first block have already
  727. ;       been setup by the common entry code.
  728. ;
  729. ;       The basic idea is that we break the read down into:
  730. ;
  731. ;          First partial (non-cache-block aligned sectors on front)
  732. ;          Full cache blocks
  733. ;          Last partial (cache-block aligned, but we don't need it all)
  734. xno_partial_on_front: jmp no_partial_on_front   ; make short branch reach
  735. cache_reads     proc    near
  736. assume  cs:zseg,ds:zseg,es:nothing
  737. cmp     byte ptr curblk_index,0 ; partial block at the front?
  738. jz      xno_partial_on_front    ;  skip if not
  739. call    check_supercache_match  ; if we're lucky, the data we want
  740. ;  is already in our RAM buffer and
  741. ;  we won't even have to hit XMS
  742. jnc     no_supercache_in_partial ; Skip if we weren't lucky
  743. ;       the block we need part of is already in the cache, copy to
  744. ;         user's buffer.  Note:  si has already been setup (pointing
  745. ;         to the target block in the supercache) and must not be trashed.
  746. call    first_partial_setup     ; get sector count, set es:di for move
  747. push    ax                      ; save # sectors
  748. mov     ax,curblk_index         ; get offset within block
  749. mul     sector_size_bytes
  750. add     si,ax                   ; point to correct source in supercache
  751. pop     ax
  752. mul     sector_size_bytes
  753. mov     cx,ax
  754. shr     cx,1                    ; convert to words
  755. mov     ds,lb_seg
  756. assume  ds:nothing
  757. ;       ds:si -> desired sector in supercache (our local RAM buffer)
  758. ;       es:di -> user's transfer address
  759. ;       cx    =  length of this transfer in words
  760. ;       ax    =  length of this transfer in bytes
  761. rep     movsw                   ; move to user's buffer
  762. push    cs
  763. pop     ds
  764. assume  ds:zseg                 ; restore addressability
  765. jmp     short next_read_block   ; update transfer, curblk, and continue
  766. ;       We're still trying to satisfy our first partial, but it wasn't
  767. ;       in the supercache.  Our next best bet is our REAL cache.
  768. no_supercache_in_partial:
  769. call    check_hit               ; see if we hit on curblk
  770. jnz     partial_was_a_hit       ;  skip if that block is present
  771. ;       the block we need isn't in cache!  We've got to hit the disk,
  772. ;         and while we're at it, we'll stick it into the cache for
  773. ;         future use.
  774. mov     cx,1                    ; just get one block
  775. call    get_curblks_into_cache  ; get the curblk into local buf
  776. ;                                       ;  and cache it!
  777. jnc     frst_prt_rdok           ; done if no disk read error
  778. ;       we couldn't read the whole block.  Now we'd better try to
  779. ;         read just the part the user wanted directly into his buffer
  780. ;         before we decide to bomb out and report an error.
  781. call    first_partial_setup     ; get es:di -> dma addr, ax=count
  782. push    ax                      ; save count
  783. mov     ah,al                   ; get count into ah
  784. mov     al,byte ptr curblk_index ; get sector within block
  785. call    read_part_curblk_from_disk
  786. pop     dx                      ; restore count into dx to preserve
  787. ; error code in ax
  788. jc      xgot_fatal_error        ; bomb out if fatal disk error
  789. ;       lucky us!  the read error was in another part of the
  790. ;       block, or, the retry was sufficient to get the data.
  791. mov     ax,dx                   ; get count just xferred
  792. mul     sector_size_bytes       ; get amount to bump xfer addr by
  793. jmp     short next_read_block
  794. xgot_fatal_pop2:                        ; BUG1 - adjust stack & exit if error
  795. add     sp,4                    ; BUG1 - pop 2 entries off stack
  796. xgot_fatal_error:       jmp     got_fatal_error ; make short branch reach
  797. ;       We've got the first partial read and cached.  Now pass it
  798. ;       back to the caller.
  799. frst_prt_rdok:
  800. call    first_partial_setup     ; setup for partial block
  801. mul     sector_size_bytes       ; get byte count for transfer
  802. mov     cx,ax
  803. shr     cx,1                    ; convert to words
  804. push    ax                      ; preserve the byte count in ax
  805. mov     ax,curblk_index         ; get starting index
  806. mul     sector_size_bytes
  807. lds     si,local_buf
  808. assume  ds:nothing
  809. add     si,ax
  810. rep     movsw                   ; move the sectors
  811. pop     ax
  812. push    cs
  813. pop     ds
  814. assume  ds:zseg                 ; restore addressability
  815. jmp     short next_read_block
  816. x_do_last_partial:      jmp     do_last_partial ; bridge for short jumps
  817. ;       the block we need part of is already in the cache, copy to
  818. ;         user's buffer.
  819. partial_was_a_hit:
  820. call    first_partial_setup
  821. push    ax                      ; save # sectors
  822. mov     ah,byte ptr curblk_index ; get al blocks, starting here
  823. ifdef   USE_VALID
  824. push    ax
  825. call    make_sure_sectors_are_valid     ; if valid_bits not set,
  826. ;                                               ;  this routine will read the
  827. ;                                               ;  whole block and make sure
  828. ;                                               ;  it's all valid.
  829. jc      xgot_fatal_pop2                 ; BUG1 exit if error reading
  830. pop     ax
  831. endif
  832. mov     bp,cache_element_index
  833. les     di,d_trans
  834. call    read_part_cache_block   ; read from cache into user buffer
  835. pop     ax                      ; restore sector count
  836. mul     sector_size_bytes
  837. ;//////////////////////////////\\\\\\\\\\\\\\\
  838. ;\\\\\\\\\\\\\\\///////////////////////////////
  839. ;       This is the main READ loop.  We come back here after successfully
  840. ;       completing the first partial or any full blocks.  AX has the number
  841. ;       of bytes just transferred, and will be added to the transfer address.
  842. ;       curblk is also incremented.
  843. next_read_block:
  844. add     word ptr d_trans,ax     ; update transfer address
  845. add     curblk_l,1              ; move to next block
  846. adc     curblk_h,0
  847. ;       Now we're block aligned.  Complete any remaining full blocks first.
  848. no_partial_on_front:
  849. mov     ax,cache_block_sectors
  850. cmp     ax,d_count              ; do we need a full block?
  851. ja      x_do_last_partial
  852. sub     d_count,ax              ; count it down
  853. call    check_supercache_match  ; did we match in supercache?
  854. jnc     no_full_block_supercache_hit
  855. ;       copy the block from supercache
  856. les     di,d_trans              ; get user buffer
  857. mov     cx,cache_block_words    ; move one full cache block
  858. mov     ds,lb_seg               ; si set by check_supercache_match
  859. assume  ds:nothing
  860. rep     movsw                   ; move from supercache
  861. push    cs
  862. pop     ds
  863. assume  ds:zseg                 ; restore addressability
  864. mov     ax,cache_block_bytes    ; size for updating pointer
  865. jmp     short next_read_block
  866. no_full_block_supercache_hit:
  867. ;       No supercache match on full cache block.  Our next best bet
  868. ;       is the REAL cache.
  869. call    check_hit               ; is curblk in cache?
  870. jz      full_nohit              ; brif not
  871. ifdef   USE_VALID
  872. mov     ax,cache_mask           ; make sure it is valid
  873. call    make_sure_sectors_are_valid_mask
  874. jc      zgot_fatal_error        ; BUG1 -- exit if read error!
  875. endif
  876. les     di,d_trans              ; get user buffer
  877. mov     bp,cache_element_index
  878. call    read_full_cache_block   ;  read the whole cached block
  879. mov     ax,cache_block_bytes    ; size for updating pointer
  880. jmp     next_read_block
  881. zgot_fatal_error:                       ; BUG1 -- error exit bridge
  882. jmp     got_fatal_error         ; BUG1
  883. ;       block not in cache.  Figure out how many contiguous nohits
  884. ;         there are in the data we need, and read them all, then
  885. ;         transfer them all into the cache at once.
  886. full_nohit:
  887. mov     ax,curblk_l
  888. mov     dl,curblk_h             ; get last block number
  889. xor     cx,cx                   ; init block needed count
  890. mov     bx,d_count              ; we need this many more sectors
  891. count_nohit_loop:
  892. inc     cx                      ; count blocks needed
  893. sub     bx,cache_block_sectors  ;  do we need another full block?
  894. jb      we_know_how_many_nohits
  895. add     ax,1                    ; point to next block
  896. adc     dl,0
  897. push    ax
  898. push    bx
  899. push    cx
  900. push    dx
  901. call    check_hit_in_regs       ; do we need to read next block?
  902. pop     dx
  903. pop     cx
  904. pop     bx
  905. pop     ax
  906. jz      count_nohit_loop        ; just keep looping while no hits
  907. we_know_how_many_nohits:
  908. ;       now cx tells us how many blocks we need to read from disk
  909. ;           bx is the number of remaining sectors after the contig nohits
  910. ;       Okay, then.  Let's jam directly on the user's buffer.
  911. cant_fit_more_in_localbuf:
  912. les     di,d_trans              ; get user buffer
  913. push    cx                      ; save number of blks for caching loop
  914. mov     ax,cx                   ; get count of blocks
  915. call    read_curblks_from_disk  ; read that sucker
  916. pop     cx
  917. jc      got_fatal_error         ; error out!  We NEED those blocks
  918. ;                                       ;  to succeed this call!
  919. ;       adjust d_count to reflect multiple blocks transferred
  920. mov     ax,cx                   ; we know this is at least one
  921. dec     ax
  922. mul     cache_block_sectors
  923. sub     d_count,ax
  924. ;       Now we've got to copy all of that shit into the cache
  925. les     di,d_trans              ; point to buffer
  926. push    es                              ;check if this is a 
  927. les     si,accessing_swap_file_ptr      ;swapfile access, if so
  928. cmp     byte ptr es:[si],0              ;dont cache it
  929. pop     es
  930. jne     skip_cache_em
  931. cache_em:
  932. push    cx
  933. push    di
  934. xor     cx,cx                   ; none of it is dirty!!!
  935. ifdef   USE_VALID
  936. mov     bx,cache_mask           ; all valid
  937. endif
  938. call    create_cache_block      ; **** create the block^
  939. pop     di
  940. push    di
  941. call    write_full_cache_block
  942. add     curblk_l,1
  943. adc     curblk_h,0
  944. pop     di
  945. pop     cx
  946. add     di,cache_block_bytes
  947. loop    cache_em
  948. done_cache_em:
  949. mov     word ptr d_trans,di     ; update d_trans
  950. ;       **** Note:  We're branching all of the way back here so
  951. ;            we can test for the case where we've done with all
  952. ;            of the full blocks.  A potential speed optimization
  953. ;            would be to duplicate the test here, and not bother
  954. ;            looking up the next block if there is another one.
  955. ;            In that case, we already know it is a hit.  The
  956. ;            block number would have to be saved above in this
  957. ;            case.
  958. jmp     no_partial_on_front
  959. skip_cache_em:
  960. add     curblk_l,1
  961. adc     curblk_h,0
  962. add     di,cache_block_bytes
  963. loop    skip_cache_em
  964. jmp     short   done_cache_em
  965. ;       pass read error condition back to caller.
  966. got_fatal_error:
  967. les     bx,user_reqblk
  968. mov     es:[bx.reqstat],ax       ; pass error code back to caller
  969. mov     es:word ptr [bx.count],0 ; no sectors complete
  970. ret
  971. ;       d_count is now less than a full cache block
  972. ;         we are cache block aligned
  973. do_last_partial:
  974. cmp     d_count,0               ; *IS* there a partial?
  975. jz      reading_done            ;  skip if not
  976. call    check_supercache_match
  977. jc      last_partial_moveit     ; just move it from supercache if so
  978. ;       last partial not in supercache.  Try regular cache next.
  979. call    check_hit               ; is last block in cache?
  980. jz      need_to_read_last_partial
  981. ;       Got it in regular cache!
  982. ifdef   USE_VALID
  983. mov     ax,d_count              ; ah=0, al=sectors we need
  984. call    make_sure_sectors_are_valid ; make sure they're valid
  985. jc      got_fatal_error         ; BUG1 fatal exit if read error
  986. endif
  987. mov     ax,d_count              ; starting with zero, read d_count
  988. les     di,d_trans
  989. mov     bp,cache_element_index
  990. call    read_part_cache_block   ; read it from cache
  991. jmp     short reading_done      ;  done!  exit okay!
  992. ;       We've gotta hit the disk.  Maybe we'll do a readahead too.
  993. need_to_read_last_partial:
  994. call    readahead_check         ; should we readahead?
  995. mov     cx,1                    ; just read this one block if we're
  996. ;                                       ;  not sequential from last time
  997. jnz     last_partial_no_readahead
  998. mov     cx,max_valid_buffers    ; read/cache this many blocks if seq.
  999. last_partial_no_readahead:
  1000. call    get_curblks_into_cache  ; get those suckers into cache
  1001. jnc     last_partial_readok     ; done if no read error
  1002. ;       read error.  We'd better try reading just exactly what the
  1003. ;         user requested.
  1004. mov     ah,byte ptr d_count     ; get count
  1005. xor     al,al                   ; start reading from front of block
  1006. les     di,d_trans
  1007. call    read_part_curblk_from_disk
  1008. jnc     reading_done            ; done if read ok!!!
  1009. jmp     got_fatal_error         ; fatal error if disk read error
  1010. last_partial_readok:
  1011. mov     si,word ptr local_buf   ; we know the data is in the
  1012. ;  front of the local_buf
  1013. ;       We will enter here when we're moving the data out of the
  1014. ;       supercache.
  1015. last_partial_moveit:
  1016. mov     ax,d_count
  1017. mul     sector_size_bytes
  1018. mov     cx,ax                   ; copy this many
  1019. shr     cx,1                    ; convert to words
  1020. les     di,d_trans
  1021. mov     ds,lb_seg
  1022. assume  ds:nothing
  1023. rep     movsw
  1024. push    cs
  1025. pop     ds                      ; restore addressability
  1026. assume  ds:zseg
  1027. reading_done:
  1028. mov     ax,curblk_l
  1029. mov     lastblk_l,ax            ; copy curblk to lastblk
  1030. mov     al,curblk_h
  1031. mov     lastblk_h,al
  1032. readwrite_done:
  1033. les     bx,user_reqblk
  1034. mov     es:[bx.reqstat],100h    ; normal completion
  1035. ret                             ; no error checking for now
  1036. cache_reads     endp
  1037. ;-----------------------------------------------------------------------
  1038. ;
  1039. ;       subroutine to check to see if curblk is just past lastblk;
  1040. ;         this condition is used during a read of anything besides
  1041. ;         a first partial, to trigger readahead.  Zero is set
  1042. ;         when (curblk-1) == lastblk
  1043. ;
  1044. ;       ****Note:  For now, we'll also return zero when curblk==lastblk.
  1045. ;           Depending on the exact exit path taken, lastblk may or may not
  1046. ;           be updated to point past the end of the previous read.
  1047. ;
  1048. ;       trashes ax, cl
  1049. readahead_check proc    near
  1050. assume  cs:zseg,ds:zseg,es:nothing
  1051. mov     ax,curblk_l
  1052. mov     cl,curblk_h
  1053. sub     ax,lastblk_l
  1054. sbb     cl,lastblk_h
  1055. and     al,0feh         ; was result 0 or 1?
  1056. or      al,ah
  1057. or      al,cl           ; set zero flag if so
  1058. ret
  1059. readahead_check endp
  1060. ifdef   USE_VALID
  1061. ;-----------------------------------------------------------------------
  1062. ;
  1063. ;       make sure that the currently needed sectors of the current
  1064. ;         block are indeed valid.  If not, we've gotta read the
  1065. ;         whole block and mark it valid.
  1066. ;
  1067. ;       Entry:  ah=first sector we need, al=number of sectors we need
  1068. ;       Exit:   carry set if we had a read error
  1069. ;               ax == error code if carry set   BUG1
  1070. ;
  1071. ;       Trashes:  all
  1072. make_sure_sectors_are_valid     proc    near
  1073. assume  cs:zseg,ds:zseg,es:nothing
  1074. mov     cx,ax                   ; get our counts into cx
  1075. mov     ax,1
  1076. shl     ax,cl                   ; get one bits for each of ours
  1077. dec     ax
  1078. mov     cl,ch                   ; now shift that for starting place
  1079. shl     ax,cl
  1080. make_sure_sectors_are_valid     endp    ; fall into similar routine w/ mask
  1081. ;-----------------------------------------------------------------------
  1082. ;
  1083. ;       make sure that the sectors in the currently looked-up cache
  1084. ;        block whose mask is in ax are valid.  Otherwise, we've got
  1085. ;        to force the whole damn cache block to be valid.
  1086. ;
  1087. ;       Entry:  ax == mask of sectors required from this block
  1088. ;       Exit:   carry set if we had a read error
  1089. ;               ax == error code if carry set BUG1
  1090. ;
  1091. ;       Trashes:  all
  1092. make_sure_sectors_are_valid_mask        proc    near
  1093. assume  cs:zseg,ds:zseg,es:nothing
  1094. log_it  0               ; tracker:  bambi type zero
  1095. mov     cx,valid_mask           ; here is what's valid
  1096. not     cx
  1097. and     cx,ax                   ; were any of our 1 bits zero bits?
  1098. jnz     make_cache_block_valid
  1099. clc                             ; return with no error
  1100. ret
  1101. make_cache_block_valid:
  1102. log_it  1               ; tracker:  bambi type one
  1103. mov     num_valid_buffers,0     ; invalidate supercache
  1104. les     di,local_buf
  1105. mov     ax,1                    ; block count
  1106. push    cx                      ; BUG1 -- save mask of needed sectors
  1107. call    read_curblks_from_disk  ; read it into buffer
  1108. pop     cx                      ; BUG1 -- restore mask of needed secs
  1109. jc      make_cache_readerror    ; skip if read error!!!!
  1110. log_it  2               ; tracker:  time stamp reading done
  1111. ;       Now we've got to copy only the NON-DIRTY sectors into
  1112. ;       the cache, so that we don't replace data that hasn't yet
  1113. ;       made it onto the disk.
  1114. mov     cx,dirty_mask
  1115. not     cx                      ; get NON-DIRTY bits
  1116. and     cx,cache_mask
  1117. xor     ah,ah                   ; ah=0 (sector zero)
  1118. ;       Here we will assume CX != 0.  If all of the bits in
  1119. ;       that block were DIRTY, they would also have to be VALID
  1120. ;       and we'd never be here in the first place.
  1121. find_one_to_copy:
  1122. inc     ah                      ; count it
  1123. shr     cx,1
  1124. jnc     find_one_to_copy        ; bypass clean block
  1125. dec     ah                      ; this is the sector number
  1126. xor     al,al                   ; count=1+number of contig ones in cl
  1127. find_number_to_copy:
  1128. inc     al
  1129. shr     cx,1
  1130. jc      find_number_to_copy     ; loop while we find more ones
  1131. shl     cx,1                    ; put a zero bit back
  1132. push    cx                      ; save mask
  1133. push    ax                      ; save count
  1134. mov     al,ah                   ; get starting sector
  1135. xor     ah,ah
  1136. mul     sector_size_bytes
  1137. les     di,local_buf            ; find location in disk buffer
  1138. add     di,ax
  1139. pop     ax                      ; restore count
  1140. push    ax                      ; save count again
  1141. mov     bp,cache_element_index
  1142. call    write_part_cache_block  ; write into cache
  1143. pop     ax
  1144. pop     cx                      ; restore continuing mask
  1145. log_it  3               ; tracker: xms written
  1146. add     ah,al                   ; update sector number
  1147. or      cx,cx
  1148. jnz     find_one_to_copy
  1149. mov     bx,cache_mask           ; valid == all
  1150. mov     valid_mask,bx
  1151. mov     cx,dirty_mask
  1152. mov     bp,cache_element_index
  1153. call    set_dirtyindex          ; mark it all valid
  1154. clc
  1155. ret                             ; return with carry set if error
  1156. ;       BUG1 -- BEGIN NEW CODE!!!!!
  1157. ;        -- the following error exit was totally messed up
  1158. ;               in the Win 3.1 version of this code, causing
  1159. ;               potential data loss in this case of bad adjacent blocks.
  1160. ;       
  1161. ;        the block we need is only partially valid, but trying
  1162. ;        the usual technique of making the whole thing valid
  1163. ;        won't work because there are bad sectors in the block.
  1164. ;        We must try to read exactly the missing sectors we
  1165. ;        need.  If this succeeds, we'll stick them in the
  1166. ;        cache, otherwise, we'll bomb out with a fatal error.
  1167. make_cache_readerror:
  1168. ;       Here is the old, wrong code.
  1169. ;BUG1   mov     bp,cache_element_index
  1170. ;BUG1   call    invalidate_element
  1171. ;BUG1   stc                             ; return error condition, ax == code
  1172. ;BUG1   ret
  1173. push    cx                      ; save mask of new sectors to read
  1174. xor     ah,ah                   ; ah=0 (sector zero)
  1175. ;       Here we will assume cx != 0, because it is the mask of
  1176. ;       sectors we need which are not valid in the cache.
  1177. find_one_to_read:
  1178. inc     ah                      ; count it
  1179. shr     cx,1
  1180. jnc     find_one_to_read        ; bypass unneeded block
  1181. dec     ah                      ; this is the sector number
  1182. xor     al,al                   ; count=1+number of contig ones in cx
  1183. find_number_to_read:
  1184. inc     al
  1185. shr     cx,1
  1186. jc      find_number_to_read     ; loop while we find more ones
  1187. shl     cx,1                    ; put a zero bit back
  1188. push    cx                      ; save mask
  1189. push    ax                      ; save count
  1190. mov     al,ah                   ; get starting sector
  1191. xor     ah,ah
  1192. mul     sector_size_bytes
  1193. les     di,local_buf            ; find location in disk buffer
  1194. add     di,ax
  1195. pop     ax                      ; restore count
  1196. ;       Now we have to read those sectors into the buffer.
  1197. push    ax
  1198. xchg    ah,al                           ; swap count and start
  1199. push    es
  1200. push    di
  1201. call    read_part_curblk_from_disk      ; read the sectors we need
  1202. pop     di
  1203. pop     es
  1204. jc      make_sure_fatal_read_error      ; abort if error
  1205. pop     ax                      ; restore start sector and count
  1206. push    ax                      ; save count again
  1207. mov     bp,cache_element_index
  1208. call    write_part_cache_block  ; write into cache
  1209. pop     ax
  1210. pop     cx                      ; restore continuing mask
  1211. log_it  3                       ; tracker: xms written
  1212. add     ah,al                   ; update sector number
  1213. or      cx,cx
  1214. jnz     find_one_to_read
  1215. pop     ax                      ; get mask of sectors we just cached
  1216. or      valid_mask,ax
  1217. mov     bx,valid_mask
  1218. mov     cx,dirty_mask
  1219. mov     bp,cache_element_index
  1220. call    set_dirtyindex          ; mark new sectors valid
  1221. clc
  1222. ret                             ; return no carry, no error
  1223. make_sure_fatal_read_error:
  1224. add     sp,6                    ; get rid of count, running mask, and
  1225. ;                                       ;  overall mask of missing sectors
  1226. stc                             ; set error condition
  1227. ret                             ; and return with error code in ax
  1228. ;       BUG1 -- end of new code
  1229. make_sure_sectors_are_valid_mask        endp
  1230. endif                           ; ifdef USE_VALID
  1231. ;-----------------------------------------------------------------------
  1232. ;
  1233. ;       Now let's do a write function, caching any data that's
  1234. ;         appropriate.
  1235. cache_write_data        proc    near
  1236. assume  cs:zseg,ds:zseg,es:nothing
  1237. test    flags_and_unit,40h      ; should we delay writes?
  1238. jz      write_without_delay
  1239. if 1
  1240. push    es                              ;check if this is a 
  1241. les     si,accessing_swap_file_ptr      ;swapfile access, if so
  1242. cmp     byte ptr es:[si],0              ;dont cache it
  1243. pop     es
  1244. jne     write_without_delay
  1245. endif
  1246. jmp     short do_delayed_writes
  1247. ;       Writes are not delayed.  Just make sure it's all in the
  1248. ;         cache (except for first partial block with no hit), then
  1249. ;         pass it through to the driver and return the error.
  1250. write_without_delay:
  1251. mov     num_valid_buffers,0     ; invalidate supercache
  1252. cmp     byte ptr curblk_index,0 ; partial block at the front?
  1253. jz      wnodel_no_first_partial
  1254. ;       count is min (cache_block_sectors - curblk_index, d_count)
  1255. mov     ax,cache_block_sectors
  1256. sub     ax,curblk_index         ; how many left in block?
  1257. cmp     ax,d_count              ; do we want that many?
  1258. jb      wnodel_need_em_all      ; skip if so
  1259. mov     ax,d_count              ; only transfer what we need
  1260. wnodel_need_em_all:
  1261. push    ax                      ; save the count
  1262. call    check_hit               ; see if we hit on curblk
  1263. pop     ax                      ; restore count into ax!!!!
  1264. jz      wnodel_first_partial_common
  1265. ;       the partial block is in the cache.  Better copy in our data.
  1266. push    ax                      ; save sector count
  1267. les     di,d_trans              ; get disk transfer address
  1268. mov     ah,byte ptr curblk_index ; get first sector #
  1269. ;       Note:  al == transfer count
  1270. call    write_part_cache_block  ; copy partial block into cache
  1271. pop     ax                      ; restore sector count
  1272. ;       come here to update pointers after dealing with first partial
  1273. ;          block.  al == number of sectors in first partial
  1274. wnodel_first_partial_common:
  1275. sub     d_count,ax              ; keep track of count
  1276. mul     sector_size_bytes       ; bump transfer addr by this much
  1277. wnodel_write_next_block:
  1278. add     word ptr d_trans,ax     ; update transfer address
  1279. add     curblk_l,1              ; let's move to next block
  1280. adc     curblk_h,0
  1281. ;       Now we're block aligned.  Complete any full blocks first.
  1282. wnodel_no_first_partial:
  1283. mov     ax,cache_block_sectors
  1284. cmp     ax,d_count              ; do we need a full block?
  1285. ja      wnodel_last_partial     ; skip if no more full blocks
  1286. sub     d_count,ax              ; count it down
  1287. call    check_hit               ; is curblk in cache?
  1288. jz      wnodel_full_common
  1289. ;       We got a hit!  Must update cache!
  1290. les     di,d_trans              ; get user buffer
  1291. call    write_full_cache_block  ; write the whole block
  1292. wnodel_full_common:
  1293. mov     ax,cache_block_bytes    ; update pointer
  1294. jmp     wnodel_write_next_block
  1295. ;       d_count is now less than a full cache block
  1296. ;         we are cache block aligned
  1297. wnodel_last_partial:
  1298. cmp     d_count,0               ; *IS* there a partial?
  1299. jz      wnodel_done             ;  skip if not
  1300. call    check_hit               ; is last partial in cache?
  1301. jz      wnodel_done             ;  skip if not
  1302. les     di,d_trans
  1303. mov     ax,d_count              ; ah=0, al=count
  1304. call    write_part_cache_block  ;  copy that data into cache
  1305. ;       Now we've updated the cache to reflect our pending write.
  1306. ;         Go ahead and do the write, and let the device driver
  1307. ;         return the error code to the caller.
  1308. wnodel_done:
  1309. jmp     call_dd_ureqblk         ;  let dd set return code
  1310. ;       The writes are being delayed.  Just put everything into
  1311. ;         the cache with dirty bits set.
  1312. do_delayed_writes:
  1313. mov     num_valid_buffers,0     ;data may have been dupped in supercache
  1314. ;so invalidate supercache 
  1315. ;PARADOX BUG FIX 8/4/92 Scottq
  1316. cmp     byte ptr curblk_index,0 ; partial block at the front?
  1317. ifdef   USE_VALID
  1318. jz      no_partial_to_write
  1319. else
  1320. jnz     must_write_partial
  1321. jmp     no_partial_to_write
  1322. endif
  1323. ;       we need a mask with curblk_index (known non-zero) low bits
  1324. ;         clear, and 'count' bits set after that, counting from bit zero.
  1325. ;         This mask gives the bits which we'll have to set in dirty_bits.
  1326. must_write_partial:
  1327. ;       count is min (cache_block_sectors - curblk_index, d_count)
  1328. mov     cx,cache_block_sectors
  1329. sub     cx,curblk_index         ; how many left in block?
  1330. cmp     cx,d_count              ; do we want that many?
  1331. jb      xbsetup_need_em_all     ; skip if so
  1332. mov     cx,d_count              ; only transfer what we need
  1333. xbsetup_need_em_all:
  1334. mov     ax,1
  1335. shl     ax,cl                   ; now put in that many one bits
  1336. dec     ax                      ; convert to mask
  1337. push    cx                      ; save the count
  1338. mov     cl,byte ptr curblk_index
  1339. shl     ax,cl                   ; that many zero bits
  1340. push    ax                      ; save the mask
  1341. call    check_hit               ; see if we hit on curblk
  1342. pop     cx                      ; restore mask into cx!!!!
  1343. pop     ax                      ; restore count into ax!!!!
  1344. push    ax                      ; re-save sector count
  1345. ;       *****************************************************
  1346. ;       The following big chunk of code varies greatly between
  1347. ;       the USE_VALID version and otherwise, so it exists in
  1348. ;       two separate versions rather than riddling the code
  1349. ;       with ifdefs
  1350. ;       *****************************************************
  1351. ifdef   USE_VALID       ; for debugging, use other code
  1352. jnz     wr_partial_was_a_hit    ; brif we hit partial
  1353. ;                                       ; seed mask is in cx
  1354. mov     bx,cx                   ; only the ones we're writing will
  1355. ;                                       ;  be valid
  1356. call    create_cache_block
  1357. jmp     short wr_partial_common
  1358. wr_partial_was_a_hit:
  1359. or      cx,dirty_mask           ; or with previous mask
  1360. ifdef   USE_VALID
  1361. mov     bx,cx                   ; set all dirty_bits valid
  1362. or      bx,valid_mask
  1363. endif
  1364. call    set_dirtyindex
  1365. wr_partial_common:
  1366. ;       Note!  We've set the dirty_bits before we filled up the
  1367. ;              buffer.  Good thing we know the commit_cache function
  1368. ;              can't be running concurrently with this mainline code.
  1369. ;       copy from cache to local_buf
  1370. ;       ***  Note:  We really only have to copy the part of the block
  1371. ;                    that we're not replacing.
  1372. mov     bp,cache_element_index  ;setup cache block index
  1373. les     di,d_trans              ;get pointer to user data
  1374. pop     ax                      ;ax is now actual count
  1375. push    ax                      ;must restore later
  1376. sub     d_count,ax              ;update global sector count
  1377. mov     ah,byte ptr curblk_index;setup for next call
  1378. call    write_part_cache_block  ;write data to xms
  1379. mov     num_valid_buffers,0     ;data may have been dupped in supercache
  1380. ;so invalidate supercache
  1381. pop     ax                      ;restore count
  1382. mul     sector_size_bytes       ;adjust to bytes
  1383. ;       go write next block
  1384. else                    ; ndef USE_VALID
  1385. jnz     wr_partial_was_a_hit    ; brif we hit partial
  1386. ;                                       ; seed mask is in cx
  1387. ;       This non-USE_VALID code path may still be used during
  1388. ;       debugging, so it still has some USE_VALID logic in it
  1389. ifdef   USE_VALID
  1390. mov     bx,cache_mask           ; all valid for now
  1391. endif
  1392. call    create_cache_block      ;  filling up local_buf
  1393. ;       NOTE:  We really only need to read the first part of the block
  1394. les     di,local_buf
  1395. mov     ax,1
  1396. mov     num_valid_buffers,0     ; invalidate local_buf
  1397. call    read_curblks_from_disk  ; read it into buffer
  1398. jnc     wr_first_partial_common
  1399. ;       Shit!  read error.  Better invalidate block & bomb!
  1400. call    invalidate_cache_block
  1401. pop     ax                      ; get sector count to write
  1402. push    ax                      ; resave count
  1403. mov     ah,al                   ; count into ah
  1404. mov     al,byte ptr curblk_index        ; get starting sector
  1405. les     di,d_trans
  1406. call    write_part_curblk_to_disk
  1407. pop     dx                      ; restore sector count
  1408. jnc     write_first_partial_recover_ok
  1409. jmp     got_fatal_error
  1410. write_first_partial_recover_ok:
  1411. mov     ax,dx                   ; get number of sectors just written
  1412. mul     sector_size_bytes       ; get amount to increase d_trans by
  1413. jmp     short write_next_block
  1414. wr_partial_was_a_hit:
  1415. or      cx,dirty_mask           ; or with previous mask
  1416. ifdef   USE_VALID
  1417. mov     bx,cx                   ; set all dirty_bits valid
  1418. or      bx,valid_mask
  1419. endif
  1420. call    set_dirtyindex
  1421. ;       Note!  We've set the dirty_bits before we filled up the
  1422. ;              buffer.  Good thing we know the commit_cache function
  1423. ;              can't be running concurrently with this mainline code.
  1424. ;       copy from cache to local_buf
  1425. ;       ***  Note:  We really only have to copy the part of the block
  1426. ;                    that we're not replacing.
  1427. mov     bp,cache_element_index  ;setup cache block index
  1428. les     di,d_trans              ;get pointer to user data
  1429. pop     ax                      ;ax is now actual count
  1430. push    ax                      ;must restore later
  1431. sub     d_count,ax              ;update global sector count
  1432. mov     ah,byte ptr curblk_index;setup for next call
  1433. call    write_part_cache_block  ;write data to xms
  1434. mov     num_valid_buffers,0     ;data may have been dupped in supercache
  1435. ;so invalidate supercache
  1436. pop     ax                      ;restore count
  1437. mul     sector_size_bytes       ;adjust to bytes
  1438. ifdef   USE_VALID
  1439. jmp     write_next_block        ;continue...
  1440. else
  1441. jmp     short write_next_block
  1442. endif
  1443. wr_first_partial_common:
  1444. mov     ax,curblk_index         ; get starting index
  1445. mul     sector_size_bytes
  1446. les     di,local_buf
  1447. add     di,ax                   ; point to destination in buffer
  1448. pop     ax                      ; get the actual transfer count
  1449. sub     d_count,ax              ; keep track of count
  1450. mul     sector_size_bytes
  1451. mov     cx,ax
  1452. shr     cx,1                    ; convert count to words
  1453. lds     si,d_trans              ; get disk transfer address
  1454. assume  ds:nothing
  1455. rep     movsw                   ; move the data
  1456. push    cs
  1457. pop     ds
  1458. assume  ds:zseg                 ; restore addressability
  1459. push    ax                      ; save byte count for update
  1460. mov     ax,1                    ; make supercache valid
  1461. call    set_supercache_valid    ;  with one block (curblk)
  1462. les     di,local_buf
  1463. call    write_full_cache_block  ; write that pig thru the cache
  1464. pop     ax                      ; restore byte count
  1465. ;       go write next block
  1466. endif                           ; ifdef USE_VALID
  1467. write_next_block:
  1468. add     word ptr d_trans,ax     ; update transfer address
  1469. add     curblk_l,1              ; let's move to next block
  1470. adc     curblk_h,0
  1471. ;       Now we're block aligned.  Complete any full blocks first.
  1472. no_partial_to_write:
  1473. mov     ax,cache_block_sectors
  1474. cmp     ax,d_count              ; do we need a full block?
  1475. ja      write_last_partial      ; skip if no more full blocks
  1476. sub     d_count,ax              ; count it down
  1477. call    check_hit               ; is curblk in cache?
  1478. jnz     wr_full_was_a_hit       ;  skip if that block is present
  1479. mov     cx,cache_mask           ; fully dirty
  1480. ifdef   USE_VALID
  1481. mov     bx,cx                   ;  and fully valid
  1482. endif
  1483. call    create_cache_block      ;  filling up local_buf
  1484. jmp     short wr_full_common
  1485. wr_full_was_a_hit:
  1486. mov     cx,cache_mask           ; mark it fully dirty
  1487. ifdef   USE_VALID
  1488. mov     bx,cx                   ;  and fully valid
  1489. or      bx,valid_mask
  1490. endif
  1491. call    set_dirtyindex
  1492. ;       okay.  copy that puppy into cache.
  1493. wr_full_common:
  1494. les     di,d_trans              ; get user buffer
  1495. call    write_full_cache_block  ; write the whole block
  1496. mov     ax,cache_block_bytes    ; update pointer
  1497. jmp     write_next_block
  1498. ;       d_count is now less than a full cache block
  1499. ;         we are cache block aligned
  1500. write_last_partial:
  1501. cmp     d_count,0               ; *IS* there a partial?
  1502. jnz     write_last_partial_not_done
  1503. jmp     short writing_done      ;  skip if not
  1504. write_last_partial_not_done:
  1505. ;       figure out our mask bits
  1506. mov     cl,byte ptr d_count
  1507. mov     ax,1
  1508. shl     ax,cl
  1509. dec     ax                      ; convert to mask
  1510. push    ax
  1511. call    check_hit               ; is last partial in cache?
  1512. pop     cx                      ; get new mask bits into cx
  1513. ;       *********************************************
  1514. ;       Here is another big block which is different for USE_VALID
  1515. ;       *********************************************
  1516. ifdef   USE_VALID
  1517. jnz     wr_last_partial_was_a_hit ;  skip if that block is present
  1518. mov     bx,cx                   ; only our writing bits are valid
  1519. call    create_cache_block      ;  filling up local_buf
  1520. jmp     short wr_last_partial_common
  1521. wr_last_partial_was_a_hit:
  1522. or      cx,dirty_mask           ; or with previous
  1523. mov     bx,cx                   ; valid=dirty
  1524. or      bx,valid_mask
  1525. call    set_dirtyindex
  1526. wr_last_partial_common:
  1527. mov     num_valid_buffers,0     ; invalidate super-cache just in case
  1528. mov     bp,cache_element_index  ;get block index
  1529. les     di,d_trans              ;get pointer to user data
  1530. mov     ax,d_count              ;get final count of last write
  1531. call    write_part_cache_block  ;write data to cache in xms
  1532. else                            ;  ndef USE_VALID
  1533. jnz     wr_last_partial_was_a_hit ;  skip if that block is present
  1534. ;       ifdef   USE_VALID
  1535. ;       mov     bx,cache_mask           ; the whole thing is valid
  1536. ;       endif
  1537. call    create_cache_block      ;  filling up local_buf
  1538. ;       Note:  We really don't need to read the whole block, only the
  1539. ;               last part of it.
  1540. les     di,local_buf
  1541. mov     ax,1
  1542. mov     num_valid_buffers,0     ; invalidate supercache
  1543. call    read_curblks_from_disk  ; read it into buffer
  1544. jnc     wr_last_partial_common
  1545. call    invalidate_cache_block
  1546. ;       Now we should attempt to write the sectors directly to the disk.
  1547. ;         Only if this fails will we actually report an error.
  1548. les     di,d_trans
  1549. mov     ah,byte ptr d_count     ; count of sectors to write
  1550. xor     al,al                   ; start from front of block
  1551. call    write_part_curblk_to_disk
  1552. ;       Note:  this may have to be split between the two different
  1553. ;               places that enter this code path.
  1554. jnc     writing_done            ; done if no error writing
  1555. jmp     got_fatal_error
  1556. wr_last_partial_was_a_hit:
  1557. or      cx,dirty_mask           ; or with previous
  1558. ;       ifdef   USE_VALID
  1559. ;       mov     bx,cx                   ; valid=dirty
  1560. ;       or      bx,valid_mask
  1561. ;       endif
  1562. call    set_dirtyindex
  1563. ;       copy from cache to local_buf
  1564. ;           Note:  we really only need to copy the part we aren't filling in.
  1565. mov     bp,cache_element_index  ;get block index
  1566. les     di,d_trans              ;get pointer to user data
  1567. mov     ax,d_count              ;get final count of last write
  1568. ;;;     ah=0!
  1569. call    write_part_cache_block  ;write data to cache in xms
  1570. mov     num_valid_buffers,0     ;be sure super-cache is consitent
  1571. ifdef   USE_VALID
  1572. jmp     writing_done            ;outtahere
  1573. else
  1574. jmp     short writing_done      ;outtahere
  1575. endif
  1576. wr_last_partial_common:
  1577. les     di,local_buf
  1578. mov     ax,d_count              ; get sectors in last partial
  1579. mul     sector_size_bytes
  1580. mov     cx,ax
  1581. shr     cx,1                    ; convert count to words
  1582. lds     si,d_trans
  1583. assume  ds:nothing
  1584. rep     movsw                   ; move the data
  1585. push    cs
  1586. pop     ds
  1587. assume  ds:zseg                 ; restore addressability
  1588. mov     ax,1
  1589. call    set_supercache_valid    ; mark the supercache as valid
  1590. les     di,local_buf
  1591. call    write_full_cache_block  ; write that pig thru the cache
  1592. endif                           ; ifdef USE_VALID
  1593. writing_done:
  1594. jmp     readwrite_done          ; no errors
  1595. cache_write_data        endp
  1596. ;-----------------------------------------------------------------------
  1597. ;
  1598. ;       the partial block we need isn't in the cache.  Read the block,
  1599. ;          and possibly the blocks after it into the cache.  Return
  1600. ;          as many blocks as can be read successfully (not marked bad,
  1601. ;          not hits, not read error) in the supercache.  Return carry
  1602. ;          if we couldn't even read the first block.
  1603. ;
  1604. ;       entry:  cx == number of blocks to read & cache.  Those blocks
  1605. ;               will be left in local_buf on return.
  1606. ;
  1607. ;       returns carry set if error on first block
  1608. ;
  1609. ;       If count > 1, that means we're doing a readahead.  We haven't
  1610. ;         actually checked to see if any of that is in the cache.
  1611. get_curblks_into_cache  proc    near
  1612. assume  cs:zseg,ds:zseg,es:nothing
  1613. push    cx                      ; save original count
  1614. mov     ax,curblk_l
  1615. mov     dl,curblk_h             ; get last curblk into dl:ax
  1616. mov     dh,original_unit        ; and original_unit into dh
  1617. jmp     short skip_hitcheck_on_1st      ; we already know first block
  1618. ;                                               ; is a nohit or we couldn't be
  1619. ;                                               ; here now.
  1620. get_curblk_ckhit_loop:
  1621. push    ax
  1622. push    cx
  1623. push    dx                      ; save blocknum & count
  1624. call    check_hit_in_regs       ; is it a hit?
  1625. pop     dx
  1626. pop     cx
  1627. pop     ax
  1628. jnz     get_curblk_ckhit_exit   ; we got a readahead stopper!
  1629. skip_hitcheck_on_1st:
  1630. push    cx
  1631. mov     cx,num_bad_blocks
  1632. jcxz    not_bad_block           ; skip if no bads exist
  1633. push    cs
  1634. pop     es      
  1635. mov     di,offset bad_blocks    ; point to list of known baddies
  1636. continue_bad_check:
  1637. repnz   scasw                   ; see if this is one.
  1638. jz      might_be_bad            ; OOOPS.  might be bad.  go check rest
  1639. ;       this block is a candidate for caching.  Loop.
  1640. not_bad_block:
  1641. pop     cx
  1642. add     ax,1
  1643. adc     dl,0                    ; adjust block number
  1644. loop    get_curblk_ckhit_loop
  1645. pop     cx                      ; restore the original count
  1646. jmp     short get_curblks_no_rdahead ; go ahead and read the whole thing
  1647. ;       the low 16 bits matched that of a known bad block.  Let's
  1648. ;       see if the high 16 do, too.
  1649. might_be_bad:
  1650.        ;        int 1
  1651. cmp     dx,[di].bad_drives-bad_blocks-2
  1652. jnz     continue_bad_check
  1653. pop     cx                      ; get our loop count from stack
  1654. ;       fall into the same logic that deals with cache hits.  Stop
  1655. ;         the read before we get here!
  1656. ;       we got a hit.  Now we have to figure out how many blocks we
  1657. ;         can read safely before the hit.
  1658. get_curblk_ckhit_exit:
  1659. pop     ax                      ; get original block count
  1660. sub     ax,cx                   ; truncate number past first nohit
  1661. mov     cx,ax
  1662. jcxz    cant_read_any_blocks    ; done if first block marked bad
  1663. get_curblks_no_rdahead:
  1664. mov     num_valid_buffers,0     ; invalidate old supercache
  1665. mov     di,offset blockids
  1666. push    cx                      ; save count
  1667. mov     ax,curblk_l
  1668. mov     dl,curblk_h
  1669. mov     dh,original_unit        ; merge unit code into cookie
  1670. if 1
  1671. push    es                              ;check if this is a 
  1672. les     si,accessing_swap_file_ptr      ;swapfile access, if so
  1673. cmp     byte ptr es:[si],0              ;dont cache it
  1674. pop     es
  1675. jne     dont_add_to_cache
  1676. endif
  1677. ;       now loop through and create cache blocks for everything we're
  1678. ;          reading.
  1679. get_curblks_00:
  1680. push    cx
  1681. push    dx
  1682. push    ax
  1683. push    di
  1684. xor     cx,cx                   ; create clean cache block before
  1685. ifdef   USE_VALID
  1686. mov     bx,cache_mask           ; all valid, please
  1687. mov     valid_mask,bx           ; set existing valid mask
  1688. endif
  1689. call    queue_element
  1690. pop     di
  1691. pop     ax
  1692. pop     dx
  1693. pop     cx
  1694. add     ax,1
  1695. adc     dl,0                    ; update block number
  1696. mov     word ptr [di],bp        ; save cache block number
  1697. add     di,2
  1698. loop    get_curblks_00
  1699. les     di,local_buf
  1700. pop     ax                      ; get block count
  1701. push    ax                      ;  and re-save on stack
  1702. call    read_curblks_from_disk  ; read them into buffer
  1703. pop     cx                      ; restore block count
  1704. jc      get_curblks_readerror   ; skip if read error!!!!
  1705. mov     ax,cx                   ; get the block count
  1706. call    set_supercache_valid    ;  and mark it valid
  1707. les     di,local_buf
  1708. mov     si,offset blockids
  1709. copy_localbuf_into_cache:
  1710. push    si
  1711. push    di
  1712. push    cx
  1713. mov     cx,cache_block_words
  1714. mov     bp,word ptr [si]        ; get cache block number
  1715. xor     si,si                   ; do entire block
  1716. call    buffer_to_cache
  1717. pop     cx
  1718. pop     di
  1719. pop     si
  1720. add     si,2
  1721. add     di,cache_block_bytes    ; update dma pointer
  1722. loop    copy_localbuf_into_cache
  1723. clc
  1724. ret                             ; no errors
  1725. cant_read_any_blocks:
  1726. stc                             ; first block was marked bad
  1727. ret
  1728. dont_add_to_cache:
  1729. pop     ax
  1730. push    ax
  1731. les     di,local_buf
  1732. call    read_curblks_from_disk  ; read them into buffer
  1733. pop     ax
  1734. jc      mark_curblk_bad
  1735. call    set_supercache_valid    ;  and mark it valid
  1736. clc
  1737. ret                             ; no errors
  1738. get_curblks_readerror:
  1739. mov     di,offset blockids
  1740. get_curblks_invalidate:
  1741. mov     bp,word ptr [di]
  1742. add     di,2
  1743. push    di
  1744. push    cx
  1745. call    invalidate_element
  1746. pop     cx
  1747. pop     di
  1748. loop    get_curblks_invalidate
  1749. ;       exit through here if we got a read error.  Actually, we should
  1750. ;       try to figure out which block was bad, but for now, we'll just
  1751. ;       assume it was the first one.  Eventually, the problem block
  1752. ;       will be marked.
  1753. mark_curblk_bad:
  1754.        ;        int 1
  1755. mov     di,next_bad_entry_ptr
  1756. mov     dx,curblk_l
  1757. mov     bad_blocks[di],dx
  1758. mov     dl,curblk_h
  1759. mov     dh,original_unit
  1760. mov     bad_drives[di],dx
  1761. add     di,2                    ; point to next entry
  1762. cmp     di,MAXBADS*2
  1763. jb      mark_curblk_bad_1
  1764. xor     di,di                   ; next one back to zero
  1765. mark_curblk_bad_1:
  1766. mov     next_bad_entry_ptr,di   ; update pointer for next bad sector
  1767. cmp     num_bad_blocks,MAXBADS
  1768. jae     no_incr_numbads
  1769. inc     num_bad_blocks
  1770. no_incr_numbads:
  1771. stc                             ; return error condition, ax == code
  1772. ret
  1773. get_curblks_into_cache  endp
  1774. ;-----------------------------------------------------------------------
  1775. ;
  1776. ;       this routine is called when we can guarantee that the information
  1777. ;         in the local_buf is one or more valid cache blocks.  This may
  1778. ;         save us an XMS transaction if we need that data again soon.
  1779. ;
  1780. ;       call with ax == number of valid blocks in local_buf
  1781. ;                       curblk_l, curblk_h == cache block of first block
  1782. ;                       original_unit         == the drive it is from
  1783. set_supercache_valid    proc    near
  1784. assume  cs:zseg,ds:zseg,es:nothing
  1785. mov     num_valid_buffers,ax
  1786. mov     ax,curblk_l
  1787. mov     bufferblk_l,ax
  1788. mov     al,curblk_h
  1789. mov     ah,original_unit
  1790. mov     bufferblk_h,ax
  1791. ret
  1792. set_supercache_valid    endp
  1793. ;-----------------------------------------------------------------------
  1794. ;
  1795. ;       check to see if curblk is in the supercache.  If so, return
  1796. ;          lb_seg:si pointing to it, ax == number of subsequent blocks present.
  1797. ;          if not in supercache, return carry false.
  1798. check_supercache_match  proc    near
  1799. assume  cs:zseg,ds:zseg,es:nothing
  1800. mov     al,curblk_h
  1801. mov     ah,original_unit
  1802. sub     ax,bufferblk_h
  1803. clc
  1804. jnz     check_supercache_exit   ; exit w/ carry false if no high match
  1805. mov     ax,curblk_l
  1806. sub     ax,bufferblk_l          ; see if we are present
  1807. cmp     ax,num_valid_buffers
  1808. jnc     check_supercache_exit
  1809. push    ax                      ; save number we need to skip
  1810. mul     cache_block_bytes
  1811. mov     si,word ptr local_buf
  1812. add     si,ax                   ; point to curblk in local_buf
  1813. pop     ax
  1814. sub     ax,num_valid_buffers
  1815. neg     ax                      ; get ax == number of blocks present
  1816. ;                                       ;  at and past curblk
  1817. stc                             ; set carry to indicate success!
  1818. check_supercache_exit:
  1819. ret
  1820. check_supercache_match  endp
  1821. ;-----------------------------------------------------------------------
  1822. ;
  1823. ;       this routine calculates the number of blocks which can be
  1824. ;         transferred in the starting partial block.  This count
  1825. ;         is returned in ax, and is automatically subtracted
  1826. ;         from d_count.  Also, es:di is pre-loaded to point to
  1827. ;         the transfer address.
  1828. ;
  1829. ;       Preserves:  MUST PRESERVE SI!!
  1830. first_partial_setup     proc    near
  1831. assume  cs:zseg,ds:zseg,es:nothing
  1832. ;       count is min (cache_block_sectors - curblk_index, d_count)
  1833. mov     ax,cache_block_sectors
  1834. sub     ax,curblk_index         ; how many left in block?
  1835. cmp     ax,d_count              ; do we want that many?
  1836. jb      pbsetup_need_em_all     ; skip if so
  1837. mov     ax,d_count              ; only transfer what we need
  1838. pbsetup_need_em_all:
  1839. sub     d_count,ax              ; keep track of count
  1840. les     di,d_trans              ; get disk transfer address
  1841. ret
  1842. first_partial_setup     endp
  1843. ;-----------------------------------------------------------------------
  1844. ;
  1845. ;       see if the block at curblk is in the cache.
  1846. ;         alternate entry has block number in dl:ax.
  1847. ;
  1848. ;       If found, return:  BP == cache block number
  1849. ;                          Zero flag clear
  1850. ;
  1851. ;       If not found, return: BP == 0ffffh
  1852. ;                             zero flag true
  1853. check_hit       proc    near
  1854. assume  cs:zseg,ds:zseg,es:nothing
  1855. mov     ax,curblk_l
  1856. mov     dl,curblk_h
  1857. check_hit_in_regs:
  1858. mov     dh,original_unit        ; merge unit code into cookie
  1859. call    fast_lookup
  1860. mov     dirty_mask,cx           ; save mask of hit element
  1861. ifdef   USE_VALID
  1862. mov     valid_mask,ax           ; save valid mask of hit element
  1863. endif
  1864. cmp     bp,0ffffh
  1865. jz      nohit_count
  1866. add     hit_l,1
  1867. adc     hit_h,0
  1868. ;       Move that queue entry to head of chain
  1869. ;call   bring_queue_entry_to_head
  1870. mov     cache_element_index,bp
  1871. cmp     bp,0ffffh               ; adjust zero flag again
  1872. ret
  1873. nohit_count:
  1874. add     nohit_l,1
  1875. adc     nohit_h,0
  1876. mov     cache_element_index,bp
  1877. cmp     bp,0ffffh
  1878. ret
  1879. check_hit       endp
  1880. ;-----------------------------------------------------------------------
  1881. ;
  1882. ;       NOTE:  We may get called back at dirty_write here!  This
  1883. ;               will trash our local_buf!!!!  Be aware!
  1884. ;
  1885. ;       Regs:  Input -- CX == initial dirty_bits value
  1886. ;                       BX == initial valid_bits value (if enabled)
  1887. create_cache_block      proc    near
  1888. assume  cs:zseg,ds:zseg,es:nothing
  1889. mov     ax,curblk_l
  1890. mov     dl,curblk_h
  1891. mov     dh,original_unit        ; merge unit code into cookie
  1892. ifdef   USE_VALID
  1893. mov     valid_mask,bx
  1894. endif
  1895. mov     dirty_mask,cx
  1896. call    queue_element
  1897. mov     cache_element_index,bp
  1898. ret
  1899. create_cache_block      endp
  1900. ;-----------------------------------------------------------------------
  1901. ;
  1902. ;       this entry is called when we created a cache block and
  1903. ;         were then unable to fill it completely.
  1904. invalidate_cache_block  proc    near
  1905. assume  cs:zseg,ds:zseg,es:nothing
  1906. mov     bp,cache_element_index
  1907. jmp     invalidate_element
  1908. invalidate_cache_block  endp
  1909. ;-----------------------------------------------------------------------
  1910. ;
  1911. ;       This puppy reads the cache block (from bp) into memory
  1912. ;         at es:di.
  1913. read_full_cache_block   proc    near
  1914. assume  cs:zseg,ds:zseg,es:nothing
  1915. mov     cx,cache_block_words
  1916. xor     si,si           ; do entire block
  1917. jmp     short read_cache_common
  1918. read_full_cache_block   endp
  1919. ;-----------------------------------------------------------------------
  1920. ;
  1921. ;       call with ah=index, al=count
  1922. read_part_cache_block   proc    near
  1923. assume  cs:zseg,ds:zseg,es:nothing
  1924. call    mash_for_xms
  1925. read_cache_common:
  1926. jmp     cache_to_buffer
  1927. read_part_cache_block   endp
  1928. ;-----------------------------------------------------------------------
  1929. ;
  1930. ;       This is similar to read_*_cache_block above except that
  1931. ;         it uses the block number in cache_element_index instead
  1932. ;         of bp.
  1933. write_full_cache_block  proc    near
  1934. assume  cs:zseg,ds:zseg,es:nothing
  1935. mov     cx,cache_block_words
  1936. xor     si,si           ; do entire block
  1937. jmp     short write_cache_common
  1938. write_full_cache_block  endp
  1939. ;-----------------------------------------------------------------------
  1940. ;
  1941. ;       called with al = count to write, ah = starting index
  1942. write_part_cache_block  proc    near
  1943. assume  cs:zseg,ds:zseg,es:nothing
  1944. call    mash_for_xms
  1945. write_cache_common:
  1946. mov     bp,cache_element_index
  1947. jmp     buffer_to_cache
  1948. write_part_cache_block  endp
  1949. ;-----------------------------------------------------------------------
  1950. ;
  1951. ;       call this for partial cache reads/writes.  Calculates
  1952. ;         cx (word count) and si (index into block) based on
  1953. ;         ah=sector index, al=sector count
  1954. mash_for_xms    proc    near
  1955. assume  cs:zseg,ds:zseg,es:nothing
  1956. push    ax              ; save first sector
  1957. xor     ah,ah
  1958. mul     sector_size_bytes
  1959. mov     cx,ax           ; count for transfer
  1960. shr     cx,1            ; convert to words
  1961. pop     ax              ; restore first sector
  1962. mov     al,ah
  1963. xor     ah,ah
  1964. mul     sector_size_bytes       ; in dx:ax
  1965. mov     si,ax           ; pass to cache manager in dx:si
  1966. ret
  1967. mash_for_xms    endp
  1968. ;-----------------------------------------------------------------------
  1969. ;
  1970. ;       this function reads blocks at curblk into memory at
  1971. ;         es:di.  curblk == 0 is a special case where only
  1972. ;         a partial read may be needed, depending on the
  1973. ;         cache_align_factor.
  1974. ;
  1975. ;       number of blocks to read is in ax
  1976. ;
  1977. ;       returns ax= device driver's return code.
  1978. ;         carry set if error condition occurred.
  1979. read_curblks_from_disk  proc    near
  1980. assume  cs:zseg,ds:zseg,es:nothing
  1981. mul     cache_block_sectors
  1982. mov     our_trans_off,di
  1983. mov     our_trans_seg,es
  1984. mov     our_count,ax
  1985. mov     ax,curblk_l
  1986. mov     dx,word ptr curblk_h
  1987. mov     cx,cache_block_shift
  1988. ;The following is a fast 32-bit shift left.  
  1989. ;WARNING: assumes CL <=16! 
  1990. ;BUG BUG: duped below!
  1991. mov di,0FFFFh           ;      set up to make a mask
  1992. rol ax,cl               ;      
  1993. shl dx,cl               ;      
  1994. shl di,cl               ;      
  1995. mov cx,ax               ;      
  1996. and ax,di               ;      
  1997. not di                  ;      
  1998. and cx,di               ;      
  1999. or  dx,cx               ;      
  2000. sub     ax,cache_align_factor
  2001. sbb     dx,0
  2002. jnb     read_curblk_go
  2003. ;       we're doing block zero and have to do a partial read
  2004. mov     ax,cache_align_factor
  2005. sub     our_count,ax
  2006. mul     sector_size_bytes
  2007. add     our_trans_off,ax
  2008. ;       *****  Alternate entry point from lookup_device
  2009. ;               routine.  Notice that it has already set up the
  2010. ;               count and transfer address fields.
  2011. read_sector_zero:
  2012. xor     ax,ax
  2013. xor     dx,dx
  2014. read_curblk_go:
  2015. les     bx,dd_header            ; point to device header
  2016. call    set_start_sector        ; store dx:ax as start sector
  2017. mov     byte ptr rblk_op,devrd
  2018. les     bx,loc_reqblk
  2019. call    call_dd                 ; call device driver
  2020. les     bx,loc_reqblk           ; be sure packet is int es:bx
  2021. mov     ax,es:[bx].reqstat      ; fetch up error code
  2022. rol     ah,1                    ; get ax bit 15 into carry
  2023. ror     ah,1                    ; without trashing ax
  2024. ret
  2025. read_curblks_from_disk  endp
  2026. ;-----------------------------------------------------------------------
  2027. ;
  2028. ;       this function reads a fraction of a block at curblk
  2029. ;         into memory at es:di.  AL=first sector, AH=number of secs.
  2030. ;         Return carry if disk read error, ax=error code from dev. drvr.
  2031. read_part_curblk_from_disk      proc    near
  2032. assume  cs:zseg,ds:zseg,es:nothing
  2033. mov     byte ptr rblk_op,devrd
  2034. jmp     short read_write_part_curblk
  2035. read_part_curblk_from_disk      endp
  2036. ;-----------------------------------------------------------------------
  2037. ;
  2038. ;       this function writes a fraction of a block at curblk from
  2039. ;         memory at es:di.  AL=first sector, AH=number of secs.
  2040. ;         Return carry if disk write error, ax=error code from dev. drvr.
  2041. write_part_curblk_to_disk       proc    near
  2042. assume  cs:zseg,ds:zseg,es:nothing
  2043. mov     byte ptr rblk_op,devwrt
  2044. read_write_part_curblk:
  2045. mov     our_trans_off,di
  2046. mov     our_trans_seg,es
  2047. mov     byte ptr our_count,ah
  2048. mov     byte ptr our_count+1,0
  2049. push    ax                      ; save first sector to read
  2050. mov     ax,curblk_l
  2051. mov     dx,word ptr curblk_h
  2052. mov     cx,cache_block_shift
  2053. ;The following is a fast 32-bit shift left.  
  2054. ;WARNING: assumes CL <=16! 
  2055. ;BUG BUG: dupped above!
  2056. mov di,0FFFFh           ;      set up to make a mask
  2057. rol ax,cl               ;      
  2058. shl dx,cl               ;      
  2059. shl di,cl               ;      
  2060. mov cx,ax               ;      
  2061. and ax,di               ;      
  2062. not di                  ;      
  2063. and cx,di               ;      
  2064. or  dx,cx               ;      
  2065. sub     ax,cache_align_factor
  2066. sbb     dx,0
  2067. ;       We don't actually have to deal with block zero here, because
  2068. ;         even if our dx:ax sector number goes negative here, the sector
  2069. ;         within the block will get added back in.  Since that reflects
  2070. ;         an actual calling program read/write request, we can assume
  2071. ;         that it will yield a valid sector number (ie: >= 0)
  2072. pop     cx                      ; get the starting sector number
  2073. xor     ch,ch                   ;  within curblk
  2074. add     ax,cx
  2075. adc     dx,0
  2076. les     bx,dd_header            ; point to device header
  2077. call    set_start_sector        ; store dx:ax as starting sector
  2078. les     bx,loc_reqblk
  2079. call    call_dd                 ; call device driver
  2080. les     bx,loc_reqblk           ; be sure packet is int es:bx
  2081. mov     ax,es:[bx].reqstat      ; fetch up error code
  2082. rol     ah,1                    ; get ax bit 15 into carry
  2083. ror     ah,1                    ; without trashing ax
  2084. ret
  2085. write_part_curblk_to_disk       endp
  2086. ;-----------------------------------------------------------------------
  2087. ;
  2088. ;       This function stores dx:ax into our local DD request packet
  2089. ;       as the starting sector.  This is more complicated than it
  2090. ;       sounds, because we have to take into account the DOS version
  2091. ;       and whether or not said device supports 32-bit block numbers.
  2092. set_start_sector        proc    near
  2093. assume  cs:zseg,ds:zseg,es:nothing
  2094. ;       ALWAYS store the block into start_l and start_h, in case
  2095. ;       some errant device driver picks them up there.
  2096. mov     our_startl,ax
  2097. mov     our_starth,dx
  2098. cmp     dos_3x,0        ; are we running on dos 3.x?
  2099. jnz     ss_dos30        ; brif so
  2100. ;       If we're running DOS 4.0 or later, we'll always try to pass
  2101. ;       block numbers in 32-bit mode if the driver supports it, since
  2102. ;       this is (??) the way those versions of DOS work.  Compaq 3.31,
  2103. ;       on the other hand, will CHOKE if you send it a 32-bit block
  2104. ;       number for a sector which could otherwise be handled with 16 bits.
  2105. test    es:byte ptr [bx.4],2    ; see if it is 32-bit capable
  2106. jz      ss_use_16
  2107. ss_use_32:
  2108. mov     our_start,-1
  2109. ret
  2110. ss_dos30:
  2111. ss_use_16:
  2112. mov     our_start+2,dx
  2113. mov     our_start,ax
  2114. ret
  2115. set_start_sector        endp
  2116. ;-----------------------------------------------------------------------
  2117. ;
  2118. ;       get actual unit code and physical device header for logical
  2119. ;         unit in al
  2120. ;
  2121. ;       return remapped unit code in al, device header in bp:dx
  2122. ;         return cx = align factor and sector size code, for use
  2123. ;          only by dirty_write since it is potentially invalid
  2124. ;          at mainline entry.
  2125. lookup_device   proc    near
  2126. assume  cs:zseg,ds:zseg,es:nothing
  2127. push    bx                      ;note: we use bx instead of
  2128. ;bp since bp will need to have
  2129. ;a DS override 4 times=8 clocks,4 bytes
  2130. ;but push/pop bx = 4 clocks,2 bytes
  2131. xor     ah,ah                   ; extend to 16 bits
  2132. mov     bx,ax                   ; snag the byte field
  2133. mov     al,byte ptr real_cache_units[bx]
  2134. shl     bx,1                    ; index word field
  2135. mov     cx,secsize_and_align_info[bx]
  2136. shl     bx,1                    ; snag dword field
  2137. mov     dx,word ptr real_dd_headers[bx]
  2138. mov     bp,word ptr real_dd_headers[bx+2]       
  2139. pop     bx
  2140. ret
  2141. lookup_device   endp
  2142. ;-----------------------------------------------------------------------
  2143. ;-----------------------------------------------------------------------
  2144. ;
  2145. ;       get the sector size and align factor for the drive in al.
  2146. ;
  2147. ;       Must preserve es:bx
  2148. get_drive_info  proc    near
  2149. assume  cs:zseg,ds:zseg,es:nothing
  2150. xor     ah,ah                   ; extend to 16 bits
  2151. mov     bp,ax
  2152. shl     bp,1                    ; index word field
  2153. mov     cx,secsize_and_align_info[bp]
  2154. cmp     ch,0ffh
  2155. jz      gotta_set_secsize_and_align
  2156. ret
  2157. ;       Now we've got to go hit the disk to get sector zero.
  2158. ;         We can safely assume we're not called from dirty_write
  2159. ;         because no sector should ever become dirty other than
  2160. ;         through the main bambi code, which guarantees that said
  2161. ;         drive has been accessed (logged in).
  2162. gotta_set_secsize_and_align:
  2163. push    es
  2164. push    bx
  2165. push    bp                      ; save the word index
  2166. ;       to calculate the align factor, find the sector address of a
  2167. ;         cluster -- (123h for my 130Mb hard drive, 21h for 1.44M flop).
  2168. ;         mask off low bits under cluster mask, subtract from cluster
  2169. ;         size.  This means 15 for 1.44M, 13 for my 130M drive c:
  2170. ;
  2171. ;       My 110M system has a data field starting at sector 1bfh, so the
  2172. ;         tuning constant is 1.
  2173. mov     num_valid_buffers,0     ; invalidate super-cache
  2174. les     di,local_buf            ; get address of temp buffer
  2175. mov     our_trans_off,di
  2176. mov     our_trans_seg,es
  2177. mov     our_count,1
  2178. call    read_sector_zero        ; read bpb
  2179. les     bx,local_buf            ; point back to block we read
  2180. jc      use_defaults
  2181. push    es
  2182. push    bx
  2183. call    verify_bpb
  2184. pop     bx
  2185. pop     es
  2186. jc      use_defaults
  2187. continue_info:
  2188. mov     ax,cache_block_bytes
  2189. xor     dx,dx
  2190. div     es:word ptr [bx].0bh    ; get secs/cache block
  2191. push    ax                      ; and save on stack
  2192. mov     al,es:byte ptr [bx].10h ; get nfats
  2193. xor     ah,ah
  2194. mul     word ptr es:[bx].16h    ; times fatsize
  2195. add     ax,es:[bx].0eh          ; add in reserved sectors
  2196. ;       now we have to add in the number of directory sectors
  2197. mov     bx,es:[bx].11h          ; get number of directory entries
  2198. mov     cl,4                    ; divide by 16 (512 bytepersec/32)
  2199. shr     bx,cl
  2200. add     ax,bx                   ; this is address of first cluster
  2201. neg     ax                      ; get negative of that
  2202. pop     cx                      ; get cache block sectors
  2203. dec     cl                      ; convert count to mask
  2204. and     al,cl                   ; al == align factor
  2205. inc     cl
  2206. ;       we still need the log2(secs/block) value for the configuration array.
  2207. mov     ah,al
  2208. mov     al,-1
  2209. calc_log2_secs_per_block:
  2210. inc     al
  2211. shr     cl,1
  2212. jnz     calc_log2_secs_per_block
  2213. mov     cx,ax
  2214. pop     bx                      ; get index for storing drive config
  2215. mov     secsize_and_align_info[bx],cx
  2216. pop     bx
  2217. pop     es
  2218. ret
  2219. use_defaults:
  2220. mov     word ptr es:[di].0bh,200h
  2221. mov     byte ptr es:[di].10h,2
  2222. mov     word ptr es:[di].16,9
  2223. mov     word ptr es:[di].0eh,1
  2224. mov     word ptr es:[di].11h,0
  2225. jmp     short continue_info
  2226. get_drive_info  endp
  2227. validate_secsize:
  2228. mov     ax,es:word ptr [bx].0bh ; get sector size
  2229. cmp     ax,64                   ; cannot be valid if sector size 
  2230. jb      invalidbootsec          ;  is <64 bytes
  2231. vs1:
  2232. shl     ax,1
  2233. jnc     vs1
  2234. jz      check_bpb_mediabyte
  2235. jmp     short   invalidbootsec  
  2236. verify_bpb proc near
  2237. ; put a sanity check for the boot sector in here to detect
  2238. ; boot sectors that do not have valid bpbs. we examine the
  2239. ; first two bytes - they must contain a long jump (69h) or a
  2240. ; short jump (ebh) followed by a nop (90h), or a short jump
  2241. ; (e9h). if this test is passed, we further check by examining
  2242. ; the signature at the end of the boot sector for the word
  2243. ; aa55h. if the signature is not present, we examine the media
  2244. ; descriptor byte to see if it is valid. for dos 3.3, this
  2245. ; logic is modified a little bit. we are not going to check
  2246. ; signature. instead we are going to sanity check the media
  2247. ; byte in bpb regardless of the validity of signature. this is
  2248. ; to save the already developed commercial products that have
  2249. ; good jump instruction and signature but with the false bpb
  2250. ; informations
  2251. ; that will crash the diskette drive operation. (for example, symphony diskette).
  2252.  cmp    byte ptr es:[bx],0      ; might be bogus Corel and Cronies?
  2253.  je     validate_secsize
  2254.  cmp    byte ptr es:[bx],069h   ; is it a direct jump?
  2255.  je     check_bpb_mediabyte             ; don't need to find a nop
  2256.  cmp    byte ptr es:[bx],0e9h   ; dos 2.0 jump?
  2257.  je     check_bpb_mediabyte             ; no need for nop
  2258.  cmp    byte ptr es:[bx],0ebh   ; how about a short jump.
  2259.  jne    invalidbootsec
  2260.  cmp    byte ptr es:[bx]+2,090h ; is next one a nop?
  2261.  jne    invalidbootsec
  2262. ; check for non-ibm disks which do not have the signature aa55 at the
  2263. ; end of the boot sector, but still have a valid boot sector. this is done
  2264. ; by examining the media descriptor in the boot sector.
  2265. check_bpb_mediabyte:
  2266. mov     al,es:[bx].EXT_BOOT_BPB.BPB_MEDIADESCRIPTOR
  2267.  and     al,0f0h
  2268.  cmp     al,0f0h                ; allow for strange media
  2269.  jnz     invalidbootsec
  2270. ; there were some (apparently a lot of them) diskettes that had been formatted
  2271. ; under dos 3.1 and earlier versions which have invalid bpbs in their boot
  2272. ; sectors. these are specifically diskettes that were formatted in drives
  2273. ; with one head, or whose side 0 was bad. these contain bpbs in the boot
  2274. ; sector that have the sec/clus field set to 2 instead of 1, as is standard
  2275. ; in dos. in order to support them, we have to introduce a "hack" that will
  2276. ; help our build bpb routine to recognise these specific cases, and to
  2277. ; set up out copy of the bpb accordingly.
  2278. ; we do this by checking to see if the boot sector is off a diskette that
  2279. ; is single-sided and is a pre-dos 3.20 diskette. if it is, we set the
  2280. ; sec/clus field to 1. if not, we carry on as normal.
  2281. checksinglesided:
  2282. mov     al,es:[bx].EXT_BOOT_BPB.BPB_MEDIADESCRIPTOR
  2283. cmp     al, 0f0h        ; is it one of the new diskette type?
  2284. je      gooddsk         ; new disks are supported only after 3.2
  2285. test    al,0001h        ; is low bit set? - indicates double sided
  2286. jnz     gooddsk
  2287. cmp     word ptr es:[bx+8],"." shl 8 + "3"
  2288. jnz     mustbeearlier
  2289. cmp     byte ptr es:[bx+10],"2"
  2290. jae     gooddsk
  2291. ; we must have a pre-3.20 diskette. set the sec/clus field to 1
  2292. mustbeearlier:
  2293. mov     es:[bx].EXT_BOOT_BPB.BPB_SECTORSPERCLUSTER,1
  2294. jmp     short gooddsk
  2295.  inc     bx                         ; indicate that boot sector invalid
  2296. gooddsk:                                    ; carry already reset
  2297.  clc
  2298.  ret
  2299. invalidbootsec:
  2300.  stc
  2301.  ret
  2302. verify_bpb endp
  2303. if 0
  2304. hard_error_hang:
  2305. mov     ax,' '-'A'      ;just leave drive letter blank
  2306. call    warning_pop_up
  2307. jmp short hard_error_hang
  2308. endif
  2309. PUBLIC resident_initialization
  2310. resident_initialization:
  2311. push    cs                      ;transient data (stack) gets blown
  2312. pop     ss                      ;away in initqueue, so we have to
  2313. ;;;hack hack!!
  2314. ;;;386max's Qcache does an int 13 on TSR, so our resident stack will be
  2315. ;;;swapped.  We set the temp stack here to the middle of the stack
  2316. ;;;assuming that the int13 will not use too much stack. We do this
  2317. ;;;since the stack must be resident, but we dont want to wast space.
  2318. mov     sp,offset cs:temp_res_stack     ;make sure our stack is safe
  2319. mov     cx,cs:number_of_cache_elements
  2320. mov     bx,cs:cache_block_bytes
  2321. mov     dx,cs:ending_address    
  2322. push    dx                      ;save this now, since transient data dies
  2323. ;in initqueue
  2324. call    InitQueue
  2325. pop     dx
  2326. add     dx,10h                  ; adjust for PSP size
  2327. mov     ax,3100h                ; terminate, stay resident
  2328. int     21h
  2329. ;;;no fall through!
  2330. ;-----------------------------------------------------------------------
  2331. zseg    ends
  2332. end