ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fs_fat_mount.c File Reference

FAT/exFAT volume detection, geometry, and mount/unmount. 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_mount.c:

Go to the source code of this file.

Functions

uint8_t * priv_sec_walk (void)
 The WALK-role sector buffer (directory scans and entry RMW).
uint8_t * priv_sec_fat (void)
 The FAT-role sector buffer (priv_fat_get and the FAT setters).
uint8_t * priv_sec_fat2 (void)
 The FAT2-role sector buffer (the FAT12 straddle's second sector).
uint8_t * priv_sec_io (void)
 The IO-role sector buffer (leaf data / bitmap sector transfers).
static ra8_fs_mount_tinternal_alloc_mount_slot (void)
 Allocate a free entry from the mount table; returns NULL if full.
ra8_fs_file_tpriv_alloc_file_slot (void)
 Allocate a free entry from the file table; returns NULL if full.
static uint8_t internal_bps_valid (uint32_t bs)
 Test whether a backend block size is one this adapter supports.
ra8_err_t priv_parse_bpb_into_mount (ra8_fs_mount_t *m)
 Parse the BPB layout fields out of g_fs_scratch into m.
static ra8_err_t internal_compute_geometry (ra8_fs_mount_t *m)
 Compute first_fat_lba, first_root_lba, first_data_lba, count_of_clusters.
static uint32_t internal_mbr_part0_lba (const uint8_t *buf)
 Return partition 0's first LBA from an MBR in buf, or 0.
static ra8_err_t internal_mbr_select_entry (const uint8_t *buf, uint8_t index, uint64_t *out_base)
 Return the first LBA of MBR primary entry index.
static ra8_err_t internal_locate_indexed (const ra8_fs_mount_t *m, uint8_t index, uint64_t *out_base)
 Resolve an explicit partition index to its first LBA.
static ra8_err_t internal_format_locked (const ra8_fs_backend_t *backend, const ra8_fs_format_opts_t *opts)
 Lay down a fresh volume – the guarded body of ra8_fs_format().
static ra8_err_t internal_read_boot_sector (ra8_fs_mount_t *m, uint8_t index)
 Read + parse the boot sector, transparently following MBR or GPT.
static ra8_err_t internal_mount_probe_bps (const ra8_fs_backend_t *backend, ra8_fs_mount_t *m)
 Probe the backend's block size into a claimed mount slot.
static ra8_err_t internal_probe_locked (const ra8_fs_backend_t *backend, ra8_fs_type_t *out_type)
 Parse a backend into temporary state and return only its format type.
static ra8_err_t internal_mount_locked (const ra8_fs_backend_t *backend, uint8_t index, ra8_fs_mount_t **out_handle)
 Mount a volume – the guarded body of ra8_fs_mount() and ra8_fs_mount_partition().
static ra8_err_t internal_unmount_locked (ra8_fs_mount_t *handle)
 Release a mount slot – the guarded body of ra8_fs_unmount().
ra8_err_t ra8_fs_format (const ra8_fs_backend_t *backend, const ra8_fs_format_opts_t *opts)
 Format a block device as a fresh, empty FAT12/FAT16/FAT32/exFAT volume.
ra8_err_t ra8_fs_probe (const ra8_fs_backend_t *backend, ra8_fs_type_t *out_type)
 Identify a FAT/exFAT volume without claiming a mount slot.
ra8_err_t ra8_fs_mount (const ra8_fs_backend_t *backend, ra8_fs_mount_t **out_handle)
 Mount a FAT volume from a block-device backend, auto-selecting the first partition.
ra8_err_t ra8_fs_mount_partition (const ra8_fs_backend_t *backend, uint8_t index, ra8_fs_mount_t **out_handle)
 Mount a FAT/exFAT volume from a specific partition of a block device.
ra8_err_t ra8_fs_unmount (ra8_fs_mount_t *handle)
 Unmount a previously mounted volume and release its slot.

Variables

static ra8_fs_mount_t s_mounts [k_ra8_fs_max_mounts] = {}
 Mount table – max k_ra8_fs_max_mounts simultaneous volumes.
static ra8_fs_file_t s_files [k_ra8_fs_max_files] = {}
 File handle table – max k_ra8_fs_max_files open at once.
uint8_t g_fs_scratch [k_ra8_fs_sector_max] = {}
 Single max-sector scratch buffer reused across all I/O.
static uint8_t s_sec_arena [k_fs_sec_roles][k_ra8_fs_sector_max] = {}
 The four fixed-role sector bounce buffers (#683).
const uint8_t k_zero_sector [k_ra8_fs_sector_max] = {}
 Implementation of k_zero_sector – see the header contract.

Detailed Description

FAT/exFAT volume detection, geometry, and mount/unmount.

Slot allocation, BPB parsing, MBR partition location, volume-type detection, and the public mount/unmount/format entry points. The GPT half of partition location lives in ra8_fs_fat_gpt.c (it outgrew this file when LBAs went 64-bit, #683); the two locators are called from here.

Since
0.1.0

Definition in file ra8_fs_fat_mount.c.

Function Documentation

◆ internal_alloc_mount_slot()

ra8_fs_mount_t * internal_alloc_mount_slot ( void )
static

Allocate a free entry from the mount table; returns NULL if full.

Linear scan of s_mounts for an entry with in_use == 0.

Returns
Pointer to a free mount slot, or NULL if all are busy.
Return values
non-NULLPointer to a ra8_fs_mount_t with in_use == 0.
NULLMount table is full.
Precondition
Module is initialized.
Caller serialises mount/unmount operations.
Postcondition
No state modified.
Returned pointer remains valid for the program lifetime.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 107 of file ra8_fs_fat_mount.c.

References k_ra8_fs_max_mounts, and s_mounts.

Referenced by internal_mount_locked().

◆ internal_bps_valid()

uint8_t internal_bps_valid ( uint32_t bs)
static

Test whether a backend block size is one this adapter supports.

The supported sizes are the powers of two from k_ra8_fs_sector_min to k_ra8_fs_sector_max (512, 1024, 2048, 4096) – exactly the values the FAT specification allows for BPB_BytsPerSec and exFAT allows for BytesPerSectorShift.

Parameters
[in]bsBackend-reported block size in bytes.
Returns
1 when bs is supported, else 0.
Return values
1bs is a power of two in 512..4096.
0Anything else.
Precondition
None (total function).
bs came from a backend get_capacity callback.
Postcondition
No state modified.
Result depends only on bs.
Note
Pure function; trivially thread-safe.
The range test is one compound decision of three conditions; its vectors live with the tests that drive it, cited as libs/ra8_fs/src/ra8_fs_fat_mount.c@priv_bps_valid.
Since
0.1.0

Definition at line 161 of file ra8_fs_fat_mount.c.

References k_ra8_fs_sector_max, and k_ra8_fs_sector_min.

Referenced by internal_format_locked(), and internal_mount_probe_bps().

◆ internal_compute_geometry()

ra8_err_t internal_compute_geometry ( ra8_fs_mount_t * m)
static

Compute first_fat_lba, first_root_lba, first_data_lba, count_of_clusters.

Derives region LBAs from the BPB and chooses FAT type using the cluster-count thresholds in MS FAT spec sec 3.5.

Parameters
[in,out]mMount with BPB fields already populated.
Returns
Error code.
Return values
k_ra8_okGeometry computed.
k_ra8_err_validation_failedTotal sectors smaller than data start.
Precondition
m is non-NULL.
priv_parse_bpb_into_mount has populated the BPB-derived fields.
Postcondition
On success, geometry fields and m->type are valid.
On failure, m is left in an inconsistent state.
Note
Pure computation; thread-safe vs other readers.
Since
0.1.0

Definition at line 229 of file ra8_fs_fat_mount.c.

References ra8_fs_mount_t::count_of_clusters, ra8_fs_mount_t::fat_size_sectors, ra8_fs_mount_t::first_data_lba, ra8_fs_mount_t::first_fat_lba, ra8_fs_mount_t::first_root_lba, k_cluster_count_fat12_max, k_cluster_count_fat16_max, k_ra8_err_validation_failed, k_ra8_fs_dir_entry_bytes, k_ra8_fs_type_fat12, k_ra8_fs_type_fat16, k_ra8_fs_type_fat32, k_ra8_ok, ra8_fs_mount_t::num_fats, priv_bps(), ra8_fs_mount_t::reserved_sectors, ra8_fs_mount_t::root_entries, ra8_fs_mount_t::sectors_per_cluster, ra8_fs_mount_t::total_sectors, and ra8_fs_mount_t::type.

Referenced by internal_mount_locked(), and internal_probe_locked().

◆ internal_format_locked()

ra8_err_t internal_format_locked ( const ra8_fs_backend_t * backend,
const ra8_fs_format_opts_t * opts )
static

Lay down a fresh volume – the guarded body of ra8_fs_format().

Validates the backend and the requested geometry, then dispatches to the FAT or exFAT formatter. The public ra8_fs_format() is the wrapper that brackets this call with the library lock; the full contract is documented there.

Parameters
[in]backendBlock-device backend to write.
[in]optsFormat options (variant, label, cluster-size hint).
Returns
Error code.
Return values
k_ra8_okVolume formatted.
k_ra8_err_null_ptrbackend or opts was NULL.
k_ra8_err_invalid_argBackend callbacks or geometry are unusable.
k_ra8_err_*As documented for ra8_fs_format().
Precondition
The library lock is held (or none is installed).
No volume from this backend is currently mounted.
Postcondition
On success the backend holds a mountable opts->type volume.
On an argument error the backend is untouched.
Note
Never call this from outside ra8_fs; it is the unlocked half.
Since
0.1.0

Definition at line 401 of file ra8_fs_fat_mount.c.

References internal_bps_valid(), internal_format_locked(), k_fmt_root_ents_f16, k_ra8_err_invalid_arg, k_ra8_err_null_ptr, k_ra8_fs_dir_entry_bytes, k_ra8_fs_type_exfat, k_ra8_fs_type_fat12, k_ra8_fs_type_fat16, k_ra8_fs_type_fat32, k_ra8_ok, priv_fmt_choose_geometry(), priv_fmt_emit_volume(), priv_fmt_reserved_for(), priv_fmt_spc_valid(), and ra8_fs_fmt_geom_t::type.

Referenced by internal_format_locked(), and ra8_fs_format().

◆ internal_locate_indexed()

ra8_err_t internal_locate_indexed ( const ra8_fs_mount_t * m,
uint8_t index,
uint64_t * out_base )
static

Resolve an explicit partition index to its first LBA.

Dispatches on the sector-0 partition-table type: a GPT disk (protective MBR type k_gpt_part_type_protective) selects GPT entry index, any other 0xAA55 MBR selects primary entry index. A sector 0 that carries no boot signature is not a partition table at all, so an explicit index has nothing to select and the caller's superfloppy request is refused. The signature bytes are tested separately (not as one compound decision) to mirror ::priv_mbr_part0_lba.

Parameters
[in]mMount with sector 0 already in g_fs_scratch.
[in]indexZero-based partition index.
[out]out_baseReceives the selected partition's first LBA.
Returns
Error code.
Return values
k_ra8_okout_base holds the volume base.
k_ra8_err_not_foundNo partition table, or an empty entry.
k_ra8_err_out_of_rangeindex is past the table.
k_ra8_err_not_supportedUnaddressable GPT geometry.
k_ra8_err_validation_failedMalformed entry or GPT header.
k_ra8_err_*Backend read failure.
Precondition
g_fs_scratch holds the contents of LBA 0.
m->partition_base_lba is still 0 (reads are absolute).
out_base is non-NULL.
Postcondition
On k_ra8_ok out_base holds a non-zero LBA.
g_fs_scratch may be overwritten (GPT path re-reads the entry array).
Note
Not thread-safe – uses module-level scratch.
Since
0.1.0

Definition at line 359 of file ra8_fs_fat_mount.c.

References g_fs_scratch, internal_mbr_select_entry(), k_bpb_off_signature_hi, k_bpb_off_signature_lo, k_bpb_sig_hi, k_bpb_sig_lo, k_gpt_part_type_protective, k_mbr_off_part0_type, k_ra8_err_not_found, and priv_gpt_locate_partition().

Referenced by internal_read_boot_sector().

◆ internal_mbr_part0_lba()

uint32_t internal_mbr_part0_lba ( const uint8_t * buf)
static

Return partition 0's first LBA from an MBR in buf, or 0.

Used only after the LBA-0 BPB parse fails: a standard SD card is MBR-partitioned, so the FAT boot sector lives at partition 0's start LBA, not at LBA 0. Returns 0 when buf is not a usable MBR (no 0x55AA, or an unused partition 0), which leaves the caller's original error in force.

Parameters
[in]bufSector-0 contents (>= 512 bytes).
Returns
Partition 0 first LBA, or 0 if not an MBR with a live partition 0.
Return values
0buf is not a usable MBR (no 0x55AA or an unused partition 0).
non-zeroPartition 0's first LBA.
Precondition
buf is non-NULL and holds at least one sector.
buf is the contents of LBA 0.
Postcondition
No state modified.
buf is unmodified.
Note
Not thread-safe (reads caller-owned memory only).
Since
0.1.0

Definition at line 271 of file ra8_fs_fat_mount.c.

References k_bpb_off_signature_hi, k_bpb_off_signature_lo, k_bpb_sig_hi, k_bpb_sig_lo, k_mbr_off_part0_lba, k_mbr_off_part0_type, and priv_rd32().

Referenced by internal_read_boot_sector().

◆ internal_mbr_select_entry()

ra8_err_t internal_mbr_select_entry ( const uint8_t * buf,
uint8_t index,
uint64_t * out_base )
static

Return the first LBA of MBR primary entry index.

Enumerates the four 16-byte primary entries. The type byte and first-LBA of entry index are read at k_mbr_off_part0_type and k_mbr_off_part0_lba plus index times k_mbr_part_entry_stride. Unlike the auto path (::priv_mbr_part0_lba), an out-of-range index, an empty slot, or a zero first-LBA are reported distinctly rather than folded to 0.

Parameters
[in]bufSector-0 (MBR) contents (>= 512 bytes).
[in]indexZero-based primary-entry index.
[out]out_baseReceives the entry's first LBA on success.
Returns
Error code.
Return values
k_ra8_okout_base holds the entry's first LBA.
k_ra8_err_out_of_rangeindex is 4 or greater.
k_ra8_err_not_foundThe selected entry is unused (type 0).
k_ra8_err_validation_failedAllocated entry with a zero first LBA.
Precondition
buf is non-NULL and holds at least one sector.
out_base is non-NULL.
Postcondition
No state modified.
buf is unmodified.
Note
Pure function.
Since
0.1.0

Definition at line 310 of file ra8_fs_fat_mount.c.

References k_mbr_off_part0_lba, k_mbr_off_part0_type, k_mbr_part_entry_count, k_mbr_part_entry_stride, k_ra8_err_not_found, k_ra8_err_out_of_range, k_ra8_err_validation_failed, k_ra8_ok, and priv_rd32().

Referenced by internal_locate_indexed().

◆ internal_mount_locked()

ra8_err_t internal_mount_locked ( const ra8_fs_backend_t * backend,
uint8_t index,
ra8_fs_mount_t ** out_handle )
static

Mount a volume – the guarded body of ra8_fs_mount() and ra8_fs_mount_partition().

Allocates a mount slot, reads the boot sector for the requested index (k_ra8_fs_partition_auto for first-partition auto-select), parses the BPB, and computes the geometry.

Parameters
[in]backendBlock-device backend to drive.
[in]indexPartition selector, or k_ra8_fs_partition_auto.
[out]out_handleOn success, opaque mount handle.
Returns
Error code.
Return values
k_ra8_okVolume mounted.
k_ra8_err_null_ptrNULL backend or out_handle.
k_ra8_err_invalid_argBackend missing required callbacks.
k_ra8_err_no_memMount table is full.
k_ra8_err_out_of_rangeindex is past the partition table.
k_ra8_err_not_foundSelected entry empty, or no table.
k_ra8_err_validation_failedNot a recognisable FAT volume.
k_ra8_err_*Backend read failure.
Precondition
The library lock is held (or none is installed).
backend and out_handle are non-NULL.
Backend's read/write/get_capacity callbacks are non-NULL.
Postcondition
On success, *out_handle is a valid mount.
On failure, no mount slot is marked in-use.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 629 of file ra8_fs_fat_mount.c.

References internal_alloc_mount_slot(), internal_compute_geometry(), internal_mount_locked(), internal_mount_probe_bps(), internal_read_boot_sector(), k_ra8_err_no_mem, k_ra8_err_null_ptr, k_ra8_fs_type_exfat, k_ra8_ok, priv_alloc_state_bind(), priv_alloc_state_release(), and priv_fsinfo_seed().

Referenced by internal_mount_locked(), ra8_fs_mount(), and ra8_fs_mount_partition().

◆ internal_mount_probe_bps()

ra8_err_t internal_mount_probe_bps ( const ra8_fs_backend_t * backend,
ra8_fs_mount_t * m )
static

Probe the backend's block size into a claimed mount slot.

The sector size is the DEVICE's block size, probed before the boot-sector parse so the parse can hold the volume to it (#683). A backend reporting a size outside 512..4096, or one that is not a power of two, is not mountable. Split out of ::priv_mount_locked so that function stays inside the function-size gate.

Parameters
[in]backendBlock-device backend being mounted.
[in,out]mClaimed mount slot; bytes_per_sector is written.
Returns
Error code.
Return values
k_ra8_okm->bytes_per_sector holds the device size.
k_ra8_err_invalid_argThe reported block size is unsupported.
k_ra8_err_*The get_capacity callback failed.
Precondition
backend and m are non-NULL; get_capacity is non-NULL.
m was zeroed by the claim.
Postcondition
On success m->bytes_per_sector is a power of two in 512..4096.
On failure m is left for the caller to abandon.
Note
Not thread-safe; callers serialise mount operations.
Since
0.1.0

Definition at line 533 of file ra8_fs_fat_mount.c.

References ra8_fs_mount_t::bytes_per_sector, ra8_fs_backend_t::ctx, ra8_fs_backend_t::get_capacity, internal_bps_valid(), k_ra8_err_invalid_arg, and k_ra8_ok.

Referenced by internal_mount_locked(), and internal_probe_locked().

◆ internal_probe_locked()

ra8_err_t internal_probe_locked ( const ra8_fs_backend_t * backend,
ra8_fs_type_t * out_type )
static

Parse a backend into temporary state and return only its format type.

Parameters
[in]backendReadable backend to probe.
[out]out_typeDetected filesystem type.
Returns
Error code from argument, capacity, partition, or volume validation.
Precondition
The library lock is held (or none is installed).
Postcondition
No mount/allocator slot is claimed and the medium is not written.
Since
0.1.0

Definition at line 560 of file ra8_fs_fat_mount.c.

References ra8_fs_mount_t::backend, internal_compute_geometry(), internal_mount_probe_bps(), internal_probe_locked(), internal_read_boot_sector(), k_ra8_err_null_ptr, k_ra8_fs_partition_auto, k_ra8_fs_type_exfat, and k_ra8_ok.

Referenced by internal_probe_locked(), and ra8_fs_probe().

◆ internal_read_boot_sector()

ra8_err_t internal_read_boot_sector ( ra8_fs_mount_t * m,
uint8_t index )
static

Read + parse the boot sector, transparently following MBR or GPT.

When index is k_ra8_fs_partition_auto this tries the BPB/VBR at the current base (LBA 0 for a superfloppy); if that parse fails and sector 0 is an MBR it retargets to partition 0's start LBA, or – for a protective MBR (type 0xEE) – to the GPT partition the entry array selects (Basic Data preferred), then re-parses, leaving the original error in force when sector 0 is neither a volume, an MBR, nor a usable GPT. For any other index the superfloppy attempt is skipped and the chosen primary/GPT entry supplies the base directly (::priv_locate_indexed); an unaddressable or empty entry fails cleanly.

Parameters
[in,out]mMount with backend bound and partition_base_lba == 0.
[in]indexPartition selector, or k_ra8_fs_partition_auto.
Returns
Error code from the (re-)parse.
Return values
k_ra8_okm holds the volume's BPB fields and base LBA.
k_ra8_err_*The backend read failed or no volume was found.
Precondition
m->partition_base_lba is 0 on entry.
m->backend is bound with a valid read_block.
Postcondition
On success m holds the volume's BPB fields and base LBA.
On failure m is left unmounted.
Note
Not thread-safe; serialize mount operations.
Since
0.1.0

Definition at line 470 of file ra8_fs_fat_mount.c.

References g_fs_scratch, internal_locate_indexed(), internal_mbr_part0_lba(), k_gpt_part_type_protective, k_mbr_off_part0_type, k_ra8_fs_partition_auto, k_ra8_ok, ra8_fs_mount_t::partition_base_lba, priv_gpt_locate_volume(), priv_parse_volume(), and priv_read_sector().

Referenced by internal_mount_locked(), and internal_probe_locked().

◆ internal_unmount_locked()

ra8_err_t internal_unmount_locked ( ra8_fs_mount_t * handle)
static

Release a mount slot – the guarded body of ra8_fs_unmount().

Writes the FAT32 FSInfo free count back if anything was allocated or freed, drops the allocator state, and marks the mount slot free. File data is not buffered, so there is nothing else to flush – callers must still close all files first.

Parameters
[in]handleMount handle from ra8_fs_mount().
Returns
Error code.
Return values
k_ra8_okVolume unmounted.
k_ra8_err_null_ptrhandle was NULL.
k_ra8_err_invalid_statehandle is not currently mounted.
k_ra8_err_*The FSInfo writeback failed; the volume is still unmounted.
Precondition
The library lock is held (or none is installed).
handle is non-NULL and currently in use.
All files opened on this mount have been closed.
Postcondition
Mount slot is free for reuse, whatever the FSInfo writeback did.
handle->type is reset to k_ra8_fs_type_unknown.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 718 of file ra8_fs_fat_mount.c.

References internal_unmount_locked(), k_ra8_err_null_ptr, k_ra8_fs_type_unknown, priv_alloc_state_release(), and priv_fsinfo_flush().

Referenced by internal_unmount_locked(), and ra8_fs_unmount().

◆ priv_alloc_file_slot()

ra8_fs_file_t * priv_alloc_file_slot ( void )

Allocate a free entry from the file table; returns NULL if full.

Linear scan of s_files for an entry with in_use == 0.

Returns
Pointer to a free file slot, or NULL if all are busy.
Return values
non-NULLPointer to a ra8_fs_file_t with in_use == 0.
NULLFile table is full.
Precondition
Module is initialized.
Caller serialises open/close operations.
Postcondition
No state modified.
Returned pointer remains valid for the program lifetime.
Note
Not thread-safe; callers serialise.
Since
0.1.0

Definition at line 118 of file ra8_fs_fat_mount.c.

References k_ra8_fs_max_files, and s_files.

Referenced by internal_create_new(), internal_exfat_open_created(), internal_exfat_open_found(), internal_open_existing(), and priv_exfat_open().

◆ priv_parse_bpb_into_mount()

ra8_err_t priv_parse_bpb_into_mount ( ra8_fs_mount_t * m)

Parse the BPB layout fields out of g_fs_scratch into m.

Validates the boot signature (0x55AA) and reads the BPB fields out of the boot sector scratch buffer.

Parameters
[in,out]mMount to populate; backend already plugged in.
Returns
Error code.
Return values
k_ra8_okFields parsed successfully.
k_ra8_err_validation_failedBad signature or sanity-check fail.
Precondition
m is non-NULL.
g_fs_scratch holds the boot sector (LBA 0).
Postcondition
On success, the relevant m->* fields are populated.
On failure, m may be partially updated.
Note
Not thread-safe – uses module-level scratch.
Since
0.1.0

Definition at line 171 of file ra8_fs_fat_mount.c.

References ra8_fs_mount_t::bytes_per_sector, ra8_fs_mount_t::fat_size_sectors, g_fs_scratch, k_bpb_off_bytes_per_sec, k_bpb_off_fat_sz_16, k_bpb_off_fat_sz_32, k_bpb_off_num_fats, k_bpb_off_root_clus, k_bpb_off_root_ent_cnt, k_bpb_off_rsvd_sec_cnt, k_bpb_off_sec_per_clus, k_bpb_off_signature_hi, k_bpb_off_signature_lo, k_bpb_off_tot_sec_16, k_bpb_off_tot_sec_32, k_bpb_sig_hi, k_bpb_sig_lo, k_ra8_err_validation_failed, k_ra8_ok, ra8_fs_mount_t::num_fats, priv_rd16(), priv_rd32(), ra8_fs_mount_t::reserved_sectors, ra8_fs_mount_t::root_cluster, ra8_fs_mount_t::root_entries, ra8_fs_mount_t::sectors_per_cluster, and ra8_fs_mount_t::total_sectors.

Referenced by priv_parse_volume().

◆ priv_sec_fat()

uint8_t * priv_sec_fat ( void )

The FAT-role sector buffer (priv_fat_get and the FAT setters).

See the arena discipline above.

Returns
Pointer to the FAT-role sector buffer.
Return values
non-NULLAlways.
Precondition
The caller holds the library lock (or none is installed).
No other FAT-role buffer is live in the current call chain.
Postcondition
The buffer contents are whatever the previous user left.
No other state is modified.
Note
Not thread-safe; the adapter is single-threaded by contract.
Since
0.1.0

Definition at line 66 of file ra8_fs_fat_mount.c.

References k_fs_sec_role_fat, and s_sec_arena.

Referenced by internal_exfat_fat_set_one(), internal_fat12_set_one(), internal_fat16_set_one(), internal_fat32_set_one(), and priv_fat_get().

◆ priv_sec_fat2()

uint8_t * priv_sec_fat2 ( void )

The FAT2-role sector buffer (the FAT12 straddle's second sector).

See the arena discipline above.

Returns
Pointer to the FAT2-role sector buffer.
Return values
non-NULLAlways.
Precondition
The caller holds the library lock (or none is installed).
Live only alongside the FAT-role buffer, in the straddle helpers.
Postcondition
The buffer contents are whatever the previous user left.
No other state is modified.
Note
Not thread-safe; the adapter is single-threaded by contract.
Since
0.1.0

Definition at line 72 of file ra8_fs_fat_mount.c.

References k_fs_sec_role_fat2, and s_sec_arena.

Referenced by internal_fat12_set_one(), and priv_fat_get().

◆ priv_sec_io()

uint8_t * priv_sec_io ( void )

The IO-role sector buffer (leaf data / bitmap sector transfers).

See the arena discipline above.

Returns
Pointer to the IO-role sector buffer.
Return values
non-NULLAlways.
Precondition
The caller holds the library lock (or none is installed).
No other IO-role buffer is live in the current call chain.
Postcondition
The buffer contents are whatever the previous user left.
No other state is modified.
Note
Not thread-safe; the adapter is single-threaded by contract.
Since
0.1.0

Definition at line 78 of file ra8_fs_fat_mount.c.

References k_fs_sec_role_io, and s_sec_arena.

Referenced by internal_exchk_bitmap_pass(), internal_exfat_bitmap_window(), internal_exfat_read_entry(), internal_read_one_chunk(), internal_space_exfat_free(), internal_trunc_zero_span(), priv_exfat_bitmap_clear(), priv_exfat_bitmap_mark(), priv_exfat_bitmap_test(), priv_exfat_next_entry(), priv_exfat_seal_cluster(), priv_exfat_write_dir_set(), and priv_write_into_sector().

◆ priv_sec_walk()

uint8_t * priv_sec_walk ( void )

The WALK-role sector buffer (directory scans and entry RMW).

See the arena discipline above. The pointer is to static storage of k_ra8_fs_sector_max bytes, valid for the whole program; only LIVENESS is scoped, by the role rules.

Returns
Pointer to the walk-role sector buffer.
Return values
non-NULLAlways.
Precondition
The caller holds the library lock (or none is installed).
No other walk-role buffer is live in the current call chain.
Postcondition
The buffer contents are whatever the previous user left.
No other state is modified.
Note
Not thread-safe; the adapter is single-threaded by contract.
Since
0.1.0

Definition at line 60 of file ra8_fs_fat_mount.c.

References k_fs_sec_role_walk, and s_sec_arena.

Referenced by internal_close_stamp(), internal_dir_cluster_init(), internal_dir_collect_chain(), internal_dir_erase_positions(), internal_dir_is_empty(), internal_fat_boot_set_label(), internal_fat_del_entry(), internal_fat_dir_next(), internal_fat_find_free_root(), internal_fat_find_vol_id(), internal_fat_fsinfo(), internal_fat_put_vol_id(), internal_fat_scan_cluster_dir(), internal_fat_scan_fixed_root(), internal_fat_trunc_commit(), internal_fsinfo_locate(), internal_get_label_fat(), internal_setattr_fat(), internal_truncate_existing(), internal_utime_fat(), priv_dir_commit(), priv_dir_find(), priv_dir_find_free_run(), priv_dir_find_long(), priv_fmt_emit_volume(), priv_fsinfo_flush(), and priv_fsinfo_seed().

◆ ra8_fs_format()

ra8_err_t ra8_fs_format ( const ra8_fs_backend_t * backend,
const ra8_fs_format_opts_t * opts )
nodiscard

Format a block device as a fresh, empty FAT12/FAT16/FAT32/exFAT volume.

Lays down a complete volume so the very next ra8_fs_mount() on the same backend detects exactly opts->type. The FAT variants are written as a superfloppy (no MBR) at LBA 0; exFAT is written into an MBR partition (see below). For the FAT variants this is a classic BPB layout:

  • a full BPB (jump prologue, OEM name, BytsPerSec, SecPerClus, RsvdSecCnt, NumFATs, RootEntCnt or RootClus, TotSec, media descriptor, FATSz, volume label, filesystem-type string, and the 0x55 0xAA boot signature);
  • the reserved FAT[0] media descriptor and FAT[1] end-of-chain marker in every FAT copy (plus the root-cluster EOC and an FSInfo sector for FAT32);
  • a zeroed root directory (FAT12/16 fixed root, or the FAT32 root cluster).

The cluster size is chosen (when opts->sectors_per_cluster == 0) so the resulting count_of_clusters lands in the band the requested type requires per Microsoft "FAT: General Overview of On-Disk Format" sec 3.5 (FAT12 < 4085, 4085 <= FAT16 < 65525, FAT32 >= 65525). If the backend's capacity cannot satisfy opts->type – too small for FAT16/FAT32, or too large for FAT12/FAT16 even at the maximum cluster size – the call fails without writing anything.

exFAT (k_ra8_fs_type_exfat) is written the way a PC writes it, so a card formatted here mounts on a desktop: a DOS/MBR partition table at LBA 0 with one type-0x07 partition aligned at 1 MiB, and the volume itself inside that partition rather than at LBA 0. ra8_fs_mount() follows the partition table back (ra8_fs_mount_t::partition_base_lba records where it landed), and also mounts a card partitioned by a desktop. Because the partition cannot start at sector 0, the device must be big enough for the 1 MiB alignment gap ON TOP OF the 32 MiB minimum volume – a 32 MiB card is no longer formattable.

Inside the partition exFAT lays down its own on-disk structures instead of a FAT BPB: the 12-sector boot region (Main + Backup) with the VBR checksum sector, the single FAT, the allocation-bitmap cluster(s), the canonical compressed up-case table (which may span several clusters), and a root-directory cluster carrying the volume-label, allocation-bitmap, and up-case-table system directory entries. The image is fsck.exfat-clean and round-trips through ra8_fs_mount() plus the whole exFAT file API: ra8_fs_open() in every mode, ra8_fs_read(), ra8_fs_write(), ra8_fs_write_file(), ra8_fs_rename(), and ra8_fs_unlink().

Parameters
[in]backendBlock-device implementation (read/write/get_capacity all non-NULL). Its write_block is driven during the format.
[in]optsFormat options. type selects the variant; label is an optional 0..11 char volume label; sectors_per_cluster pins the cluster size (0 = auto-select).
Returns
ra8_err_t
Return values
k_ra8_okVolume formatted; ready to mount.
k_ra8_err_null_ptrbackend or opts is NULL.
k_ra8_err_invalid_argBackend has NULL callbacks, the reported block size is not a power of two in 512..4096, or sectors_per_cluster is non-zero and not a power of two in 1..128.
k_ra8_err_not_supportedopts->type is unknown / not a writable filesystem, or the device is too small to hold a partitioned exFAT volume (the 1 MiB alignment gap plus the 32 MiB minimum).
k_ra8_err_invalid_sizeCapacity cannot satisfy opts->type.
k_ra8_err_*Backend read/write failure (volume may be partially written on a mid-format I/O error).
Precondition
backend->write_block and backend->get_capacity are non-NULL.
No volume from this backend is currently mounted (the caller has unmounted it first; formatting under a live mount corrupts cached geometry).
Postcondition
On success the backend's first sectors hold a valid opts->type BPB, FAT, and an empty root directory.
On k_ra8_err_invalid_size / argument errors, the backend is untouched.
Note
Not thread-safe unless a lock is installed (see ra8_fs_set_lock()).
Warning
Destroys all data on the device.
Example:
opts.label = "SCRATCH";
if (ra8_fs_format(&backend, &opts) == k_ra8_ok) {
ra8_fs_mount_t* mnt = nullptr;
(void)ra8_fs_mount(&backend, &mnt); // mnt->type == k_ra8_fs_type_fat16
}
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_t ra8_fs_format(const ra8_fs_backend_t *backend, const ra8_fs_format_opts_t *opts)
Format a block device as a fresh, empty FAT12/FAT16/FAT32/exFAT volume.
ra8_err_t ra8_fs_mount(const ra8_fs_backend_t *backend, ra8_fs_mount_t **out_handle)
Mount a FAT volume from a block-device backend, auto-selecting the first partition.
@ k_ra8_fs_type_fat16
4085 <= count_of_clusters < 65525.
Tunables for ra8_fs_format() (the on-disk geometry of a fresh volume).
ra8_fs_type_t type
FAT variant to lay down (12/16/32).
const char * label
0..11 char volume label, or NULL.
Cached parse of one mounted FAT volume.
See also
ra8_fs_mount() Detects the type this routine wrote.
Since
0.1.0

Definition at line 744 of file ra8_fs_fat_mount.c.

References internal_format_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_format().

Referenced by demo_fs_format_mount(), demo_fs_format_or_panic(), eoh_mount_or_halt(), etoc_mount_or_halt(), fs_fmt_run_exfat(), fs_fmt_run_one_type(), internal_demo_mount(), internal_demo_mount(), internal_demo_probe_fat(), internal_format_mount(), internal_pc_mount_or_halt(), internal_ra8_io_roundtrip_format_mount(), internal_swap_run_one(), main(), ra8_fs_format(), ra8_io_roundtrip_mount(), and sdhi_demo_mount_via_io().

◆ ra8_fs_mount()

ra8_err_t ra8_fs_mount ( const ra8_fs_backend_t * backend,
ra8_fs_mount_t ** out_handle )
nodiscard

Mount a FAT volume from a block-device backend, auto-selecting the first partition.

Reads sector 0 and, if it is not itself a boot sector, follows the partition table to the first volume: MBR partition 0, or – on a GPT disk (protective MBR type 0xEE) – the first Microsoft Basic Data entry. It then validates the BPB signature and bytes-per-sector, computes the cluster count, dispatches to FAT12 / FAT16 / FAT32, and caches the layout in *out_handle. Exactly equivalent to ra8_fs_mount_partition() with k_ra8_fs_partition_auto; use that sibling to reach any other partition.

Parameters
[in]backendBlock-device implementation. Must remain alive for the lifetime of the mount.
[out]out_handlePopulated mount handle on success.
Returns
ra8_err_t
Return values
k_ra8_okVolume mounted successfully.
k_ra8_err_null_ptrbackend or out_handle is NULL.
k_ra8_err_invalid_argBackend has NULL function pointers.
k_ra8_err_no_memNo free mount slot.
k_ra8_err_validation_failedBPB signature invalid / unsupported.
Precondition
backend->read_block is non-NULL.
out_handle is non-NULL.
Postcondition
On success, out_handle->in_use == 1 and type != unknown.
On failure, *out_handle is left untouched.
Note
Not thread-safe unless a lock is installed (see ra8_fs_set_lock()).
See also
ra8_fs_mount_partition() Mount a partition chosen by index.
Since
0.1.0

Definition at line 762 of file ra8_fs_fat_mount.c.

References internal_mount_locked(), k_ra8_fs_partition_auto, priv_lock_acquire(), priv_lock_release(), and ra8_fs_mount().

Referenced by demo_fs_format_mount(), demo_fs_format_or_panic(), eoh_mount_or_halt(), etoc_mount_or_halt(), fileops_mount_volume(), fs_fmt_run_exfat(), fs_fmt_run_one_type(), imp_mount_or_halt(), internal_demo_mount(), internal_demo_mount(), internal_format_mount(), internal_mount(), internal_mount_image(), internal_mount_sd(), internal_native_mount(), internal_pc_mount_or_halt(), internal_ra8_io_roundtrip_format_mount(), internal_swap_run_one(), main(), ra8_fs_mount(), ra8_io_roundtrip_mount(), sd_demo_mount_or_halt(), sdhi_demo_mount_via_io(), selftest_mount_volume(), selftest_mount_volume(), selftest_mount_volume(), selftest_mount_volume(), selftest_mount_volume(), and sh_sd_mount().

◆ ra8_fs_mount_partition()

ra8_err_t ra8_fs_mount_partition ( const ra8_fs_backend_t * backend,
uint8_t index,
ra8_fs_mount_t ** out_handle )
nodiscard

Mount a FAT/exFAT volume from a specific partition of a block device.

Generalises ra8_fs_mount() with an explicit partition selector so a multi-partition card or disk exposes every volume, not just the first. Sector 0 decides the table type: a GPT disk (protective MBR type 0xEE) selects entry index of the GPT partition-entry array; any other 0xAA55 MBR selects primary entry index (0-3). The chosen partition's first LBA becomes out_handle->partition_base_lba and every subsequent access is partition-relative. Passing k_ra8_fs_partition_auto reproduces ra8_fs_mount() exactly, including transparent superfloppy (LBA 0) mounts; an explicit index requires a partition table, so a superfloppy with no table returns k_ra8_err_not_found.

Parameters
[in]backendBlock-device implementation. Must remain alive for the lifetime of the mount.
[in]indexZero-based partition index, or k_ra8_fs_partition_auto.
[out]out_handlePopulated mount handle on success.
Returns
ra8_err_t
Return values
k_ra8_okVolume mounted successfully.
k_ra8_err_null_ptrbackend or out_handle is NULL.
k_ra8_err_invalid_argBackend has NULL function pointers.
k_ra8_err_no_memNo free mount slot.
k_ra8_err_out_of_rangeindex is past the partition table.
k_ra8_err_not_foundThe selected entry is empty, or there is no partition table to index.
k_ra8_err_not_supportedGPT entry-array geometry this backend cannot address (non-128-byte entries, or a first LBA above 32 bits).
k_ra8_err_validation_failedBPB signature invalid / unsupported.
Precondition
backend->read_block is non-NULL.
out_handle is non-NULL.
Postcondition
On success, out_handle->in_use == 1 and type != unknown.
On failure, *out_handle is left untouched.
Note
Not thread-safe unless a lock is installed (see ra8_fs_set_lock()).
See also
ra8_fs_mount() Auto-select the first partition.
Since
0.1.0

Definition at line 773 of file ra8_fs_fat_mount.c.

References internal_mount_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_mount_partition().

Referenced by ra8_fs_mount_partition().

◆ ra8_fs_probe()

ra8_err_t ra8_fs_probe ( const ra8_fs_backend_t * backend,
ra8_fs_type_t * out_type )
nodiscard

Identify a FAT/exFAT volume without claiming a mount slot.

Runs the same superfloppy/MBR/GPT discovery and BPB/VBR validation as ra8_fs_mount(), but parses into temporary caller-invisible state and returns only the detected type. This is the authoritative probe used by the pluggable format registry: partitioned exFAT is not mistaken for an unknown format merely because LBA 0 is an MBR.

Parameters
[in]backendReadable block backend.
[out]out_typeDetected FAT12/16/32 or exFAT type.
Return values
k_ra8_okA supported volume was validated.
k_ra8_err_null_ptrEither argument was NULL.
k_ra8_err_invalid_argRequired backend operations/capacity are invalid.
k_ra8_err_validation_failedNo supported volume is present.
k_ra8_err_*Backend or partition-parse failure.
Precondition
No concurrent filesystem call unless a lock is installed.
Postcondition
No mount/file slot is consumed and the medium is not modified.
On failure out_type is untouched.
Since
0.1.0

Definition at line 753 of file ra8_fs_fat_mount.c.

References internal_probe_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_probe().

Referenced by internal_exfat_probe(), internal_fat_probe(), and ra8_fs_probe().

◆ ra8_fs_unmount()

ra8_err_t ra8_fs_unmount ( ra8_fs_mount_t * handle)
nodiscard

Unmount a previously mounted volume and release its slot.

On a FAT32 volume carrying a valid FSInfo sector this is also where the free-cluster count and next-free hint are written back, so a card the firmware wrote reports the right free space on a desktop and fsck.fat stops calling the summary wrong. The slot is released even when that write fails – an unmount that could be refused would be worse than a stale free count.

Parameters
[in,out]handleMount handle returned by ra8_fs_mount().
Return values
k_ra8_okSlot released.
k_ra8_err_null_ptrhandle is NULL.
k_ra8_err_invalid_stateSlot was not in use.
k_ra8_err_*FSInfo writeback failed; the slot is still released.
Precondition
handle was returned by ra8_fs_mount.
Postcondition
handle->in_use == 0.
Any pending FSInfo update has been attempted exactly once.
Since
0.1.0

Definition at line 782 of file ra8_fs_fat_mount.c.

References internal_unmount_locked(), priv_lock_acquire(), priv_lock_release(), and ra8_fs_unmount().

Referenced by demo_thread_entry(), fileops_run_ladder(), fs_fmt_run_exfat(), fs_fmt_run_one_type(), internal_finish_image(), internal_native_unmount(), internal_run_font(), internal_swap_run_one(), main(), priv_mkbookimg_build_image(), ra8_fs_unmount(), ra8_sdfont_load(), selftest_host_pass(), and selftest_host_pass().

Variable Documentation

◆ g_fs_scratch

uint8_t g_fs_scratch[k_ra8_fs_sector_max] = {}

Single max-sector scratch buffer reused across all I/O.

Shared by every FAT/exFAT translation unit; declared extern in ra8_fs_fat_internal.h and defined here exactly once. Sized to k_ra8_fs_sector_max so a 4Kn medium fits without allocation.

One module-wide bounce buffer for every BPB, FAT, directory, and data-sector access. Sized to k_ra8_fs_sector_max so a 4Kn medium fits; a 512-byte mount simply uses the first quarter. Defined once in ra8_fs_fat_mount.c.

Note
Not reentrant; the adapter is single-threaded by contract.
Warning
Do not access concurrently; callers serialise all FS operations.
Since
0.1.0

Definition at line 40 of file ra8_fs_fat_mount.c.

Referenced by internal_exfat_write_bitmap(), internal_exfat_write_boot(), internal_exfat_write_boot_tail(), internal_exfat_write_fat(), internal_exfat_write_mbr(), internal_exfat_write_root(), internal_fmt_seed_fats(), internal_fmt_write_fsinfo(), internal_gpt_read_geom(), internal_gpt_scan_entries(), internal_locate_indexed(), internal_read_boot_sector(), priv_exfat_write_upcase(), priv_gpt_locate_partition(), priv_parse_bpb_into_mount(), and priv_parse_volume().

◆ k_zero_sector

const uint8_t k_zero_sector[k_ra8_fs_sector_max] = {}

Implementation of k_zero_sector – see the header contract.

One whole sector of zero bytes, in read-only storage.

Definition at line 57 of file ra8_fs_fat_mount.c.

Referenced by internal_dir_cluster_init(), internal_dir_grow(), internal_exfat_close_gap(), and priv_exfat_zero_cluster().

◆ s_files

ra8_fs_file_t s_files[k_ra8_fs_max_files] = {}
static

File handle table – max k_ra8_fs_max_files open at once.

Definition at line 32 of file ra8_fs_fat_mount.c.

Referenced by internal_file_valid(), internal_free_file(), priv_alloc_file_slot(), ra8_io_vfs_init(), and ra8_io_vfs_unmount().

◆ s_mounts

ra8_fs_mount_t s_mounts[k_ra8_fs_max_mounts] = {}
static

Mount table – max k_ra8_fs_max_mounts simultaneous volumes.

Definition at line 29 of file ra8_fs_fat_mount.c.

Referenced by internal_alloc_mount_slot().

◆ s_sec_arena

uint8_t s_sec_arena[k_fs_sec_roles][k_ra8_fs_sector_max] = {}
static

The four fixed-role sector bounce buffers (#683).

Backing storage for priv_sec_walk / priv_sec_fat / priv_sec_fat2 / priv_sec_io – see the arena discipline in ra8_fs_fat_bytes_internal.h. Static because 4 KiB frames do not belong on firmware stacks; four buffers because that is the whole simultaneous-liveness depth of the call graph.

Note
Not reentrant; the adapter is single-threaded by contract.
Warning
Never index directly; take a buffer through its role accessor.
Since
0.1.0

Definition at line 54 of file ra8_fs_fat_mount.c.

Referenced by priv_sec_fat(), priv_sec_fat2(), priv_sec_io(), and priv_sec_walk().