6.4 KiB
Lofi-12 XT — Findings Library
Living knowledge base for this device. Process/tips live in RE-PROCESS.md.
Per-version firmware notes: Lofi-12XT_v*/…/reversed.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, silkscreenIC300/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 withCN201A/CN200A/CN203A/CN203Bboard-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 keepinlofi_pack.pypreserves).- Proof: GF(2) linear solve per image for the 32 unknown bits at
[8:12]givesK = 0xC27C6282on all three images independently (2⁻⁶⁴ fluke); forward recompute reproducesF58AF539 / DFF0D8C2 / B17C0857;unpack→packrebuilds stock v1.5.205 byte-identical; aThreshold→ThresholXmod forges to a self-consistent462F735B. - Code anchors (bootloader DSP): CRC routine
C70A0A60(NOT A6→state, polyEDB88320viaMVK/MVKH, byte loop, finalNOTin delay slot ≡ zlib chainingF(buf,len,init)); 4K-chunk callerC708E4E4(MVK 0x1000,CMPGT,CALLP C70A0A60); check fnC709E7C0(16-byte header CRC init 0 → chained 0x40000 chunks →CMPEQ A13,A12compare); orchestratorC708678C CALLP C709E7C0, reject path buildsERROR : 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+0x08flags 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).