Subversion Repositories Kolibri OS

Rev

Rev 4429 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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