1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** FileX Component */
16 /** */
17 /** Utility */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define FX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "fx_api.h"
28 #include "fx_system.h"
29 #include "fx_utility.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _fx_utility_logical_sector_cache_entry_read PORTABLE C */
37 /* 6.1.10 */
38 /* AUTHOR */
39 /* */
40 /* William E. Lamie, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function handles logical sector cache read requests for the */
45 /* logical sector read function. If the function finds the requested */
46 /* sector in the cache, it setup the appropriate pointers and */
47 /* returns a FX_NULL. */
48 /* */
49 /* INPUT */
50 /* */
51 /* media_ptr Media control block pointer */
52 /* logical_sector Logical sector number */
53 /* previous_cache_entry Pointer to previous entry in */
54 /* non-hashed cache */
55 /* */
56 /* OUTPUT */
57 /* */
58 /* FX_CACHED_SECTOR * Cache entry to setup */
59 /* */
60 /* CALLS */
61 /* */
62 /* None */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* _fx_utility_logical_sector_read Logical sector read function */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
73 /* 09-30-2020 William E. Lamie Modified comment(s), and */
74 /* added conditional to */
75 /* disable cache, */
76 /* resulting in version 6.1 */
77 /* 01-31-2022 William E. Lamie Modified comment(s), fixed */
78 /* errors without cache, */
79 /* resulting in version 6.1.10 */
80 /* */
81 /**************************************************************************/
_fx_utility_logical_sector_cache_entry_read(FX_MEDIA * media_ptr,ULONG64 logical_sector,FX_CACHED_SECTOR ** previous_cache_entry)82 FX_CACHED_SECTOR *_fx_utility_logical_sector_cache_entry_read(FX_MEDIA *media_ptr, ULONG64 logical_sector,
83 FX_CACHED_SECTOR **previous_cache_entry)
84 {
85
86 #ifndef FX_DISABLE_CACHE
87 FX_CACHED_SECTOR *cache_entry;
88 FX_CACHED_SECTOR temp_storage;
89 ULONG cache_size;
90 ULONG index;
91
92
93 /* Determine if the logical sector cache access should use the hash function. */
94 if (media_ptr -> fx_media_sector_cache_hashed)
95 {
96
97 /* Calculate the area of the cache for this logical sector. */
98
99 /* First compute the hashed value of this index by simply using the lower bits of
100 the sector number. */
101 index = (ULONG)(logical_sector & media_ptr -> fx_media_sector_cache_hash_mask);
102
103 /* Set the bit indicating there is one or more valid sectors at this cache index. */
104 media_ptr -> fx_media_sector_cache_hashed_sector_valid |= ((ULONG)1) << (index % 32);
105
106 /* Compute the actual array index by multiplying by the cache depth. */
107 index = index * FX_SECTOR_CACHE_DEPTH;
108
109 /* Build a pointer to the cache entry. */
110 cache_entry = &(media_ptr -> fx_media_sector_cache[index]);
111
112 /* Determine if the logical sector is in the cache - assuming the depth of the
113 sector cache is 4 entries. */
114 if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
115 {
116
117 /* Yes, we found a match. Simply setup the pointer to this
118 buffer and return. */
119 media_ptr -> fx_media_memory_buffer = cache_entry -> fx_cached_sector_memory_buffer;
120
121 #ifndef FX_MEDIA_STATISTICS_DISABLE
122
123 /* Increment the number of logical sectors cache read hits. */
124 media_ptr -> fx_media_logical_sector_cache_read_hits++;
125 #endif
126 /* Success, return to caller immediately! */
127 return(FX_NULL);
128 }
129 else if (((cache_entry + 1) -> fx_cached_sector_valid) && ((cache_entry + 1) -> fx_cached_sector == logical_sector))
130 {
131
132 /* Yes, we found a match. Simply setup the pointer to this
133 buffer and return. */
134 media_ptr -> fx_media_memory_buffer = (cache_entry + 1) -> fx_cached_sector_memory_buffer;
135
136 #ifndef FX_MEDIA_STATISTICS_DISABLE
137
138 /* Increment the number of logical sectors cache read hits. */
139 media_ptr -> fx_media_logical_sector_cache_read_hits++;
140 #endif
141
142 /* Swap the first and second cache entries to keep the most recently used
143 at the top. */
144 temp_storage.fx_cached_sector_memory_buffer = (cache_entry) -> fx_cached_sector_memory_buffer;
145 temp_storage.fx_cached_sector = (cache_entry) -> fx_cached_sector;
146 temp_storage.fx_cached_sector_buffer_dirty = (cache_entry) -> fx_cached_sector_buffer_dirty;
147 temp_storage.fx_cached_sector_valid = (cache_entry) -> fx_cached_sector_valid;
148 temp_storage.fx_cached_sector_type = (cache_entry) -> fx_cached_sector_type;
149
150 (cache_entry) -> fx_cached_sector_memory_buffer = (cache_entry + 1) -> fx_cached_sector_memory_buffer;
151 (cache_entry) -> fx_cached_sector = (cache_entry + 1) -> fx_cached_sector;
152 (cache_entry) -> fx_cached_sector_buffer_dirty = (cache_entry + 1) -> fx_cached_sector_buffer_dirty;
153 (cache_entry) -> fx_cached_sector_valid = (cache_entry + 1) -> fx_cached_sector_valid;
154 (cache_entry) -> fx_cached_sector_type = (cache_entry + 1) -> fx_cached_sector_type;
155
156 (cache_entry + 1) -> fx_cached_sector_memory_buffer = temp_storage.fx_cached_sector_memory_buffer;
157 (cache_entry + 1) -> fx_cached_sector = temp_storage.fx_cached_sector;
158 (cache_entry + 1) -> fx_cached_sector_buffer_dirty = temp_storage.fx_cached_sector_buffer_dirty;
159 (cache_entry + 1) -> fx_cached_sector_valid = temp_storage.fx_cached_sector_valid;
160 (cache_entry + 1) -> fx_cached_sector_type = temp_storage.fx_cached_sector_type;
161
162 /* Success, return to caller immediately! */
163 return(FX_NULL);
164 }
165 else if (((cache_entry + 2) -> fx_cached_sector_valid) && ((cache_entry + 2) -> fx_cached_sector == logical_sector))
166 {
167
168 /* Yes, we found a match. Simply setup the pointer to this
169 buffer and return. */
170 media_ptr -> fx_media_memory_buffer = (cache_entry + 2) -> fx_cached_sector_memory_buffer;
171
172 #ifndef FX_MEDIA_STATISTICS_DISABLE
173
174 /* Increment the number of logical sectors cache read hits. */
175 media_ptr -> fx_media_logical_sector_cache_read_hits++;
176 #endif
177
178 /* Move the third entry to the top and the first two entries down. */
179 temp_storage.fx_cached_sector_memory_buffer = (cache_entry) -> fx_cached_sector_memory_buffer;
180 temp_storage.fx_cached_sector = (cache_entry) -> fx_cached_sector;
181 temp_storage.fx_cached_sector_buffer_dirty = (cache_entry) -> fx_cached_sector_buffer_dirty;
182 temp_storage.fx_cached_sector_valid = (cache_entry) -> fx_cached_sector_valid;
183 temp_storage.fx_cached_sector_type = (cache_entry) -> fx_cached_sector_type;
184
185 (cache_entry) -> fx_cached_sector_memory_buffer = (cache_entry + 2) -> fx_cached_sector_memory_buffer;
186 (cache_entry) -> fx_cached_sector = (cache_entry + 2) -> fx_cached_sector;
187 (cache_entry) -> fx_cached_sector_buffer_dirty = (cache_entry + 2) -> fx_cached_sector_buffer_dirty;
188 (cache_entry) -> fx_cached_sector_valid = (cache_entry + 2) -> fx_cached_sector_valid;
189 (cache_entry) -> fx_cached_sector_type = (cache_entry + 2) -> fx_cached_sector_type;
190
191 (cache_entry + 2) -> fx_cached_sector_memory_buffer = (cache_entry + 1) -> fx_cached_sector_memory_buffer;
192 (cache_entry + 2) -> fx_cached_sector = (cache_entry + 1) -> fx_cached_sector;
193 (cache_entry + 2) -> fx_cached_sector_buffer_dirty = (cache_entry + 1) -> fx_cached_sector_buffer_dirty;
194 (cache_entry + 2) -> fx_cached_sector_valid = (cache_entry + 1) -> fx_cached_sector_valid;
195 (cache_entry + 2) -> fx_cached_sector_type = (cache_entry + 1) -> fx_cached_sector_type;
196
197 (cache_entry + 1) -> fx_cached_sector_memory_buffer = temp_storage.fx_cached_sector_memory_buffer;
198 (cache_entry + 1) -> fx_cached_sector = temp_storage.fx_cached_sector;
199 (cache_entry + 1) -> fx_cached_sector_buffer_dirty = temp_storage.fx_cached_sector_buffer_dirty;
200 (cache_entry + 1) -> fx_cached_sector_valid = temp_storage.fx_cached_sector_valid;
201 (cache_entry + 1) -> fx_cached_sector_type = temp_storage.fx_cached_sector_type;
202
203 /* Success, return to caller immediately! */
204 return(FX_NULL);
205 }
206 else if (((cache_entry + 3) -> fx_cached_sector_valid) && ((cache_entry + 3) -> fx_cached_sector == logical_sector))
207 {
208
209 /* Yes, we found a match. Simply setup the pointer to this
210 buffer and return. */
211 media_ptr -> fx_media_memory_buffer = (cache_entry + 3) -> fx_cached_sector_memory_buffer;
212
213 #ifndef FX_MEDIA_STATISTICS_DISABLE
214
215 /* Increment the number of logical sectors cache read hits. */
216 media_ptr -> fx_media_logical_sector_cache_read_hits++;
217 #endif
218
219 /* Move the last entry to the top and the first three entries down. */
220 temp_storage.fx_cached_sector_memory_buffer = (cache_entry) -> fx_cached_sector_memory_buffer;
221 temp_storage.fx_cached_sector = (cache_entry) -> fx_cached_sector;
222 temp_storage.fx_cached_sector_buffer_dirty = (cache_entry) -> fx_cached_sector_buffer_dirty;
223 temp_storage.fx_cached_sector_valid = (cache_entry) -> fx_cached_sector_valid;
224 temp_storage.fx_cached_sector_type = (cache_entry) -> fx_cached_sector_type;
225
226 (cache_entry) -> fx_cached_sector_memory_buffer = (cache_entry + 3) -> fx_cached_sector_memory_buffer;
227 (cache_entry) -> fx_cached_sector = (cache_entry + 3) -> fx_cached_sector;
228 (cache_entry) -> fx_cached_sector_buffer_dirty = (cache_entry + 3) -> fx_cached_sector_buffer_dirty;
229 (cache_entry) -> fx_cached_sector_valid = (cache_entry + 3) -> fx_cached_sector_valid;
230 (cache_entry) -> fx_cached_sector_type = (cache_entry + 3) -> fx_cached_sector_type;
231
232 (cache_entry + 3) -> fx_cached_sector_memory_buffer = (cache_entry + 2) -> fx_cached_sector_memory_buffer;
233 (cache_entry + 3) -> fx_cached_sector = (cache_entry + 2) -> fx_cached_sector;
234 (cache_entry + 3) -> fx_cached_sector_buffer_dirty = (cache_entry + 2) -> fx_cached_sector_buffer_dirty;
235 (cache_entry + 3) -> fx_cached_sector_valid = (cache_entry + 2) -> fx_cached_sector_valid;
236 (cache_entry + 3) -> fx_cached_sector_type = (cache_entry + 2) -> fx_cached_sector_type;
237
238 (cache_entry + 2) -> fx_cached_sector_memory_buffer = (cache_entry + 1) -> fx_cached_sector_memory_buffer;
239 (cache_entry + 2) -> fx_cached_sector = (cache_entry + 1) -> fx_cached_sector;
240 (cache_entry + 2) -> fx_cached_sector_buffer_dirty = (cache_entry + 1) -> fx_cached_sector_buffer_dirty;
241 (cache_entry + 2) -> fx_cached_sector_valid = (cache_entry + 1) -> fx_cached_sector_valid;
242 (cache_entry + 2) -> fx_cached_sector_type = (cache_entry + 1) -> fx_cached_sector_type;
243
244 (cache_entry + 1) -> fx_cached_sector_memory_buffer = temp_storage.fx_cached_sector_memory_buffer;
245 (cache_entry + 1) -> fx_cached_sector = temp_storage.fx_cached_sector;
246 (cache_entry + 1) -> fx_cached_sector_buffer_dirty = temp_storage.fx_cached_sector_buffer_dirty;
247 (cache_entry + 1) -> fx_cached_sector_valid = temp_storage.fx_cached_sector_valid;
248 (cache_entry + 1) -> fx_cached_sector_type = temp_storage.fx_cached_sector_type;
249
250 /* Success, return to caller immediately! */
251 return(FX_NULL);
252 }
253
254 /* At this point we have a cache miss. We need to move all of the sectors down one slot, swapping
255 the 4th entry with the first. */
256 temp_storage.fx_cached_sector_memory_buffer = (cache_entry + 3) -> fx_cached_sector_memory_buffer;
257 temp_storage.fx_cached_sector = (cache_entry + 3) -> fx_cached_sector;
258 temp_storage.fx_cached_sector_buffer_dirty = (cache_entry + 3) -> fx_cached_sector_buffer_dirty;
259 temp_storage.fx_cached_sector_valid = (cache_entry + 3) -> fx_cached_sector_valid;
260 temp_storage.fx_cached_sector_type = (cache_entry + 3) -> fx_cached_sector_type;
261
262 (cache_entry + 3) -> fx_cached_sector_memory_buffer = (cache_entry + 2) -> fx_cached_sector_memory_buffer;
263 (cache_entry + 3) -> fx_cached_sector = (cache_entry + 2) -> fx_cached_sector;
264 (cache_entry + 3) -> fx_cached_sector_buffer_dirty = (cache_entry + 2) -> fx_cached_sector_buffer_dirty;
265 (cache_entry + 3) -> fx_cached_sector_valid = (cache_entry + 2) -> fx_cached_sector_valid;
266 (cache_entry + 3) -> fx_cached_sector_type = (cache_entry + 2) -> fx_cached_sector_type;
267
268 (cache_entry + 2) -> fx_cached_sector_memory_buffer = (cache_entry + 1) -> fx_cached_sector_memory_buffer;
269 (cache_entry + 2) -> fx_cached_sector = (cache_entry + 1) -> fx_cached_sector;
270 (cache_entry + 2) -> fx_cached_sector_buffer_dirty = (cache_entry + 1) -> fx_cached_sector_buffer_dirty;
271 (cache_entry + 2) -> fx_cached_sector_valid = (cache_entry + 1) -> fx_cached_sector_valid;
272 (cache_entry + 2) -> fx_cached_sector_type = (cache_entry + 1) -> fx_cached_sector_type;
273
274 (cache_entry + 1) -> fx_cached_sector_memory_buffer = (cache_entry) -> fx_cached_sector_memory_buffer;
275 (cache_entry + 1) -> fx_cached_sector = (cache_entry) -> fx_cached_sector;
276 (cache_entry + 1) -> fx_cached_sector_buffer_dirty = (cache_entry) -> fx_cached_sector_buffer_dirty;
277 (cache_entry + 1) -> fx_cached_sector_valid = (cache_entry) -> fx_cached_sector_valid;
278 (cache_entry + 1) -> fx_cached_sector_type = (cache_entry) -> fx_cached_sector_type;
279
280 (cache_entry) -> fx_cached_sector_memory_buffer = temp_storage.fx_cached_sector_memory_buffer;
281 (cache_entry) -> fx_cached_sector = temp_storage.fx_cached_sector;
282 (cache_entry) -> fx_cached_sector_buffer_dirty = temp_storage.fx_cached_sector_buffer_dirty;
283 (cache_entry) -> fx_cached_sector_valid = temp_storage.fx_cached_sector_valid;
284 (cache_entry) -> fx_cached_sector_type = temp_storage.fx_cached_sector_type;
285
286 /* Set the previous pointer to NULL to avoid the linked list update below. */
287 *previous_cache_entry = FX_NULL;
288 }
289 else
290 {
291
292 /* Search for an entry in the cache that matches this request. */
293 cache_size = media_ptr -> fx_media_sector_cache_size;
294 cache_entry = media_ptr -> fx_media_sector_cache_list_ptr;
295 *previous_cache_entry = FX_NULL;
296
297 /* Look at the cache entries until a match is found or the end of
298 the cache is reached. */
299 while (cache_size--)
300 {
301
302 /* Determine if the requested sector has been found. */
303 if ((cache_entry -> fx_cached_sector_valid) && (cache_entry -> fx_cached_sector == logical_sector))
304 {
305
306 /* Yes, we found a match. Simply setup the pointer to this
307 buffer and return. */
308 media_ptr -> fx_media_memory_buffer = cache_entry -> fx_cached_sector_memory_buffer;
309
310 /* Determine if we need to update the last used list. */
311 if (*previous_cache_entry)
312 {
313
314 /* Yes, the current entry is not at the front of the list
315 so we need to change the order. */
316
317 /* Link the previous entry to this entry's next pointer. */
318 (*previous_cache_entry) -> fx_cached_sector_next_used =
319 cache_entry -> fx_cached_sector_next_used;
320
321 /* Place this entry at the head of the list. */
322 cache_entry -> fx_cached_sector_next_used =
323 media_ptr -> fx_media_sector_cache_list_ptr;
324 media_ptr -> fx_media_sector_cache_list_ptr = cache_entry;
325 }
326
327 #ifndef FX_MEDIA_STATISTICS_DISABLE
328
329 /* Increment the number of logical sectors cache read hits. */
330 media_ptr -> fx_media_logical_sector_cache_read_hits++;
331 #endif
332
333 /* Success, return to caller immediately! */
334 return(FX_NULL);
335 }
336
337 /* Otherwise, we have not found the cached entry yet. */
338
339 /* If there are more entries, move to the next one. */
340 if (cache_entry -> fx_cached_sector_next_used)
341 {
342
343 *previous_cache_entry = cache_entry;
344 cache_entry = cache_entry -> fx_cached_sector_next_used;
345 }
346 }
347 }
348
349 /* The requested sector is not in cache, return the last cache entry. */
350 return(cache_entry);
351 #else
352 FX_PARAMETER_NOT_USED(media_ptr);
353 FX_PARAMETER_NOT_USED(logical_sector);
354 FX_PARAMETER_NOT_USED(previous_cache_entry);
355 return(FX_NULL);
356 #endif /* FX_DISABLE_CACHE */
357 }
358
359