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 File Reference

exFAT formatter (mkfs) for the ra8_fs adapter. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_fs.h"
#include "ra8_fs_fat_internal.h"
Include dependency graph for ra8_fs_fat_exfat_fmt.c:

Go to the source code of this file.

Data Structures

struct  exfat_geom_t
 Resolved exFAT volume geometry produced by priv_exfat_geometry. More...

Functions

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 uint8_t internal_exfat_spc_shift (uint64_t total_sectors, uint8_t bps_shift)
 Return the default SectorsPerClusterShift for an exFAT volume.
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.
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 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_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_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_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_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_bitmap (const ra8_fs_backend_t *backend, const exfat_geom_t *g)
 Zero the allocation bitmap region, then mark the pre-allocated clusters.
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 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 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.
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_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.
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).

Detailed Description

exFAT formatter (mkfs) for the ra8_fs adapter.

VBR + checksum construction, FAT/bitmap/up-case seeding, and the root directory writer for a freshly-formatted exFAT volume.

Since
0.1.0

Definition in file ra8_fs_fat_exfat_fmt.c.

Function Documentation

◆ internal_exfat_build_vbr()

void internal_exfat_build_vbr ( uint8_t * sec,
const exfat_geom_t * g )
static

Build the 512-byte exFAT Main Boot Sector (VBR) into sec.

Zeroes sec, then writes all mandatory exFAT VBR fields: the 3-byte JMP instruction, the "EXFAT " file-system name, PartitionOffset, VolumeLength, FatOffset, FatLength, ClusterHeapOffset, ClusterCount, RootDirectory first cluster, VolumeSerialNumber (XOR of constant and total_sectors), FileSystemRevision (1.00), BytesPerSectorShift, SectorsPerClusterShift, NumberOfFats, PercentInUse, and the 0xAA55 boot signature. All values are written as little-endian fields per the Microsoft exFAT spec.

Parameters
[out]secCaller-provided sector buffer to receive the VBR.
[in]gResolved exFAT geometry from priv_exfat_geometry().
Returns
Nothing.
Precondition
sec is non-NULL and points to at least g->bps writable bytes.
g is non-NULL and was filled by a successful priv_exfat_geometry() call.
Postcondition
sec holds a spec-compliant exFAT Main Boot Sector.
All g->bps bytes of sec have been written (zeroed, then fields set).
Note
Not thread-safe; part of single-threaded format.
Since
0.1.0

Definition at line 209 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::bps, exfat_geom_t::bps_shift, exfat_geom_t::cluster_count, exfat_geom_t::fat_length, exfat_geom_t::fat_offset, exfat_geom_t::heap_offset, k_exfat_fmt_boot_sig, k_exfat_fmt_drive, k_exfat_fmt_fs_rev, k_exfat_fmt_jump0, k_exfat_fmt_jump1, k_exfat_fmt_jump2, k_exfat_fmt_num_fats, k_exfat_fmt_percent, k_exfat_fmt_serial, k_exfat_foff_boot_sig, k_exfat_foff_drive, k_exfat_foff_fs_rev, k_exfat_foff_jump, k_exfat_foff_part_off, k_exfat_foff_percent, k_exfat_foff_serial, k_exfat_foff_vol_len, k_exfat_fsname_len, k_exfat_off_bps_shift, k_exfat_off_clus_count, k_exfat_off_fat_lba, k_exfat_off_fat_len, k_exfat_off_fsname, k_exfat_off_heap_lba, k_exfat_off_num_fats, k_exfat_off_root_clus, k_exfat_off_spc_shift, exfat_geom_t::part_lba, priv_wr16(), priv_wr32(), priv_wr64(), exfat_geom_t::root_cluster, exfat_geom_t::spc_shift, and exfat_geom_t::total_sectors.

Referenced by internal_exfat_write_boot().

◆ internal_exfat_fmt_place()

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 )
static

Size and place the exFAT partition on the device, or refuse.

The preamble of priv_exfat_format, split out so the emit sequence stays inside the function-size gate: derives log2(bps), aligns the partition at 1 MiB, and applies the two size refusals – a device too small for the minimum volume plus the alignment gap, and one whose partition would not fit the MBR's 32-bit fields (past-2-TiB media arrive GPT-partitioned; mounting them is the supported half, #683).

Parameters
[in]total_sectorsWhole-device sector count.
[in]bpsDevice sector size (a power of two, 512..4096).
[out]out_bps_shiftReceives log2(bps).
[out]out_part_lbaReceives the partition's first LBA.
[out]out_part_sectorsReceives the partition's sector count.
Returns
Error code.
Return values
k_ra8_okThe partition is sized and placed.
k_ra8_err_not_supportedDevice too small, or past the MBR's fields.
Precondition
bps was validated by the format entry point.
Every output pointer is non-NULL.
Postcondition
On success the three outputs are populated.
No device state is touched on any path.
Note
Pure computation; trivially thread-safe.
The two size refusals are single-condition decisions, driven by the formatter tests' too-small and (new) beyond-2-TiB vectors.
Since
0.1.0

Definition at line 767 of file ra8_fs_fat_exfat_fmt.c.

References k_exfat_fmt_min_sectors, k_exfat_fmt_part_align, k_ra8_err_not_supported, k_ra8_fs_sector_min, and k_ra8_ok.

Referenced by priv_exfat_format().

◆ internal_exfat_geometry()

ra8_err_t internal_exfat_geometry ( uint64_t total_sectors,
exfat_geom_t * g )
static

Resolve the exFAT region geometry for a device of total_sectors.

Picks the cluster size, fixed-points the FAT length against the cluster count (the FAT shrinks the heap which shrinks the count which shrinks the FAT), then lays the allocation bitmap, up-case table, and root directory as the first contiguous clusters of the heap.

Parameters
[in]total_sectorsPartition sector count (device sectors).
[out]gReceives the resolved geometry (bps / bps_shift already populated by the caller).
Returns
Error code.
Return values
k_ra8_okGeometry resolved.
k_ra8_err_invalid_sizeDevice too small to hold a volume.
Precondition
g is non-NULL with bps and bps_shift set.
total_sectors is the partition capacity in device sectors (non-zero).
Postcondition
On k_ra8_ok, every field of g is consistent with the exFAT spec.
On k_ra8_err_invalid_size, g may be partially written and must be discarded.
Note
Bounded loop (NASA Rule 2): k_exfat_fmt_geom_iters passes.
Since
0.1.0

Definition at line 141 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::bitmap_bytes, exfat_geom_t::bitmap_clusters, exfat_geom_t::bps, exfat_geom_t::bps_shift, exfat_geom_t::cluster_count, exfat_geom_t::fat_length, exfat_geom_t::fat_offset, exfat_geom_t::heap_offset, internal_exfat_spc_shift(), k_exfat_fmt_boot_secs, k_exfat_fmt_byte_bits, k_exfat_fmt_first_clus, k_exfat_fmt_geom_iters, k_exfat_fmt_upc_std_bytes, k_ra8_err_invalid_size, k_ra8_ok, exfat_geom_t::root_cluster, exfat_geom_t::spc, exfat_geom_t::spc_shift, exfat_geom_t::total_sectors, exfat_geom_t::upcase_cluster, exfat_geom_t::upcase_clusters, and exfat_geom_t::used_clusters.

Referenced by priv_exfat_format().

◆ internal_exfat_label_utf16()

uint32_t internal_exfat_label_utf16 ( uint8_t * dst,
const char * label )
static

Pack an ASCII volume label into a UTF-16LE buffer for the exFAT VolumeLabel entry.

Converts up to k_exfat_fmt_label_max ASCII characters of label into UTF-16LE by zero-extending each byte: the low byte of each UTF-16 code-unit receives the ASCII character and the high byte is set to zero. Stops at the NUL terminator or the 11-character limit, whichever comes first. A NULL label writes nothing and returns 0.

Parameters
[out]dstDestination buffer for the UTF-16LE character array (at least k_exfat_fmt_label_max * 2 bytes).
[in]labelNUL-terminated ASCII label, or NULL for no label.
Returns
Number of UTF-16 code units written to dst.
Return values
0label is NULL or is an empty string.
11label has 11 or more non-NUL characters.
Precondition
dst is non-NULL and has at least k_exfat_fmt_label_max * 2 writable bytes.
label, if non-NULL, is NUL-terminated and contains only ASCII characters.
Postcondition
dst[0 .. (return*2)-1] holds the UTF-16LE label characters.
No byte beyond the written range of dst is modified.
Note
Pure function on the output buffer; trivially thread-safe on distinct buffers.
Since
0.1.0

Definition at line 556 of file ra8_fs_fat_exfat_fmt.c.

References k_exfat_fmt_label_max.

Referenced by internal_exfat_write_root().

◆ internal_exfat_lba_to_chs()

void internal_exfat_lba_to_chs ( uint32_t lba,
uint8_t * out3 )
static

Encode an LBA as legacy CHS bytes using the 255-head / 63-sector geometry.

Fills the three-byte CHS field an MBR partition entry carries. Above k_mbr_fmt_chs_max (the first LBA the 1024-cylinder CHS space cannot address) the universal 0xFE/0xFF/0xFF "beyond CHS, use LBA" sentinel is written, matching what fdisk/sfdisk emit for large disks; below it a real cylinder/head/sector triple is packed (sector in bits[5:0], cylinder bits[9:8] in bits[7:6] of the second byte, cylinder low byte in the third).

Parameters
[in]lbaLogical block address to encode.
[out]out3Three-byte CHS field to fill.
Returns
Nothing.
Precondition
out3 points to at least 3 writable bytes.
lba is the sector this CHS field should describe.
Postcondition
out3 holds the packed CHS (or the overflow sentinel).
No bytes outside out3[0..2] are modified.
Note
Pure aside from out3; part of single-threaded format.
Since
0.1.0

Definition at line 663 of file ra8_fs_fat_exfat_fmt.c.

References k_byte_mask, k_mbr_fmt_chs_cyl_hi_mask, k_mbr_fmt_chs_cyl_hi_shift, k_mbr_fmt_chs_heads, k_mbr_fmt_chs_max, k_mbr_fmt_chs_ovf_h, k_mbr_fmt_chs_ovf_l, k_mbr_fmt_chs_ovf_m, k_mbr_fmt_chs_sec_mask, and k_mbr_fmt_chs_spt.

Referenced by internal_exfat_write_mbr().

◆ internal_exfat_put32()

void internal_exfat_put32 ( uint8_t * buf,
uint32_t idx,
uint32_t val )
static

Write a 32-bit little-endian word at slot idx in a sector buffer.

Computes the byte offset as idx * 4 and calls priv_wr32() to store val in little-endian order. Used to populate FAT entries and checksum-sector words without repeating the stride arithmetic.

Parameters
[in,out]bufSector buffer to write into.
[in]idxZero-based 32-bit word index within buf.
[in]val32-bit value to store.
Returns
Nothing.
Precondition
buf is non-NULL and has at least (idx+1)*4 writable bytes.
idx does not overflow the sector (caller verifies the range).
Postcondition
Bytes buf[idx*4 .. idx*4+3] hold val in little-endian order.
No bytes outside the four-byte target word are modified.
Note
Not thread-safe; the caller serialises access to buf.
Since
0.1.0

Definition at line 300 of file ra8_fs_fat_exfat_fmt.c.

References priv_wr32().

Referenced by internal_exfat_write_boot_tail(), and internal_exfat_write_fat().

◆ internal_exfat_spc_shift()

uint8_t internal_exfat_spc_shift ( uint64_t total_sectors,
uint8_t bps_shift )
static

Return the default SectorsPerClusterShift for an exFAT volume.

Implements the size-tiered lookup from Microsoft exFAT spec section 12.1, expressed in cluster BYTES so every sector size lands on the same cluster size a 512-byte device of equal capacity gets: up to 256 MB uses 4 kB clusters, up to 32 GB uses 32 kB, up to 256 GB uses 128 kB, and larger devices use 256 kB clusters. The thresholds are counts of 512-byte-equivalent sectors, so the device's count is scaled by bps / 512 first; the returned shift is log2(cluster bytes) - bps_shift, the sectors-per-cluster shift the VBR records.

Parameters
[in]total_sectorsWhole-device sector count (device sectors).
[in]bps_shiftlog2 of the device sector size (9..12).
Returns
SectorsPerClusterShift value for the exFAT VBR.
Return values
0Cluster equals one sector (4 kB clusters on a 4Kn device).
9256 kB clusters on a 512-byte device.
Precondition
total_sectors is the actual backend capacity in device sectors.
total_sectors is non-zero; bps_shift is 9..12.
Postcondition
Return value plus bps_shift is one of the four cluster tiers.
Return value is a valid SectorsPerClusterShift for the exFAT spec.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 88 of file ra8_fs_fat_exfat_fmt.c.

References k_exfat_bps_shift_min, k_exfat_fmt_clus_128k, k_exfat_fmt_clus_256k, k_exfat_fmt_clus_32k, k_exfat_fmt_clus_4k, k_exfat_fmt_thr_256g, k_exfat_fmt_thr_256m, and k_exfat_fmt_thr_32g.

Referenced by internal_exfat_geometry().

◆ internal_exfat_wr_dual()

ra8_err_t internal_exfat_wr_dual ( const ra8_fs_backend_t * b,
uint64_t part_lba,
uint32_t lba,
const uint8_t * buf )
static

Write a sector to both its primary and backup locations in the exFAT boot region.

Calls b->write_block twice: once for the primary copy at lba, and once for the backup copy at lba + k_exfat_fmt_backup_lba (12 sectors later, per the Microsoft exFAT spec). The first write failure aborts; the backup write is skipped to avoid partial state.

Parameters
[in]bBlock-device backend with a non-NULL write_block function.
[in]part_lbaPartition start LBA added to every write (0 = whole-disk).
[in]lbaPartition-relative primary LBA (0 <= lba < k_exfat_fmt_boot_secs).
[in]bufOne whole-sector image to write.
Returns
Error code from the backend.
Return values
k_ra8_okBoth primary and backup copies written successfully.
k_ra8_err_*The primary or backup write_block call failed.
Precondition
b and b->write_block are non-NULL.
buf is non-NULL and holds one whole device sector.
Postcondition
On k_ra8_ok, sectors lba and lba+k_exfat_fmt_backup_lba are identical.
On failure, the primary may be written but the backup state is undefined.
Note
Not thread-safe; part of single-threaded format.
Since
0.1.0

Definition at line 265 of file ra8_fs_fat_exfat_fmt.c.

References k_exfat_fmt_backup_lba, and k_ra8_ok.

Referenced by internal_exfat_write_boot(), and internal_exfat_write_boot_tail().

◆ internal_exfat_write_bitmap()

ra8_err_t internal_exfat_write_bitmap ( const ra8_fs_backend_t * backend,
const exfat_geom_t * g )
static

Zero the allocation bitmap region, then mark the pre-allocated clusters.

Clears all bitmap sectors via priv_fmt_clear_region(), then builds the first bitmap sector in g_fs_scratch. The g->used_clusters count (bitmap + up-case + root) is marked allocated: full bytes are set to 0xFF and the trailing partial byte gets a mask of the remaining bits. The populated sector is then written to the bitmap's heap LBA.

Parameters
[in]backendBlock-device backend with non-NULL write_block.
[in]gResolved exFAT geometry from priv_exfat_geometry().
Returns
Error code from the backend.
Return values
k_ra8_okBitmap region zeroed and pre-allocated clusters marked.
k_ra8_err_*Backend clear or write failure.
Precondition
backend and backend->write_block are non-NULL.
g was filled by a successful priv_exfat_geometry() call.
Postcondition
On k_ra8_ok, the first g->used_clusters bits of the bitmap are set to 1.
Remaining bitmap bits beyond g->used_clusters read as zero.
Note
Not thread-safe; part of single-threaded format.
Since
0.1.0

Definition at line 507 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::bitmap_clusters, exfat_geom_t::bps, ra8_fs_backend_t::ctx, g_fs_scratch, exfat_geom_t::heap_offset, k_exfat_fmt_byte_bits, k_exfat_fmt_byte_full, k_ra8_ok, exfat_geom_t::part_lba, priv_fmt_clear_region(), exfat_geom_t::spc, exfat_geom_t::used_clusters, and ra8_fs_backend_t::write_block.

Referenced by priv_exfat_format().

◆ internal_exfat_write_boot()

ra8_err_t internal_exfat_write_boot ( const ra8_fs_backend_t * backend,
const exfat_geom_t * g )
static

Write the complete exFAT main and backup boot regions (sectors 0-23).

Builds the VBR in g_fs_scratch via priv_exfat_build_vbr(), then accumulates the boot checksum over sector 0, skipping the three bytes that the exFAT spec excludes from the checksum: VolumeFlags bytes (offsets 106-107) and PercentInUse (offset 112). The three ranges [0, 106), [108, 112), and [113, 512) are folded via priv_exfat_csum32(). Sector 0 is then written to both main (LBA 0) and backup (LBA 12) by priv_exfat_wr_dual(). The remaining boot sectors 1-11 and their backups are written by priv_exfat_write_boot_tail() using the running checksum.

Parameters
[in]backendBlock-device backend with a non-NULL write_block hook.
[in]gResolved exFAT geometry from priv_exfat_geometry().
Returns
Error code from the backend.
Return values
k_ra8_okBoth main and backup boot regions (sectors 0-23) written.
k_ra8_err_*Backend write failure; format is aborted.
Precondition
backend and backend->write_block are non-NULL.
g was filled by a successful priv_exfat_geometry() call.
Postcondition
On k_ra8_ok, sectors 0-23 on the device hold spec-compliant boot regions.
The boot checksum stored in sectors 11 and 23 covers sectors 0-10.
Note
Not thread-safe; part of single-threaded format.
Since
0.1.0

Definition at line 407 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::bps, g_fs_scratch, internal_exfat_build_vbr(), internal_exfat_wr_dual(), internal_exfat_write_boot_tail(), k_exfat_fmt_csum_skip0, k_exfat_fmt_csum_skip2, k_exfat_off_bps_shift, k_ra8_ok, exfat_geom_t::part_lba, and priv_exfat_csum32().

Referenced by priv_exfat_format().

◆ internal_exfat_write_boot_tail()

ra8_err_t internal_exfat_write_boot_tail ( const ra8_fs_backend_t * backend,
const exfat_geom_t * g,
uint32_t cs )
static

Write exFAT boot sectors 1-11 (ext-boot, OEM, reserved, checksum) to main and backup.

Takes the running boot checksum cs (which already covers sector 0) and completes the boot region. Sectors 1-8 each receive an extended boot sector with only the ExtendedBootSignature (0xAA550000) set; sector 9 (OEM) and sector 10 (reserved) are all-zero. Each sector is folded into cs via priv_exfat_csum32() before being written via priv_exfat_wr_dual() to both the main and backup regions. Sector 11 (checksum) is then filled with k_exfat_fmt_csum_copies copies of the final checksum word and written to both regions. The global g_fs_scratch buffer is used as a scratch pad.

Parameters
[in]backendBlock-device backend with a non-NULL write_block hook.
[in]gResolved geometry (partition base + sector size).
[in]csRunning boot checksum accumulated over sector 0.
Returns
Error code from the backend.
Return values
k_ra8_okAll sectors written to both main and backup regions.
k_ra8_err_*Backend write_block failure; format is aborted.
Precondition
backend and backend->write_block are non-NULL.
cs reflects the checksum folded over sector 0 of the VBR.
Postcondition
On k_ra8_ok, sectors 1-11 and their backups (13-23) are written.
The checksum sector (11 and 23) contains the finalised boot checksum.
Note
Not thread-safe; part of single-threaded format.
Since
0.1.0

Definition at line 337 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::bps, g_fs_scratch, internal_exfat_put32(), internal_exfat_wr_dual(), k_exfat_fmt_csum_lba, k_exfat_fmt_ext_count, k_exfat_fmt_ext_first, k_exfat_fmt_ext_sig, k_exfat_fmt_oem_lba, k_exfat_fmt_resv_lba, k_exfat_foff_ext_sig, k_ra8_fs_sector_min, k_ra8_ok, exfat_geom_t::part_lba, priv_exfat_csum32(), and priv_wr32().

Referenced by internal_exfat_write_boot().

◆ internal_exfat_write_fat()

ra8_err_t internal_exfat_write_fat ( const ra8_fs_backend_t * backend,
const exfat_geom_t * g )
static

Zero the exFAT FAT region, then seed the media, EOC, and chain entries.

Clears all FAT sectors via priv_fmt_clear_region(), then builds the first FAT sector in g_fs_scratch. FAT[0] is set to the media byte (k_exfat_fmt_fat_media) and FAT[1] to the end-of-chain sentinel (k_exfat_fmt_fat_eoc). The bitmap and up-case cluster chains are each written as a linked run terminating with EOC (the up-case table may span more than one cluster), and the root directory cluster receives a single EOC entry. Finally, the populated first sector is written to the FAT start LBA (partition-adjusted).

Parameters
[in]backendBlock-device backend with non-NULL write_block.
[in]gResolved exFAT geometry from priv_exfat_geometry().
Returns
Error code from the backend.
Return values
k_ra8_okFAT region zeroed and initial entries written.
k_ra8_err_*Backend clear or write failure.
Precondition
backend and backend->write_block are non-NULL.
g was filled by a successful priv_exfat_geometry() call.
Postcondition
On k_ra8_ok, FAT[0..1] and the pre-allocated cluster chains are seeded.
The remainder of the FAT region beyond the first sector reads as zero.
Note
Not thread-safe; part of single-threaded format.
Since
0.1.0

Definition at line 455 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::bitmap_clusters, exfat_geom_t::bps, ra8_fs_backend_t::ctx, exfat_geom_t::fat_length, exfat_geom_t::fat_offset, g_fs_scratch, internal_exfat_put32(), k_exfat_fmt_fat_eoc, k_exfat_fmt_fat_media, k_exfat_fmt_first_clus, k_ra8_ok, exfat_geom_t::part_lba, priv_fmt_clear_region(), exfat_geom_t::root_cluster, exfat_geom_t::upcase_cluster, exfat_geom_t::upcase_clusters, and ra8_fs_backend_t::write_block.

Referenced by priv_exfat_format().

◆ internal_exfat_write_mbr()

ra8_err_t internal_exfat_write_mbr ( const ra8_fs_backend_t * backend,
uint32_t bps,
uint32_t part_lba,
uint32_t part_sectors )
static

Write the MBR (LBA 0) with one type-0x07 exFAT partition at part_lba.

Zeroes the sector, stamps a disk signature at offset 440, lays a single primary partition entry at offset 446 (non-bootable, type 0x07 exFAT/NTFS, packed start/end CHS via priv_exfat_lba_to_chs(), 32-bit start LBA and sector count), and writes the 0x55AA boot signature. A PC then sees standard partitioned removable media rather than a "superfloppy" volume at sector 0.

Parameters
[in]backendBlock-device backend with a non-NULL write_block hook.
[in]bpsDevice sector size in bytes.
[in]part_lbaFirst LBA of the exFAT partition (1 MiB aligned).
[in]part_sectorsPartition length in sectors.
Returns
Error code from the backend.
Return values
k_ra8_okMBR written at LBA 0.
k_ra8_err_*Backend write_block failure.
Precondition
backend and backend->write_block are non-NULL.
part_lba + part_sectors does not exceed the device capacity.
Postcondition
On k_ra8_ok, LBA 0 holds an MBR describing the exFAT partition.
Byte 510/511 hold the 0x55/0xAA signature.
Note
Not thread-safe; part of single-threaded format.
Since
0.1.0

Definition at line 712 of file ra8_fs_fat_exfat_fmt.c.

References ra8_fs_backend_t::ctx, g_fs_scratch, internal_exfat_lba_to_chs(), k_exfat_fmt_boot_sig, k_exfat_foff_boot_sig, k_mbr_fmt_boot_none, k_mbr_fmt_disk_sig_base, k_mbr_fmt_disk_sig_off, k_mbr_fmt_part0_off, k_mbr_fmt_pe_boot, k_mbr_fmt_pe_chs_end, k_mbr_fmt_pe_chs_start, k_mbr_fmt_pe_lba, k_mbr_fmt_pe_nsect, k_mbr_fmt_pe_type, k_mbr_fmt_type_exfat, priv_wr16(), priv_wr32(), and ra8_fs_backend_t::write_block.

Referenced by priv_exfat_format().

◆ internal_exfat_write_root()

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 )
static

Write the exFAT root directory entry set (bitmap, up-case, label).

Builds the root directory sector in g_fs_scratch and writes it to the root cluster in the heap. The sector contains three directory entries: an Allocation Bitmap entry (0x81) pointing to the first cluster of the bitmap and recording bitmap_bytes as the DataLength; an Up-case Table entry (0x82) with upcase_csum, the up-case cluster, and k_exfat_fmt_upc_std_bytes as the DataLength; and a Volume Label entry (0x83) with the label packed into UTF-16LE via priv_exfat_label_utf16().

Parameters
[in]backendBlock-device backend with non-NULL write_block.
[in]gResolved exFAT geometry from priv_exfat_geometry().
[in]upcase_csumRotate-add checksum of the up-case table data.
[in]labelOptional NUL-terminated ASCII volume label, or NULL.
Returns
Error code from the backend.
Return values
k_ra8_okRoot directory sector written to the root cluster.
k_ra8_err_*Backend write_block failure.
Precondition
backend and backend->write_block are non-NULL.
g was filled by a successful priv_exfat_geometry() call.
Postcondition
On k_ra8_ok, the root cluster contains the three mandatory directory entries.
Every sector of the root cluster past the first reads as zero.
The label entry holds the UTF-16LE encoding of label (or zero length if NULL).
Note
Not thread-safe; part of single-threaded format.
Since
0.1.0

Definition at line 599 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::bitmap_bytes, exfat_geom_t::bps, ra8_fs_backend_t::ctx, g_fs_scratch, exfat_geom_t::heap_offset, internal_exfat_label_utf16(), k_exfat_de_data_len, k_exfat_de_first_clus, k_exfat_de_lbl_cnt, k_exfat_de_lbl_name, k_exfat_de_second, k_exfat_de_third, k_exfat_de_upc_csum, k_exfat_entry_bitmap, k_exfat_entry_label, k_exfat_entry_upcase, k_exfat_fmt_first_clus, k_exfat_fmt_upc_std_bytes, k_ra8_ok, exfat_geom_t::part_lba, priv_fmt_clear_region(), priv_wr32(), exfat_geom_t::root_cluster, exfat_geom_t::spc, exfat_geom_t::upcase_cluster, and ra8_fs_backend_t::write_block.

Referenced by priv_exfat_format().

◆ priv_exfat_csum32()

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).

Folds len bytes of buf into the running checksum cs with cs = ror1(cs) + byte per the Microsoft exFAT spec (sections 3.4 and 8.2.2). Shared by the boot-region checksum (which folds surrounding byte ranges to skip the three volatile bytes) and the up-case-table checksum.

Parameters
[in]csRunning checksum (0 to start).
[in]bufBytes to fold in.
[in]lenNumber of bytes to fold.
Returns
Updated checksum.
Return values
0..UINT32_MAXThe rotate-add fold of cs over buf[0..len-1].
Precondition
buf holds at least len bytes.
len is the exact byte count of the span to fold.
Postcondition
No state is modified; the function is pure.
Return value depends only on cs, buf, and len.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 50 of file ra8_fs_fat_exfat_fmt.c.

References k_exfat_fmt_csum_hibit.

Referenced by internal_exfat_write_boot(), internal_exfat_write_boot_tail(), priv_exfat_upcase_checksum(), and priv_exfat_write_upcase().

◆ priv_exfat_format()

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).

Writes a DOS/MBR partition table at LBA 0 with a single type-0x07 (exFAT/NTFS) partition aligned at ::k_exfat_fmt_part_lba, then lays a complete exFAT volume INSIDE that partition: main + backup boot regions with boot checksums (VolumeLength = partition length, PartitionOffset = k_exfat_fmt_part_lba), the single FAT (bitmap/up-case/root chains), the allocation bitmap with the system clusters pre-marked, the canonical Microsoft up-case table + its checksum, and the root directory entry set. A PC therefore sees a normal partitioned removable disk and the volume mounts with no repair; ra8_fs_mount follows the MBR back to the partition.

Parameters
[in]backendBlock-device backend.
[in]total_sectorsDevice capacity in device sectors.
[in]bpsDevice sector size in bytes (a power of two, 512..4096, validated by the format entry point).
[in]labelOptional volume label (<= 11 chars), may be NULL.
Returns
Error code.
Return values
k_ra8_okA mountable partitioned exFAT volume was written.
k_ra8_err_invalid_sizePartition too small for an exFAT volume.
k_ra8_err_not_supportedBelow the exFAT minimum plus the 1 MiB partition alignment, past the MBR's 32-bit fields (2 TiB at 512-byte sectors), or system cluster chains exceed FAT sector 0.
k_ra8_err_*Backend write failure.
Precondition
backend and backend->write_block are non-NULL.
total_sectors is the actual device capacity reported by the backend.
Postcondition
On k_ra8_ok, LBA 0 holds an MBR and the partition holds a complete exFAT volume.
On failure, partial writes may have been made; the device should be reformatted.
Note
Not thread-safe; serialize with mounts on the same backend.
Since
0.1.0

Definition at line 798 of file ra8_fs_fat_exfat_fmt.c.

References exfat_geom_t::heap_offset, internal_exfat_fmt_place(), internal_exfat_geometry(), internal_exfat_write_bitmap(), internal_exfat_write_boot(), internal_exfat_write_fat(), internal_exfat_write_mbr(), internal_exfat_write_root(), k_exfat_fmt_first_clus, k_ra8_err_not_supported, k_ra8_ok, exfat_geom_t::part_lba, priv_exfat_write_upcase(), exfat_geom_t::root_cluster, exfat_geom_t::spc, and exfat_geom_t::upcase_cluster.