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_FAT_flush PORTABLE C */
37 /* 6.1.2 */
38 /* AUTHOR */
39 /* */
40 /* William E. Lamie, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function flushes the contents of the FAT cache to the media. */
45 /* 12-bit, 16-bit and 32-bit FAT writing is supported. */
46 /* */
47 /* INPUT */
48 /* */
49 /* media_ptr Media control block pointer */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* return status */
54 /* */
55 /* CALLS */
56 /* */
57 /* _fx_utility_16_unsigned_write Write a UINT into buffer */
58 /* _fx_utility_32_unsigned_read Read a ULONG from buffer */
59 /* _fx_utility_32_unsigned_write Write a ULONG into buffer */
60 /* _fx_utility_logical_sector_read Read FAT sector into memory */
61 /* _fx_utility_logical_sector_write Write FAT sector back to disk */
62 /* */
63 /* CALLED BY */
64 /* */
65 /* FileX System Functions */
66 /* */
67 /* RELEASE HISTORY */
68 /* */
69 /* DATE NAME DESCRIPTION */
70 /* */
71 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
72 /* 09-30-2020 William E. Lamie Modified comment(s), */
73 /* resulting in version 6.1 */
74 /* 11-09-2020 William E. Lamie Modified comment(s), */
75 /* updated logic for */
76 /* FAT secondary update map, */
77 /* resulting in version 6.1.2 */
78 /* */
79 /**************************************************************************/
_fx_utility_FAT_flush(FX_MEDIA * media_ptr)80 UINT _fx_utility_FAT_flush(FX_MEDIA *media_ptr)
81 {
82
83 ULONG FAT_sector;
84 ULONG byte_offset;
85 UCHAR *FAT_ptr;
86 UINT temp, i;
87 UINT status, index, ind;
88 ULONG cluster, next_cluster;
89 UCHAR sectors_per_bit;
90 INT multi_sector_entry;
91 ULONG sector;
92
93 #ifndef FX_MEDIA_STATISTICS_DISABLE
94 /* Increment the number of cache flush requests. */
95 media_ptr -> fx_media_fat_cache_flushes++;
96 #endif
97
98 /* Loop through the media's FAT cache and flush out dirty entries. */
99 for (index = 0; index < FX_MAX_FAT_CACHE; index++)
100 {
101
102 /* Determine if the entry is dirty. */
103 if ((media_ptr -> fx_media_fat_cache[index].fx_fat_cache_entry_dirty) == 0)
104 {
105
106 /* No, just advance to the next entry. */
107 continue;
108 }
109
110 /* Otherwise, the entry is indeed dirty and must be flushed out. Process
111 relative to the type of FAT that is being used. */
112
113 /* Pickup the contents of the FAT cache entry. */
114 cluster = media_ptr -> fx_media_fat_cache[index].fx_fat_cache_entry_cluster;
115
116 /* Determine which type of FAT is present. */
117 if (media_ptr -> fx_media_12_bit_FAT)
118 {
119
120 /* Calculate the byte offset to the cluster entry. */
121 byte_offset = (((ULONG)cluster << 1) + cluster) >> 1;
122
123 /* Calculate the FAT sector the requested FAT entry resides in. */
124 FAT_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
125 (ULONG)media_ptr -> fx_media_reserved_sectors;
126
127 /* Initialize as not written. */
128 multi_sector_entry = -1;
129
130 for (;;)
131 {
132
133 /* Pickup the FAT sector. */
134 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
135 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
136
137 /* Determine if an error occurred. */
138 if (status != FX_SUCCESS)
139 {
140
141 /* Return the error status. */
142 return(status);
143 }
144
145 /* Determine if a mulit-sector FAT update is present. */
146 if (multi_sector_entry != -1)
147 {
148
149 /* Yes, store the remaining portion of the new FAT entry in the
150 next FAT sector. */
151
152 /* Setup a pointer into the buffer. */
153 FAT_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer;
154
155 /* Pickup the cluster and next cluster. */
156 cluster = (media_ptr -> fx_media_fat_cache[multi_sector_entry].fx_fat_cache_entry_cluster);
157 next_cluster = media_ptr -> fx_media_fat_cache[multi_sector_entry].fx_fat_cache_entry_value;
158
159 /* Determine if the cluster entry is odd or even. */
160 if (cluster & 1)
161 {
162
163 /* Store the upper 8 bits of the FAT entry. */
164 *FAT_ptr = (UCHAR)((next_cluster >> 4) & 0xFF);
165 }
166 else
167 {
168
169 /* Store the upper 4 bits of the FAT entry. */
170 temp = ((UINT)*FAT_ptr) & 0xF0;
171 *FAT_ptr = (UCHAR)(temp | ((next_cluster >> 8) & 0xF));
172 }
173
174 /* Clear the multi-sector flag. */
175 multi_sector_entry = -1;
176 }
177
178 /* Loop through the remainder of the cache to check for multiple entries
179 within the same FAT sector being written out. */
180 for (i = index; i < FX_MAX_FAT_CACHE; i++)
181 {
182
183 /* Is the cache entry dirty? */
184 if ((media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty) == 0)
185 {
186
187 /* Not dirty, does not need to be flushed. */
188 continue;
189 }
190
191 /* Isolate the cluster. */
192 cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
193
194 /* Calculate the byte offset to the cluster entry. */
195 byte_offset = (((ULONG)cluster << 1) + cluster) >> 1;
196
197 /* Pickup the sector. */
198 sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
199 (ULONG)media_ptr -> fx_media_reserved_sectors;
200
201 /* Is it the current FAT sector? */
202 if (sector != FAT_sector)
203 {
204
205 /* Different FAT sector - not in this pass of the loop. */
206 continue;
207 }
208
209 /* Pickup new value for this FAT entry. */
210 next_cluster = media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
211
212 /* Now calculate the byte offset into this FAT sector. */
213 byte_offset = byte_offset -
214 ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
215 media_ptr -> fx_media_bytes_per_sector);
216
217 /* Determine if we are now past the end of the FAT buffer in memory. */
218 if (byte_offset == (ULONG)(media_ptr -> fx_media_bytes_per_sector - 1))
219 {
220
221 /* Yes, we need to read the next sector */
222 multi_sector_entry = (INT)i;
223 }
224
225 /* Setup a pointer into the buffer. */
226 FAT_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
227
228 /* Clear the dirty flag. */
229 media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
230
231 /* Determine if the cluster entry is odd or even. */
232 if (cluster & 1)
233 {
234
235 /* Odd cluster number. */
236
237 /* Pickup the upper nibble of the FAT entry. */
238
239 /* First, set the lower nibble of the FAT entry. */
240 temp = (((UINT)*FAT_ptr) & 0x0F);
241 *FAT_ptr = (UCHAR)(temp | ((next_cluster << 4) & 0xF0));
242
243 /* Determine if this is a mulit-sector entry. */
244 if ((multi_sector_entry) == (INT)i)
245 {
246
247 /* Yes, requires multiple sector - will write rest of the part later. */
248 continue;
249 }
250
251 /* Move to the next byte of the FAT entry. */
252 FAT_ptr++;
253
254 /* Store the upper 8 bits of the FAT entry. */
255 *FAT_ptr = (UCHAR)((next_cluster >> 4) & 0xFF);
256 }
257 else
258 {
259
260 /* Even cluster number. */
261
262 /* Store the lower byte of the FAT entry. */
263 *FAT_ptr = (UCHAR)(next_cluster & 0xFF);
264
265 /* Determine if this is a mulit-sector entry. */
266 if ((multi_sector_entry) == (INT)i)
267 {
268
269 /* Yes, requires multiple sector - will write rest of the part later. */
270 continue;
271 }
272
273 /* Move to the next nibble of the FAT entry. */
274 FAT_ptr++;
275
276 /* Store the upper 4 bits of the FAT entry. */
277 temp = ((UINT)*FAT_ptr) & 0xF0;
278 *FAT_ptr = (UCHAR)(temp | ((next_cluster >> 8) & 0xF));
279 }
280 }
281
282 /* First, write out the current sector. */
283 status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
284 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
285 /* Determine if an error occurred. */
286 if (status != FX_SUCCESS)
287 {
288
289 /* Return the error status. */
290 return(status);
291 }
292
293 /* Mark the FAT sector update bit map to indicate this sector has been written. */
294 if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
295 {
296 sectors_per_bit = (UCHAR)((UINT)media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
297 }
298 else
299 {
300 sectors_per_bit = (UCHAR)((UINT)media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3) + 1);
301 }
302
303 /* Check for invalid value. */
304 if (sectors_per_bit == 0)
305 {
306
307 /* Invalid media, return error. */
308 return(FX_MEDIA_INVALID);
309 }
310
311 ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
312 media_ptr -> fx_media_fat_secondary_update_map[ind] =
313 (UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
314 | (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
315
316 /* Determine if the multi-sector flag is set. */
317 if (multi_sector_entry != -1)
318 {
319
320 /* Yes, position to the next sector and read it in. */
321 FAT_sector++;
322 }
323 else
324 {
325
326 /* No, we are finished with this loop. */
327 break;
328 }
329 }
330 }
331 else if (!media_ptr -> fx_media_32_bit_FAT)
332 {
333
334 /* 16-bit FAT is present. */
335
336 /* Calculate the byte offset to the cluster entry. */
337 byte_offset = (((ULONG)cluster) << 1);
338
339 /* Calculate the FAT sector the requested FAT entry resides in. */
340 FAT_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
341 (ULONG)media_ptr -> fx_media_reserved_sectors;
342
343 /* Read the FAT sector. */
344 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
345 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
346
347 /* Determine if an error occurred. */
348 if (status != FX_SUCCESS)
349 {
350
351 /* Return the error status. */
352 return(status);
353 }
354
355 /* Loop through the remainder of the cache to check for multiple entries
356 within the same FAT sector being written out. */
357 for (i = index; i < FX_MAX_FAT_CACHE; i++)
358 {
359
360 /* Determine if the entry is dirty. */
361 if (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty == 0)
362 {
363
364 /* Not dirty, does not need to be flushed. */
365 continue;
366 }
367
368 /* Isolate the cluster. */
369 cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
370
371 /* Calculate the byte offset to the cluster entry. */
372 byte_offset = (((ULONG)cluster) * 2);
373
374 /* Pickup the sector. */
375 sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
376 (ULONG)media_ptr -> fx_media_reserved_sectors;
377
378 /* Is it the current FAT sector? */
379 if (sector != FAT_sector)
380 {
381
382 /* Different FAT sector - not in this pass of the loop. */
383 continue;
384 }
385
386 /* Now calculate the byte offset into this FAT sector. */
387 byte_offset = byte_offset -
388 ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
389 media_ptr -> fx_media_bytes_per_sector);
390
391 /* Setup a pointer into the buffer. */
392 FAT_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
393
394 /* Pickup new value for this FAT entry. */
395 next_cluster = media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
396
397 /* Store the FAT entry. */
398 _fx_utility_16_unsigned_write(FAT_ptr, (UINT)next_cluster);
399
400 /* Clear the dirty flag. */
401 media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
402 }
403
404 /* Write the last written FAT sector out. */
405 status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
406 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
407
408 /* Determine if an error occurred. */
409 if (status != FX_SUCCESS)
410 {
411 /* Return the error status. */
412 return(status);
413 }
414
415 /* Mark the FAT sector update bit map to indicate this sector has been
416 written. */
417 if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
418 {
419 sectors_per_bit = (UCHAR)(media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
420 }
421 else
422 {
423 sectors_per_bit = (UCHAR)((media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3)) + 1);
424 }
425 ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
426 media_ptr -> fx_media_fat_secondary_update_map[ind] =
427 (UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
428 | (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
429 }
430 else
431 {
432
433 /* 32-bit FAT is present. */
434
435 /* Calculate the byte offset to the cluster entry. */
436 byte_offset = (((ULONG)cluster) * 4);
437
438 /* Calculate the FAT sector the requested FAT entry resides in. */
439 FAT_sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
440 (ULONG)media_ptr -> fx_media_reserved_sectors;
441
442 /* Read the FAT sector. */
443 status = _fx_utility_logical_sector_read(media_ptr, (ULONG64) FAT_sector,
444 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
445
446 /* Determine if an error occurred. */
447 if (status != FX_SUCCESS)
448 {
449
450 /* Return the error status. */
451 return(status);
452 }
453
454 /* Loop through the remainder of the cache to check for multiple entries
455 within the same FAT sector being written out. */
456 for (i = index; i < FX_MAX_FAT_CACHE; i++)
457 {
458
459 /* Determine if the entry is dirty. */
460 if (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty == 0)
461 {
462
463 /* Not dirty, does not need to be flushed. */
464 continue;
465 }
466
467 /* Isolate the cluster. */
468 cluster = (media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster);
469
470 /* Calculate the byte offset to the cluster entry. */
471 byte_offset = (((ULONG)cluster) * 4);
472
473 /* Pickup the sector. */
474 sector = (byte_offset / media_ptr -> fx_media_bytes_per_sector) +
475 (ULONG)media_ptr -> fx_media_reserved_sectors;
476
477 /* Is it the current FAT sector? */
478 if (sector != FAT_sector)
479 {
480
481 /* Different FAT sector - not in this pass of the loop. */
482 continue;
483 }
484
485 /* Now calculate the byte offset into this FAT sector. */
486 byte_offset = byte_offset -
487 ((FAT_sector - (ULONG)media_ptr -> fx_media_reserved_sectors) *
488 media_ptr -> fx_media_bytes_per_sector);
489
490 /* Setup a pointer into the buffer. */
491 FAT_ptr = (UCHAR *)media_ptr -> fx_media_memory_buffer + (UINT)byte_offset;
492
493 /* Pickup new value for this FAT entry. */
494 next_cluster = media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value;
495
496 /* Store the FAT entry. */
497 _fx_utility_32_unsigned_write(FAT_ptr, next_cluster);
498
499 /* Clear the dirty flag. */
500 media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty = 0;
501 }
502
503 /* Write the last written FAT sector out. */
504 status = _fx_utility_logical_sector_write(media_ptr, (ULONG64) FAT_sector,
505 media_ptr -> fx_media_memory_buffer, ((ULONG) 1), FX_FAT_SECTOR);
506
507 /* Determine if an error occurred. */
508 if (status != FX_SUCCESS)
509 {
510
511 /* Return the error status. */
512 return(status);
513 }
514
515
516 /* Mark the FAT sector update bit map to indicate this sector has been
517 written. */
518 if (media_ptr -> fx_media_sectors_per_FAT % (FX_FAT_MAP_SIZE << 3) == 0)
519 {
520 sectors_per_bit = (UCHAR)(media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3));
521 }
522 else
523 {
524 sectors_per_bit = (UCHAR)((media_ptr -> fx_media_sectors_per_FAT / (FX_FAT_MAP_SIZE << 3)) + 1);
525 }
526 ind = ((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) >> 3;
527 media_ptr -> fx_media_fat_secondary_update_map[ind] =
528 (UCHAR)((INT)media_ptr -> fx_media_fat_secondary_update_map[ind]
529 | (1 <<(((FAT_sector - media_ptr -> fx_media_reserved_sectors) / sectors_per_bit) & 7)));
530 }
531 }
532
533 #ifdef FX_ENABLE_FAULT_TOLERANT
534
535 /* While fault_tolerant is enabled, this function will be called before the return of all APIs. */
536 if (media_ptr -> fx_media_fault_tolerant_enabled)
537 {
538
539 /* Delete the record of FAT sector since all FAT entries are flushed. */
540 media_ptr -> fx_media_fault_tolerant_cached_FAT_sector = 0;
541 }
542 #endif /* FX_ENABLE_FAULT_TOLERANT */
543
544 /* Return successful status. */
545 return(FX_SUCCESS);
546 }
547
548