Files
Dejvino 1eb6ba6b9f Review must-fix: LICENSE, dangling ref, obsolete markers
- LICENSE (MIT, own work) + README license section
- FINDINGS.md per-version notes point into docs/firmware/
- checksum brute-forcers marked superseded (code + tool docs)
2026-09-30 22:52:21 +02:00

122 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lofi-12 XT — Findings Library
Living knowledge base for this device. Process/tips live in `RE-PROCESS.md`.
Per-version structural notes: `docs/firmware/notes-v{1.1.156,1.2.179,1.5.205}.md`; version diff: `rev-diff.md`;
mod feasibility: `tweakability-report.md`; tool docs: `tools/README.md`.
Deep dives: `docs/hardware.md`, `docs/bootloader.md`, `docs/firmware-update.md`,
`docs/firmware/v1.5.205.md`.
## 1. Hardware
- Device: Sonicware Lofi-12 XT (shares platform with SmplTrek/Cydrums).
- Main SoC (core module): **TI TMS320C6748** — ARM9 + C674x DSP. Marking on unit:
`TMS320 C6748EZW T / 13CP99W / GI 375 / 527 ZWT`.
- DRAM (core module): **EtronTech EM68C16CWQG-25H** — 1 Gbit DDR2, base `0xC0000000`.
- SPI flash (core module, 2×): **Macronix MX25L12833F** (`MXIC MX 25L12833F M2I-10G`),
16 MByte each, SOIC-8, silkscreen `IC300` / `IC301`. Shipping units hide the
marking under small stickers (`C047`/`C949`-style labels) — peel + photo to confirm.
- USB/aux MCU (main board): **ARTERY AT32F421K8T** (own firmware, out of scope).
- Storage: full-size SD slot (firmware update + samples/projects).
- PCBs seen: `405-VTOR-3852` (I/O), `405-VTOR-3849B` (main), `405-VTOR-3853` (jack),
core module with `CN201A/CN200A/CN203A/CN203B` board-to-board connectors.
- Silkscreen pin tables on main board expose `UART1_RX1/TX1`, `SPI1_SCK/MOSI`,
`SD_*`, `USB_DP/DN`, key/LED matrix — worth mapping before any invasive work.
## 2. Memory map (DDR2)
| Region | Content |
|---|---|
| `0xC0000000…` | DDR2 base (128 MB) |
| `0xC2xxxxxx` | SD `.bin` application image (DSP). v1.5 code `C2B80C00`, strings `C2D84DE0`, assets `C2DA7600` |
| `0xC7074630–C70B0598` | SPI AIS bootloader image (DSP), entry `C70A28A0` |
| `0xC706F280` | Runtime constant seen in updater (also == checksum seed, §5) |
| `0xC27C6282` | Scratch DDR used by updater (§5; value doubles as checksum seed) |
## 3. SPI flash layout (`ic300.bin` / `ic301.bin`, 16 MiB each)
Dumps: `ic300.bin` (`c2b86808…`), `ic301.bin` (`81f7b1f5…`). Always keep these
as recovery backups; re-verify with a second read (`sha256sum` + `cmp`).
**IC300 (boot + app):** TI AIS image, magic `0x41504954` (`TIPA`) at file `0x0`.
PLL/DDR config (`0x5853590D` ×2), then 10× Section Load (`0x58535901`):
| File off | DDR | Size |
|---|---|---|
| `0x000050` | `C7074630` | `0x1D0` |
| `0x00022C` | `C7074800` | `0x33B00` (main code) |
| `0x033D38` | `C70A8300` | `0x28CC` (rodata) |
| … | `C70AABD0`/`C70AABE0`/`C70AABF0` | `0xC`/`0xC`/`0xD44` |
| … | `C70AF000`/`C70AF4E8`/`C70AF5EC`/`C70AF660` | `0x200`/`0x104`/`0x70`/`0xF38` |
`JumpClose (0x58535906)` at file `0x38660` → entry `C70A28A0` (DSP reset prelude
`ZERO b0; mvc b0,ier; mvc b0,csr`). After it: `FF` gap to `~0x100000`, data to
`~0x1EFFFF`, `FF` gap `0x1F–0x4Fxxxx`, data `0x500000–0xFC7C17`. No AIS CRC opcodes.
**IC301 (data):** `AILS` header + drum-pattern names (`KICK/HIHAT/BALLAD/BLUES/…`),
24× `RIFF/WAVE` starting `0x8007E0`, nearly full to `0xFFFD7B`. Factory-sample flash.
**Update path (from updater strings + code):** `SystemUpdater::{start,
updateBootSection, updateMainSection, updatePresetSection, updateMCUSection,
updateMCUBootSection}(CatMetaData::ROMSection)` + `SystemVerify::verifyPresetSection`.
Public ZIPs ship only the SYSTEM section (the SD `.bin`); BOOT/PRESET/MCU use
separate (unreleased) files. Updater lives in AIS flash, so a bad SYSTEM image
cannot kill recovery — hold PAD while powering on → `SYSTEM UPDATE` still works.
## 4. SD `.bin` container (`cmtd/mmtd/sect → EOF`)
| Off | Field |
|---|---|
| `0x00` | `cmtd` magic |
| `0x04` | u32 LE filesize (must match actual) |
| `0x08` | u32 checksum — **solved, §5** |
| `0x0C` | reserved 0 |
| `0x10–0x2F` | `12, 1, 3, fw_maj, fw_min, fw_patch, 48, remaining` |
| `0x30` | `mmtd` magic; `+0x04` remaining; `+0x08` flags (per-build, part of hash) |
| `0x40` | fw triple; `0x4C` entry point; `0x50` sect count |
| `0x54…` | `sect` ×N: `73 65 63 74` + u32 load_addr + u32 len + payload; must tile EOF |
Known builds: v1.1.156 (1,595,605 B, entry `C26C4820`, 7 sects), v1.2.179
(1,606,197 B, entry `C26CA4C0`, 6 sects), v1.5.205 (1,707,049 B, entry
`C2CD1AA0`, 7 sects). Code is C674x LE, entropy ~6.89, unencrypted. Parser/packer:
`tools/lofi_image.py` (`parse_image` asserts filesize + chain fit).
## 5. Checksum (SOLVED)
**Rule:** `cmtd+0x08` = CRC32-IEEE (init 0) over the entire file with bytes
`[8:12]` replaced by `0xC27C6282`.
- `tools/lofi_image.py`: `CKSEED = 0xC27C6282`, `compute_checksum()`; `build_image()`
auto-computes by default (`--checksum keep` in `lofi_pack.py` preserves).
- Proof: GF(2) linear solve per image for the 32 unknown bits at `[8:12]` gives
`K = 0xC27C6282` on **all three** images independently (2⁻⁶⁴ fluke); forward
recompute reproduces `F58AF539 / DFF0D8C2 / B17C0857`; `unpack→pack` rebuilds
stock v1.5.205 byte-identical; a `Threshold→ThresholX` mod forges to a
self-consistent `462F735B`.
- Code anchors (bootloader DSP): CRC routine `C70A0A60`
(`NOT A6→state`, poly `EDB88320` via `MVK/MVKH`, byte loop, final `NOT` in delay
slot ≡ zlib chaining `F(buf,len,init)`); 4K-chunk caller `C708E4E4`
(`MVK 0x1000`, `CMPGT`, `CALLP C70A0A60`); check fn `C709E7C0`
(16-byte header CRC init 0 → chained 0x40000 chunks → `CMPEQ A13,A12` compare);
orchestrator `C708678C CALLP C709E7C0`, reject path builds
`ERROR : This file is invalid.` (`C70A8E82`).
- Forging: build image normally, then set `[8:12] = compute_checksum(image)`.
## 6. OLED / updater UI strings (orientation)
`Checking... 0%`, `Check the firmware file.`, `ERROR : This file is invalid.`,
`Erasing.../Writing.../Verifying... 0%`, `100%, done./OK./NG.`,
`Update completed./Update failed.`, `Please restart.`, `Are you sure?`,
`[CLR] : No / [OK] : Yes`, `>> BOOT/MCU/MCU Boot/PRESET/SYSTEM`,
`BOOT:/MCU:/MCU Boot:/PRESET:/SYSTEM:`, `$ systemupdate`, `[Lofi-12 XT] ~`,
`SYSTEM INFO/VERSION/BOOT/SYSTEM/MCU`, crash dumper (`Legacy NMI Exception`,
`A0–A31/B0–B31`, `NTSR/ITSR/…`). v1.5-only markers: `AppAudioExport*`,
`MIsolator/MRackComp/SlipRoll/HoldDelay`, `MIDINoteMap`, `REVERSE`,
`removeResourceFork` (all present in IC300 → board runs v1.5).
## 7. Open questions
- `mmtd+0x08` flags semantics (timestamp? covered by checksum as-is, no need to crack).
- Exact flash section table for BOOT/PRESET/MCU offsets (only SYSTEM reverse-engineered).
- AT32F421 firmware extraction/update protocol.
- UART/JTAG test-point mapping (silkscreen names exist, continuity not traced).