Firmware Robustness & ROM Archival
Firmware Robustness & ROM Archival
Two questions about the KN7000’s main‑CPU firmware, answered by static reverse engineering of the program ROM:
- Can data from outside the instrument make the CPU run code? — the expansion connector and the SD card are the two places an outside party supplies bytes. Could either one seat a ROM, or a crafted file, that the firmware would execute?
- Can the instrument non‑destructively archive its own firmware? — some KN7000 units carry an undocumented earlier program‑ROM revision that deserves preservation. What can the machine’s own diagnostics tell us, and hand us, without desoldering a chip?
The short answers: no, external data cannot run code on the KN7000 (by construction, on both surfaces); and the instrument can identify its firmware revision non‑destructively but cannot hand over its contents — a full dump needs a hardware read or a code‑execution route. The detail is below. All of it is ordinary preservation reverse engineering; nothing here is an attack recipe, and the one memory‑safety wrinkle it turns up is something a faithful emulator should reproduce, not fix.
1. The two external surfaces, and the pattern that closes the door
Bytes reach the KN7000 from outside through exactly two channels:
- the CN106 expansion connector (the SY‑EW wave bus / SOUND‑RAM windows — see Expansion Bus & Wave‑ROM Dump), and
- the SD card (and its sibling floppy — see Storage & File System).
Both are handled by the same shape of code, and it is that shape that makes code execution impossible. The firmware never takes an address from the data and jumps to it. Instead it matches the data against fixed tables to derive a small bounded index, and calls a fixed handler baked into the ROM. The outside bytes choose which of a fixed set of routines runs; they never supply the routine’s address.
For the SD card this is the disk‑file dispatcher at 0x4852B6B0: it matches a file’s tag/extension
against the string tables DiskFileTagTable (0x48664090) and DiskFileExtTable (0x48664438),
turns the match into an index (asl 3 / mulu 0xc), and calls a fixed PC‑relative handler. A scan of
the whole dispatcher finds zero register‑indirect calls or jumps that take their target from file
data. The expansion connector’s board‑probe path has the identical property.
2. The expansion connector — a capability that was removed
The older SX‑KN6000 / KN6500 firmware did have a way for an expansion board to run code: a routine
that memory‑compares an XAPR signature on the board window and then calls vectors read from the
board. On the KN7000, that facility was excised. The only trace left is a dead checksum stub at
0x4849FD9E that nothing reaches. The XAPR and HD‑SX3 markers that look like support on the
KN7000 are shared‑codebase residue — the KN2400, which has no expansion connector at all, shows the
same singletons.
Three independent reverse‑engineering passes (~0.97 confidence) confirmed there is no native
code‑execution vector and no memory‑corruption path to the program counter from the expansion
board. What a malformed board can do is bounded to an arbitrary read (information disclosure back
into the instrument) and a denial of service (a hang/crash). Board content that the firmware does
copy lands in fixed work‑RAM buffers (the copy base is a compile‑time constant, *(0x501496B8) =
0x840327E8), never a pointer that is later called.
3. SD media — seven parsers, five clean, two that overflow
Every SD file format was reverse‑engineered and classified on two axes: does any file byte become a control‑transfer target or store base (control‑flow), and is any copy sized by a file‑supplied number into an unbounded buffer (memory‑safety)?
| Format (extension) | Control‑flow | Memory‑safety | Notes |
|---|---|---|---|
.AST custom data (zlib) |
fixed‑table | safe | zlib 1.0.4 streaming inflate into a fixed scratch cap, then a fixed flash region; the claimed decompressed size is range‑checked, never trusted as a copy count |
SMF .MID / .SEQ / .SQF |
fixed‑table | safe | table‑driven MIDI state machine; SysEx/meta lengths streamed‑and‑discarded, not trusted to size a copy |
.ACT demo script |
fixed‑table | safe | a text/markup interpreter dispatched through a fixed handler table keyed by a string‑matched token |
.FAV / .MD / .HMP → SRAM |
fixed‑table | safe | compile‑time‑fixed byte counts into fixed SRAM; no file‑supplied count governs any copy |
| SD µ‑COM transport | fixed‑table | safe | every SD byte consumed as data; no execute‑from‑SD, no SD firmware update; the runtime library loads from program flash, not the card |
.JPG (JFIF/JPEG) |
fixed‑table | ⚠ unbounded write | §3.1 |
.HMP embedded BMP |
fixed‑table | ⚠ unbounded write | §3.2 |
There is no execute‑from‑SD path of any kind — no overlay loader, no plug‑in, no firmware update from the card. Five of the seven parsers are also cleanly bounded. The two exceptions are the image decoders, and they fail the same way.
3.1 JPEG
.JPG is a genuine SD file type (the picture/wallpaper feature). The SOF0 marker parser reads the
declared height and width and checks only that they are positive — it never compares them against
the fixed 640×240 display plane (0x500D4080 / 0x500F9880) they are about to fill, and it
decodes before it asks how big the image is. The pixel writer computes its destination as
base + (y_origin + row)·640 + x_origin + col with no clamp against the plane. A well‑formed JPEG
declaring, say, 640×480 is decoded at full size and the writer walks off the bottom of the buffer,
laying file‑derived pixels into the RAM that follows.
3.2 BMP
The BMP header validation is otherwise careful (signature, header size, bit depth, compression,
palette) but never validates the width. Height is clipped to the 240 rows; width is not. Each row
is copied with a length taken straight from the file into a buffer with a fixed 640‑pixel stride, so a
wide enough BMP overruns it. Because the home‑page code centres the picture with
X = (screen − width)/2, an oversized width wraps X to a huge unsigned value and the destination
wanders.
3.3 What it is — and what it is not
In both cases control‑flow stays safe: the file controls the length and offset of a write, not a pointer that is loaded and called. This is memory corruption, not a jump to attacker code — and whether it could be steered all the way to the program counter is unproven (the writes land in work RAM ahead of the display plane, not on the stack). It is the same open residual the expansion board leaves.
For emulation this is reassuring rather than alarming: MAME runs the instrument’s real decoder on the real CPU core over RAM the memory map keeps bounded, so the host is never wild‑written and the emulated instrument corrupts its own RAM exactly as hardware would. Faithfulness means not adding the bounds check the firmware never had.
4. Archiving the firmware — what the instrument will and won’t give up
The second question is preservation: a KN7000 with an undocumented early program‑ROM revision. The firmware’s own diagnostics were mapped to see how far they get.
4.1 It tells you its version (the easy, zero‑risk win)
The KN7000 has a built‑in SOFTWARE VERSION screen. Each firmware component prints a decimal number
via a %4d format string — PROGRAM : %4d (0x485D67E0), TABLE : %4d, RHYTHM : %4d,
PICTURE : %4d, under the header --- SOFTWARE VERSION --- (0x485D5D9C). The PROGRAM number is a
single 16‑bit build stamp read straight out of program flash:
mov (0x4873660C), d0 ; the PROGRAM build stamp, in flash at file offset 0x33660C
movhu d0, (0x50007DC4) ; -> formatted as "PROGRAM : %4d"
In the reference firmware image this cell reads 941 (0x03AD, verified). An earlier revision will
show a smaller integer — and that integer is the revision identifier. The owner opens the Version
screen and reads it off the LCD; no tools, no risk, no disassembly. Once a unit is dumped by any means,
the same u16 at the equivalent of 0x4873660C re‑identifies the build.
This has already found an unpreserved firmware: a real instrument reports PROGRAM : 893
and TABLE : 80. For where each of the four numbers comes from — only PROGRAM is a
compiled-in constant; TABLE, RHYTHM and PICTURE are parsed as ASCII decimal out of their
own flash devices — see the SOFT VERSION screen.
4.2 The ROM device test checks integrity, but shows no fingerprint
Service diagnostic §8.1 “ROM device test” (MainRomTestFunc 0x4849FDF8, reached by holding
C#3 + D#3 + C#4 at power‑on, then PAGE to the item and EXECUTE) sweeps the full 8 MB flash
window 0x48000000–0x487FFFFF — table ROM plus the program flash (IC16) — as interleaved halfwords,
accumulating two 32‑bit additive sums. But it runs the sweep twice and compares the two sums for
self‑consistency (its golden‑value seed table is all zeros in this build), and reports only OK / NG
on the LCD. No number is shown; the sums are discarded. So the test confirms the flash reads back
cleanly but cannot fingerprint a revision on‑screen. Usefully, its algorithm is now fully
specified, so a unique fingerprint can be computed offline from any dump: two 32‑bit additive
halfword sums over 0x48000000–0x487FFFFF.
4.3 No firmware‑mediated byte dump exists
The decisive negative: no KN7000 diagnostic ever emits program‑flash bytes to MIDI, serial, or disk. The ROM test posts only UI OK/NG events; the firmware‑update path is strictly write‑only (disk → flash); and there is no CPU‑observable program‑flash read port analogous to the tone‑generator wave‑ROM read port that made the wave ROMs dumpable. The firmware can identify the revision but not reproduce it.
4.4 So how do you get the contents?
| Route | Non‑destructive? | Status |
|---|---|---|
| SOFTWARE VERSION screen | yes — read PROGRAM : NNNN off the LCD |
✅ identifies the revision now, zero risk |
| §8.1 ROM device test | yes — OK/NG integrity | ✅ confirms the flash reads cleanly |
| In‑circuit clip read of IC16 (CPU held in reset) | yes — reading doesn’t modify the chip | pragmatic path to full contents; extends the ROM‑dumping roadmap |
| Video capture of the MEMORY DUMP screen | yes — the viewer cannot write and cannot export; it only paints | 99.87 % byte‑exact in emulation; refuses every real composite frame so far. ~50 min of held button per 4 MB. No hardware capture has been attempted |
| Photographing the MEMORY DUMP screen | yes | done, partially: 37 screenfuls = 9,472 bytes of build 893 transcribed by hand. ~16,000 photographs would be needed for a whole chip, so this is a calibration method, not an archival one |
| Code‑execution dumper (CPU runs a small flash reader → observable port) | yes | the only firmware‑only route to full contents; uncertain — no proven corruption→PC path exists |
| Desolder + programmer | no (risks the part) | the route this whole investigation exists to avoid |
The first step costs nothing and should be done first: photograph the Version screen and record the §8.1 result. The full dump then follows by clip read (recommended) or, if a path is ever found, by a firmware‑only dumper.
A third route now exists on paper and is measured in emulation but has never met hardware: the instrument cannot export bytes, but it can display them, and the rear composite VIDEO OUT carries whatever the hidden hex viewer shows. See Reading ROM out of the screen. And 9,472 bytes of build 893 have already been recovered the slow way, by transcribing photographs of that screen — Recovering build 893.
4.5 Where does the flash updater live? (unresolved)
The KN7000 unquestionably has a flash updater — holding PANEL MEMORY 1+2+3+4 at power‑on enters Flash Memory Update, and the public update disks work. The question is which device the updater code sits in, because that device is the one place a program‑flash update cannot erase, and it is therefore where a rescue or dump routine would have to be found.
This section replaces
rom-backup-and-update-format.md§2.2, which is refuted. That section concluded the resident updater lives in the un‑dumped top0x90FFof the program flash (0x487F6F01–0x487FFFFF). It does not.
What killed it. An owner hardware read on 2026‑08‑09, via the instrument’s own
MEMORY DUMP screen on a PROGRAM 893 machine:
0x487F55CF–0x487FFFFF is one unbroken block of 0xFF, with code immediately below it. A
factory‑programmed resident block would be build‑independent, so that null applies to build 941 too.
| Hypothesis | Verdict |
|---|---|
H1 — a resident block in the top 0x90FF of program flash |
REFUTED (the region is erased on real hardware) |
| H2 — the update writes the payload and leaves the rest erased | SUPPORTED — but it describes the payload, and says nothing about where the machinery lives |
| H3 — the updater is somewhere in the dumped 8 MB, unidentified | REFUTED for uncompressed forms |
| H4 — the updater is loaded from the update floppy | REFUTED for the disks we hold |
| H5 — the updater is in another device | SUPPORTED — the only survivor; which device is undecided |
The cross‑reference evidence behind §2.2 was a byte‑misframing artifact. It rested partly on “33
dword cross‑references into 0x487Fxxxx, several past the dump end”. Two independent kills:
- Noise floor. Scanning 4,157,185 unaligned positions for a 37,119‑byte window has an expected random yield of ~36 hits. The scan finds 12 — below chance.
- Mechanism identified. At
0x485D6860there is an 8‑byte‑record{u32 id, u32 handler}table. Every real pointer in it (0x48487E00,0x48487FA7,0x48487FBC,0x48487FEA,0x48487E60) is inside the dumped image. Read three bytes early, they become the phantoms0x487FA700,0x487FBC00and0x487FEA00×6 — and the “individually improbable” six‑fold repeat is simply one default handler slot occurring six times.
An opcode‑anchored imm32 scan (28,000+ sites) finds zero references into
0x487F6F01–0x48800000, and a linear disassembly of 0x48400000–0x4858FFFF yielding 128,781
branch targets finds zero real branches above 0x487F6F00.
H3 was tested four ways, each with a measured control. The AMD unlock idiom scores 4 hits in the
program image and 1 in the table image, while three control constant pairs with comparable load
counts score 0/0/0 in both — and the only real flash driver in the whole 8 MB is
0x4847E7C0–0x4847FB96, hardwired to absolute 0x9680AAAA / 0x96805554 — that is the KN7000’s
custom‑data flash IC21, not IC16/IC17. Command sequences
stored as data tables: 0 hits in the KN7000 program image, 0 in the table image, 0 in the KN5000
program image. The uncached write alias (proven by the firmware’s own boot, which writes work RAM
through 0x90000000) puts the program flash’s command window at 0x88400000 — and imm32 loads
with high byte 0x88 number zero in both images. A per‑64 KB code‑density map shows the table
half contains no MN10300 code at all (max 1 hit per 64 KB across 63 blocks, versus 103–970 in program
code blocks), where a relocatable blob would spike.
Stated honestly: a packed or compressed updater cannot be excluded by any of those tests. Nothing supports one, and the KN5000 analogue is not packed.
The KN5000 template says where to look. De‑interleaving the KN5000’s table‑data ROM pair gives, at
CPU 0x9FA000, the update‑disk signature records (Technics KN5000 Program DATA FILE 1/2, …) in a
block running 0x9FA000–0x9FFFCF — the top 0x6000 of the 2 MB table‑data mask ROM — with a
real flash driver inside it and its own interrupt vector table at 0x9FFF00. Decisively, the KN5000’s
resident firmware cannot write its own program flash either. The updater lives in a device no
update can erase. That is the pattern to look for on the KN7000.
Where the KN7000’s positional analogue is. IC16 + IC17 are one 8 MB pair spanning
0x48000000–0x487FFFFF — 21 address lines (A2–A22) on a 32‑bit bus, corroborated by the
firmware’s own §8.1 ROM test at 0x4849FC54 sweeping 0x200000 iterations of a 4‑byte stride under
the row PROGRAM ROM: IC16 = , IC17 = . So the “table ROM” is the lower half of the same flash
pair, and there is no unread upper half at 0x48800000. That leaves exactly one never‑read region:
★ The unread hole:
0x483E94D4–0x483FFFFF(93,484 bytes)The top of the lower half, immediately above where our table image ends (
kn7000_table.romis0x3E94D4bytes). It is the exact positional analogue of the KN5000’s0x9FA000. Probe0x483FFF00first.
| # | Address to dial | Why | What would be interesting |
|---|---|---|---|
| 1 | 0x483FFF00 |
top of the lower half; the KN5000 positional analogue; the only unread part of the 8 MB | dense code, a vector table, or ASCII signature records — or 0xFF |
| 2 | 0x40000000 |
IC18 rhythm window; the firmware’s prober strncmps Technics Rhythms at region_base+0x10000, so the first 64 KB is not rhythm data |
anything non‑0xFF means a device is there |
| 3 | 0x97800000 |
IC19 picture ROM (64 Mbit mask): no update disk targets it, so it survives every flash operation by construction — exactly the KN5000 property | graphics data, or better |
| 4 | 0x97FFFF00 |
top of IC19 — the KN5000 template position translated | code / vectors / 0xFF / a mirror of probe 3 |
| 5 | 0x483E9400 |
bounds the hole from below on a build‑80 table | our build 84 ends at 0x483E94D3 |
Size: unknown. We cannot yet say the updater exists in any reachable flash. For scale, the
KN5000’s analogous block is 0x6000 = 24,576 bytes ≈ 96 screenfuls at 256 bytes per screen.
⚠ Do not dial
0x88400000. The+0x40000000uncached‑alias convention is real, so that is the program flash’s command window, and the viewer repaints the address it is parked on.⚠ If probe 1 shows real content, do not run a TABLE update on that instrument until the region is dumped — the table payload ends at
0x483E94D3and erase‑sector geometry may take the block with it.★ A preservation risk found on the way: the shipped firmware can erase and fully rewrite the 2 MB custom‑data flash IC21 —
0x4847FB68is a whole‑chip programmer.⚠ Do not re‑run raw byte‑pattern searches for addresses in
0x487Fxxxx/0x483Fxxxxwithout computing a noise floor first. That is the error this section corrects.
Sources & related pages
- SOFT VERSION Screen · MEMORY DUMP Screen
- Recovering build 893 · Reading ROM out of the screen
- Program‑ROM Clip Read (IC16/IC17)
- ROM Dumping Roadmap · Wave‑ROM Dump Tutorial
- Expansion Bus & Wave‑ROM Dump · Storage & File System
- Findings notes (project repo):
FINDINGS-expansion-buses-and-code-exec.md,FINDINGS-sd-media-codeexec-and-parsers.md,FINDINGS-program-rom-version-and-dump-paths.md,FINDINGS-updater-location-2026-08-09.md.
This page is preservation reverse engineering of hardware the project maintains. The memory‑safety observations are documented so that emulation stays faithful; they are not exploitation instructions.