Subversion Repositories Kolibri OS

Rev

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

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