# QuNexus firmware v2.2.1 — reverse-engineered source Disassembly and pseudo-decompilation of the Keith McMillen / KESUMO QuNexus application firmware (EFM8UB20F64G, an 8051-core MCU), produced with radare2. This is a **nested git repository** (its own repo, living under the parent `qunexus-qt6` project). It is self-contained: the stock input binary is included so every artifact here can be regenerated with one command. ## Input | File | What | |---|---| | `QuNexus_Firmware_v2.2.1.bin` | stock v2.2.1 application image, flat binary, base `0x2400`, 54 279 bytes, spans `0x2400`–`0xF806`. (The bootloader region `0x0000`–`0x23FF` is not in this image and is not decompiled here.) | ## Generated artifacts | File | What | Lines | |---|---|---| | `qunexus_v2.2.1.asm` | **Full linear disassembly** of the whole image, absolute code-space addresses (`0x2400`+), with xrefs & comments. Nothing omitted. | 37 287 | | `pseudocode_all.c` | r2 `pdc` C-like **pseudocode for all 1002 functions**. 668 complete; 334 end with `// chop` (r2's size limit on big functions — see those in the asm). | 38 396 | | `functions.txt` | r2 function index: `address size nblocks name` — 1002 functions. | 1 002 | ## Reproduce ``` brew install radare2 # one-time ./regen.sh # rebuilds the three artifacts from the .bin ``` `regen.sh` runs `r2 -a 8051 -b 8 -m 0x2400 -i r2script.r2 QuNexus_Firmware_v2.2.1.bin`. `r2script.r2` is the exact radare2 script used. ## Faithfulness — does it re-compile? The disassembly is **byte-faithful**: reconstructing the binary from the asm's byte columns (30 560 instructions + 195 small data gaps) reproduces the original 54 279-byte image **byte-for-byte**. So the listing is a complete, accurate representation — nothing lost or corrupted. The r2 `.asm` file is **not** directly valid input to an 8051 assembler (it is r2 display format: function borders, xref comments, `fcn.xxxx` labels, address prefixes). To re-assemble into a flashable binary it must be converted to a real assembler's syntax (e.g. `sdas8051` from SDCC, or Keil A51): strip r2 annotations, turn `ljmp`/`lcall` targets into labels, emit the 195 data gaps as `.db`, and set `.org 0x2400`. With that conversion it re-assembles to the identical binary. (Round-trip via SDCC is the natural next step if needed.) ## Known landmarks (verified in the output) | Address | Meaning | |---|---| | `0x2400` | app reset vector (`ljmp 0xb691`) | | `0xA57B` | USB-MIDI router: cable number → destination ring buffer | | `0xDF05` | USB-MIDI event dispatcher | | `0xDF28` | `LCALL 0xA57B` — the single call site the USB-1→CV patch retargets | | `0x8126` | 23-byte `0xFF` padding region the patch's stub is written into | | `0xE8E6` | `LJMP 0x0000` — the only bootloader-entry jump | | `0xB48D` | SysEx command handler (bootloader-entry path) | ## Caveats - r2's 8051 auto-analysis is decent but imperfect: data-in-code regions decode as the matching instruction (a linear-sweep artifact). Use `ljmp`/`lcall`/ `acall` targets and `functions.txt` as the map of real code. - `pdc` chops ~1/3 of functions (the big ones). The asm listing covers them fully. For unchopped Ghidra-quality pseudocode, the `r2ghidra` plugin (`r2pm install r2ghidra`, then `pdg @ func`) is the upgrade path. ## Provenance Decompiled 2026-08-17 from the stock `QuNexus_Firmware_v2.2.1.bin` (the same image shipped in the qunexus-qt6 editor's Qt resources as `QuNexus_Firmware_v2.2.1-cs512.syx`). The reverse-engineering was done in service of a USB-1→CV routing patch (see `../patch_usb1_to_cv.py` and `../c2probe/`); this repo captures the reference disassembly of the unmodified firmware.