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