Subversion Repositories Kolibri OS

Rev

Rev 2455 | Rev 2653 | 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: 2643 $
  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]
  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+4], 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      ?
  377. cache_chain_size        dd      ?
  378. cache_chain_pos         dd      ?
  379. cache_chain_ptr         dd      ?
  380. endl
  381. ; If there is no cache for this disk, nothing to do.
  382.         cmp     [esi+DISKCACHE.pointer], 0
  383.         jz      .flush
  384. ;-----------------------------------------------------------
  385. ; write all changed sectors to disk
  386. ;-----------------------------------------------------------
  387.  
  388.         ; write difference ( 2 ) from cache to DISK
  389.         mov     ecx, [esi+DISKCACHE.sad_size]
  390.         mov     esi, [esi+DISKCACHE.pointer]
  391.         add     esi, 12
  392.         mov     edi, 1
  393. .write_cache_more:
  394.         cmp     dword [esi+8], 2        ; if cache slot is not different
  395.         jne     .write_chain
  396.         mov     dword [esi+8], 1        ; same as in hd
  397.         mov     eax, [esi]
  398.         mov     edx, [esi+4]            ; edx:eax = sector to write
  399. ; Îáúåäèíÿåì çàïèñü öåïî÷êè ïîñëåäîâàòåëüíûõ ñåêòîðîâ â îäíî îáðàùåíèå ê äèñêó
  400.         cmp     ecx, 1
  401.         jz      .nonext
  402.         cmp     dword [esi+12+8], 2
  403.         jnz     .nonext
  404.         push    eax edx
  405.         add     eax, 1
  406.         adc     edx, 0
  407.         cmp     eax, [esi+12]
  408.         jnz     @f
  409.         cmp     edx, [esi+12+4]
  410. @@:
  411.         pop     edx eax
  412.         jnz     .nonext
  413.         cmp     [cache_chain_started], 1
  414.         jz      @f
  415.         mov     [cache_chain_started], 1
  416.         mov     [cache_chain_size], 0
  417.         mov     [cache_chain_pos], edi
  418.         mov     [cache_chain_ptr], esi
  419. @@:
  420.         inc     [cache_chain_size]
  421.         cmp     [cache_chain_size], 16
  422.         jnz     .continue
  423.         jmp     .write_chain
  424. .nonext:
  425.         call    .flush_cache_chain
  426.         test    eax, eax
  427.         jnz     .nothing
  428.         mov     [cache_chain_size], 1
  429.         mov     [cache_chain_ptr], esi
  430.         call    .write_cache_sector
  431.         test    eax, eax
  432.         jnz     .nothing
  433.         jmp     .continue
  434. .write_chain:
  435.         call    .flush_cache_chain
  436.         test    eax, eax
  437.         jnz     .nothing
  438. .continue:
  439.         add     esi, 12
  440.         inc     edi
  441.         dec     ecx
  442.         jnz     .write_cache_more
  443.         call    .flush_cache_chain
  444.         test    eax, eax
  445.         jnz     .nothing
  446. .flush:
  447.         mov     esi, [disk]
  448.         mov     al, DISKFUNC.flush
  449.         call    disk_call_driver
  450. .nothing:
  451.         ret
  452.  
  453. .flush_cache_chain:
  454.         xor     eax, eax
  455.         cmp     [cache_chain_started], eax
  456.         jz      @f
  457.         call    .write_cache_chain
  458.         mov     [cache_chain_started], 0
  459. @@:
  460.         retn
  461.  
  462. .write_cache_sector:
  463.         mov     [cache_chain_size], 1
  464.         mov     [cache_chain_pos], edi
  465. .write_cache_chain:
  466.         pusha
  467.         mov     edi, [cache_chain_pos]
  468.         mov     ecx, [ebp-12]
  469.         shl     edi, 9
  470.         add     edi, [ecx+DISKCACHE.data]
  471.         mov     ecx, [cache_chain_size]
  472.         push    ecx
  473.         push    esp     ; numsectors
  474.         mov     eax, [cache_chain_ptr]
  475.         pushd   [eax+4]
  476.         pushd   [eax]   ; startsector
  477.         push    edi     ; buffer
  478.         mov     esi, [ebp]
  479.         mov     esi, [esi+PARTITION.Disk]
  480.         mov     al, DISKFUNC.write
  481.         call    disk_call_driver
  482.         pop     ecx
  483.         mov     [esp+28], eax
  484.         popa
  485.         retn
  486. endp
  487.  
  488. ; This internal function is called from disk_add to initialize the caching for
  489. ; a new DISK.
  490. ; The algorithm is inherited from getcache.inc: take 1/32 part of the available
  491. ; physical memory, round down to 8 pages, limit by 128K from below and by 1M
  492. ; from above. Reserve 1/8 part of the cache for system data and 7/8 for app
  493. ; data.
  494. ; After the size is calculated, but before the cache is allocated, the device
  495. ; driver can adjust the size. In particular, setting size to zero disables
  496. ; caching: there is no sense in a cache for a ramdisk. In fact, such action
  497. ; is most useful example of a non-trivial adjustment.
  498. ; esi = pointer to DISK structure
  499. disk_init_cache:
  500. ; 1. Calculate the suggested cache size.
  501. ; 1a. Get the size of free physical memory in pages.
  502.         mov     eax, [pg_data.pages_free]
  503. ; 1b. Use the value to calculate the size.
  504.         shl     eax, 12 - 5     ; 1/32 of it in bytes
  505.         and     eax, -8*4096    ; round down to the multiple of 8 pages
  506. ; 1c. Force lower and upper limits.
  507.         cmp     eax, 1024*1024
  508.         jb      @f
  509.         mov     eax, 1024*1024
  510. @@:
  511.         cmp     eax, 128*1024
  512.         ja      @f
  513.         mov     eax, 128*1024
  514. @@:
  515. ; 1d. Give a chance to the driver to adjust the size.
  516.         push    eax
  517.         mov     al, DISKFUNC.adjust_cache_size
  518.         call    disk_call_driver
  519. ; Cache size calculated.
  520.         mov     [esi+DISK.cache_size], eax
  521.         test    eax, eax
  522.         jz      .nocache
  523. ; 2. Allocate memory for the cache.
  524. ; 2a. Call the allocator.
  525.         stdcall kernel_alloc, eax
  526.         test    eax, eax
  527.         jnz     @f
  528. ; 2b. If it failed, say a message and return with eax = 0.
  529.         dbgstr 'no memory for disk cache'
  530.         jmp     .nothing
  531. @@:
  532. ; 3. Fill two DISKCACHE structures.
  533.         mov     [esi+DISK.SysCache.pointer], eax
  534.         lea     ecx, [esi+DISK.SysCache.mutex]
  535.         call    mutex_init
  536.         lea     ecx, [esi+DISK.AppCache.mutex]
  537.         call    mutex_init
  538. ; The following code is inherited from getcache.inc.
  539.         mov     edx, [esi+DISK.SysCache.pointer]
  540.         and     [esi+DISK.SysCache.search_start], 0
  541.         and     [esi+DISK.AppCache.search_start], 0
  542.         mov     eax, [esi+DISK.cache_size]
  543.         shr     eax, 3
  544.         mov     [esi+DISK.SysCache.data_size], eax
  545.         add     edx, eax
  546.         imul    eax, 7
  547.         mov     [esi+DISK.AppCache.data_size], eax
  548.         mov     [esi+DISK.AppCache.pointer], edx
  549.  
  550.         mov     eax, [esi+DISK.SysCache.data_size]
  551.         push    ebx
  552.         call    calculate_for_hd
  553.         pop     ebx
  554.         add     eax, [esi+DISK.SysCache.pointer]
  555.         mov     [esi+DISK.SysCache.data], eax
  556.         mov     [esi+DISK.SysCache.sad_size], ecx
  557.  
  558.         push    edi
  559.         mov     edi, [esi+DISK.SysCache.pointer]
  560.         lea     ecx, [ecx*3]
  561.         xor     eax, eax
  562.         rep stosd
  563.         pop     edi
  564.  
  565.         mov     eax, [esi+DISK.AppCache.data_size]
  566.         push    ebx
  567.         call    calculate_for_hd
  568.         pop     ebx
  569.         add     eax, [esi+DISK.AppCache.pointer]
  570.         mov     [esi+DISK.AppCache.data], eax
  571.         mov     [esi+DISK.AppCache.sad_size], ecx
  572.  
  573.         push    edi
  574.         mov     edi, [esi+DISK.AppCache.pointer]
  575.         lea     ecx, [ecx*3]
  576.         xor     eax, eax
  577.         rep stosd
  578.         pop     edi
  579.  
  580. ; 4. Return with nonzero al.
  581.         mov     al, 1
  582. ; 5. Return.
  583. .nothing:
  584.         ret
  585. ; No caching is required for this driver. Zero cache pointers and return with
  586. ; nonzero al.
  587. .nocache:
  588.         mov     [esi+DISK.SysCache.pointer], eax
  589.         mov     [esi+DISK.AppCache.pointer], eax
  590.         mov     al, 1
  591.         ret
  592.  
  593. ; This internal function is called from disk_media_dereference to free the
  594. ; allocated cache, if there is one.
  595. ; esi = pointer to DISK structure
  596. disk_free_cache:
  597. ; The algorithm is straightforward.
  598.         mov     eax, [esi+DISK.SysCache.pointer]
  599.         test    eax, eax
  600.         jz      .nothing
  601.         stdcall kernel_free, eax
  602. .nothing:
  603.         ret
  604.  
  605. ; This function flushes all modified data from both caches for the given DISK.
  606. ; esi = pointer to DISK
  607. disk_sync:
  608. ; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure,
  609. ; this request should be processed by write_cache.
  610.         cmp     esi, 'old'
  611.         jz      write_cache
  612. ; The algorithm is straightforward.
  613.         push    esi
  614.         push    esi     ; for second write_cache64
  615.         push    esi     ; for first write_cache64
  616.         add     esi, DISK.SysCache
  617.         call    write_cache64
  618.         add     esi, DISK.AppCache - DISK.SysCache
  619.         call    write_cache64
  620.         pop     esi
  621.         ret
  622.