# Firmware update (SD path) How a stock or modded `.bin` gets onto the device and exactly what is verified. No hardware access needed — SD card + OLED only. ## Trigger File named `Lofi-12 XT.bin` at SD root (from the official update ZIP: https://sonicware.jp/pages/downloads), then hold **PAD while powering on**. Updater (`SYSTEM UPDATE`) lives in SPI AIS flash, **not** in the `.bin`, so a bad SYSTEM image can always be reverted with a stock SD. ## Stages (OLED text) 1. `Checking... 0%` — parse + validate the file (checks below). Failures: `The firmware file not exist.`, `This card is invalid format.`, `ERROR : This file is invalid.` / `Check the firmware file.` 2. `Are you sure?` — `[CLR] : No / [OK] : Yes`. 3. Per section (`>> BOOT / SYSTEM / PRESET / MCU / MCU Boot`, prompts `BOOT:`…): `Erasing...`, `Writing...`, `Verifying...` with `%` progress. 4. `100%, done.` / `Update completed.` (`100%, NG.` / `Update failed.` on error) → `Please restart.` ## Checks performed on the `.bin` 1. Magic: `cmtd` @`0x00`, `mmtd` @`0x30`, `sect` chain from `0x54`. 2. `cmtd+0x04` filesize equals actual file size. 3. `sect` chain tiles EOF exactly (`next = off + 12 + len`); load addresses must land in DDR (`0xC2xxxxxx`); entry point must sit inside the code sect. 4. **Checksum** `cmtd+0x08` — recomputed and compared (`CMPEQ`, reject = `ERROR : This file is invalid.`). Rule (proven 3/3, see below): CRC32-IEEE, init 0, over the whole file with bytes `[8:12]` replaced by `0xC27C6282`. `mmtd+0x08` flags are covered as-is (no special handling). ## Forging a valid image ```bash python3 tools/lofi_patch_string.py stock.bin mod.bin OldString NewStringX python3 tools/prove_checksum.py mod.bin # expect MATCH ``` `lofi_pack.py`/`lofi_patch_string.py` stamp the checksum automatically (`lofi_image.compute_checksum`); `--checksum keep` preserves the old value. `analysis/solve_ckseed.py` re-derives the seed constant from any stock image (GF(2) solve, expect `C27C6282`). ## Notes - Public ZIPs ship only the SYSTEM section; BOOT/PRESET/MCU use separate files. - Only same-length string/asset/constant edits keep every address stable (Level-0). Longer content needs slack-space pointer patching (`lofi_xref.py`). - The AT32 USB MCU updates through `updateMCUSection` — protocol unreversed; leave MCU sections alone.