ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fs_fat_exfat_fmt.c
Go to the documentation of this file.
1
13
14#include <stddef.h>
15#include <stdint.h>
16
17#include "ra8_attributes.h"
18#include "ra8_fs.h"
19#include "ra8_fs_fat_internal.h"
20
21/* ===========================================================================
22 * exFAT format (mkfs)
23 * ===========================================================================
24 */
25
30typedef struct {
31 uint64_t part_lba;
32 uint64_t total_sectors;
33 uint32_t bps;
34 uint8_t bps_shift;
35 uint8_t spc_shift;
36 uint32_t spc;
37 uint32_t fat_offset;
38 uint32_t fat_length;
39 uint32_t heap_offset;
40 uint32_t cluster_count;
41 uint32_t bitmap_bytes;
42 uint32_t bitmap_clusters;
43 uint32_t upcase_cluster;
44 uint32_t upcase_clusters;
45 uint32_t root_cluster;
46 uint32_t used_clusters;
48
49/* `priv_exfat_csum32()`: see header for the documented contract. */
50uint32_t priv_exfat_csum32(uint32_t cs, const uint8_t* buf, uint32_t len)
51{
52 for (uint32_t i = 0U; i < len; i++) {
53 cs = (((cs & 1U) != 0U) ? (uint32_t)k_exfat_fmt_csum_hibit : 0U) + (cs >> 1) + (uint32_t)buf[i];
54 }
55 return cs;
56}
57
88static uint8_t internal_exfat_spc_shift(uint64_t total_sectors, uint8_t bps_shift)
89{
90 /* The subtraction is guarded even though every caller passes 9..12: the
91 * analyzer cannot see the cross-function bound, and an under-9 shift here
92 * would be a 2^32-sized left shift rather than a wrong answer. */
93 const uint32_t scale = ((uint32_t)bps_shift > (uint32_t)k_exfat_bps_shift_min)
94 ? ((uint32_t)bps_shift - (uint32_t)k_exfat_bps_shift_min)
95 : 0U;
96 const uint64_t total_512 = total_sectors << scale;
97 uint32_t clus_shift = (uint32_t)k_exfat_fmt_clus_256k;
98 if (total_512 <= (uint64_t)k_exfat_fmt_thr_256m) {
99 clus_shift = (uint32_t)k_exfat_fmt_clus_4k;
100 } else if (total_512 <= (uint64_t)k_exfat_fmt_thr_32g) {
101 clus_shift = (uint32_t)k_exfat_fmt_clus_32k;
102 } else if (total_512 <= (uint64_t)k_exfat_fmt_thr_256g) {
103 clus_shift = (uint32_t)k_exfat_fmt_clus_128k;
104 } else {
105 clus_shift = (uint32_t)k_exfat_fmt_clus_256k;
106 }
107 if (clus_shift <= (uint32_t)bps_shift) {
108 return 0U;
109 }
110 return (uint8_t)(clus_shift - (uint32_t)bps_shift);
111}
112
141static ra8_err_t internal_exfat_geometry(uint64_t total_sectors, exfat_geom_t* g)
142{
143 g->total_sectors = total_sectors;
144 g->spc_shift = internal_exfat_spc_shift(total_sectors, g->bps_shift);
145 g->spc = 1U << g->spc_shift;
146 g->fat_offset = (uint32_t)k_exfat_fmt_boot_secs;
147 if (total_sectors <= g->fat_offset) {
149 }
150 uint32_t clusters = (uint32_t)((total_sectors - g->fat_offset) / g->spc);
151 g->fat_length = 0U;
152 g->heap_offset = 0U;
153 for (uint32_t i = 0U; i < (uint32_t)k_exfat_fmt_geom_iters; i++) {
154 const uint64_t fat_bytes = ((uint64_t)clusters + 2U) * 4U;
155 const uint32_t fat_len = (uint32_t)((fat_bytes + g->bps - 1U) / g->bps);
156 const uint32_t heap = g->fat_offset + fat_len;
157 if (total_sectors <= heap) {
159 }
160 const uint32_t next = (uint32_t)((total_sectors - heap) / g->spc);
161 g->fat_length = fat_len;
162 g->heap_offset = heap;
163 if (next == clusters) {
164 break;
165 }
166 clusters = next;
167 }
168 g->cluster_count = (uint32_t)((total_sectors - g->heap_offset) / g->spc);
169 const uint32_t cluster_bytes = g->spc * g->bps;
170 g->bitmap_bytes =
171 (g->cluster_count + (uint32_t)k_exfat_fmt_byte_bits - 1U) / (uint32_t)k_exfat_fmt_byte_bits;
172 g->bitmap_clusters = (g->bitmap_bytes + cluster_bytes - 1U) / cluster_bytes;
173 g->upcase_clusters = ((uint32_t)k_exfat_fmt_upc_std_bytes + cluster_bytes - 1U) / cluster_bytes;
176 g->used_clusters = g->bitmap_clusters + g->upcase_clusters + 1U; /* bitmap + up-case + root */
177 if (g->cluster_count < g->used_clusters) {
179 }
180 return k_ra8_ok;
181}
182
209static void internal_exfat_build_vbr(uint8_t* sec, const exfat_geom_t* g)
210{
211 for (uint32_t i = 0U; i < g->bps; i++) {
212 sec[i] = 0U;
213 }
214 sec[(uint32_t)k_exfat_foff_jump] = (uint8_t)k_exfat_fmt_jump0;
215 sec[(uint32_t)k_exfat_foff_jump + 1U] = (uint8_t)k_exfat_fmt_jump1;
216 sec[(uint32_t)k_exfat_foff_jump + 2U] = (uint8_t)k_exfat_fmt_jump2;
217 static const char nm[k_exfat_fsname_len] = {'E', 'X', 'F', 'A', 'T', ' ', ' ', ' '};
218 for (uint32_t i = 0U; i < (uint32_t)k_exfat_fsname_len; i++) {
219 sec[(uint32_t)k_exfat_off_fsname + i] = (uint8_t)nm[i];
220 }
228 priv_wr32(&sec[k_exfat_foff_serial], (uint32_t)k_exfat_fmt_serial ^ (uint32_t)g->total_sectors);
233 sec[(uint32_t)k_exfat_foff_drive] = (uint8_t)k_exfat_fmt_drive;
234 sec[(uint32_t)k_exfat_foff_percent] = (uint8_t)k_exfat_fmt_percent;
236}
237
266 uint64_t part_lba,
267 uint32_t lba,
268 const uint8_t* buf)
269{
270 const ra8_err_t err = b->write_block(b->ctx, part_lba + lba, 1U, buf);
271 if (err != k_ra8_ok) {
272 return err;
273 }
274 return b->write_block(b->ctx, part_lba + lba + (uint32_t)k_exfat_fmt_backup_lba, 1U, buf);
275}
276
300static void internal_exfat_put32(uint8_t* buf, uint32_t idx, uint32_t val)
301{
302 priv_wr32(&buf[(size_t)idx * 4U], val);
303}
304
336static ra8_err_t
338{
339 /* Sectors 1-8: extended boot (ext-boot signature only). The extended boot
340 * signature sits in the sector's LAST four bytes (exFAT spec sec 3.2). */
341 for (uint32_t i = 0U; i < g->bps; i++) {
342 g_fs_scratch[i] = 0U;
343 }
344 priv_wr32(
345 &g_fs_scratch[g->bps - ((uint32_t)k_ra8_fs_sector_min - (uint32_t)k_exfat_foff_ext_sig)],
346 (uint32_t)k_exfat_fmt_ext_sig);
347 for (uint32_t s = (uint32_t)k_exfat_fmt_ext_first;
348 s < (uint32_t)k_exfat_fmt_ext_first + (uint32_t)k_exfat_fmt_ext_count;
349 s++) {
350 cs = priv_exfat_csum32(cs, g_fs_scratch, g->bps);
351 const ra8_err_t e = internal_exfat_wr_dual(backend, g->part_lba, s, g_fs_scratch);
352 if (e != k_ra8_ok) {
353 return e;
354 }
355 }
356 /* Sectors 9 (OEM) + 10 (reserved): all zero. */
357 for (uint32_t i = 0U; i < g->bps; i++) {
358 g_fs_scratch[i] = 0U;
359 }
360 cs = priv_exfat_csum32(cs, g_fs_scratch, g->bps);
361 ra8_err_t err =
363 if (err != k_ra8_ok) {
364 return err;
365 }
366 cs = priv_exfat_csum32(cs, g_fs_scratch, g->bps);
368 if (err != k_ra8_ok) {
369 return err;
370 }
371 /* Checksum sector: every 32-bit word = the boot checksum. */
372 for (uint32_t i = 0U; i < (g->bps / 4U); i++) {
374 }
376}
377
408{
410 /* Boot checksum over sector 0 skips bytes 106,107 (VolumeFlags) and 112
411 * (PercentInUse): fold [0,106), [108,112), [113,bps). */
412 uint32_t cs = priv_exfat_csum32(0U, &g_fs_scratch[0], (uint32_t)k_exfat_fmt_csum_skip0);
413 cs = priv_exfat_csum32(cs,
415 (uint32_t)k_exfat_fmt_csum_skip2 - (uint32_t)k_exfat_off_bps_shift);
416 cs = priv_exfat_csum32(cs,
417 &g_fs_scratch[(uint32_t)k_exfat_fmt_csum_skip2 + 1U],
418 g->bps - ((uint32_t)k_exfat_fmt_csum_skip2 + 1U));
419 const ra8_err_t err = internal_exfat_wr_dual(backend, g->part_lba, 0U, g_fs_scratch);
420 if (err != k_ra8_ok) {
421 return err;
422 }
423 return internal_exfat_write_boot_tail(backend, g, cs);
424}
425
456{
457 ra8_err_t err =
458 priv_fmt_clear_region(backend, g->part_lba + g->fat_offset, g->fat_length, g->bps);
459 if (err != k_ra8_ok) {
460 return err;
461 }
462 for (uint32_t i = 0U; i < g->bps; i++) {
463 g_fs_scratch[i] = 0U;
464 }
467 const uint32_t bmp_last = (uint32_t)k_exfat_fmt_first_clus + g->bitmap_clusters - 1U;
468 for (uint32_t c = (uint32_t)k_exfat_fmt_first_clus; c <= bmp_last; c++) {
469 const uint32_t next = (c < bmp_last) ? (c + 1U) : (uint32_t)k_exfat_fmt_fat_eoc;
471 }
472 const uint32_t upc_last = g->upcase_cluster + g->upcase_clusters - 1U;
473 for (uint32_t c = g->upcase_cluster; c <= upc_last; c++) {
474 const uint32_t next = (c < upc_last) ? (c + 1U) : (uint32_t)k_exfat_fmt_fat_eoc;
476 }
478 return backend->write_block(backend->ctx, g->part_lba + g->fat_offset, 1U, g_fs_scratch);
479}
480
508{
509 const uint64_t bmp_lba = g->part_lba + g->heap_offset;
510 const uint32_t bmp_sectors = g->bitmap_clusters * g->spc;
511 ra8_err_t err = priv_fmt_clear_region(backend, bmp_lba, bmp_sectors, g->bps);
512 if (err != k_ra8_ok) {
513 return err;
514 }
515 for (uint32_t i = 0U; i < g->bps; i++) {
516 g_fs_scratch[i] = 0U;
517 }
518 const uint32_t full = g->used_clusters / (uint32_t)k_exfat_fmt_byte_bits;
519 for (uint32_t i = 0U; i < full; i++) {
521 }
522 const uint32_t rem = g->used_clusters % (uint32_t)k_exfat_fmt_byte_bits;
523 if (rem != 0U) {
524 g_fs_scratch[full] = (uint8_t)((1U << rem) - 1U);
525 }
526 return backend->write_block(backend->ctx, bmp_lba, 1U, g_fs_scratch);
527}
528
556static uint32_t internal_exfat_label_utf16(uint8_t* dst, const char* label)
557{
558 uint32_t n = 0U;
559 if (label != nullptr) {
560 for (; (n < (uint32_t)k_exfat_fmt_label_max) && (label[n] != '\0'); n++) {
561 dst[(size_t)n * 2U] = (uint8_t)label[n];
562 dst[((size_t)n * 2U) + 1U] = 0U;
563 }
564 }
565 return n;
566}
567
600 const exfat_geom_t* g,
601 uint32_t upcase_csum,
602 const char* label)
603{
604 const uint64_t lba = (uint64_t)g->heap_offset +
605 ((uint64_t)(g->root_cluster - (uint32_t)k_exfat_fmt_first_clus) * g->spc);
606 /* Zero the WHOLE root cluster, not just the sector the three system entries
607 * land in. The rest must read as end-of-directory (0x00), or a directory that
608 * fills past the first sector -- or a rename that relocates an entry set into
609 * it -- runs the scan straight into whatever the device held before the format
610 * (#603). Directory growth already zeroes every cluster it appends; the initial
611 * root cluster was the one spot that skipped it. */
612 const ra8_err_t ze = priv_fmt_clear_region(backend, g->part_lba + lba, g->spc, g->bps);
613 if (ze != k_ra8_ok) {
614 return ze;
615 }
616 for (uint32_t i = 0U; i < g->bps; i++) {
617 g_fs_scratch[i] = 0U;
618 }
619 /* Allocation Bitmap entry (0x81). */
623 /* Up-case Table entry (0x82). */
624 uint8_t* upc = &g_fs_scratch[k_exfat_de_second];
625 upc[0] = (uint8_t)k_exfat_entry_upcase;
626 priv_wr32(&upc[k_exfat_de_upc_csum], upcase_csum);
629 /* Volume Label entry (0x83). */
630 uint8_t* lbl = &g_fs_scratch[k_exfat_de_third];
631 const uint32_t n = internal_exfat_label_utf16(&lbl[k_exfat_de_lbl_name], label);
632 lbl[0] = (uint8_t)k_exfat_entry_label;
633 lbl[k_exfat_de_lbl_cnt] = (uint8_t)n;
634 return backend->write_block(backend->ctx, g->part_lba + lba, 1U, g_fs_scratch);
635}
636
663static void internal_exfat_lba_to_chs(uint32_t lba, uint8_t* out3)
664{
665 if (lba >= (uint32_t)k_mbr_fmt_chs_max) {
666 out3[0] = (uint8_t)k_mbr_fmt_chs_ovf_h;
667 out3[1] = (uint8_t)k_mbr_fmt_chs_ovf_m;
668 out3[2] = (uint8_t)k_mbr_fmt_chs_ovf_l;
669 return;
670 }
671 const uint32_t spt = (uint32_t)k_mbr_fmt_chs_spt;
672 const uint32_t hpc = (uint32_t)k_mbr_fmt_chs_heads;
673 const uint32_t cyl = lba / (hpc * spt);
674 const uint32_t head = (lba / spt) % hpc;
675 const uint32_t sec = (lba % spt) + 1U;
676 out3[0] = (uint8_t)head;
677 out3[1] = (uint8_t)((sec & (uint32_t)k_mbr_fmt_chs_sec_mask) |
678 ((cyl & (uint32_t)k_mbr_fmt_chs_cyl_hi_mask) >>
679 (uint32_t)k_mbr_fmt_chs_cyl_hi_shift));
680 out3[2] = (uint8_t)(cyl & (uint32_t)k_byte_mask);
681}
682
713 uint32_t bps,
714 uint32_t part_lba,
715 uint32_t part_sectors)
716{
717 for (uint32_t i = 0U; i < bps; i++) {
718 g_fs_scratch[i] = 0U;
719 }
721 (uint32_t)k_mbr_fmt_disk_sig_base ^ part_sectors);
722 uint8_t* pe = &g_fs_scratch[k_mbr_fmt_part0_off];
726 internal_exfat_lba_to_chs((part_lba + part_sectors) - 1U, &pe[k_mbr_fmt_pe_chs_end]);
727 priv_wr32(&pe[k_mbr_fmt_pe_lba], part_lba);
728 priv_wr32(&pe[k_mbr_fmt_pe_nsect], part_sectors);
730 return backend->write_block(backend->ctx, 0U, 1U, g_fs_scratch);
731}
732
767static ra8_err_t internal_exfat_fmt_place(uint64_t total_sectors,
768 uint32_t bps,
769 uint8_t* out_bps_shift,
770 uint32_t* out_part_lba,
771 uint32_t* out_part_sectors)
772{
773 uint32_t bps_shift = 0U;
774 for (uint32_t w = bps; w > 1U; w >>= 1U) {
775 bps_shift++;
776 }
777 const uint32_t part_lba = (uint32_t)k_exfat_fmt_part_align / bps;
778 const uint64_t min_total =
779 (uint64_t)part_lba +
780 (((uint64_t)k_exfat_fmt_min_sectors * (uint32_t)k_ra8_fs_sector_min) / bps);
781 if (total_sectors < min_total) {
783 }
784 /* The MBR this formatter writes records the partition in 32-bit fields, so
785 * a device whose partition would not fit them (past 2 TiB at 512-byte
786 * sectors) is refused with a clean error rather than a truncated table.
787 * Beyond-2-TiB media formatted elsewhere (GPT) mount and address fine. */
788 if ((total_sectors - part_lba) > (uint64_t)UINT32_MAX) {
790 }
791 *out_bps_shift = (uint8_t)bps_shift;
792 *out_part_lba = part_lba;
793 *out_part_sectors = (uint32_t)(total_sectors - part_lba);
794 return k_ra8_ok;
795}
796
797/* `priv_exfat_format()`: see header for the documented contract. */
799 uint64_t total_sectors,
800 uint32_t bps,
801 const char* label)
802{
803 uint8_t bps_shift = 0U;
804 uint32_t part_lba = 0U;
805 uint32_t part_sectors = 0U;
806 ra8_err_t err =
807 internal_exfat_fmt_place(total_sectors, bps, &bps_shift, &part_lba, &part_sectors);
808 if (err != k_ra8_ok) {
809 return err;
810 }
811 exfat_geom_t g = {.bps = bps, .bps_shift = bps_shift};
812 err = internal_exfat_geometry(part_sectors, &g);
813 if (err != k_ra8_ok) {
814 return err;
815 }
816 g.part_lba = part_lba;
817 /* The bitmap/up-case/root chains are seeded in FAT sector 0 only. */
818 if ((g.root_cluster * 4U) >= bps) {
820 }
821 err = internal_exfat_write_mbr(backend, bps, part_lba, part_sectors);
822 if (err != k_ra8_ok) {
823 return err;
824 }
825 err = internal_exfat_write_boot(backend, &g);
826 if (err != k_ra8_ok) {
827 return err;
828 }
829 err = internal_exfat_write_fat(backend, &g);
830 if (err != k_ra8_ok) {
831 return err;
832 }
833 err = internal_exfat_write_bitmap(backend, &g);
834 if (err != k_ra8_ok) {
835 return err;
836 }
837 const uint64_t upcase_lba =
838 g.part_lba + g.heap_offset +
839 ((uint64_t)(g.upcase_cluster - (uint32_t)k_exfat_fmt_first_clus) * g.spc);
840 uint32_t upcase_csum = 0U;
841 err = priv_exfat_write_upcase(backend, upcase_lba, bps, &upcase_csum);
842 if (err != k_ra8_ok) {
843 return err;
844 }
845 return internal_exfat_write_root(backend, &g, upcase_csum, label);
846}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
void priv_wr64(uint8_t *p, uint64_t v)
Encode a uint64_t into a byte buffer, little-endian.
Definition ra8_fs_fat.c:77
void priv_wr32(uint8_t *p, uint32_t v)
Encode a little-endian uint32_t into a byte buffer.
Definition ra8_fs_fat.c:68
void priv_wr16(uint8_t *p, uint16_t v)
Encode a little-endian uint16_t into a byte buffer.
Definition ra8_fs_fat.c:61
static uint8_t internal_exfat_spc_shift(uint64_t total_sectors, uint8_t bps_shift)
Return the default SectorsPerClusterShift for an exFAT volume.
uint32_t priv_exfat_csum32(uint32_t cs, const uint8_t *buf, uint32_t len)
exFAT 32-bit rotate-right-add checksum (boot region + up-case table).
static ra8_err_t internal_exfat_fmt_place(uint64_t total_sectors, uint32_t bps, uint8_t *out_bps_shift, uint32_t *out_part_lba, uint32_t *out_part_sectors)
Size and place the exFAT partition on the device, or refuse.
static ra8_err_t internal_exfat_write_boot(const ra8_fs_backend_t *backend, const exfat_geom_t *g)
Write the complete exFAT main and backup boot regions (sectors 0-23).
static ra8_err_t internal_exfat_wr_dual(const ra8_fs_backend_t *b, uint64_t part_lba, uint32_t lba, const uint8_t *buf)
Write a sector to both its primary and backup locations in the exFAT boot region.
static void internal_exfat_build_vbr(uint8_t *sec, const exfat_geom_t *g)
Build the 512-byte exFAT Main Boot Sector (VBR) into sec.
static uint32_t internal_exfat_label_utf16(uint8_t *dst, const char *label)
Pack an ASCII volume label into a UTF-16LE buffer for the exFAT VolumeLabel entry.
static void internal_exfat_lba_to_chs(uint32_t lba, uint8_t *out3)
Encode an LBA as legacy CHS bytes using the 255-head / 63-sector geometry.
ra8_err_t priv_exfat_format(const ra8_fs_backend_t *backend, uint64_t total_sectors, uint32_t bps, const char *label)
Format the backend as a PC-standard partitioned exFAT volume (#102).
static void internal_exfat_put32(uint8_t *buf, uint32_t idx, uint32_t val)
Write a 32-bit little-endian word at slot idx in a sector buffer.
static ra8_err_t internal_exfat_write_bitmap(const ra8_fs_backend_t *backend, const exfat_geom_t *g)
Zero the allocation bitmap region, then mark the pre-allocated clusters.
static ra8_err_t internal_exfat_write_root(const ra8_fs_backend_t *backend, const exfat_geom_t *g, uint32_t upcase_csum, const char *label)
Write the exFAT root directory entry set (bitmap, up-case, label).
static ra8_err_t internal_exfat_write_boot_tail(const ra8_fs_backend_t *backend, const exfat_geom_t *g, uint32_t cs)
Write exFAT boot sectors 1-11 (ext-boot, OEM, reserved, checksum) to main and backup.
static ra8_err_t internal_exfat_write_fat(const ra8_fs_backend_t *backend, const exfat_geom_t *g)
Zero the exFAT FAT region, then seed the media, EOC, and chain entries.
static ra8_err_t internal_exfat_write_mbr(const ra8_fs_backend_t *backend, uint32_t bps, uint32_t part_lba, uint32_t part_sectors)
Write the MBR (LBA 0) with one type-0x07 exFAT partition at part_lba.
static ra8_err_t internal_exfat_geometry(uint64_t total_sectors, exfat_geom_t *g)
Resolve the exFAT region geometry for a device of total_sectors.
ra8_err_t priv_exfat_write_upcase(const ra8_fs_backend_t *backend, uint64_t abs_lba, uint32_t bps, uint32_t *out_csum)
Write the canonical exFAT up-case table and return its checksum.
ra8_err_t priv_fmt_clear_region(const ra8_fs_backend_t *backend, uint64_t lba, uint64_t count, uint32_t bps)
Clear count blocks at lba to zero – bulk-erase if the backend can.
Cross-TU shared declarations for the FAT/exFAT ra8_fs adapter.
uint8_t g_fs_scratch[k_ra8_fs_sector_max]
Single max-sector scratch buffer reused across all I/O.
@ k_exfat_fmt_csum_hibit
Rotate-right wrap bit (32-bit).
@ k_exfat_fmt_fat_eoc
FatEntry end-of-chain.
@ k_exfat_fmt_clus_4k
log2 cluster BYTES for 4 KB clusters.
@ k_exfat_fmt_thr_256g
<= 256 GB -> 128 KB clusters.
@ k_exfat_fmt_first_clus
First cluster of the heap.
@ k_exfat_entry_label
Volume Label directory entry.
@ k_exfat_fmt_label_max
Volume-label cap (UTF-16 units).
@ k_exfat_fmt_fs_rev
FileSystemRevision = 1.00.
@ k_exfat_fmt_ext_sig
ExtendedBootSignature (sectors 1-8).
@ k_exfat_fmt_thr_32g
<= 32 GB -> 32 KB clusters.
@ k_exfat_fmt_csum_lba
Boot Checksum sector.
@ k_exfat_fmt_byte_full
A fully-allocated bitmap byte.
@ k_exfat_fmt_byte_bits
Bits per bitmap byte.
@ k_exfat_fmt_num_fats
exFAT uses a single FAT.
@ k_exfat_fmt_boot_sig
BootSignature (sector 0).
@ k_exfat_fmt_min_sectors
Smallest exFAT volume: 32 MiB.
@ k_exfat_fmt_thr_256m
<= 256 MB -> 4 KB clusters.
@ k_exfat_fmt_serial
Arbitrary volume-serial base.
@ k_exfat_fmt_upc_std_bytes
Canonical Microsoft up-case table len.
@ k_exfat_fmt_oem_lba
OEM Parameters sector.
@ k_exfat_fmt_backup_lba
Backup boot region start.
@ k_exfat_fmt_clus_256k
... 256 KB (> 256 GB cards).
@ k_exfat_fmt_clus_128k
... 128 KB.
@ k_exfat_fmt_csum_skip0
Checksum-excluded byte: VolumeFlags.
@ k_exfat_fmt_jump2
JumpBoot byte 2.
@ k_exfat_fmt_ext_count
Extended boot sector count.
@ k_exfat_fmt_boot_secs
12 main + 12 backup boot sectors.
@ k_exfat_fmt_geom_iters
Fixed-point geometry passes.
@ k_exfat_entry_upcase
Up-case Table directory entry.
@ k_exfat_fmt_percent
PercentInUse = 0% (fresh volume).
@ k_exfat_fmt_jump0
JumpBoot byte 0.
@ k_exfat_fmt_part_align
exFAT partition alignment: 1 MiB.
@ k_exfat_fmt_csum_skip2
Checksum-excluded byte: PercentInUse.
@ k_exfat_fmt_fat_media
FatEntry[0] media descriptor.
@ k_exfat_fmt_ext_first
First extended boot sector.
@ k_exfat_fmt_drive
DriveSelect (first fixed disk).
@ k_exfat_fmt_clus_32k
... 32 KB.
@ k_exfat_fmt_jump1
JumpBoot byte 1.
@ k_exfat_fmt_resv_lba
Reserved sector.
@ k_exfat_off_root_clus
FirstClusterOfRootDirectory.
@ k_exfat_off_fat_lba
FatOffset (sectors from VBR).
@ k_exfat_off_spc_shift
SectorsPerClusterShift (log2).
@ k_exfat_off_fat_len
FatLength (sectors).
@ k_exfat_off_bps_shift
BytesPerSectorShift (log2).
@ k_exfat_off_fsname
"EXFAT " filesystem-name field (8 chars).
@ k_exfat_off_num_fats
NumberOfFats.
@ k_exfat_off_clus_count
ClusterCount.
@ k_exfat_off_heap_lba
ClusterHeapOffset (sectors from VBR).
@ k_exfat_entry_bitmap
Allocation-bitmap directory entry.
@ k_exfat_bps_shift_min
log2(512): smallest BytesPerSectorShift.
@ k_exfat_fsname_len
"EXFAT " field length.
@ k_mbr_fmt_pe_lba
Entry: first LBA (4 bytes LE).
@ k_mbr_fmt_part0_off
First partition-table entry.
@ k_mbr_fmt_pe_boot
Entry: boot flag (relative).
@ k_mbr_fmt_chs_cyl_hi_mask
Cylinder bits [9:8] before packing.
@ k_mbr_fmt_pe_type
Entry: partition type byte.
@ k_mbr_fmt_chs_cyl_hi_shift
Shift packing cyl[9:8] into bits[7:6].
@ k_mbr_fmt_disk_sig_base
Arbitrary disk-signature base.
@ k_mbr_fmt_pe_nsect
Entry: sector count (4 bytes LE).
@ k_mbr_fmt_chs_spt
Conventional sectors-per-track.
@ k_mbr_fmt_chs_ovf_h
Overflow CHS head byte.
@ k_mbr_fmt_disk_sig_off
MBR disk signature (4 bytes LE).
@ k_mbr_fmt_pe_chs_start
Entry: start CHS (3 bytes).
@ k_mbr_fmt_chs_ovf_l
Overflow CHS cylinder-low byte.
@ k_mbr_fmt_chs_ovf_m
Overflow CHS sector/cyl-hi byte.
@ k_mbr_fmt_chs_heads
Conventional heads-per-cylinder.
@ k_mbr_fmt_chs_sec_mask
Low 6 bits of the CHS sector byte.
@ k_mbr_fmt_boot_none
Non-bootable partition.
@ k_mbr_fmt_pe_chs_end
Entry: end CHS (3 bytes).
@ k_mbr_fmt_type_exfat
Partition type: exFAT/NTFS/HPFS.
@ k_mbr_fmt_chs_max
1024*255*63: first LBA past CHS.
@ k_byte_mask
Byte mask.
@ k_exfat_foff_drive
DriveSelect.
@ k_exfat_foff_part_off
PartitionOffset (64-bit).
@ k_exfat_de_upc_csum
Up-case entry: TableChecksum (32-bit).
@ k_exfat_foff_ext_sig
ExtendedBootSignature (extended sectors).
@ k_exfat_foff_jump
JumpBoot (3 bytes).
@ k_exfat_foff_boot_sig
BootSignature 0xAA55 (16-bit).
@ k_exfat_foff_vol_len
VolumeLength (64-bit).
@ k_exfat_foff_percent
PercentInUse.
@ k_exfat_de_lbl_name
Volume-label entry: UTF-16 label.
@ k_exfat_foff_fs_rev
FileSystemRevision (16-bit).
@ k_exfat_de_third
Offset of the 3rd dir entry in a set.
@ k_exfat_foff_serial
VolumeSerialNumber (32-bit).
@ k_exfat_de_lbl_cnt
Volume-label entry: CharacterCount.
@ k_exfat_de_data_len
Bitmap/Up-case entry: DataLength (64-bit).
@ k_exfat_de_second
Offset of the 2nd dir entry in a set.
@ k_exfat_de_first_clus
Bitmap/Up-case entry: FirstCluster.
@ k_ra8_fs_sector_min
Smallest supported sector size.
Resolved exFAT volume geometry produced by priv_exfat_geometry.
uint32_t upcase_clusters
Clusters the up-case table occupies.
uint32_t fat_offset
FatOffset (sectors from VBR).
uint32_t root_cluster
First cluster of the root directory.
uint32_t upcase_cluster
First cluster of the up-case table.
uint8_t bps_shift
BytesPerSectorShift (log2 of bps).
uint64_t total_sectors
Partition sector count (VolumeLength).
uint32_t used_clusters
bitmap + up-case + root (pre-allocated).
uint32_t spc
Sectors per cluster (1 << spc_shift).
uint32_t heap_offset
ClusterHeapOffset (sectors from VBR).
uint32_t bitmap_clusters
Clusters the bitmap occupies.
uint32_t fat_length
FatLength (sectors).
uint64_t part_lba
Partition start LBA (VBR sits here, not 0).
uint32_t bitmap_bytes
Allocation-bitmap logical size (DataLength).
uint32_t cluster_count
ClusterCount.
uint8_t spc_shift
SectorsPerClusterShift (log2).
uint32_t bps
Device sector size in bytes.
Block-device interface that ra8_fs runs on top of.
ra8_err_t(* write_block)(void *ctx, uint64_t lba, uint32_t count, const uint8_t *buf)
Write count consecutive blocks starting at lba.
void * ctx
Caller-owned context passed back into the function pointers.