Subversion Repositories Kolibri OS

Rev

Rev 2987 | Rev 3500 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 2140 $
  9.  
  10. ; This function is intended to replace the old 'hd_read' function when
  11. ; [hdd_appl_data] = 0, so its input/output parameters are the same, except
  12. ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'.
  13. ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure
  14. ; eax is relative to partition start
  15. ; out: eax = error code; 0 = ok
  16. fs_read32_sys:
  17. ; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure,
  18. ; this request should be processed by hd_read.
  19.         cmp     [ebp+PARTITION.Disk], 'old'
  20.         jnz     @f
  21.         add     eax, dword [ebp+PARTITION.FirstSector]
  22.         mov     [hdd_appl_data], 0
  23.         call    hd_read
  24.         mov     [hdd_appl_data], 1      ; restore to default state
  25.         mov     eax, [hd_error]
  26.         ret
  27. @@:
  28. ; In the normal case, save ecx, set ecx to SysCache and let the common part
  29. ; do its work.
  30.         push    ecx
  31.         mov     ecx, [ebp+PARTITION.Disk]
  32.         add     ecx, DISK.SysCache
  33.         jmp     fs_read32_common
  34.  
  35. ; This function is intended to replace the old 'hd_read' function when
  36. ; [hdd_appl_data] = 1, so its input/output parameters are the same, except
  37. ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'.
  38. ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure
  39. ; eax is relative to partition start
  40. ; out: eax = error code; 0 = ok
  41. fs_read32_app:
  42. ; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure,
  43. ; this request should be processed by hd_read.
  44.         cmp     [ebp+PARTITION.Disk], 'old'
  45.         jnz     @f
  46.         add     eax, dword [ebp+PARTITION.FirstSector]
  47.         mov     [hdd_appl_data], 1
  48.         call    hd_read
  49.         mov     eax, [hd_error]
  50.         ret
  51. @@:
  52. ; In the normal case, save ecx, set ecx to AppCache and let the common part
  53. ; do its work.
  54.         push    ecx
  55.         mov     ecx, [ebp+PARTITION.Disk]
  56.         add     ecx, DISK.AppCache
  57.  
  58. ; This label is the common part of fs_read32_sys and fs_read32_app.
  59. fs_read32_common:
  60. ; 1. Check that the required sector is inside the partition. If no, return
  61. ; DISK_STATUS_END_OF_MEDIA.
  62.         cmp     dword [ebp+PARTITION.Length+4], 0
  63.         jnz     @f
  64.         cmp     dword [ebp+PARTITION.Length], eax
  65.         ja      @f
  66.         mov     eax, DISK_STATUS_END_OF_MEDIA
  67.         pop     ecx
  68.         ret
  69. @@:
  70. ; 2. Get the absolute sector on the disk.
  71.         push    edx esi
  72.         xor     edx, edx
  73.         add     eax, dword [ebp+PARTITION.FirstSector]
  74.         adc     edx, dword [ebp+PARTITION.FirstSector+4]
  75. ; 3. If there is no cache for this disk, just pass the request to the driver.
  76.         cmp     [ecx+DISKCACHE.pointer], 0
  77.         jnz     .scancache
  78.         push    1
  79.         push    esp     ; numsectors
  80.         push    edx     ; startsector
  81.         push    eax     ; startsector
  82.         push    ebx     ; buffer
  83.         mov     esi, [ebp+PARTITION.Disk]
  84.         mov     al, DISKFUNC.read
  85.         call    disk_call_driver
  86.         pop     ecx
  87.         pop     esi edx
  88.         pop     ecx
  89.         ret
  90. .scancache:
  91. ; 4. Scan the cache.
  92.         push    edi ecx ; scan cache
  93.         push    edx eax
  94. virtual at esp
  95. .sector_lo      dd      ?
  96. .sector_hi      dd      ?
  97. .cache          dd      ?
  98. end virtual
  99. ; The following code is inherited from hd_read. The differences are:
  100. ; all code is protected by the cache lock; instead of static calls
  101. ; to hd_read_dma/hd_read_pio/bd_read the dynamic call to DISKFUNC.read is used;
  102. ; sector is 64-bit, not 32-bit.
  103.         call    mutex_lock
  104.         mov     eax, [.sector_lo]
  105.         mov     edx, [.sector_hi]
  106.         mov     esi, [ecx+DISKCACHE.pointer]
  107.         mov     ecx, [ecx+DISKCACHE.sad_size]
  108.         add     esi, 12
  109.  
  110.         mov     edi, 1
  111.  
  112. .hdreadcache:
  113.  
  114.         cmp     dword [esi+8], 0        ; empty
  115.         je      .nohdcache
  116.  
  117.         cmp     [esi], eax      ; correct sector
  118.         jne     .nohdcache
  119.         cmp     [esi+4], edx    ; correct sector
  120.         je      .yeshdcache
  121.  
  122. .nohdcache:
  123.  
  124.         add     esi, 12
  125.         inc     edi
  126.         dec     ecx
  127.         jnz     .hdreadcache
  128.  
  129.         mov     esi, [.cache]
  130.         call    find_empty_slot64       ; ret in edi
  131.         test    eax, eax
  132.         jnz     .read_done
  133.  
  134.         push    1
  135.         push    esp
  136.         push    edx
  137.         push    [.sector_lo+12]
  138.         mov     ecx, [.cache+16]
  139.         mov     eax, edi
  140.         shl     eax, 9
  141.         add     eax, [ecx+DISKCACHE.data]
  142.         push    eax
  143.         mov     esi, [ebp+PARTITION.Disk]
  144.         mov     al, DISKFUNC.read
  145.         call    disk_call_driver
  146.         pop     ecx
  147.         dec     ecx
  148.         jnz     .read_done
  149.  
  150.         mov     ecx, [.cache]
  151.         lea     eax, [edi*3]
  152.         mov     esi, [ecx+DISKCACHE.pointer]
  153.         lea     esi, [eax*4+esi]
  154.  
  155.         mov     eax, [.sector_lo]
  156.         mov     edx, [.sector_hi]
  157.         mov     [esi], eax      ; sector number
  158.         mov     [esi+4], edx    ; sector number
  159.         mov     dword [esi+8], 1; hd read - mark as same as in hd
  160.  
  161. .yeshdcache:
  162.  
  163.         mov     esi, edi
  164.         mov     ecx, [.cache]
  165.         shl     esi, 9
  166.         add     esi, [ecx+DISKCACHE.data]
  167.  
  168.         mov     edi, ebx
  169.         mov     ecx, 512/4
  170.         rep     movsd           ; move data
  171.         xor     eax, eax        ; successful read
  172. .read_done:
  173.         mov     ecx, [.cache]
  174.         push    eax
  175.         call    mutex_unlock
  176.         pop     eax
  177.         add     esp, 12
  178.         pop     edi esi edx ecx
  179.         ret
  180.  
  181. ; This function is intended to replace the old 'hd_write' function when
  182. ; [hdd_appl_data] = 0, so its input/output parameters are the same, except
  183. ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'.
  184. ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure
  185. ; eax is relative to partition start
  186. ; out: eax = error code; 0 = ok
  187. fs_write32_sys:
  188. ; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure,
  189. ; this request should be processed by hd_write.
  190.         cmp     [ebp+PARTITION.Disk], 'old'
  191.         jnz     @f
  192.         add     eax, dword [ebp+PARTITION.FirstSector]
  193.         mov     [hdd_appl_data], 0
  194.         call    hd_write
  195.         mov     [hdd_appl_data], 1      ; restore to default state
  196.         mov     eax, [hd_error]
  197.         ret
  198. @@:
  199. ; In the normal case, save ecx, set ecx to SysCache and let the common part
  200. ; do its work.
  201.         push    ecx
  202.         mov     ecx, [ebp+PARTITION.Disk]
  203.         add     ecx, DISK.SysCache
  204.         jmp     fs_write32_common
  205.  
  206. ; This function is intended to replace the old 'hd_write' function when
  207. ; [hdd_appl_data] = 1, so its input/output parameters are the same, except
  208. ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'.
  209. ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure
  210. ; eax is relative to partition start
  211. ; out: eax = error code; 0 = ok
  212. fs_write32_app:
  213. ; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure,
  214. ; this request should be processed by hd_write.
  215.         cmp     [ebp+PARTITION.Disk], 'old'
  216.         jnz     @f
  217.         add     eax, dword [ebp+PARTITION.FirstSector]
  218.         mov     [hdd_appl_data], 1
  219.         call    hd_write
  220.         mov     eax, [hd_error]
  221.         ret
  222. @@:
  223. ; In the normal case, save ecx, set ecx to AppCache and let the common part
  224. ; do its work.
  225.         push    ecx
  226.         mov     ecx, [ebp+PARTITION.Disk]
  227.         add     ecx, DISK.AppCache
  228.  
  229. ; This label is the common part of fs_read32_sys and fs_read32_app.
  230. fs_write32_common:
  231. ; 1. Check that the required sector is inside the partition. If no, return
  232. ; DISK_STATUS_END_OF_MEDIA.
  233.         cmp     dword [ebp+PARTITION.Length+4], 0
  234.         jnz     @f
  235.         cmp     dword [ebp+PARTITION.Length], eax
  236.         ja      @f
  237.         mov     eax, DISK_STATUS_END_OF_MEDIA
  238.         pop     ecx
  239.         ret
  240. @@:
  241.         push    edx esi
  242. ; 2. Get the absolute sector on the disk.
  243.         xor     edx, edx
  244.         add     eax, dword [ebp+PARTITION.FirstSector]
  245.         adc     edx, dword [ebp+PARTITION.FirstSector+4]
  246. ; 3. If there is no cache for this disk, just pass request to the driver.
  247.         cmp     [ecx+DISKCACHE.pointer], 0
  248.         jnz     .scancache
  249.         push    1
  250.         push    esp     ; numsectors
  251.         push    edx     ; startsector
  252.         push    eax     ; startsector
  253.         push    ebx     ; buffer
  254.         mov     esi, [ebp+PARTITION.Disk]
  255.         mov     al, DISKFUNC.write
  256.         call    disk_call_driver
  257.         pop     ecx
  258.         pop     esi edx
  259.         pop     ecx
  260.         ret
  261. .scancache:
  262. ; 4. Scan the cache.
  263.         push    edi ecx ; scan cache
  264.         push    edx eax
  265. virtual at esp
  266. .sector_lo      dd      ?
  267. .sector_hi      dd      ?
  268. .cache          dd      ?
  269. end virtual
  270. ; The following code is inherited from hd_write. The differences are:
  271. ; all code is protected by the cache lock;
  272. ; sector is 64-bit, not 32-bit.
  273.         call    mutex_lock
  274.  
  275.         ; check if the cache already has the sector and overwrite it
  276.         mov     eax, [.sector_lo]
  277.         mov     edx, [.sector_hi]
  278.         mov     esi, [ecx+DISKCACHE.pointer]
  279.         mov     ecx, [ecx+DISKCACHE.sad_size]
  280.         add     esi, 12
  281.  
  282.         mov     edi, 1
  283.  
  284. .hdwritecache:
  285.         cmp     dword [esi+8], 0        ; if cache slot is empty
  286.         je      .not_in_cache_write
  287.  
  288.         cmp     [esi], eax      ; if the slot has the sector
  289.         jne     .not_in_cache_write
  290.         cmp     [esi+4], edx    ; if the slot has the sector
  291.         je      .yes_in_cache_write
  292.  
  293. .not_in_cache_write:
  294.  
  295.         add     esi, 12
  296.         inc     edi
  297.         dec     ecx
  298.         jnz     .hdwritecache
  299.  
  300.         ; sector not found in cache
  301.         ; write the block to a new location
  302.  
  303.         mov     esi, [.cache]
  304.         call    find_empty_slot64       ; ret in edi
  305.         test    eax, eax
  306.         jne     .hd_write_access_denied
  307.  
  308.         mov     ecx, [.cache]
  309.         lea     eax, [edi*3]
  310.         mov     esi, [ecx+DISKCACHE.pointer]
  311.         lea     esi, [eax*4+esi]
  312.  
  313.         mov     eax, [.sector_lo]
  314.         mov     edx, [.sector_hi]
  315.         mov     [esi], eax      ; sector number
  316.         mov     [esi+4], edx    ; sector number
  317.  
  318. .yes_in_cache_write:
  319.  
  320.         mov     dword [esi+8], 2        ; write - differs from hd
  321.  
  322.         shl     edi, 9
  323.         mov     ecx, [.cache]
  324.         add     edi, [ecx+DISKCACHE.data]
  325.  
  326.         mov     esi, ebx
  327.         mov     ecx, 512/4
  328.         rep     movsd           ; move data
  329.         xor     eax, eax        ; success
  330. .hd_write_access_denied:
  331.         mov     ecx, [.cache]
  332.         push    eax
  333.         call    mutex_unlock
  334.         pop     eax
  335.         add     esp, 12
  336.         pop     edi esi edx ecx
  337.         ret
  338.  
  339. ; This internal function is called from fs_read32_* and fs_write32_*. It is the
  340. ; analogue of find_empty_slot for 64-bit sectors.
  341. find_empty_slot64:
  342. ;-----------------------------------------------------------
  343. ; find empty or read slot, flush cache if next 12.5% is used by write
  344. ; output : edi = cache slot
  345. ;-----------------------------------------------------------
  346. .search_again:
  347.         mov     ecx, [esi+DISKCACHE.sad_size]
  348.         mov     edi, [esi+DISKCACHE.search_start]
  349.         shr     ecx, 3
  350. .search_for_empty:
  351.         inc     edi
  352.         cmp     edi, [esi+DISKCACHE.sad_size]
  353.         jbe     .inside_cache
  354.         mov     edi, 1
  355. .inside_cache:
  356.         lea     eax, [edi*3]
  357.         shl     eax, 2
  358.         add     eax, [esi+DISKCACHE.pointer]
  359.         cmp     dword [eax+8], 2
  360.         jb      .found_slot             ; it's empty or read
  361.         dec     ecx
  362.         jnz     .search_for_empty
  363.         stdcall write_cache64, [ebp+PARTITION.Disk] ; no empty slots found, write all
  364.         test    eax, eax
  365.         jne     .found_slot_access_denied
  366.         jmp     .search_again           ; and start again
  367. .found_slot:
  368.         mov     [esi+DISKCACHE.search_start], edi
  369.         xor     eax, eax        ; success
  370. .found_slot_access_denied:
  371.         ret
  372.  
  373. ; This function is intended to replace the old 'write_cache' function.
  374. proc write_cache64 uses ecx edx esi edi, disk:dword
  375. locals
  376. cache_chain_started     dd      0
  377. cache_chain_size        dd      ?
  378. cache_chain_pos         dd      ?
  379. cache_chain_ptr         dd      ?
  380. endl
  381. saved_esi_pos = 16+12 ; size of local variables + size of registers before esi
  382. ; If there is no cache for this disk, nothing to do.
  383.         cmp     [esi+DISKCACHE.pointer], 0
  384.         jz      .flush
  385. ;-----------------------------------------------------------
  386. ; write all changed sectors to disk
  387. ;-----------------------------------------------------------
  388.  
  389.         ; write difference ( 2 ) from cache to DISK
  390.         mov     ecx, [esi+DISKCACHE.sad_size]
  391.         mov     esi, [esi+DISKCACHE.pointer]
  392.         add     esi, 12
  393.         mov     edi, 1
  394. .write_cache_more:
  395.         cmp     dword [esi+8], 2        ; if cache slot is not different
  396.         jne     .write_chain
  397.         mov     dword [esi+8], 1        ; same as in hd
  398.         mov     eax, [esi]
  399.         mov     edx, [esi+4]            ; edx:eax = sector to write
  400. ; ╬с·хфшэ хь чряшё№ Ўхяюўъш яюёыхфютрЄхы№э√ї ёхъЄюЁют т юфэю юсЁр∙хэшх ъ фшёъє
  401.         cmp     ecx, 1
  402.         jz      .nonext
  403.         cmp     dword [esi+12+8], 2
  404.         jnz     .nonext
  405.         push    eax edx
  406.         add     eax, 1
  407.         adc     edx, 0
  408.         cmp     eax, [esi+12]
  409.         jnz     @f
  410.         cmp     edx, [esi+12+4]
  411. @@:
  412.         pop     edx eax
  413.         jnz     .nonext
  414.         cmp     [cache_chain_started], 1
  415.         jz      @f
  416.         mov     [cache_chain_started], 1
  417.         mov     [cache_chain_size], 0
  418.         mov     [cache_chain_pos], edi
  419.         mov     [cache_chain_ptr], esi
  420. @@:
  421.         inc     [cache_chain_size]
  422.         cmp     [cache_chain_size], 16
  423.         jnz     .continue
  424.         jmp     .write_chain
  425. .nonext:
  426.         call    .flush_cache_chain
  427.         test    eax, eax
  428.         jnz     .nothing
  429.         mov     [cache_chain_size], 1
  430.         mov     [cache_chain_ptr], esi
  431.         call    .write_cache_sector
  432.         test    eax, eax
  433.         jnz     .nothing
  434.         jmp     .continue
  435. .write_chain:
  436.         call    .flush_cache_chain
  437.         test    eax, eax
  438.         jnz     .nothing
  439. .continue:
  440.         add     esi, 12
  441.         inc     edi
  442.         dec     ecx
  443.         jnz     .write_cache_more
  444.         call    .flush_cache_chain
  445.         test    eax, eax
  446.         jnz     .nothing
  447. .flush:
  448.         mov     esi, [disk]
  449.         mov     al, DISKFUNC.flush
  450.         call    disk_call_driver
  451. .nothing:
  452.         ret
  453.  
  454. .flush_cache_chain:
  455.         xor     eax, eax
  456.         cmp     [cache_chain_started], eax
  457.         jz      @f
  458.         call    .write_cache_chain
  459.         mov     [cache_chain_started], 0
  460. @@:
  461.         retn
  462.  
  463. .write_cache_sector:
  464.         mov     [cache_chain_size], 1
  465.         mov     [cache_chain_pos], edi
  466. .write_cache_chain:
  467.         pusha
  468.         mov     edi, [cache_chain_pos]
  469.         mov     ecx, [ebp-saved_esi_pos]
  470.         shl     edi, 9
  471.         add     edi, [ecx+DISKCACHE.data]
  472.         mov     ecx, [cache_chain_size]
  473.         push    ecx
  474.         push    esp     ; numsectors
  475.         mov     eax, [cache_chain_ptr]
  476.         pushd   [eax+4]
  477.         pushd   [eax]   ; startsector
  478.         push    edi     ; buffer
  479.         mov     esi, [ebp]
  480.         mov     esi, [esi+PARTITION.Disk]
  481.         mov     al, DISKFUNC.write
  482.         call    disk_call_driver
  483.         pop     ecx
  484.         mov     [esp+28], eax
  485.         popa
  486.         retn
  487. endp
  488.  
  489. ; This internal function is called from disk_add to initialize the caching for
  490. ; a new DISK.
  491. ; The algorithm is inherited from getcache.inc: take 1/32 part of the available
  492. ; physical memory, round down to 8 pages, limit by 128K from below and by 1M
  493. ; from above. Reserve 1/8 part of the cache for system data and 7/8 for app
  494. ; data.
  495. ; After the size is calculated, but before the cache is allocated, the device
  496. ; driver can adjust the size. In particular, setting size to zero disables
  497. ; caching: there is no sense in a cache for a ramdisk. In fact, such action
  498. ; is most useful example of a non-trivial adjustment.
  499. ; esi = pointer to DISK structure
  500. disk_init_cache:
  501. ; 1. Calculate the suggested cache size.
  502. ; 1a. Get the size of free physical memory in pages.
  503.         mov     eax, [pg_data.pages_free]
  504. ; 1b. Use the value to calculate the size.
  505.         shl     eax, 12 - 5     ; 1/32 of it in bytes
  506.         and     eax, -8*4096    ; round down to the multiple of 8 pages
  507. ; 1c. Force lower and upper limits.
  508.         cmp     eax, 1024*1024
  509.         jb      @f
  510.         mov     eax, 1024*1024
  511. @@:
  512.         cmp     eax, 128*1024
  513.         ja      @f
  514.         mov     eax, 128*1024
  515. @@:
  516. ; 1d. Give a chance to the driver to adjust the size.
  517.         push    eax
  518.         mov     al, DISKFUNC.adjust_cache_size
  519.         call    disk_call_driver
  520. ; Cache size calculated.
  521.         mov     [esi+DISK.cache_size], eax
  522.         test    eax, eax
  523.         jz      .nocache
  524. ; 2. Allocate memory for the cache.
  525. ; 2a. Call the allocator.
  526.         stdcall kernel_alloc, eax
  527.         test    eax, eax
  528.         jnz     @f
  529. ; 2b. If it failed, say a message and return with eax = 0.
  530.         dbgstr 'no memory for disk cache'
  531.         jmp     .nothing
  532. @@:
  533. ; 3. Fill two DISKCACHE structures.
  534.         mov     [esi+DISK.SysCache.pointer], eax
  535.         lea     ecx, [esi+DISK.SysCache.mutex]
  536.         call    mutex_init
  537.         lea     ecx, [esi+DISK.AppCache.mutex]
  538.         call    mutex_init
  539. ; The following code is inherited from getcache.inc.
  540.         mov     edx, [esi+DISK.SysCache.pointer]
  541.         and     [esi+DISK.SysCache.search_start], 0
  542.         and     [esi+DISK.AppCache.search_start], 0
  543.         mov     eax, [esi+DISK.cache_size]
  544.         shr     eax, 3
  545.         mov     [esi+DISK.SysCache.data_size], eax
  546.         add     edx, eax
  547.         imul    eax, 7
  548.         mov     [esi+DISK.AppCache.data_size], eax
  549.         mov     [esi+DISK.AppCache.pointer], edx
  550.  
  551.         mov     eax, [esi+DISK.SysCache.data_size]
  552.         push    ebx
  553.         call    calculate_for_hd64
  554.         pop     ebx
  555.         add     eax, [esi+DISK.SysCache.pointer]
  556.         mov     [esi+DISK.SysCache.data], eax
  557.         mov     [esi+DISK.SysCache.sad_size], ecx
  558.  
  559.         push    edi
  560.         mov     edi, [esi+DISK.SysCache.pointer]
  561.         lea     ecx, [ecx*3]
  562.         xor     eax, eax
  563.         rep     stosd
  564.         pop     edi
  565.  
  566.         mov     eax, [esi+DISK.AppCache.data_size]
  567.         push    ebx
  568.         call    calculate_for_hd64
  569.         pop     ebx
  570.         add     eax, [esi+DISK.AppCache.pointer]
  571.         mov     [esi+DISK.AppCache.data], eax
  572.         mov     [esi+DISK.AppCache.sad_size], ecx
  573.  
  574.         push    edi
  575.         mov     edi, [esi+DISK.AppCache.pointer]
  576.         lea     ecx, [ecx*3]
  577.         xor     eax, eax
  578.         rep     stosd
  579.         pop     edi
  580.  
  581. ; 4. Return with nonzero al.
  582.         mov     al, 1
  583. ; 5. Return.
  584. .nothing:
  585.         ret
  586. ; No caching is required for this driver. Zero cache pointers and return with
  587. ; nonzero al.
  588. .nocache:
  589.         mov     [esi+DISK.SysCache.pointer], eax
  590.         mov     [esi+DISK.AppCache.pointer], eax
  591.         mov     al, 1
  592.         ret
  593.  
  594. calculate_for_hd64:
  595.         push    eax
  596.         mov     ebx, eax
  597.         shr     eax, 9
  598.         lea     eax, [eax*3]
  599.         shl     eax, 2
  600.         sub     ebx, eax
  601.         shr     ebx, 9
  602.         mov     ecx, ebx
  603.         shl     ebx, 9
  604.         pop     eax
  605.         sub     eax, ebx
  606.         dec     ecx
  607.         ret
  608.  
  609.  
  610. ; This internal function is called from disk_media_dereference to free the
  611. ; allocated cache, if there is one.
  612. ; esi = pointer to DISK structure
  613. disk_free_cache:
  614. ; The algorithm is straightforward.
  615.         mov     eax, [esi+DISK.SysCache.pointer]
  616.         test    eax, eax
  617.         jz      .nothing
  618.         stdcall kernel_free, eax
  619. .nothing:
  620.         ret
  621.  
  622. ; This function flushes all modified data from both caches for the given DISK.
  623. ; esi = pointer to DISK
  624. disk_sync:
  625. ; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure,
  626. ; this request should be processed by write_cache.
  627.         cmp     esi, 'old'
  628.         jnz     @f
  629.         mov     [hdd_appl_data], 0
  630.         call    write_cache
  631.         mov     [hdd_appl_data], 1
  632.         jmp     write_cache
  633. @@:
  634. ; The algorithm is straightforward.
  635.         push    esi
  636.         push    esi     ; for second write_cache64
  637.         push    esi     ; for first write_cache64
  638.         add     esi, DISK.SysCache
  639.         call    write_cache64
  640.         add     esi, DISK.AppCache - DISK.SysCache
  641.         call    write_cache64
  642.         pop     esi
  643.         ret
  644.