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