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

Canonical Microsoft exFAT up-case table, its writer, and its reader. 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_upcase.c:

Go to the source code of this file.

Functions

uint16_t priv_exfat_upcase_unit (uint16_t unit)
 Fold a UTF-16 code unit through the canonical exFAT up-case table.
uint32_t priv_exfat_upcase_checksum (void)
 Rotate-add checksum of the up-case table this build embeds.
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.

Variables

static const uint8_t s_exfat_upcase [k_exfat_fmt_upc_std_bytes]
 The canonical Microsoft exFAT up-case table (compressed, 5836 bytes).

Detailed Description

Canonical Microsoft exFAT up-case table, its writer, and its reader.

exFAT stores a Unicode up-case table so the file system can fold names to a single case for its case-insensitive lookups. The Microsoft reference table covers the whole Basic Multilingual Plane in run-length-compressed form; it is the exact byte sequence mkfs.exfat and the Windows formatter emit, and its rotate-add checksum is the well-known 0xE619D30D. Embedding it verbatim (rather than the earlier a-z-only stub) makes a card the firmware formats byte-for-byte compatible with a PC-formatted one and folds accented / Greek / Cyrillic file names correctly – so a book dragged onto the card from any computer resolves regardless of case.

This table is 5836 bytes (k_exfat_fmt_upc_std_bytes), lives in its own translation unit to keep ra8_fs_fat_exfat_fmt.c under the source-size cap, and is written by priv_exfat_write_upcase across the up-case clusters of a freshly formatted volume.

Reading it back (#606)

The table was write-only until name handling needed to FOLD a case, and it is the fold the exFAT specification defines NameHash against – so hashing with an ASCII-only up-case, which is what the create path used to do, stored a hash a compliant host disagrees with for any name outside ASCII. priv_exfat_upcase_unit() answers the same question the table does, by walking the compressed form in place rather than expanding it: a full 64 Ki-entry expansion is 128 KiB of RAM on a part that has 1.6 MB in total, to answer a query that arrives a few times per file name.

The compressed encoding is the specification's: a unit that is not k_exfat_upc_run_tag is the mapping for the next code point, and one that is introduces a run length of code points that map to themselves. The table ends with a k_exfat_upc_run_tag that has no length after it – the mapping for U+FFFF, which is its own up-case – so a walk that runs out of words while expecting a run length returns the identity, which is the right answer there.

priv_exfat_upcase_checksum() folds the same bytes with the same rotate-add the writer uses, which is what lets a mount COMPARE this build's table against the one the volume actually carries instead of assuming they agree.

Since
0.1.0

Definition in file ra8_fs_fat_exfat_upcase.c.

Function Documentation

◆ priv_exfat_upcase_checksum()

uint32_t priv_exfat_upcase_checksum ( void )

Rotate-add checksum of the up-case table this build embeds.

The same 32-bit fold priv_exfat_write_upcase records in the volume's up-case directory entry, computed over the in-flash table. Having it as a function rather than a constant is the point: a constant could drift from the bytes it claims to describe, and this cannot.

Returns
Checksum of k_exfat_fmt_upc_std_bytes table bytes.
Return values
0xE619D30DThe canonical Microsoft table, which is what is embedded.
Precondition
None.
The caller compares it against a volume's TableChecksum.
Postcondition
No state modified.
The result is the same on every call.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 471 of file ra8_fs_fat_exfat_upcase.c.

References k_exfat_fmt_upc_std_bytes, priv_exfat_csum32(), and s_exfat_upcase.

Referenced by priv_exfat_upcase_verify().

◆ priv_exfat_upcase_unit()

uint16_t priv_exfat_upcase_unit ( uint16_t unit)

Fold a UTF-16 code unit through the canonical exFAT up-case table.

The exFAT specification defines both NameHash and name comparison over the UP-CASED name, using the table the volume carries. This build embeds and writes the canonical Microsoft table – the one mkfs.exfat and the Windows formatter emit, checksum 0xE619D30D – and this is the reader for it, so the hash stored on create is the hash a host recomputes.

Look-up walks the compressed table rather than expanding it, because the expansion is 128 KiB. The ASCII range short-circuits to priv_ascii_upper, which the table agrees with for every one of those 128 units.

A surrogate unit folds to itself: the table covers the BMP, and a supplementary code point has no simple case mapping inside a single unit.

Parameters
[in]unitUTF-16 code unit to fold.
Returns
The up-cased unit.
Return values
unitNo mapping applies (identity run, or past the table).
otherThe table's mapping for unit.
Precondition
None; every 16-bit value is a legal input.
The caller wants the VOLUME's fold and has checked ra8_fs_mount_t::exfat_upcase_ok, or is folding a FAT long name.
Postcondition
No state modified.
The result depends only on unit and the embedded table.
Note
Pure function; trivially thread-safe.
Since
0.1.0

Definition at line 435 of file ra8_fs_fat_exfat_upcase.c.

References k_exfat_upc_run_tag, k_exfat_upc_words, k_utf_ascii_max, priv_ascii_upper(), priv_rd16(), and s_exfat_upcase.

Referenced by priv_exfat_name_chunk_eq(), priv_exfat_name_hash(), and priv_utf16_ieq().

◆ priv_exfat_write_upcase()

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.

Streams the 5836-byte Microsoft up-case table (k_exfat_fmt_upc_std_bytes, embedded in ra8_fs_fat_exfat_upcase.c) to the device starting at absolute LBA abs_lba, one bps-byte sector at a time, zero-padding the final partial sector. The rotate-add checksum (priv_exfat_csum32) is accumulated over exactly the table bytes – not the pad – so it equals the well-known 0xE619D30D and can be stamped into the root Up-case directory entry.

Parameters
[in]backendBlock-device backend with a non-NULL write_block.
[in]abs_lbaAbsolute (partition-adjusted) first LBA of the up-case table's cluster run.
[in]bpsDevice sector size in bytes (a power of two, 512..4096).
[out]out_csumReceives the table checksum on success.
Returns
Error code from the backend.
Return values
k_ra8_okTable written; out_csum populated.
k_ra8_err_*Backend write_block failure; out_csum unspecified.
Precondition
backend and backend->write_block are non-NULL.
out_csum is non-NULL; abs_lba's cluster run holds the table span.
Postcondition
On k_ra8_ok the up-case cluster run holds the canonical table.
On k_ra8_ok out_csum holds the checksum for the root Up-case entry.
Note
Not thread-safe; uses the module scratch buffer.
Since
0.1.0

Definition at line 477 of file ra8_fs_fat_exfat_upcase.c.

References ra8_fs_backend_t::ctx, g_fs_scratch, k_exfat_fmt_upc_std_bytes, k_ra8_ok, priv_byte_copy(), priv_exfat_csum32(), s_exfat_upcase, and ra8_fs_backend_t::write_block.

Referenced by priv_exfat_format().

Variable Documentation

◆ s_exfat_upcase

const uint8_t s_exfat_upcase[k_exfat_fmt_upc_std_bytes]
static

The canonical Microsoft exFAT up-case table (compressed, 5836 bytes).

Little-endian UTF-16 up-case mapping table in the exFAT run-length compressed encoding, identical to the one mkfs.exfat writes. Its rotate-add checksum is 0xE619D30D. Read-only; lives in flash.

Note
Access only via priv_exfat_write_upcase.
Warning
Do not edit by hand – the bytes and their checksum are a matched pair the exFAT reader validates.
Since
0.1.0

Definition at line 66 of file ra8_fs_fat_exfat_upcase.c.

Referenced by priv_exfat_upcase_checksum(), priv_exfat_upcase_unit(), and priv_exfat_write_upcase().