Subversion Repositories Kolibri OS

Rev

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