Rev 4265 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4265 | Rev 5201 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
2 | ;; ;; |
3 | ;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;; |
3 | ;; Copyright (C) KolibriOS team 2011-2014. All rights reserved. ;; |
4 | ;; Distributed under terms of the GNU General Public License ;; |
4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
5 | ;; ;; |
6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
Line 7... | Line 7... | ||
7 | 7 | ||
Line -... | Line 8... | ||
- | 8 | $Revision: 3742 $ |
|
- | 9 | ||
- | 10 | ; Read/write functions try to do large operations, |
|
- | 11 | ; it is significantly faster than several small operations. |
|
- | 12 | ; This requires large buffers. |
|
- | 13 | ; We can't use input/output buffers directly - they can be controlled |
|
- | 14 | ; by user-mode application, so they can be modified between the operation |
|
- | 15 | ; and copying to/from cache, giving invalid data in cache. |
|
- | 16 | ; It is unclear how to use cache directly, currently cache items are |
|
- | 17 | ; allocated/freed sector-wise, so items for sequential sectors can be |
|
- | 18 | ; scattered over all the cache. |
|
- | 19 | ; So read/write functions allocate a temporary buffer which is |
|
- | 20 | ; 1) not greater than half of free memory and |
|
- | 21 | ; 2) not greater than the following constant. |
|
- | 22 | CACHE_MAX_ALLOC_SIZE = 4 shl 20 |
|
- | 23 | ||
- | 24 | ; Legacy interface for filesystems fs_{read,write}32_{sys,app} |
|
- | 25 | ; gives only one sector for FS. However, per-sector reading is inefficient, |
|
- | 26 | ; so internally fs_read32_{sys,app} reads to the cache several sequential |
|
- | 27 | ; sectors, hoping that they will be useful. |
|
- | 28 | ; Total number of sectors is given by the following constant. |
|
- | 29 | CACHE_LEGACY_READ_SIZE = 16 |
|
- | 30 | ||
- | 31 | ; This structure describes one item in the cache. |
|
- | 32 | struct CACHE_ITEM |
|
- | 33 | SectorLo dd ? ; low 32 bits of sector |
|
- | 34 | SectorHi dd ? ; high 32 bits of sector |
|
- | 35 | Status dd ? ; one of CACHE_ITEM_* |
|
- | 36 | ends |
|
- | 37 | ||
- | 38 | ; Possible values for CACHE_ITEM_* |
|
- | 39 | CACHE_ITEM_EMPTY = 0 |
|
- | 40 | CACHE_ITEM_COPY = 1 |
|
- | 41 | CACHE_ITEM_MODIFIED = 2 |
|
- | 42 | ||
- | 43 | ; Read several sequential sectors using cache #1. |
|
- | 44 | ; in: edx:eax = start sector, relative to start of partition |
|
- | 45 | ; in: ecx = number of sectors to read |
|
- | 46 | ; in: ebx -> buffer |
|
- | 47 | ; in: ebp -> PARTITION |
|
- | 48 | ; out: eax = error code, 0 = ok |
|
- | 49 | ; out: ecx = number of sectors that were read |
|
- | 50 | fs_read64_sys: |
|
- | 51 | ; Save ebx, set ebx to SysCache and let the common part do its work. |
|
- | 52 | push ebx ebx |
|
- | 53 | mov ebx, [ebp+PARTITION.Disk] |
|
- | 54 | add ebx, DISK.SysCache |
|
- | 55 | jmp fs_read64_common |
|
- | 56 | ||
- | 57 | ; Read several sequential sectors using cache #2. |
|
- | 58 | ; in: edx:eax = start sector, relative to start of partition |
|
- | 59 | ; in: ecx = number of sectors to read |
|
- | 60 | ; in: edi -> buffer |
|
- | 61 | ; in: ebp -> PARTITION |
|
- | 62 | ; out: eax = error code, 0 = ok |
|
- | 63 | ; out: ecx = number of sectors that were read |
|
- | 64 | fs_read64_app: |
|
- | 65 | ; Save ebx, set ebx to AppCache and let the common part do its work. |
|
- | 66 | push ebx ebx |
|
- | 67 | mov ebx, [ebp+PARTITION.Disk] |
|
- | 68 | add ebx, DISK.AppCache |
|
- | 69 | ||
- | 70 | ; Common part of fs_read64_{app,sys}: |
|
- | 71 | ; read several sequential sectors using the given cache. |
|
- | 72 | fs_read64_common: |
|
- | 73 | ; 1. Setup stack frame. |
|
- | 74 | push esi edi ; save used registers to be stdcall |
|
- | 75 | push 0 ; initialize .error_code |
|
- | 76 | push ebx edx eax ecx ecx ; initialize stack variables |
|
- | 77 | virtual at esp |
|
- | 78 | .local_vars: |
|
- | 79 | .num_sectors_orig dd ? |
|
- | 80 | ; Number of sectors that should be read. Used to generate output value of ecx. |
|
- | 81 | .num_sectors dd ? |
|
- | 82 | ; Number of sectors that remain to be read. Decreases from .num_sectors_orig to 0. |
|
- | 83 | .sector_lo dd ? ; low 32 bits of the current sector |
|
- | 84 | .sector_hi dd ? ; high 32 bits of the current sector |
|
- | 85 | .cache dd ? ; pointer to DISKCACHE |
|
- | 86 | .error_code dd ? ; current status |
|
- | 87 | .local_vars_size = $ - .local_vars |
|
- | 88 | .saved_regs rd 2 |
|
- | 89 | .buffer dd ? ; filled by fs_read64_{sys,app} |
|
- | 90 | end virtual |
|
- | 91 | ; 2. Validate parameters against partition length: |
|
- | 92 | ; immediately return error if edx:eax are beyond partition end, |
|
- | 93 | ; decrease .num_sectors and .num_sectors_orig, if needed, |
|
- | 94 | ; so that the entire operation fits in the partition limits. |
|
- | 95 | mov eax, dword [ebp+PARTITION.Length] |
|
- | 96 | mov edx, dword [ebp+PARTITION.Length+4] |
|
- | 97 | sub eax, [.sector_lo] |
|
- | 98 | sbb edx, [.sector_hi] |
|
- | 99 | jb .end_of_media |
|
- | 100 | jnz .no_end_of_media |
|
- | 101 | cmp ecx, eax |
|
- | 102 | jbe .no_end_of_media |
|
- | 103 | ; If .num_sectors got decreased, set status to DISK_STATUS_END_OF_MEDIA; |
|
- | 104 | ; if all subsequent operations would be successful, this would become the final |
|
- | 105 | ; status, otherwise this would be rewritten by failed operation. |
|
- | 106 | mov [.num_sectors], eax |
|
- | 107 | mov [.num_sectors_orig], eax |
|
- | 108 | mov [.error_code], DISK_STATUS_END_OF_MEDIA |
|
- | 109 | .no_end_of_media: |
|
- | 110 | ; 3. If number of sectors to read is zero, either because zero-sectors operation |
|
- | 111 | ; was requested or because it got decreased to zero due to partition limits, |
|
- | 112 | ; just return the current status. |
|
- | 113 | cmp [.num_sectors], 0 |
|
- | 114 | jz .return |
|
- | 115 | ; 4. Shift sector from partition-relative to absolute. |
|
- | 116 | mov eax, dword [ebp+PARTITION.FirstSector] |
|
- | 117 | mov edx, dword [ebp+PARTITION.FirstSector+4] |
|
- | 118 | add [.sector_lo], eax |
|
- | 119 | adc [.sector_hi], edx |
|
- | 120 | ; 5. If the cache is disabled, pass the request directly to the driver. |
|
- | 121 | cmp [ebx+DISKCACHE.pointer], 0 |
|
- | 122 | jz .nocache |
|
- | 123 | ; 6. Look for sectors in the cache, sequentially from the beginning. |
|
- | 124 | ; Stop at the first sector that is not in the cache |
|
- | 125 | ; or when all sectors were read from the cache. |
|
- | 126 | ; 6a. Acquire the lock. |
|
- | 127 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 128 | add ecx, DISK.CacheLock |
|
- | 129 | call mutex_lock |
|
- | 130 | .lookup_in_cache_loop: |
|
- | 131 | ; 6b. For each sector, call the lookup function without adding to the cache. |
|
- | 132 | mov eax, [.sector_lo] |
|
- | 133 | mov edx, [.sector_hi] |
|
- | 134 | call cache_lookup_read |
|
- | 135 | ; 6c. If it has failed, the sector is not in cache; |
|
- | 136 | ; release the lock and go to 7. |
|
- | 137 | jc .not_found_in_cache |
|
- | 138 | ; The sector is found in cache. |
|
- | 139 | ; 6d. Copy data for the caller, advance [.buffer]. |
|
- | 140 | mov esi, edi |
|
- | 141 | mov edi, [.buffer] |
|
- | 142 | mov eax, 1 |
|
- | 143 | shl eax, cl |
|
- | 144 | mov ecx, eax |
|
- | 145 | shr ecx, 2 |
|
- | 146 | rep movsd |
|
- | 147 | mov [.buffer], edi |
|
- | 148 | ; 6e. Advance the sector. |
|
- | 149 | add [.sector_lo], 1 |
|
- | 150 | adc [.sector_hi], 0 |
|
- | 151 | ; 6f. Decrement number of sectors left. |
|
- | 152 | ; If all sectors were read, release the lock and return. |
|
- | 153 | dec [.num_sectors] |
|
- | 154 | jnz .lookup_in_cache_loop |
|
- | 155 | ; Release the lock acquired at 6a. |
|
- | 156 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 157 | add ecx, DISK.CacheLock |
|
- | 158 | call mutex_unlock |
|
- | 159 | .return: |
|
- | 160 | mov eax, [.error_code] |
|
- | 161 | mov ecx, [.num_sectors_orig] |
|
- | 162 | sub ecx, [.num_sectors] |
|
- | 163 | .nothing: |
|
- | 164 | add esp, .local_vars_size |
|
- | 165 | pop edi esi ebx ebx ; restore used registers to be stdcall |
|
- | 166 | ret |
|
- | 167 | .not_found_in_cache: |
|
- | 168 | ; Release the lock acquired at 6a. |
|
- | 169 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 170 | add ecx, DISK.CacheLock |
|
- | 171 | call mutex_unlock |
|
- | 172 | ; The current sector is not present in the cache. |
|
- | 173 | ; Ask the driver to read all requested not-yet-read sectors, |
|
- | 174 | ; put results in the cache. |
|
- | 175 | ; Also, see the comment before the definition of CACHE_MAX_ALLOC_SIZE. |
|
- | 176 | ; 7. Allocate buffer for operations. |
|
- | 177 | ; Normally, create buffer that is sufficient for all remaining data. |
|
- | 178 | ; However, for extra-large requests make an upper limit: |
|
- | 179 | ; do not use more than half of the free memory |
|
- | 180 | ; or more than CACHE_MAX_ALLOC_SIZE bytes. |
|
- | 181 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
|
- | 182 | mov ebx, [pg_data.pages_free] |
|
- | 183 | shr ebx, 1 |
|
- | 184 | jz .nomemory |
|
- | 185 | cmp ebx, CACHE_MAX_ALLOC_SIZE shr 12 |
|
- | 186 | jbe @f |
|
- | 187 | mov ebx, CACHE_MAX_ALLOC_SIZE shr 12 |
|
- | 188 | @@: |
|
- | 189 | shl ebx, 12 |
|
- | 190 | shr ebx, cl |
|
- | 191 | jz .nomemory |
|
- | 192 | cmp ebx, [.num_sectors] |
|
- | 193 | jbe @f |
|
- | 194 | mov ebx, [.num_sectors] |
|
- | 195 | @@: |
|
- | 196 | mov eax, ebx |
|
- | 197 | shl eax, cl |
|
- | 198 | stdcall kernel_alloc, eax |
|
- | 199 | ; If failed, return the appropriate error code. |
|
- | 200 | test eax, eax |
|
- | 201 | jz .nomemory |
|
- | 202 | mov esi, eax |
|
- | 203 | ; Split the request to chunks that fit in the allocated buffer. |
|
- | 204 | .read_loop: |
|
- | 205 | ; 8. Get iteration size: either size of allocated buffer in sectors |
|
- | 206 | ; or number of sectors left, select what is smaller. |
|
- | 207 | cmp ebx, [.num_sectors] |
|
- | 208 | jbe @f |
|
- | 209 | mov ebx, [.num_sectors] |
|
- | 210 | @@: |
|
- | 211 | ; 9. Create second portion of local variables. |
|
- | 212 | ; Note that variables here and above are esp-relative; |
|
- | 213 | ; it means that all addresses should be corrected when esp is changing. |
|
- | 214 | push ebx esi esi |
|
- | 215 | push ebx |
|
- | 216 | ; In particular, num_sectors is now [.num_sectors+.local_vars2_size]. |
|
- | 217 | virtual at esp |
|
- | 218 | .local_vars2: |
|
- | 219 | .current_num_sectors dd ? ; number of sectors that were read |
|
- | 220 | .current_buffer dd ? |
|
- | 221 | ; pointer inside .allocated_buffer that points |
|
- | 222 | ; to the beginning of not-processed data |
|
- | 223 | .allocated_buffer dd ? ; saved in safe place |
|
- | 224 | .iteration_size dd ? ; saved in safe place |
|
- | 225 | .local_vars2_size = $ - .local_vars2 |
|
- | 226 | end virtual |
|
- | 227 | ; 10. Call the driver, reading the next chunk. |
|
- | 228 | push esp ; numsectors |
|
- | 229 | push [.sector_hi+.local_vars2_size+4] ; startsector |
|
- | 230 | push [.sector_lo+.local_vars2_size+8] ; startsector |
|
- | 231 | push esi ; buffer |
|
- | 232 | mov esi, [ebp+PARTITION.Disk] |
|
- | 233 | mov al, DISKFUNC.read |
|
- | 234 | call disk_call_driver |
|
- | 235 | ; If failed, save error code. |
|
- | 236 | test eax, eax |
|
- | 237 | jz @f |
|
- | 238 | mov [.error_code+.local_vars2_size], eax |
|
- | 239 | @@: |
|
- | 240 | ; 11. Copy data for the caller, advance .buffer. |
|
- | 241 | cmp [.current_num_sectors], 0 |
|
- | 242 | jz .copy_done |
|
- | 243 | mov ebx, [.cache+.local_vars2_size] |
|
- | 244 | mov eax, [.current_num_sectors] |
|
- | 245 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
|
- | 246 | shl eax, cl |
|
- | 247 | mov esi, [.allocated_buffer] |
|
- | 248 | mov edi, [.buffer+.local_vars2_size] |
|
- | 249 | mov ecx, eax |
|
- | 250 | shr ecx, 2 |
|
- | 251 | rep movsd |
|
- | 252 | mov [.buffer+.local_vars2_size], edi |
|
- | 253 | ; 12. Copy data to the cache. |
|
- | 254 | ; 12a. Acquire the lock. |
|
- | 255 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 256 | add ecx, DISK.CacheLock |
|
- | 257 | call mutex_lock |
|
- | 258 | ; 12b. Prepare for the loop: create a local variable that |
|
- | 259 | ; stores number of sectors to be copied. |
|
- | 260 | push [.current_num_sectors] |
|
- | 261 | .store_to_cache: |
|
- | 262 | ; 12c. For each sector, call the lookup function with adding to the cache, if not yet. |
|
- | 263 | mov eax, [.sector_lo+.local_vars2_size+4] |
|
- | 264 | mov edx, [.sector_hi+.local_vars2_size+4] |
|
- | 265 | call cache_lookup_write |
|
- | 266 | test eax, eax |
|
- | 267 | jnz .cache_error |
|
- | 268 | ; 12d. If the sector was already present in the cache as modified, |
|
- | 269 | ; data that were read at step 10 for this sector are obsolete, |
|
- | 270 | ; so rewrite data for the caller from the cache. |
|
- | 271 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
- | 272 | jnz .not_modified |
|
- | 273 | mov esi, edi |
|
- | 274 | mov edi, [.buffer+.local_vars2_size+4] |
|
- | 275 | mov eax, [esp] |
|
- | 276 | shl eax, cl |
|
- | 277 | sub edi, eax |
|
- | 278 | mov eax, 1 |
|
- | 279 | shl eax, cl |
|
- | 280 | mov ecx, eax |
|
- | 281 | shr ecx, 2 |
|
- | 282 | rep movsd |
|
- | 283 | add [.current_buffer+4], eax |
|
- | 284 | jmp .sector_done |
|
- | 285 | .not_modified: |
|
- | 286 | ; 12e. For each not-modified sector, |
|
- | 287 | ; copy data, mark the item as not-modified copy of the disk, |
|
- | 288 | ; advance .current_buffer and .sector_hi:.sector_lo to the next sector. |
|
- | 289 | mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
|
- | 290 | mov eax, 1 |
|
- | 291 | shl eax, cl |
|
- | 292 | mov esi, [.current_buffer+4] |
|
- | 293 | mov ecx, eax |
|
- | 294 | shr ecx, 2 |
|
- | 295 | rep movsd |
|
- | 296 | mov [.current_buffer+4], esi |
|
- | 297 | .sector_done: |
|
- | 298 | add [.sector_lo+.local_vars2_size+4], 1 |
|
- | 299 | adc [.sector_hi+.local_vars2_size+4], 0 |
|
- | 300 | ; 12f. Continue the loop 12c-12e until all sectors are read. |
|
- | 301 | dec dword [esp] |
|
- | 302 | jnz .store_to_cache |
|
- | 303 | .cache_error: |
|
- | 304 | ; 12g. Restore after the loop: pop the local variable. |
|
- | 305 | pop ecx |
|
- | 306 | ; 12h. Release the lock. |
|
- | 307 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 308 | add ecx, DISK.CacheLock |
|
- | 309 | call mutex_unlock |
|
- | 310 | .copy_done: |
|
- | 311 | ; 13. Remove portion of local variables created at step 9. |
|
- | 312 | pop ecx |
|
- | 313 | pop esi esi ebx |
|
- | 314 | ; 14. Continue iterations while number of sectors read by the driver |
|
- | 315 | ; is equal to number of sectors requested and there are additional sectors. |
|
- | 316 | cmp ecx, ebx |
|
- | 317 | jnz @f |
|
- | 318 | sub [.num_sectors], ebx |
|
- | 319 | jnz .read_loop |
|
- | 320 | @@: |
|
- | 321 | ; 15. Free the buffer allocated at step 7 and return. |
|
- | 322 | stdcall kernel_free, esi |
|
- | 323 | jmp .return |
|
- | 324 | ||
- | 325 | ; Special branches: |
|
- | 326 | .nomemory: |
|
- | 327 | ; memory allocation failed at step 7: return the corresponding error |
|
- | 328 | mov [.error_code], DISK_STATUS_NO_MEMORY |
|
- | 329 | jmp .return |
|
- | 330 | .nocache: |
|
- | 331 | ; step 5, after correcting number of sectors to fit in partition limits |
|
- | 332 | ; and advancing partition-relative sector to absolute, |
|
- | 333 | ; sees that cache is disabled: pass corrected request to the driver |
|
- | 334 | lea eax, [.num_sectors] |
|
- | 335 | push eax ; numsectors |
|
- | 336 | push [.sector_hi+4] ; startsector |
|
- | 337 | push [.sector_lo+8] ; startsector |
|
- | 338 | push [.buffer+12] ; buffer |
|
- | 339 | mov esi, [ebp+PARTITION.Disk] |
|
- | 340 | mov al, DISKFUNC.read |
|
- | 341 | call disk_call_driver |
|
- | 342 | test eax, eax |
|
- | 343 | jnz @f |
|
- | 344 | mov eax, [.error_code] |
|
- | 345 | @@: |
|
- | 346 | mov ecx, [.num_sectors] |
|
- | 347 | jmp .nothing |
|
- | 348 | .end_of_media: |
|
- | 349 | ; requested sector is beyond the partition end: return the corresponding error |
|
- | 350 | mov [.error_code], DISK_STATUS_END_OF_MEDIA |
|
- | 351 | jmp .return |
|
- | 352 | ||
- | 353 | ; Write several sequential sectors using cache #1. |
|
- | 354 | ; in: edx:eax = start sector |
|
- | 355 | ; in: ecx = number of sectors to write |
|
- | 356 | ; in: ebx -> buffer |
|
- | 357 | ; in: ebp -> PARTITION |
|
- | 358 | ; out: eax = error code, 0 = ok |
|
- | 359 | ; out: ecx = number of sectors that were written |
|
- | 360 | fs_write64_sys: |
|
- | 361 | ; Save ebx, set ebx to SysCache and let the common part do its work. |
|
- | 362 | push ebx |
|
- | 363 | mov ebx, [ebp+PARTITION.Disk] |
|
- | 364 | add ebx, DISK.SysCache |
|
- | 365 | jmp fs_write64_common |
|
- | 366 | ||
- | 367 | ; Write several sequential sectors using cache #2. |
|
- | 368 | ; in: edx:eax = start sector |
|
- | 369 | ; in: ecx = number of sectors to write |
|
- | 370 | ; in: ebx -> buffer |
|
- | 371 | ; in: ebp -> PARTITION |
|
- | 372 | ; out: eax = error code, 0 = ok |
|
- | 373 | ; out: ecx = number of sectors that were written |
|
- | 374 | fs_write64_app: |
|
- | 375 | ; Save ebx, set ebx to AppCache and let the common part do its work. |
|
- | 376 | push ebx |
|
- | 377 | mov ebx, [ebp+PARTITION.Disk] |
|
- | 378 | add ebx, DISK.AppCache |
|
- | 379 | ||
- | 380 | ; Common part of fs_write64_{app,sys}: |
|
- | 381 | ; write several sequential sectors using the given cache. |
|
- | 382 | fs_write64_common: |
|
- | 383 | ; 1. Setup stack frame. |
|
- | 384 | push esi edi ; save used registers to be stdcall |
|
- | 385 | push 0 ; initialize .error_code |
|
- | 386 | push edx eax ecx ecx ; initialize stack variables |
|
- | 387 | push [.buffer-4] ; copy [.buffer] to [.cur_buffer] |
|
- | 388 | ; -4 is due to esp-relative addressing |
|
- | 389 | virtual at esp |
|
- | 390 | .local_vars: |
|
- | 391 | .cur_buffer dd ? ; pointer to data that are currently copying |
|
- | 392 | .num_sectors_orig dd ? |
|
- | 393 | ; Number of sectors that should be written. Used to generate output value of ecx. |
|
- | 394 | .num_sectors dd ? |
|
- | 395 | ; Number of sectors that remain to be written. |
|
- | 396 | .sector_lo dd ? ; low 32 bits of the current sector |
|
- | 397 | .sector_hi dd ? ; high 32 bits of the current sector |
|
- | 398 | .error_code dd ? ; current status |
|
- | 399 | .local_vars_size = $ - .local_vars |
|
- | 400 | .saved_regs rd 2 |
|
- | 401 | .buffer dd ? ; filled by fs_write64_{sys,app} |
|
- | 402 | end virtual |
|
- | 403 | ; 2. Validate parameters against partition length: |
|
- | 404 | ; immediately return error if edx:eax are beyond partition end, |
|
- | 405 | ; decrease .num_sectors and .num_sectors_orig, if needed, |
|
- | 406 | ; so that the entire operation fits in the partition limits. |
|
- | 407 | mov eax, dword [ebp+PARTITION.Length] |
|
- | 408 | mov edx, dword [ebp+PARTITION.Length+4] |
|
- | 409 | sub eax, [.sector_lo] |
|
- | 410 | sbb edx, [.sector_hi] |
|
- | 411 | jb .end_of_media |
|
- | 412 | jnz .no_end_of_media |
|
- | 413 | cmp ecx, eax |
|
- | 414 | jbe .no_end_of_media |
|
- | 415 | ; If .num_sectors got decreased, set status to DISK_STATUS_END_OF_MEDIA; |
|
- | 416 | ; if all subsequent operations would be successful, this would become the final |
|
- | 417 | ; status, otherwise this would be rewritten by failed operation. |
|
- | 418 | mov [.num_sectors], eax |
|
- | 419 | mov [.num_sectors_orig], eax |
|
- | 420 | mov [.error_code], DISK_STATUS_END_OF_MEDIA |
|
- | 421 | .no_end_of_media: |
|
- | 422 | ; 3. If number of sectors to write is zero, either because zero-sectors operation |
|
- | 423 | ; was requested or because it got decreased to zero due to partition limits, |
|
- | 424 | ; just return the current status. |
|
- | 425 | cmp [.num_sectors], 0 |
|
- | 426 | jz .return |
|
- | 427 | ; 4. Shift sector from partition-relative to absolute. |
|
- | 428 | mov eax, dword [ebp+PARTITION.FirstSector] |
|
- | 429 | mov edx, dword [ebp+PARTITION.FirstSector+4] |
|
- | 430 | add [.sector_lo], eax |
|
- | 431 | adc [.sector_hi], edx |
|
- | 432 | ; 5. If the cache is disabled, pass the request directly to the driver. |
|
- | 433 | cmp [ebx+DISKCACHE.pointer], 0 |
|
- | 434 | jz .nocache |
|
- | 435 | ; 6. Store sectors in the cache, sequentially from the beginning. |
|
- | 436 | ; 6a. Acquire the lock. |
|
- | 437 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 438 | add ecx, DISK.CacheLock |
|
- | 439 | call mutex_lock |
|
- | 440 | .lookup_in_cache_loop: |
|
- | 441 | ; 6b. For each sector, call the lookup function with adding to the cache, if not yet. |
|
- | 442 | mov eax, [.sector_lo] |
|
- | 443 | mov edx, [.sector_hi] |
|
- | 444 | call cache_lookup_write |
|
- | 445 | test eax, eax |
|
- | 446 | jnz .cache_error |
|
- | 447 | ; 6c. For each sector, copy data, mark the item as modified and not saved, |
|
- | 448 | ; advance .current_buffer to the next sector. |
|
- | 449 | mov [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
- | 450 | mov eax, 1 |
|
- | 451 | shl eax, cl |
|
- | 452 | mov esi, [.cur_buffer] |
|
- | 453 | mov ecx, eax |
|
- | 454 | shr ecx, 2 |
|
- | 455 | rep movsd |
|
- | 456 | mov [.cur_buffer], esi |
|
- | 457 | ; 6d. Remove the sector from the other cache. |
|
- | 458 | ; Normally it should not be there, but prefetching could put to the app cache |
|
- | 459 | ; data that normally should belong to the sys cache and vice versa. |
|
- | 460 | ; Note: this requires that both caches must be protected by the same lock. |
|
- | 461 | mov eax, [.sector_lo] |
|
- | 462 | mov edx, [.sector_hi] |
|
- | 463 | push ebx |
|
- | 464 | sub ebx, [ebp+PARTITION.Disk] |
|
- | 465 | xor ebx, DISK.SysCache xor DISK.AppCache |
|
- | 466 | add ebx, [ebp+PARTITION.Disk] |
|
- | 467 | call cache_lookup_read |
|
- | 468 | jc @f |
|
- | 469 | mov [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY |
|
- | 470 | @@: |
|
- | 471 | pop ebx |
|
- | 472 | ; 6e. Advance .sector_hi:.sector_lo to the next sector. |
|
- | 473 | add [.sector_lo], 1 |
|
- | 474 | adc [.sector_hi], 0 |
|
- | 475 | ; 6f. Continue the loop at 6b-6e until all sectors are processed. |
|
- | 476 | dec [.num_sectors] |
|
- | 477 | jnz .lookup_in_cache_loop |
|
- | 478 | .unlock_return: |
|
- | 479 | ; 6g. Release the lock and return. |
|
- | 480 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 481 | add ecx, DISK.CacheLock |
|
- | 482 | call mutex_unlock |
|
- | 483 | .return: |
|
- | 484 | mov eax, [.error_code] |
|
- | 485 | mov ecx, [.num_sectors_orig] |
|
- | 486 | sub ecx, [.num_sectors] |
|
- | 487 | .nothing: |
|
- | 488 | add esp, .local_vars_size |
|
- | 489 | pop edi esi ebx |
|
- | 490 | ret |
|
- | 491 | ||
- | 492 | ; Special branches: |
|
- | 493 | .cache_error: |
|
- | 494 | ; error at flushing the cache while adding sector to the cache: |
|
- | 495 | ; return the error from the lookup function |
|
- | 496 | mov [.error_code], eax |
|
- | 497 | jmp .unlock_return |
|
- | 498 | .end_of_media: |
|
- | 499 | ; requested sector is beyond the partition end: return the corresponding error |
|
- | 500 | mov eax, DISK_STATUS_END_OF_MEDIA |
|
- | 501 | xor ecx, ecx |
|
- | 502 | jmp .nothing |
|
- | 503 | .nocache: |
|
- | 504 | ; step 5, after correcting number of sectors to fit in partition limits |
|
- | 505 | ; and advancing partition-relative sector to absolute, |
|
- | 506 | ; sees that cache is disabled: pass corrected request to the driver |
|
- | 507 | lea eax, [.num_sectors] |
|
- | 508 | push eax ; numsectors |
|
- | 509 | push [.sector_hi+4] ; startsector |
|
- | 510 | push [.sector_lo+8] ; startsector |
|
- | 511 | push [.buffer+12] ; buffer |
|
- | 512 | mov esi, [ebp+PARTITION.Disk] |
|
- | 513 | mov al, DISKFUNC.write |
|
- | 514 | call disk_call_driver |
|
- | 515 | mov ecx, [.num_sectors] |
|
- | 516 | jmp .nothing |
|
8 | $Revision: 3742 $ |
517 | |
9 | 518 | ; Legacy. Use fs_read64_sys instead. |
|
10 | ; This function is intended to replace the old 'hd_read' function when |
519 | ; 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 |
520 | ; [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'. |
521 | ; 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 |
522 | ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure |
14 | ; eax is relative to partition start |
523 | ; eax is relative to partition start |
15 | ; out: eax = error code; 0 = ok |
524 | ; out: eax = error code; 0 = ok |
16 | fs_read32_sys: |
525 | fs_read32_sys: |
17 | ; Save ecx, set ecx to SysCache and let the common part do its work. |
526 | ; Save ebx, set ebx to SysCache and let the common part do its work. |
18 | push ecx |
527 | push ebx |
19 | mov ecx, [ebp+PARTITION.Disk] |
528 | mov ebx, [ebp+PARTITION.Disk] |
Line -... | Line 529... | ||
- | 529 | add ebx, DISK.SysCache |
|
20 | add ecx, DISK.SysCache |
530 | jmp fs_read32_common |
21 | jmp fs_read32_common |
531 | |
22 | 532 | ; Legacy. Use fs_read64_app instead. |
|
23 | ; This function is intended to replace the old 'hd_read' function when |
533 | ; This function is intended to replace the old 'hd_read' function when |
24 | ; [hdd_appl_data] = 1, so its input/output parameters are the same, except |
534 | ; [hdd_appl_data] = 1, so its input/output parameters are the same, except |
25 | ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'. |
535 | ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'. |
26 | ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure |
536 | ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure |
27 | ; eax is relative to partition start |
537 | ; eax is relative to partition start |
28 | ; out: eax = error code; 0 = ok |
538 | ; out: eax = error code; 0 = ok |
29 | fs_read32_app: |
539 | fs_read32_app: |
30 | ; Save ecx, set ecx to AppCache and let the common part do its work. |
540 | ; Save ebx, set ebx to AppCache and let the common part do its work. |
Line 31... | Line 541... | ||
31 | push ecx |
541 | push ebx |
32 | mov ecx, [ebp+PARTITION.Disk] |
542 | mov ebx, [ebp+PARTITION.Disk] |
33 | add ecx, DISK.AppCache |
543 | add ebx, DISK.AppCache |
34 | 544 | ||
35 | ; This label is the common part of fs_read32_sys and fs_read32_app. |
545 | ; This label is the common part of fs_read32_sys and fs_read32_app. |
36 | fs_read32_common: |
546 | fs_read32_common: |
37 | ; 1. Check that the required sector is inside the partition. If no, return |
547 | ; 1. Check that the required sector is inside the partition. If no, return |
38 | ; DISK_STATUS_END_OF_MEDIA. |
548 | ; DISK_STATUS_END_OF_MEDIA. |
39 | cmp dword [ebp+PARTITION.Length+4], 0 |
549 | cmp dword [ebp+PARTITION.Length+4], 0 |
40 | jnz @f |
550 | jnz @f |
41 | cmp dword [ebp+PARTITION.Length], eax |
551 | cmp dword [ebp+PARTITION.Length], eax |
42 | ja @f |
552 | ja @f |
43 | mov eax, DISK_STATUS_END_OF_MEDIA |
553 | mov eax, DISK_STATUS_END_OF_MEDIA |
44 | pop ecx |
554 | pop ebx |
45 | ret |
555 | ret |
46 | @@: |
556 | @@: |
47 | ; 2. Get the absolute sector on the disk. |
557 | ; 2. Get the absolute sector on the disk. |
48 | push edx esi |
558 | push ecx edx esi edi |
49 | xor edx, edx |
559 | xor edx, edx |
50 | add eax, dword [ebp+PARTITION.FirstSector] |
560 | add eax, dword [ebp+PARTITION.FirstSector] |
51 | adc edx, dword [ebp+PARTITION.FirstSector+4] |
561 | adc edx, dword [ebp+PARTITION.FirstSector+4] |
52 | ; 3. If there is no cache for this disk, just pass the request to the driver. |
562 | ; 3. If there is no cache for this disk, just pass the request to the driver. |
53 | cmp [ecx+DISKCACHE.pointer], 0 |
563 | cmp [ebx+DISKCACHE.pointer], 0 |
54 | jnz .scancache |
564 | jnz .scancache |
55 | push 1 |
565 | push 1 |
56 | push esp ; numsectors |
566 | push esp ; numsectors |
57 | push edx ; startsector |
567 | push edx ; startsector |
58 | push eax ; startsector |
568 | push eax ; startsector |
59 | push ebx ; buffer |
569 | pushd [esp+32]; buffer |
60 | mov esi, [ebp+PARTITION.Disk] |
570 | mov esi, [ebp+PARTITION.Disk] |
61 | mov al, DISKFUNC.read |
571 | mov al, DISKFUNC.read |
62 | call disk_call_driver |
572 | call disk_call_driver |
63 | pop ecx |
573 | pop ecx |
64 | pop esi edx |
- | |
65 | pop ecx |
- | |
66 | ret |
574 | pop edi esi edx ecx |
67 | .scancache: |
575 | pop ebx |
- | 576 | ret |
|
68 | ; 4. Scan the cache. |
577 | .scancache: |
69 | push edi ecx ; scan cache |
578 | push ebx edx eax |
70 | push edx eax |
579 | virtual at esp |
- | 580 | .local_vars: |
|
- | 581 | .sector_lo dd ? |
|
- | 582 | .sector_hi dd ? |
|
71 | virtual at esp |
583 | .cache dd ? |
72 | .sector_lo dd ? |
584 | .local_vars_size = $ - .local_vars |
73 | .sector_hi dd ? |
585 | .saved_regs rd 4 |
- | 586 | .buffer dd ? |
|
74 | .cache dd ? |
587 | end virtual |
75 | end virtual |
588 | ; 4. Scan for the requested sector in the cache. |
76 | ; The following code is inherited from hd_read. The differences are: |
589 | ; If found, copy the data and return. |
- | 590 | ; 4a. Acquire the lock. |
|
77 | ; all code is protected by the cache lock; instead of static calls |
591 | mov ecx, [ebp+PARTITION.Disk] |
78 | ; to hd_read_dma/hd_read_pio/bd_read the dynamic call to DISKFUNC.read is used; |
592 | add ecx, DISK.CacheLock |
79 | ; sector is 64-bit, not 32-bit. |
593 | call mutex_lock |
- | 594 | ; 4b. Call the lookup function without adding to the cache. |
|
80 | call mutex_lock |
595 | mov eax, [.sector_lo] |
- | 596 | mov edx, [.sector_hi] |
|
- | 597 | call cache_lookup_read |
|
81 | mov eax, [.sector_lo] |
598 | ; If not found, go to 5. |
82 | mov edx, [.sector_hi] |
- | |
- | 599 | jc .not_found_in_cache |
|
83 | mov esi, [ecx+DISKCACHE.pointer] |
600 | .found_in_cache: |
84 | mov ecx, [ecx+DISKCACHE.sad_size] |
- | |
85 | add esi, 12 |
601 | ; 4c. Copy the data. |
86 | - | ||
87 | mov edi, 1 |
602 | mov esi, edi |
88 | 603 | mov edi, [.buffer] |
|
89 | .hdreadcache: |
- | |
- | 604 | mov eax, 1 |
|
- | 605 | shl eax, cl |
|
90 | 606 | mov ecx, eax |
|
91 | cmp dword [esi+8], 0 ; empty |
607 | shr ecx, 2 |
92 | je .nohdcache |
608 | rep movsd |
- | 609 | ; 4d. Release the lock and return success. |
|
93 | 610 | mov ecx, [ebp+PARTITION.Disk] |
|
94 | cmp [esi], eax ; correct sector |
- | |
95 | jne .nohdcache |
611 | add ecx, DISK.CacheLock |
96 | cmp [esi+4], edx ; correct sector |
- | |
- | 612 | call mutex_unlock |
|
97 | je .yeshdcache |
613 | .return: |
98 | 614 | xor eax, eax |
|
- | 615 | .return_eax: |
|
- | 616 | add esp, .local_vars_size |
|
- | 617 | pop edi esi edx ecx |
|
- | 618 | pop ebx |
|
- | 619 | ret |
|
- | 620 | .not_found_in_cache: |
|
- | 621 | ; 5. Decide whether we need to prefetch further sectors. |
|
- | 622 | ; If so, advance to 6. If not, go to 13. |
|
- | 623 | ; Assume that devices < 3MB are floppies which are slow |
|
99 | .nohdcache: |
624 | ; (ramdisk does not have a cache, so we don't even get here for ramdisk). |
- | 625 | ; This is a dirty hack, but the entire function is somewhat hacky. Use fs_read64*. |
|
100 | 626 | mov ecx, [ebp+PARTITION.Disk] |
|
101 | add esi, 12 |
627 | cmp dword [ecx+DISK.MediaInfo.Capacity+4], 0 |
- | 628 | jnz @f |
|
- | 629 | cmp dword [ecx+DISK.MediaInfo.Capacity], 3 shl (20-9) |
|
- | 630 | jb .floppy |
|
102 | inc edi |
631 | @@: |
- | 632 | ; We want to prefetch CACHE_LEGACY_READ_SIZE sectors. |
|
- | 633 | ; 6. Release the lock acquired at step 4a. |
|
- | 634 | mov ecx, [ebp+PARTITION.Disk] |
|
103 | dec ecx |
635 | add ecx, DISK.CacheLock |
- | 636 | call mutex_unlock |
|
- | 637 | ; 7. Allocate buffer for CACHE_LEGACY_READ_SIZE sectors. |
|
- | 638 | mov eax, CACHE_LEGACY_READ_SIZE |
|
104 | jnz .hdreadcache |
639 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
- | 640 | shl eax, cl |
|
- | 641 | stdcall kernel_alloc, eax |
|
- | 642 | ; If failed, return the corresponding error code. |
|
- | 643 | test eax, eax |
|
- | 644 | jz .nomemory |
|
- | 645 | ; 8. Create second portion of local variables. |
|
- | 646 | push eax eax |
|
- | 647 | push CACHE_LEGACY_READ_SIZE |
|
- | 648 | virtual at esp |
|
- | 649 | .local_vars2: |
|
- | 650 | .num_sectors dd ? ; number of sectors left |
|
- | 651 | .current_buffer dd ? ; pointer to data that are currently copying |
|
- | 652 | .allocated_buffer dd ? ; saved at safe place |
|
- | 653 | .local_vars2_size = $ - .local_vars2 |
|
- | 654 | end virtual |
|
- | 655 | ; 9. Call the driver to read CACHE_LEGACY_READ_SIZE sectors. |
|
- | 656 | push esp ; numsectors |
|
- | 657 | push [.sector_hi+.local_vars2_size+4] ; startsector |
|
- | 658 | push [.sector_lo+.local_vars2_size+8] ; startsector |
|
- | 659 | push eax ; buffer |
|
- | 660 | mov esi, [ebp+PARTITION.Disk] |
|
- | 661 | mov al, DISKFUNC.read |
|
- | 662 | call disk_call_driver |
|
- | 663 | ; Note: we're ok if at least one sector is read, |
|
- | 664 | ; read error somewhere after that just limits data to be put in cache. |
|
- | 665 | cmp [.num_sectors], 0 |
|
- | 666 | jz .read_error |
|
- | 667 | ; 10. Copy data for the caller. |
|
- | 668 | mov esi, [.allocated_buffer] |
|
- | 669 | mov edi, [.buffer+.local_vars2_size] |
|
- | 670 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
|
- | 671 | mov eax, 1 |
|
- | 672 | shl eax, cl |
|
- | 673 | mov ecx, eax |
|
- | 674 | shr ecx, 2 |
|
- | 675 | rep movsd |
|
- | 676 | ; 11. Store all sectors that were successfully read to the cache. |
|
- | 677 | ; 11a. Acquire the lock. |
|
- | 678 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 679 | add ecx, DISK.CacheLock |
|
- | 680 | call mutex_lock |
|
- | 681 | .store_to_cache: |
|
- | 682 | ; 11b. For each sector, call the lookup function with adding to the cache, if not yet. |
|
- | 683 | mov eax, [.sector_lo+.local_vars2_size] |
|
- | 684 | mov edx, [.sector_hi+.local_vars2_size] |
|
- | 685 | call cache_lookup_write |
|
- | 686 | test eax, eax |
|
- | 687 | jnz .cache_error |
|
- | 688 | ; 11c. Ignore sectors marked as modified: for them the cache is more recent that disk data. |
|
- | 689 | mov eax, 1 |
|
105 | 690 | shl eax, cl |
|
- | 691 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
- | 692 | jnz .not_modified |
|
- | 693 | add [.current_buffer], eax |
|
- | 694 | jmp .sector_done |
|
- | 695 | .not_modified: |
|
- | 696 | ; 11d. For each sector, copy data, mark the item as not-modified copy of the disk, |
|
- | 697 | ; advance .current_buffer and .sector_hi:.sector_lo to the next sector. |
|
- | 698 | mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
|
- | 699 | mov esi, [.current_buffer] |
|
- | 700 | mov ecx, eax |
|
- | 701 | shr ecx, 2 |
|
- | 702 | rep movsd |
|
- | 703 | mov [.current_buffer], esi |
|
- | 704 | .sector_done: |
|
- | 705 | add [.sector_lo+.local_vars2_size], 1 |
|
- | 706 | adc [.sector_hi+.local_vars2_size], 0 |
|
- | 707 | ; 11e. Continue the loop at 11b-11d until all sectors are processed. |
|
- | 708 | dec [.num_sectors] |
|
- | 709 | jnz .store_to_cache |
|
- | 710 | .cache_error: |
|
- | 711 | ; 11f. Release the lock. |
|
- | 712 | mov ecx, [ebp+PARTITION.Disk] |
|
- | 713 | add ecx, DISK.CacheLock |
|
- | 714 | call mutex_unlock |
|
- | 715 | .copy_done: |
|
- | 716 | ; 12. Remove portion of local variables created at step 8, |
|
- | 717 | ; free the buffer allocated at step 7 and return. |
|
- | 718 | pop ecx ecx |
|
- | 719 | stdcall kernel_free |
|
- | 720 | jmp .return |
|
- | 721 | .read_error: |
|
- | 722 | ; If no sectors were read, free the buffer allocated at step 7 |
|
- | 723 | ; and pass the error to the caller. |
|
- | 724 | push eax |
|
- | 725 | stdcall kernel_free, [.allocated_buffer+4] |
|
- | 726 | pop eax |
|
- | 727 | add esp, .local_vars2_size |
|
- | 728 | jmp .return_eax |
|
- | 729 | .nomemory: |
|
- | 730 | mov eax, DISK_STATUS_NO_MEMORY |
|
- | 731 | jmp .return_eax |
|
- | 732 | .floppy: |
|
- | 733 | ; We don't want to prefetch anything, just read one sector. |
|
- | 734 | ; We are still holding the lock acquired at step 4a. |
|
- | 735 | ; 13. Call the lookup function adding sector to the cache. |
|
Line -... | Line 736... | ||
- | 736 | call cache_lookup_write |
|
106 | mov esi, [.cache] |
737 | test eax, eax |
107 | call find_empty_slot64 ; ret in edi |
738 | jnz .floppy_cache_error |
108 | test eax, eax |
739 | push esi |
109 | jnz .read_done |
740 | |
110 | - | ||
111 | push 1 |
- | |
112 | push esp |
- | |
113 | push edx |
- | |
114 | push [.sector_lo+12] |
741 | ; 14. Call the driver to read one sector. |
115 | mov ecx, [.cache+16] |
742 | push 1 |
116 | mov eax, edi |
743 | push esp |
117 | shl eax, 9 |
744 | push edx |
118 | add eax, [ecx+DISKCACHE.data] |
745 | push [.sector_lo+16] |
119 | push eax |
746 | push edi |
120 | mov esi, [ebp+PARTITION.Disk] |
747 | mov esi, [ebp+PARTITION.Disk] |
121 | mov al, DISKFUNC.read |
- | |
122 | call disk_call_driver |
748 | mov al, DISKFUNC.read |
123 | pop ecx |
- | |
124 | dec ecx |
749 | call disk_call_driver |
125 | jnz .read_done |
750 | pop ecx |
126 | - | ||
127 | mov ecx, [.cache] |
751 | dec ecx |
128 | lea eax, [edi*3] |
752 | jnz .floppy_read_error |
129 | mov esi, [ecx+DISKCACHE.pointer] |
753 | ; 15. Get the slot and pointer to the cache item, |
130 | lea esi, [eax*4+esi] |
754 | ; change the status to not-modified copy of the disk |
131 | - | ||
132 | mov eax, [.sector_lo] |
- | |
133 | mov edx, [.sector_hi] |
- | |
134 | mov [esi], eax ; sector number |
755 | ; and go to 4c. |
135 | mov [esi+4], edx ; sector number |
756 | pop esi |
136 | mov dword [esi+8], 1; hd read - mark as same as in hd |
757 | mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
137 | 758 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
|
138 | .yeshdcache: |
- | |
139 | - | ||
140 | mov esi, edi |
759 | jmp .found_in_cache |
141 | mov ecx, [.cache] |
760 | |
142 | shl esi, 9 |
- | |
143 | add esi, [ecx+DISKCACHE.data] |
761 | ; On error at steps 13-14, release the lock |
144 | - | ||
145 | mov edi, ebx |
762 | ; and pass the error to the caller. |
146 | mov ecx, 512/4 |
763 | .floppy_read_error: |
147 | rep movsd ; move data |
764 | pop ecx |
148 | xor eax, eax ; successful read |
765 | .floppy_cache_error: |
149 | .read_done: |
- | |
150 | mov ecx, [.cache] |
766 | mov ecx, [ebp+PARTITION.Disk] |
151 | push eax |
- | |
Line 152... | Line 767... | ||
152 | call mutex_unlock |
767 | add ecx, DISK.CacheLock |
153 | pop eax |
768 | push eax |
154 | add esp, 12 |
769 | call mutex_unlock |
155 | pop edi esi edx ecx |
770 | pop eax |
156 | ret |
771 | jmp .return_eax |
157 | 772 | ||
158 | ; This function is intended to replace the old 'hd_write' function when |
773 | ; This function is intended to replace the old 'hd_write' function when |
159 | ; [hdd_appl_data] = 0, so its input/output parameters are the same, except |
774 | ; [hdd_appl_data] = 0, so its input/output parameters are the same, except |
160 | ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'. |
775 | ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'. |
161 | ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure |
776 | ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure |
162 | ; eax is relative to partition start |
777 | ; eax is relative to partition start |
163 | ; out: eax = error code; 0 = ok |
778 | ; out: eax = error code; 0 = ok |
- | 779 | fs_write32_sys: |
|
- | 780 | ; Just call the advanced function. |
|
Line 164... | Line 781... | ||
164 | fs_write32_sys: |
781 | push ecx edx |
165 | ; Save ecx, set ecx to SysCache and let the common part do its work. |
782 | xor edx, edx |
166 | push ecx |
783 | mov ecx, 1 |
167 | mov ecx, [ebp+PARTITION.Disk] |
784 | call fs_write64_sys |
168 | add ecx, DISK.SysCache |
785 | pop edx ecx |
169 | jmp fs_write32_common |
786 | ret |
170 | 787 | ||
171 | ; This function is intended to replace the old 'hd_write' function when |
- | |
172 | ; [hdd_appl_data] = 1, so its input/output parameters are the same, except |
- | |
173 | ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'. |
- | |
174 | ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure |
788 | ; This function is intended to replace the old 'hd_write' function when |
175 | ; eax is relative to partition start |
- | |
176 | ; out: eax = error code; 0 = ok |
- | |
177 | fs_write32_app: |
- | |
178 | ; Save ecx, set ecx to AppCache and let the common part do its work. |
- | |
179 | push ecx |
- | |
180 | mov ecx, [ebp+PARTITION.Disk] |
- | |
181 | add ecx, DISK.AppCache |
- | |
182 | - | ||
183 | ; This label is the common part of fs_read32_sys and fs_read32_app. |
- | |
184 | fs_write32_common: |
- | |
185 | ; 1. Check that the required sector is inside the partition. If no, return |
- | |
186 | ; DISK_STATUS_END_OF_MEDIA. |
- | |
187 | cmp dword [ebp+PARTITION.Length+4], 0 |
- | |
188 | jnz @f |
789 | ; [hdd_appl_data] = 1, so its input/output parameters are the same, except |
189 | cmp dword [ebp+PARTITION.Length], eax |
- | |
190 | ja @f |
790 | ; that it can't use the global variables 'hd_error' and 'hdd_appl_data'. |
191 | mov eax, DISK_STATUS_END_OF_MEDIA |
- | |
192 | pop ecx |
- | |
193 | ret |
- | |
194 | @@: |
- | |
195 | push edx esi |
- | |
196 | ; 2. Get the absolute sector on the disk. |
- | |
197 | xor edx, edx |
- | |
198 | add eax, dword [ebp+PARTITION.FirstSector] |
- | |
199 | adc edx, dword [ebp+PARTITION.FirstSector+4] |
- | |
200 | ; 3. If there is no cache for this disk, just pass request to the driver. |
- | |
201 | cmp [ecx+DISKCACHE.pointer], 0 |
- | |
202 | jnz .scancache |
- | |
203 | push 1 |
- | |
204 | push esp ; numsectors |
791 | ; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure |
205 | push edx ; startsector |
792 | ; eax is relative to partition start |
206 | push eax ; startsector |
793 | ; out: eax = error code; 0 = ok |
207 | push ebx ; buffer |
794 | fs_write32_app: |
208 | mov esi, [ebp+PARTITION.Disk] |
- | |
209 | mov al, DISKFUNC.write |
- | |
210 | call disk_call_driver |
- | |
211 | pop ecx |
- | |
212 | pop esi edx |
- | |
213 | pop ecx |
- | |
214 | ret |
- | |
215 | .scancache: |
- | |
216 | ; 4. Scan the cache. |
- | |
217 | push edi ecx ; scan cache |
- | |
218 | push edx eax |
- | |
219 | virtual at esp |
- | |
220 | .sector_lo dd ? |
- | |
Line -... | Line 795... | ||
- | 795 | ; Just call the advanced function. |
|
221 | .sector_hi dd ? |
796 | push ecx edx |
222 | .cache dd ? |
797 | xor edx, edx |
223 | end virtual |
798 | mov ecx, 1 |
224 | ; The following code is inherited from hd_write. The differences are: |
799 | call fs_write64_app |
- | 800 | pop edx ecx |
|
- | 801 | ret |
|
- | 802 | ||
- | 803 | ; Lookup for the given sector in the given cache. |
|
- | 804 | ; If the sector is not present, return error. |
|
225 | ; all code is protected by the cache lock; |
805 | ; The caller must acquire the cache lock. |
226 | ; sector is 64-bit, not 32-bit. |
806 | ; in: edx:eax = sector |
Line 227... | Line 807... | ||
227 | call mutex_lock |
807 | ; in: ebx -> DISKCACHE structure |
Line 228... | Line 808... | ||
228 | 808 | ; out: CF set if sector is not in cache |
|
229 | ; check if the cache already has the sector and overwrite it |
- | |
230 | mov eax, [.sector_lo] |
- | |
231 | mov edx, [.sector_hi] |
- | |
232 | mov esi, [ecx+DISKCACHE.pointer] |
- | |
233 | mov ecx, [ecx+DISKCACHE.sad_size] |
- | |
234 | add esi, 12 |
- | |
235 | - | ||
236 | mov edi, 1 |
- | |
237 | - | ||
238 | .hdwritecache: |
- | |
239 | cmp dword [esi+8], 0 ; if cache slot is empty |
- | |
240 | je .not_in_cache_write |
- | |
241 | - | ||
242 | cmp [esi], eax ; if the slot has the sector |
- | |
243 | jne .not_in_cache_write |
- | |
244 | cmp [esi+4], edx ; if the slot has the sector |
- | |
245 | je .yes_in_cache_write |
- | |
246 | - | ||
247 | .not_in_cache_write: |
- | |
248 | - | ||
249 | add esi, 12 |
- | |
250 | inc edi |
- | |
251 | dec ecx |
- | |
252 | jnz .hdwritecache |
- | |
253 | - | ||
254 | ; sector not found in cache |
- | |
255 | ; write the block to a new location |
- | |
256 | - | ||
257 | mov esi, [.cache] |
- | |
258 | call find_empty_slot64 ; ret in edi |
- | |
259 | test eax, eax |
- | |
260 | jne .hd_write_access_denied |
- | |
Line -... | Line 809... | ||
- | 809 | ; out: ecx = sector_size_log |
|
261 | 810 | ; out: esi -> sector:status |
|
Line -... | Line 811... | ||
- | 811 | ; out: edi -> sector data |
|
- | 812 | proc cache_lookup_read |
|
- | 813 | mov esi, [ebx+DISKCACHE.pointer] |
|
- | 814 | add esi, sizeof.CACHE_ITEM |
|
262 | mov ecx, [.cache] |
815 | |
- | 816 | mov edi, 1 |
|
- | 817 | ||
- | 818 | .hdreadcache: |
|
- | 819 | ||
Line 263... | Line -... | ||
263 | lea eax, [edi*3] |
- | |
264 | mov esi, [ecx+DISKCACHE.pointer] |
820 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY |
265 | lea esi, [eax*4+esi] |
- | |
Line 266... | Line 821... | ||
266 | 821 | je .nohdcache |
|
267 | mov eax, [.sector_lo] |
822 | |
268 | mov edx, [.sector_hi] |
- | |
269 | mov [esi], eax ; sector number |
823 | cmp [esi+CACHE_ITEM.SectorLo], eax |
270 | mov [esi+4], edx ; sector number |
- | |
271 | 824 | jne .nohdcache |
|
272 | .yes_in_cache_write: |
825 | cmp [esi+CACHE_ITEM.SectorHi], edx |
273 | - | ||
274 | mov dword [esi+8], 2 ; write - differs from hd |
- | |
275 | - | ||
276 | shl edi, 9 |
- | |
277 | mov ecx, [.cache] |
826 | jne .nohdcache |
- | 827 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
|
Line 278... | Line 828... | ||
278 | add edi, [ecx+DISKCACHE.data] |
828 | shl edi, cl |
279 | 829 | add edi, [ebx+DISKCACHE.data] |
|
- | 830 | clc |
|
280 | mov esi, ebx |
831 | ret |
- | 832 | ||
- | 833 | .nohdcache: |
|
- | 834 | ||
- | 835 | add esi, sizeof.CACHE_ITEM |
|
- | 836 | inc edi |
|
- | 837 | cmp edi, [ebx+DISKCACHE.sad_size] |
|
- | 838 | jbe .hdreadcache |
|
- | 839 | stc |
|
- | 840 | ret |
|
281 | mov ecx, 512/4 |
841 | endp |
282 | rep movsd ; move data |
842 | |
283 | xor eax, eax ; success |
843 | ; Lookup for the given sector in the given cache. |
284 | .hd_write_access_denied: |
844 | ; If the sector is not present, allocate space for it, |
- | 845 | ; possibly flushing data. |
|
- | 846 | ; in: edx:eax = sector |
|
- | 847 | ; in: ebx -> DISKCACHE structure |
|
285 | mov ecx, [.cache] |
848 | ; in: ebp -> PARTITION structure |
286 | push eax |
849 | ; out: eax = error code |
287 | call mutex_unlock |
850 | ; out: esi -> sector:status |
288 | pop eax |
851 | ; out: edi -> sector data |
- | 852 | proc cache_lookup_write |
|
- | 853 | call cache_lookup_read |
|
- | 854 | jnc .return0 |
|
289 | add esp, 12 |
855 | push edx eax |
290 | pop edi esi edx ecx |
856 | ;----------------------------------------------------------- |
- | 857 | ; find empty or read slot, flush cache if next 12.5% is used by write |
|
291 | ret |
858 | ; output : ecx = cache slot |
292 | 859 | ;----------------------------------------------------------- |
|
293 | ; This internal function is called from fs_read32_* and fs_write32_*. It is the |
860 | ; Note: the code is essentially inherited, so probably |
- | 861 | ; no analysis of efficiency were done. |
|
- | 862 | ; However, it works. |
|
294 | ; analogue of find_empty_slot for 64-bit sectors. |
863 | .search_again: |
295 | find_empty_slot64: |
- | |
296 | ;----------------------------------------------------------- |
- | |
297 | ; find empty or read slot, flush cache if next 12.5% is used by write |
864 | mov eax, [ebx+DISKCACHE.sad_size] |
298 | ; output : edi = cache slot |
- | |
299 | ;----------------------------------------------------------- |
865 | mov ecx, [ebx+DISKCACHE.search_start] |
300 | .search_again: |
866 | shr eax, 3 |
301 | mov ecx, [esi+DISKCACHE.sad_size] |
867 | lea esi, [ecx*sizeof.CACHE_ITEM/4] |
302 | mov edi, [esi+DISKCACHE.search_start] |
868 | shl esi, 2 |
303 | shr ecx, 3 |
869 | add esi, [ebx+DISKCACHE.pointer] |
304 | .search_for_empty: |
870 | .search_for_empty: |
305 | inc edi |
871 | inc ecx |
306 | cmp edi, [esi+DISKCACHE.sad_size] |
872 | add esi, sizeof.CACHE_ITEM |
307 | jbe .inside_cache |
873 | cmp ecx, [ebx+DISKCACHE.sad_size] |
- | 874 | jbe .inside_cache |
|
- | 875 | mov ecx, 1 |
|
- | 876 | mov esi, [ebx+DISKCACHE.pointer] |
|
- | 877 | add esi, sizeof.CACHE_ITEM |
|
- | 878 | .inside_cache: |
|
- | 879 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
- | 880 | jb .found_slot ; it's empty or read |
|
- | 881 | dec eax |
|
308 | mov edi, 1 |
882 | jnz .search_for_empty |
- | 883 | stdcall write_cache64, [ebp+PARTITION.Disk] ; no empty slots found, write all |
|
309 | .inside_cache: |
884 | test eax, eax |
- | 885 | jne .found_slot_access_denied |
|
310 | lea eax, [edi*3] |
886 | jmp .search_again ; and start again |
- | 887 | .found_slot: |
|
Line -... | Line 888... | ||
- | 888 | mov [ebx+DISKCACHE.search_start], ecx |
|
311 | shl eax, 2 |
889 | popd [esi+CACHE_ITEM.SectorLo] |
- | 890 | popd [esi+CACHE_ITEM.SectorHi] |
|
312 | add eax, [esi+DISKCACHE.pointer] |
891 | mov [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY |
- | 892 | mov edi, ecx |
|
- | 893 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
|
- | 894 | shl edi, cl |
|
- | 895 | add edi, [ebx+DISKCACHE.data] |
|
- | 896 | .return0: |
|
313 | cmp dword [eax+8], 2 |
897 | xor eax, eax ; success |
- | 898 | ret |
|
- | 899 | .found_slot_access_denied: |
|
- | 900 | add esp, 8 |
|
- | 901 | ret |
|
- | 902 | endp |
|
- | 903 | ||
- | 904 | ; Flush the given cache. |
|
314 | jb .found_slot ; it's empty or read |
905 | ; The caller must acquire the cache lock. |
- | 906 | ; in: ebx -> DISKCACHE |
|
- | 907 | ; in: first argument in stdcall convention -> PARTITION |
|
- | 908 | proc write_cache64 |
|
- | 909 | ; 1. Setup stack frame. |
|
- | 910 | push esi edi ; save used registers to be stdcall |
|
315 | dec ecx |
911 | sub esp, .local_vars_size ; reserve space for local vars |
- | 912 | virtual at esp |
|
- | 913 | .local_vars: |
|
- | 914 | .cache_end dd ? ; item past the end of the cache |
|
316 | jnz .search_for_empty |
915 | .size_left dd ? ; items left to scan |
- | 916 | .current_ptr dd ? ; pointer to the current item |
|
- | 917 | ; |
|
317 | stdcall write_cache64, [ebp+PARTITION.Disk] ; no empty slots found, write all |
918 | ; Write operations are coalesced in chains, |
318 | test eax, eax |
919 | ; one chain describes a sequential interval of sectors, |
319 | jne .found_slot_access_denied |
- | |
320 | jmp .search_again ; and start again |
920 | ; they can be sequential or scattered in the cache. |
321 | .found_slot: |
921 | .sequential dd ? |
322 | mov [esi+DISKCACHE.search_start], edi |
922 | ; boolean variable, 1 if the current chain is sequential in the cache, |
323 | xor eax, eax ; success |
923 | ; 0 if additional buffer is needed to perform the operation |
- | 924 | .chain_start_pos dd ? ; data of chain start item |
|
- | 925 | .chain_start_ptr dd ? ; pointer to chain start item |
|
- | 926 | .chain_size dd ? ; chain size (thanks, C.O.) |
|
- | 927 | .iteration_size dd ? |
|
- | 928 | ; If the chain size is too large, split the operation to several iterations. |
|
- | 929 | ; This is size in sectors for one iterations. |
|
324 | .found_slot_access_denied: |
930 | .iteration_buffer dd ? ; temporary buffer for non-sequential chains |
- | 931 | .local_vars_size = $ - .local_vars |
|
- | 932 | rd 2 ; saved registers |
|
325 | ret |
933 | dd ? ; return address |
326 | 934 | .disk dd ? ; first argument |
|
- | 935 | end virtual |
|
- | 936 | ; 1. If there is no cache for this disk, nothing to do, just return zero. |
|
- | 937 | cmp [ebx+DISKCACHE.pointer], 0 |
|
- | 938 | jz .return0 |
|
- | 939 | ; 2. Prepare for the loop: initialize current pointer and .size_left, |
|
- | 940 | ; calculate .cache_end. |
|
- | 941 | mov ecx, [ebx+DISKCACHE.sad_size] |
|
- | 942 | mov [.size_left], ecx |
|
- | 943 | lea ecx, [ecx*sizeof.CACHE_ITEM/4] |
|
- | 944 | shl ecx, 2 |
|
- | 945 | mov esi, [ebx+DISKCACHE.pointer] |
|
- | 946 | add esi, sizeof.CACHE_ITEM |
|
327 | ; This function is intended to replace the old 'write_cache' function. |
947 | add ecx, esi |
- | 948 | mov [.cache_end], ecx |
|
- | 949 | ; 3. Main loop: go over all items, go to 5 for every modified item. |
|
- | 950 | .look: |
|
- | 951 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
- | 952 | jz .begin_write |
|
- | 953 | .look_next: |
|
328 | proc write_cache64 uses ecx edx esi edi, disk:dword |
954 | add esi, sizeof.CACHE_ITEM |
- | 955 | dec [.size_left] |
|
- | 956 | jnz .look |
|
- | 957 | ; 4. Return success. |
|
- | 958 | .return0: |
|
329 | locals |
959 | xor eax, eax |
- | 960 | .return: |
|
- | 961 | add esp, .local_vars_size |
|
- | 962 | pop edi esi ; restore used registers to be stdcall |
|
- | 963 | ret 4 ; return popping one argument |
|
- | 964 | .begin_write: |
|
- | 965 | ; We have found a modified item. |
|
- | 966 | ; 5. Prepare for chain finding: save the current item, initialize chain variables. |
|
- | 967 | mov [.current_ptr], esi |
|
- | 968 | ; Initialize chain as sequential zero-length starting at the current item. |
|
- | 969 | mov [.chain_start_ptr], esi |
|
- | 970 | mov eax, [ebx+DISKCACHE.sad_size] |
|
- | 971 | sub eax, [.size_left] |
|
- | 972 | inc eax |
|
- | 973 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
|
- | 974 | shl eax, cl |
|
- | 975 | add eax, [ebx+DISKCACHE.data] |
|
- | 976 | mov [.chain_start_pos], eax |
|
- | 977 | mov [.chain_size], 0 |
|
- | 978 | mov [.sequential], 1 |
|
- | 979 | ; 6. Expand the chain backward. |
|
- | 980 | ; Note: the main loop in step 2 looks for items sequentially, |
|
- | 981 | ; so the previous item is not modified. If the previous sector |
|
- | 982 | ; is present in the cache, it automatically makes the chain scattered. |
|
- | 983 | ; 6a. Calculate sector number: one before the sector for the current item. |
|
- | 984 | mov eax, [esi+CACHE_ITEM.SectorLo] |
|
- | 985 | mov edx, [esi+CACHE_ITEM.SectorHi] |
|
- | 986 | sub eax, 1 |
|
- | 987 | sbb edx, 0 |
|
- | 988 | .find_chain_start: |
|
- | 989 | ; 6b. For each sector where the previous item does not expand the chain, |
|
- | 990 | ; call the lookup function without adding to the cache. |
|
- | 991 | call cache_lookup_read |
|
- | 992 | ; 6c. If the sector is not found in cache or is not modified, stop expanding |
|
330 | cache_chain_started dd 0 |
993 | ; and advance to step 7. |
- | 994 | jc .found_chain_start |
|
- | 995 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
- | 996 | jnz .found_chain_start |
|
- | 997 | ; 6d. We have found a new block that expands the chain backwards. |
|
- | 998 | ; It makes the chain non-sequential. |
|
- | 999 | ; Normally, sectors come in sequential blocks, so try to look at previous items |
|
- | 1000 | ; before returning to 6b; if there is a sequential block indeed, this saves some |
|
- | 1001 | ; time instead of many full-fledged lookups. |
|
- | 1002 | mov [.sequential], 0 |
|
- | 1003 | mov [.chain_start_pos], edi |
|
- | 1004 | .look_backward: |
|
- | 1005 | ; 6e. For each sector, update chain start pos/ptr, decrement sector number, |
|
- | 1006 | ; look at the previous item. |
|
- | 1007 | mov [.chain_start_ptr], esi |
|
- | 1008 | inc [.chain_size] |
|
- | 1009 | sub eax, 1 |
|
331 | cache_chain_size dd ? |
1010 | sbb edx, 0 |
332 | cache_chain_pos dd ? |
1011 | sub esi, sizeof.CACHE_ITEM |
333 | cache_chain_ptr dd ? |
1012 | ; If the previous item exists... |
334 | endl |
1013 | cmp esi, [ebx+DISKCACHE.pointer] |
- | 1014 | jbe .find_chain_start |
|
335 | saved_esi_pos = 16+12 ; size of local variables + size of registers before esi |
1015 | ; ...describes the correct sector... |
336 | ; If there is no cache for this disk, nothing to do. |
1016 | cmp [esi+CACHE_ITEM.SectorLo], eax |
337 | cmp [esi+DISKCACHE.pointer], 0 |
1017 | jnz .find_chain_start |
338 | jz .flush |
- | |
339 | ;----------------------------------------------------------- |
1018 | cmp [esi+CACHE_ITEM.SectorHi], edx |
340 | ; write all changed sectors to disk |
1019 | jnz .find_chain_start |
341 | ;----------------------------------------------------------- |
1020 | ; ...and is modified... |
- | 1021 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
342 | 1022 | jnz .found_chain_start |
|
- | 1023 | ; ...expand the chain one sector backwards and continue the loop at 6e. |
|
- | 1024 | ; Otherwise, advance to step 7 if the previous item describes the correct sector |
|
343 | ; write difference ( 2 ) from cache to DISK |
1025 | ; but is not modified, and return to step 6b otherwise. |
344 | mov ecx, [esi+DISKCACHE.sad_size] |
1026 | mov edi, 1 |
345 | mov esi, [esi+DISKCACHE.pointer] |
1027 | shl edi, cl |
- | 1028 | sub [.chain_start_pos], edi |
|
346 | add esi, 12 |
1029 | jmp .look_backward |
- | 1030 | .found_chain_start: |
|
- | 1031 | ; 7. Expand the chain forward. |
|
- | 1032 | ; 7a. Prepare for the loop at 7b: |
|
- | 1033 | ; set esi = pointer to current item, edx:eax = current sector. |
|
- | 1034 | mov esi, [.current_ptr] |
|
- | 1035 | mov eax, [esi+CACHE_ITEM.SectorLo] |
|
- | 1036 | mov edx, [esi+CACHE_ITEM.SectorHi] |
|
- | 1037 | .look_forward: |
|
- | 1038 | ; 7b. First, look at the next item. If it describes the next sector: |
|
- | 1039 | ; if it is modified, expand the chain with that sector and continue this step, |
|
- | 1040 | ; if it is not modified, the chain is completed, so advance to step 8. |
|
- | 1041 | inc [.chain_size] |
|
- | 1042 | add eax, 1 |
|
- | 1043 | adc edx, 0 |
|
- | 1044 | add esi, sizeof.CACHE_ITEM |
|
- | 1045 | cmp esi, [.cache_end] |
|
- | 1046 | jae .find_chain_end |
|
- | 1047 | cmp [esi+CACHE_ITEM.SectorLo], eax |
|
- | 1048 | jnz .find_chain_end |
|
- | 1049 | cmp [esi+CACHE_ITEM.SectorHi], edx |
|
- | 1050 | jnz .find_chain_end |
|
- | 1051 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
- | 1052 | jnz .found_chain_end |
|
- | 1053 | jmp .look_forward |
|
- | 1054 | .find_chain_end: |
|
- | 1055 | ; 7c. Otherwise, call the lookup function. |
|
- | 1056 | call cache_lookup_read |
|
- | 1057 | ; 7d. If the next sector is present in the cache and is modified, |
|
- | 1058 | ; mark the chain as non-sequential and continue to step 7b. |
|
- | 1059 | jc .found_chain_end |
|
- | 1060 | cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED |
|
- | 1061 | jnz .found_chain_end |
|
- | 1062 | mov [.sequential], 0 |
|
- | 1063 | jmp .look_forward |
|
- | 1064 | .found_chain_end: |
|
- | 1065 | ; 8. Decide whether the chain is sequential or scattered. |
|
- | 1066 | ; Advance to step 9 for sequential chains, go to step 10 for scattered chains. |
|
347 | mov edi, 1 |
1067 | cmp [.sequential], 0 |
- | 1068 | jz .write_non_sequential |
|
- | 1069 | .write_sequential: |
|
- | 1070 | ; 9. Write a sequential chain to disk. |
|
348 | .write_cache_more: |
1071 | ; 9a. Pass the entire chain to the driver. |
- | 1072 | mov eax, [.chain_start_ptr] |
|
349 | cmp dword [esi+8], 2 ; if cache slot is not different |
1073 | lea ecx, [.chain_size] |
350 | jne .write_chain |
1074 | push ecx ; numsectors |
351 | mov dword [esi+8], 1 ; same as in hd |
1075 | pushd [eax+CACHE_ITEM.SectorHi] ; startsector |
352 | mov eax, [esi] |
1076 | pushd [eax+CACHE_ITEM.SectorLo] ; startsector |
353 | mov edx, [esi+4] ; edx:eax = sector to write |
1077 | push [.chain_start_pos+12] ; buffer |
354 | ; Объединяем запись цепочки последовательных секторов в одно обращение к диску |
- | |
355 | cmp ecx, 1 |
- | |
356 | jz .nonext |
- | |
357 | cmp dword [esi+12+8], 2 |
1078 | mov esi, [ebp+PARTITION.Disk] |
358 | jnz .nonext |
- | |
359 | push eax edx |
1079 | mov al, DISKFUNC.write |
360 | add eax, 1 |
1080 | call disk_call_driver |
361 | adc edx, 0 |
1081 | ; 9b. If failed, pass the error code to the driver. |
362 | cmp eax, [esi+12] |
1082 | test eax, eax |
363 | jnz @f |
1083 | jnz .return |
364 | cmp edx, [esi+12+4] |
1084 | ; 9c. If succeeded, mark all sectors in the chain as not-modified, |
365 | @@: |
1085 | ; advance current item and number of items left to skip the chain. |
366 | pop edx eax |
1086 | mov esi, [.current_ptr] |
367 | jnz .nonext |
1087 | mov eax, [.chain_size] |
368 | cmp [cache_chain_started], 1 |
1088 | sub [.size_left], eax |
369 | jz @f |
1089 | @@: |
370 | mov [cache_chain_started], 1 |
1090 | mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
371 | mov [cache_chain_size], 0 |
1091 | add esi, sizeof.CACHE_ITEM |
372 | mov [cache_chain_pos], edi |
1092 | dec eax |
373 | mov [cache_chain_ptr], esi |
1093 | jnz @b |
374 | @@: |
1094 | ; 9d. Continue the main loop at step 2 if there are more sectors. |
- | 1095 | ; Return success otherwise. |
|
375 | inc [cache_chain_size] |
1096 | cmp [.size_left], 0 |
376 | cmp [cache_chain_size], 16 |
1097 | jnz .look |
377 | jnz .continue |
1098 | jmp .return0 |
378 | jmp .write_chain |
1099 | .write_non_sequential: |
379 | .nonext: |
1100 | ; Write a non-sequential chain to the disk. |
380 | call .flush_cache_chain |
1101 | ; 10. Allocate a temporary buffer. |
- | 1102 | ; Use [.chain_size] sectors, but |
|
381 | test eax, eax |
1103 | ; not greater than CACHE_MAX_ALLOC_SIZE bytes |
- | 1104 | ; and not greater than half of free memory. |
|
382 | jnz .nothing |
1105 | mov eax, [pg_data.pages_free] |
383 | mov [cache_chain_size], 1 |
1106 | shr eax, 1 |
384 | mov [cache_chain_ptr], esi |
1107 | jz .nomemory |
385 | call .write_cache_sector |
- | |
386 | test eax, eax |
1108 | cmp eax, CACHE_MAX_ALLOC_SIZE shr 12 |
387 | jnz .nothing |
1109 | jbe @f |
388 | jmp .continue |
1110 | mov eax, CACHE_MAX_ALLOC_SIZE shr 12 |
389 | .write_chain: |
- | |
390 | call .flush_cache_chain |
- | |
391 | test eax, eax |
- | |
392 | jnz .nothing |
1111 | @@: |
393 | .continue: |
1112 | shl eax, 12 |
394 | add esi, 12 |
1113 | shr eax, cl |
395 | inc edi |
1114 | jz .nomemory |
396 | dec ecx |
- | |
397 | jnz .write_cache_more |
1115 | cmp eax, [.chain_size] |
398 | call .flush_cache_chain |
1116 | jbe @f |
399 | test eax, eax |
- | |
400 | jnz .nothing |
- | |
401 | .flush: |
- | |
402 | mov esi, [disk] |
- | |
403 | mov al, DISKFUNC.flush |
1117 | mov eax, [.chain_size] |
404 | call disk_call_driver |
- | |
405 | .nothing: |
- | |
406 | ret |
1118 | @@: |
407 | 1119 | mov [.iteration_size], eax |
|
408 | .flush_cache_chain: |
- | |
409 | xor eax, eax |
- | |
410 | cmp [cache_chain_started], eax |
1120 | shl eax, cl |
411 | jz @f |
- | |
412 | call .write_cache_chain |
1121 | stdcall kernel_alloc, eax |
413 | mov [cache_chain_started], 0 |
1122 | test eax, eax |
414 | @@: |
- | |
415 | retn |
1123 | jz .nomemory |
416 | 1124 | mov [.iteration_buffer], eax |
|
- | 1125 | .write_non_sequential_iteration: |
|
- | 1126 | ; 11. Split the chain so that each iteration fits in the allocated buffer. |
|
- | 1127 | ; Iteration size is the minimum of chain size and allocated size. |
|
- | 1128 | mov eax, [.chain_size] |
|
- | 1129 | cmp eax, [.iteration_size] |
|
- | 1130 | jae @f |
|
- | 1131 | mov [.iteration_size], eax |
|
- | 1132 | @@: |
|
- | 1133 | ; 12. Prepare arguments for the driver. |
|
- | 1134 | mov esi, [.chain_start_ptr] |
|
- | 1135 | mov edi, [.iteration_buffer] |
|
417 | .write_cache_sector: |
1136 | push [.iteration_size] |
- | 1137 | push esp ; numsectors |
|
- | 1138 | push [esi+CACHE_ITEM.SectorHi] ; startsector |
|
- | 1139 | push [esi+CACHE_ITEM.SectorLo] ; startsector |
|
- | 1140 | push edi ; buffer |
|
- | 1141 | ; 13. Copy data from the cache to the temporary buffer, |
|
- | 1142 | ; advancing chain_start pos/ptr and marking sectors as not-modified. |
|
- | 1143 | ; 13a. Prepare for the loop: push number of sectors to process. |
|
- | 1144 | push [.iteration_size+20] ; temporary variable |
|
- | 1145 | .copy_loop: |
|
- | 1146 | ; 13b. For each sector, copy the data. |
|
- | 1147 | ; Note that edi is advanced automatically. |
|
- | 1148 | mov esi, [.chain_start_pos+24] |
|
- | 1149 | mov ecx, [ebx+DISKCACHE.sector_size_log] |
|
- | 1150 | mov eax, 1 |
|
- | 1151 | shl eax, cl |
|
- | 1152 | mov ecx, eax |
|
- | 1153 | shr ecx, 2 |
|
- | 1154 | rep movsd |
|
- | 1155 | mov ecx, eax ; keep for 13e |
|
- | 1156 | ; 13c. Mark the item as not-modified. |
|
- | 1157 | mov esi, [.chain_start_ptr+24] |
|
- | 1158 | mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY |
|
- | 1159 | ; 13d. Check whether the next sector continues the chain. |
|
- | 1160 | ; If so, advance to 13e. Otherwise, go to 13f. |
|
- | 1161 | mov eax, [esi+CACHE_ITEM.SectorLo] |
|
- | 1162 | mov edx, [esi+CACHE_ITEM.SectorHi] |
|
- | 1163 | add esi, sizeof.CACHE_ITEM |
|
- | 1164 | add eax, 1 |
|
- | 1165 | adc edx, 0 |
|
- | 1166 | cmp esi, [.cache_end+24] |
|
- | 1167 | jae .no_forward |
|
- | 1168 | cmp [esi+CACHE_ITEM.SectorLo], eax |
|
- | 1169 | jnz .no_forward |
|
- | 1170 | cmp [esi+CACHE_ITEM.SectorHi], edx |
|
- | 1171 | jnz .no_forward |
|
- | 1172 | ; 13e. Increment position/pointer to the chain and |
|
- | 1173 | ; continue the loop. |
|
- | 1174 | add [.chain_start_pos+24], ecx |
|
- | 1175 | mov [.chain_start_ptr+24], esi |
|
- | 1176 | dec dword [esp] |
|
- | 1177 | jnz .copy_loop |
|
- | 1178 | jmp .copy_done |
|
418 | mov [cache_chain_size], 1 |
1179 | .no_forward: |
419 | mov [cache_chain_pos], edi |
1180 | ; 13f. Call the lookup function without adding to the cache. |
420 | .write_cache_chain: |
1181 | ; Update position/pointer with returned value. |
- | 1182 | ; Note: for the last sector in the chain, edi/esi may contain |
|
- | 1183 | ; garbage; we are not going to use them in this case. |
|
- | 1184 | push edi |
|
- | 1185 | call cache_lookup_read |
|
- | 1186 | mov [.chain_start_pos+28], edi |
|
421 | pusha |
1187 | mov [.chain_start_ptr+28], esi |
- | 1188 | pop edi |
|
422 | mov edi, [cache_chain_pos] |
1189 | dec dword [esp] |
- | 1190 | jnz .copy_loop |
|
- | 1191 | .copy_done: |
|
- | 1192 | ; 13g. Restore the stack after 13a. |
|
- | 1193 | pop ecx |
|
- | 1194 | ; 14. Call the driver. |
|
- | 1195 | mov esi, [ebp+PARTITION.Disk] |
|
- | 1196 | mov al, DISKFUNC.write |
|
- | 1197 | call disk_call_driver |
|
- | 1198 | pop ecx ; numsectors |
|
423 | mov ecx, [ebp-saved_esi_pos] |
1199 | ; 15. If the driver has returned an error, free the buffer allocated at step 10 |
- | 1200 | ; and pass the error to the caller. |
|
- | 1201 | ; Otherwise, remove the processed part from the chain and continue iterations |
|
- | 1202 | ; starting in step 11 if there are more data to process. |
|
424 | shl edi, 9 |
1203 | test eax, eax |
425 | add edi, [ecx+DISKCACHE.data] |
1204 | jnz .nonsequential_error |
Line 426... | Line 1205... | ||
426 | mov ecx, [cache_chain_size] |
1205 | sub [.chain_size], ecx |
427 | push ecx |
1206 | jnz .write_non_sequential_iteration |
428 | push esp ; numsectors |
1207 | ; 16. The chain is written. Free the temporary buffer |
Line 450... | Line 1229... | ||
450 | ; driver can adjust the size. In particular, setting size to zero disables |
1229 | ; driver can adjust the size. In particular, setting size to zero disables |
451 | ; caching: there is no sense in a cache for a ramdisk. In fact, such action |
1230 | ; caching: there is no sense in a cache for a ramdisk. In fact, such action |
452 | ; is most useful example of a non-trivial adjustment. |
1231 | ; is most useful example of a non-trivial adjustment. |
453 | ; esi = pointer to DISK structure |
1232 | ; esi = pointer to DISK structure |
454 | disk_init_cache: |
1233 | disk_init_cache: |
- | 1234 | ; 1. Verify sector size. The code requires it to be a power of 2 not less than 4. |
|
- | 1235 | ; In the name of sanity check that sector size is not too small or too large. |
|
- | 1236 | bsf ecx, [esi+DISK.MediaInfo.SectorSize] |
|
- | 1237 | jz .invalid_sector_size |
|
- | 1238 | mov eax, 1 |
|
- | 1239 | shl eax, cl |
|
- | 1240 | cmp eax, [esi+DISK.MediaInfo.SectorSize] |
|
- | 1241 | jnz .invalid_sector_size |
|
- | 1242 | cmp ecx, 6 |
|
- | 1243 | jb .invalid_sector_size |
|
- | 1244 | cmp ecx, 14 |
|
- | 1245 | jbe .normal_sector_size |
|
- | 1246 | .invalid_sector_size: |
|
- | 1247 | DEBUGF 1,'K : sector size %x is invalid\n',[esi+DISK.MediaInfo.SectorSize] |
|
- | 1248 | xor eax, eax |
|
- | 1249 | ret |
|
- | 1250 | .normal_sector_size: |
|
- | 1251 | mov [esi+DISK.SysCache.sector_size_log], ecx |
|
- | 1252 | mov [esi+DISK.AppCache.sector_size_log], ecx |
|
455 | ; 1. Calculate the suggested cache size. |
1253 | ; 2. Calculate the suggested cache size. |
456 | ; 1a. Get the size of free physical memory in pages. |
1254 | ; 2a. Get the size of free physical memory in pages. |
457 | mov eax, [pg_data.pages_free] |
1255 | mov eax, [pg_data.pages_free] |
458 | ; 1b. Use the value to calculate the size. |
1256 | ; 2b. Use the value to calculate the size. |
459 | shl eax, 12 - 5 ; 1/32 of it in bytes |
1257 | shl eax, 12 - 5 ; 1/32 of it in bytes |
460 | and eax, -8*4096 ; round down to the multiple of 8 pages |
1258 | and eax, -8*4096 ; round down to the multiple of 8 pages |
461 | ; 1c. Force lower and upper limits. |
1259 | ; 2c. Force lower and upper limits. |
462 | cmp eax, 1024*1024 |
1260 | cmp eax, 1024*1024 |
463 | jb @f |
1261 | jb @f |
464 | mov eax, 1024*1024 |
1262 | mov eax, 1024*1024 |
465 | @@: |
1263 | @@: |
466 | cmp eax, 128*1024 |
1264 | cmp eax, 128*1024 |
467 | ja @f |
1265 | ja @f |
468 | mov eax, 128*1024 |
1266 | mov eax, 128*1024 |
469 | @@: |
1267 | @@: |
470 | ; 1d. Give a chance to the driver to adjust the size. |
1268 | ; 2d. Give a chance to the driver to adjust the size. |
471 | push eax |
1269 | push eax |
472 | mov al, DISKFUNC.adjust_cache_size |
1270 | mov al, DISKFUNC.adjust_cache_size |
473 | call disk_call_driver |
1271 | call disk_call_driver |
474 | ; Cache size calculated. |
1272 | ; Cache size calculated. |
475 | mov [esi+DISK.cache_size], eax |
1273 | mov [esi+DISK.cache_size], eax |
476 | test eax, eax |
1274 | test eax, eax |
477 | jz .nocache |
1275 | jz .nocache |
478 | ; 2. Allocate memory for the cache. |
1276 | ; 3. Allocate memory for the cache. |
479 | ; 2a. Call the allocator. |
1277 | ; 3a. Call the allocator. |
480 | stdcall kernel_alloc, eax |
1278 | stdcall kernel_alloc, eax |
481 | test eax, eax |
1279 | test eax, eax |
482 | jnz @f |
1280 | jnz @f |
483 | ; 2b. If it failed, say a message and return with eax = 0. |
1281 | ; 3b. If it failed, say a message and return with eax = 0. |
484 | dbgstr 'no memory for disk cache' |
1282 | dbgstr 'no memory for disk cache' |
485 | jmp .nothing |
1283 | jmp .nothing |
486 | @@: |
1284 | @@: |
487 | ; 3. Fill two DISKCACHE structures. |
1285 | ; 4. Fill two DISKCACHE structures. |
488 | mov [esi+DISK.SysCache.pointer], eax |
1286 | mov [esi+DISK.SysCache.pointer], eax |
489 | lea ecx, [esi+DISK.SysCache.mutex] |
- | |
490 | call mutex_init |
- | |
491 | lea ecx, [esi+DISK.AppCache.mutex] |
1287 | lea ecx, [esi+DISK.CacheLock] |
492 | call mutex_init |
1288 | call mutex_init |
493 | ; The following code is inherited from getcache.inc. |
1289 | ; The following code is inherited from getcache.inc. |
494 | mov edx, [esi+DISK.SysCache.pointer] |
1290 | mov edx, [esi+DISK.SysCache.pointer] |
495 | and [esi+DISK.SysCache.search_start], 0 |
1291 | and [esi+DISK.SysCache.search_start], 0 |
496 | and [esi+DISK.AppCache.search_start], 0 |
1292 | and [esi+DISK.AppCache.search_start], 0 |
Line 501... | Line 1297... | ||
501 | imul eax, 7 |
1297 | imul eax, 7 |
502 | mov [esi+DISK.AppCache.data_size], eax |
1298 | mov [esi+DISK.AppCache.data_size], eax |
503 | mov [esi+DISK.AppCache.pointer], edx |
1299 | mov [esi+DISK.AppCache.pointer], edx |
Line 504... | Line 1300... | ||
504 | 1300 | ||
505 | mov eax, [esi+DISK.SysCache.data_size] |
- | |
506 | push ebx |
1301 | mov eax, [esi+DISK.SysCache.data_size] |
507 | call calculate_for_hd64 |
- | |
508 | pop ebx |
1302 | call calculate_cache_slots |
509 | add eax, [esi+DISK.SysCache.pointer] |
1303 | add eax, [esi+DISK.SysCache.pointer] |
510 | mov [esi+DISK.SysCache.data], eax |
1304 | mov [esi+DISK.SysCache.data], eax |
Line 511... | Line 1305... | ||
511 | mov [esi+DISK.SysCache.sad_size], ecx |
1305 | mov [esi+DISK.SysCache.sad_size], ecx |
Line 516... | Line 1310... | ||
516 | xor eax, eax |
1310 | xor eax, eax |
517 | rep stosd |
1311 | rep stosd |
518 | pop edi |
1312 | pop edi |
Line 519... | Line 1313... | ||
519 | 1313 | ||
520 | mov eax, [esi+DISK.AppCache.data_size] |
- | |
521 | push ebx |
1314 | mov eax, [esi+DISK.AppCache.data_size] |
522 | call calculate_for_hd64 |
- | |
523 | pop ebx |
1315 | call calculate_cache_slots |
524 | add eax, [esi+DISK.AppCache.pointer] |
1316 | add eax, [esi+DISK.AppCache.pointer] |
525 | mov [esi+DISK.AppCache.data], eax |
1317 | mov [esi+DISK.AppCache.data], eax |
Line 526... | Line 1318... | ||
526 | mov [esi+DISK.AppCache.sad_size], ecx |
1318 | mov [esi+DISK.AppCache.sad_size], ecx |
Line 530... | Line 1322... | ||
530 | lea ecx, [(ecx+1)*3] |
1322 | lea ecx, [(ecx+1)*3] |
531 | xor eax, eax |
1323 | xor eax, eax |
532 | rep stosd |
1324 | rep stosd |
533 | pop edi |
1325 | pop edi |
Line 534... | Line 1326... | ||
534 | 1326 | ||
535 | ; 4. Return with nonzero al. |
1327 | ; 5. Return with nonzero al. |
536 | mov al, 1 |
1328 | mov al, 1 |
537 | ; 5. Return. |
1329 | ; 6. Return. |
538 | .nothing: |
1330 | .nothing: |
539 | ret |
1331 | ret |
540 | ; No caching is required for this driver. Zero cache pointers and return with |
1332 | ; No caching is required for this driver. Zero cache pointers and return with |
541 | ; nonzero al. |
1333 | ; nonzero al. |
542 | .nocache: |
1334 | .nocache: |
543 | mov [esi+DISK.SysCache.pointer], eax |
1335 | mov [esi+DISK.SysCache.pointer], eax |
544 | mov [esi+DISK.AppCache.pointer], eax |
1336 | mov [esi+DISK.AppCache.pointer], eax |
545 | mov al, 1 |
1337 | mov al, 1 |
Line 546... | Line 1338... | ||
546 | ret |
1338 | ret |
547 | 1339 | ||
548 | calculate_for_hd64: |
1340 | calculate_cache_slots: |
549 | push eax |
1341 | push eax |
550 | mov ebx, eax |
1342 | mov ecx, [esi+DISK.MediaInfo.SectorSize] |
551 | shr eax, 9 |
1343 | add ecx, sizeof.CACHE_ITEM |
552 | lea eax, [eax*3] |
1344 | xor edx, edx |
553 | shl eax, 2 |
1345 | div ecx |
554 | sub ebx, eax |
1346 | mov ecx, eax |
555 | shr ebx, 9 |
- | |
556 | mov ecx, ebx |
1347 | imul eax, [esi+DISK.MediaInfo.SectorSize] |
557 | shl ebx, 9 |
- | |
558 | pop eax |
1348 | sub [esp], eax |
559 | sub eax, ebx |
1349 | pop eax |
Line 560... | Line 1350... | ||
560 | dec ecx |
1350 | dec ecx |
Line 575... | Line 1365... | ||
575 | 1365 | ||
576 | ; This function flushes all modified data from both caches for the given DISK. |
1366 | ; This function flushes all modified data from both caches for the given DISK. |
577 | ; esi = pointer to DISK |
1367 | ; esi = pointer to DISK |
578 | disk_sync: |
1368 | disk_sync: |
- | 1369 | ; The algorithm is straightforward. |
|
- | 1370 | cmp [esi+DISK.SysCache.pointer], 0 |
|
- | 1371 | jz .nothing |
|
- | 1372 | lea ecx, [esi+DISK.CacheLock] |
|
579 | ; The algorithm is straightforward. |
1373 | call mutex_lock |
580 | push esi |
1374 | push ebx |
581 | push esi ; for second write_cache64 |
1375 | push esi ; for second write_cache64 |
582 | push esi ; for first write_cache64 |
1376 | push esi ; for first write_cache64 |
583 | add esi, DISK.SysCache |
1377 | lea ebx, [esi+DISK.SysCache] |
584 | call write_cache64 |
1378 | call write_cache64 |
585 | add esi, DISK.AppCache - DISK.SysCache |
1379 | add ebx, DISK.AppCache - DISK.SysCache |
586 | call write_cache64 |
1380 | call write_cache64 |
- | 1381 | pop ebx |
|
- | 1382 | lea ecx, [esi+DISK.CacheLock] |
|
- | 1383 | call mutex_unlock |
|
- | 1384 | .nothing: |
|
- | 1385 | mov al, DISKFUNC.flush |
|
587 | pop esi |
1386 | call disk_call_driver |