Platform index / Digital mixing console
Yamaha DM7
Not one console CPU but a small cluster of identical i.MX8M Mini computers running one Linux rootfs in four roles — and the only platform here that ships its entire mixer parameter model as plain XML.
The load-bearing finding. app/Descriptor/mms_*.xml — 27 files, 1,701 collections, 2,693 parameters — declares every parameter's C type, array dimension, minimum, maximum, default and step, and every collection's packed datasize. That describes the console's binary state layout, not merely its parameter names, and it ships in a downloadable update. The audio itself is off-CPU on Yamaha SSP3 DSPs and a SHARC, exactly as the QL's was.
Verdict. The audio is off-CPU on Yamaha SSP3 DSPs and a SHARC, so this is no more a rehosting target than the SQ-5 or the HD96. What is different is everything above the DSP boundary: where the HD96 documents itself in Thrift and Protobuf, the DM7 hands over a typed, dimensioned, byte-sized schema of its entire mixer state as XML in a public update. This is a console to interoperate with, and almost all of that work can be done before touching one.
Method
Static analysis of the public firmware image DM7_firmware_V1.75.bin (release V1.75, main system R1.02): a walk of the container format, extraction of the Linux root filesystem and console application, a C++ RTTI type-name census of the stripped application binary, and disassembly of a small number of functions. No hardware was involved and no console was opened.
Artifacts examined
DM7_firmware_V1.75.bin— 174,392,092 bytes, 23 members, format#YAMAHA MBDFArchiveapp_console.tar.xzV1.75 — the console application: three role binaries, 67 plugin.so, 27 XML descriptorsrootfs-DM7-2026-01-29-…tar.xzR1.02 — the arm64 Linux root filesystemDOM4.2.8.7 — a nested#YAMAHA MBDFArchivecarrying its own kernel, initramfs,dom.dtband three Xilinx bitstreamsinstaller/install_scriptR0.20 — the update procedure, in plain bash- DM7 Editor — 27 parameter descriptors and 303
.dm7ppresets shipped with the free editor. No factory scenes: this is the one model in the family whose console-wide state file has not been read
No manufacturer firmware, binaries or documentation are redistributed here. Artifacts are referenced by name and version only. See the method and legal statement for the basis on which this analysis was performed and the boundaries it observes.
Hardware architecture
| Item | Finding | Confidence |
|---|---|---|
| Application processor | NXP i.MX8M Mini (fsl-imx8mm), arm64 Cortex-A53 — from the device trees, /etc/os-release and /boot/imx-boot-eMMC_dm7_20231128.bin | Verified |
| System topology | Four board roles boot from one root filesystem, selected by device tree: main, bay, ctrl (the CTL-DM7 surface) and main-jig (a factory test rig). A DM7 is a cluster of identical i.MX computers, not one CPU with peripherals | Verified |
| Mixing DSP | 2 × Yamaha SSP3 at IC120 and IC123, plus a third for USB audio at IC136/IC124. The application's own factory-diagnostic strings print the board reference designators and BGA ball coordinates | Verified |
| Effects DSP | Analog Devices ADSP-21469 SHARC, over SPI, on the NAIO board — the symbol CspiNaio21469SharcController names transport, board and part in one string. More than one is present (SHARC#%d, kernel [dspNo]) | Verified |
| FPGAs and CPLDs | PUBe and PY64-MD are Xilinx 7-series bitstreams; NAB is an Altera .rpd and NAB_L a Lattice ECP5 .bit at the same version V0.33c; HIC, HIC_L and FDC are JAM STAPL JTAG programming streams. Each identified from its own magic bytes | Verified |
| Xilinx parts, by name | The two 7-series members name their own devices in the bitstream's IDCODE configuration packet: PUBe is an XC7A35T (0x0362D093, 3,330 configured frames) and PY64-MD an XC7A100T (0x03631093, 7,464 frames). Both are Vivado-compressed — they carry multi-frame-write packets, which a frame reader that ignores MFWR will silently mis-expand | Verified |
| Second-sourced silicon | The _L members are the same board in different fabric — NAB/NAB_L share V0.33c and HIC/HIC_L pair the same way, with the console programming whichever it finds. The contemporaneous Behringer X32 image carries the same Xilinx/Lattice pairing, so a second-source bitstream is itself a fingerprint of a 2021–2023 respin | Inferred |
| Dante subsystem (DOM) | A second computer, not a chip: Xilinx Zynq-7000, dual Cortex-A9, 512 MB, Micron n25q512a QSPI boot flash, two Cadence GEM MACs for Dante primary/secondary, running its own Linux. From the decompiled dom.dtb, model = "YAMAHA DOM". The part is XC7Z020 in the clg484 package — its three bitstreams are stock .bit files, so they carry Vivado's own header naming the part 7z020clg484, the top-level design khaju_hc_top, the toolchain 2019.2 and a build date of 2025/07/18, the three SRC variants differing only by build minute. That is the same device as the SQ-5 mixes on, doing an entirely different job | Verified |
| Dante bridge fabric | A custom Yamaha FPGA IP block in the DOM's programmable logic, compatible = "xlnx,akashi" at 0x60000000, with interrupts named ts/rx/tx/rxerr/smi and rx_act/meter/rx_ka/daif. Three shipped bitstream variants (noSRC, syncSRC, asyncSRC) select the sample-rate-conversion mode | Verified |
| Microcontrollers | Seven ARM Cortex-M images — JK (AES I/O), P-U2S2, P-MD2, P-HR1, P-FDC2 (panel boards), PY-MIDI-GPI (slot card) and USB2HOST — each identified from its vector table. Two SRAM bases appear (0x2000_0000 and 0x1000_0000), so at least two MCU families are in use. USB2HOST is filed as DSP_V105.bin but is a 3.8 MB Cortex-M image, not DSP code | Verified |
| Ethernet switch | Marvell 88E6352 managed switch, configured from userspace — the application names 88E6352 PORT#0, PORT#5 and PORT#6, so at least three ports are software-visible | Verified |
| Internal networks | control on 192.168.53.100/24, the three expansion bays on 240.0.10.x/24, and Dante as a MACVLAN parent with its own MAC carrying dante0 and dante1. The bay links use IANA-reserved 240.0.0.0/4 space, which is a good fingerprint for telling console plumbing from console I/O in a capture | Verified |
Software architecture
| Item | Finding | Confidence |
|---|---|---|
| Operating system | NXP i.MX Release Distro 4.19-warrior, image ID=ymh-cpum-wayland (Yamaha CPU-M, Wayland), Linux 4.19, systemd, Weston and Qt, plus about ten yamaha-*.service units | Verified |
| Console application | app_console_{main,bay,ctrl}, arm64 ELF, stripped — unlike the DM3's, which ships with named functions. Retained build paths disclose the source tree: project codename hagoromo, internal framework Citrus, an OpenCV-linked AI core Trident, and a vendored shureacn | Verified |
| Parameter model | 27 mms_*.xml descriptors: 1,701 collections, 2,693 parameters, 6,572,842 bytes of declared datasize. Every parameter carries a C type and array dimension; numerics carry minimum, maximum, default and step; collections carry arraysize and the packed byte size of one instance | Verified |
| Control protocols | Three. Yamaha SCP (232 recovered types, the complete command set with client and server sides), a Yamaha OSC dialect addressed /yosc: (30 server commands, 12 notifications), and a vendored Shure ACN SDT/DMP stack for wireless microphone control with a Yamaha-written discovery supplement | Verified |
| SCP and YOSC are one model | YOSC is an OSC-shaped front end onto the SCP engine, not a second control model — every YOSC concept is a wrapper class over the SCP implementation of the same thing, and SCPMODE exists as a command in both. The competing reading, two independent engines, is unsupported: the type census contains no second parameter engine | Inferred |
| OSC address grammar | /yosc:%s/%s/ts: — the ts: segment is a path into the parameter tree whose names line up with the descriptor collections, and subscribe is a distinct verb, so the protocol is subscribe/notify rather than poll-only. The two %s fields are unresolved; a device or session identifier and a target name is inference from shape only | Inferred |
| Service ports | Not recovered, and possibly not constants. Only four bind call sites exist in 22 MB of .text because the application uses standalone Asio, and none yields a port; no port-shaped literal sits near any protocol symbol; the only mDNS service types in the binary are Audinate's. A YSDP class family — responder, listener and a per-host service list — is present, and its wire format is undetermined | Unknown |
| Plugin ABI | The same Perseus ABI as the QL. createPerseusPlugin_203 appears verbatim in both, the coefficient address format is unchanged in shape, and four Premium Rack plugins have byte-identical step/pmcoef/dmcoef profiles across the two consoles — the same algorithms across a decade and two CPU architectures | Verified |
| Console plugin linkage | 67 separate .so files under /yamaha/app/Plugins — 34 algorithms in GUI/DSP pairs — loaded at runtime, where the QL statically links its Premium Rack into the firmware image. All 34 DSP resource manifests were lifted statically from .rodata, with no host services involved | Verified |
| SHARC algorithm code | Not present anywhere in the image. Established by scanning all three application binaries, both Perseus libraries and every device member — 17 files, roughly 150 MB — for ADSP-214xx loader block chains, which finds none. There is also no NAIO firmware member in the update at all | Verified |
| Mixing coefficient layer | Mix1000DSP (213 recovered types) is the SSP3-side layer and names the whole mixer signal path, with array dimensions readable from its template arguments — 32 in-ports, 16 and 4 out-ports, a 20-tap port delay, a 32 × 8 port filter. It sits on a generic DspFramework whose class names are shared with the DM3 | Verified |
| Installer | Plain bash. For each member it compares a version file against the installed copy, deletes and re-copies on mismatch, runs an optional per-member hook to flash the device, repeats the procedure for each mounted bay, and returns early on a control-surface CPU. About a third of the script is a recovery branch for one shipped root-filesystem bug | Verified |
| Shared codebase with the DM3 | SystemSetting.ini is headed "DM3シリーズ本体用" — for the DM3 series. Its ApplicationType key enumerates firmware, fader_iqc, editor and emulator, so the same binary lineage runs off-console, and UseMMSExplorer names a built-in browser over the parameter tree that ships switched off | Verified |
| The shipped parameter model predicts the file layout | The XML above is not only a description of the running console — it is the decoder for what the console writes. The DM7's input-channel record is declared 1,785 bytes × 120, with a nine-byte input-patch field at offset 93 and the signal selector ahead of it: a different shape from the DM3 and TF pair, which put a patch field at offset 100 and differ from each other in its width. Same container across the family, different layout in every model | Verified |
| The one model whose declared size does not add up | Summing each collection's size × array length in document order gives 1,784 against a declared 1,785, so there is a padding byte somewhere in the record and its position is not stated. The DM3 and TF sum exactly, so a decoder written and tested against those two would never discover the discrepancy — it would simply read every DM7 field after the padding one byte early | Verified |
Update path & security model
| Item | Finding | Confidence |
|---|---|---|
| Image signing | None. Neither the container nor installer/install_script carries or checks a signature | Verified |
| Encryption | None — every one of the 23 member payloads is a zlib stream, and the two .tar.xz members are wrapped in zlib stored blocks so a reader can decompress unconditionally | Verified |
| Per-member integrity | None. There is no digest field per member and nothing to check a payload against; the only integrity-shaped field in the whole format is 20 bytes in the archive header | Verified |
| Archive header id | 20 bytes at offset 0x34. Not a SHA-1 of the image or of any obvious sub-range. Every nested archive carries its own and all four observed values begin 5601, which reads more like a version or type prefix than a pure digest | Unknown |
| Update validation | The installer validates nothing beyond comparing a version file, so a member whose version string is unchanged is not reinstalled even if its contents differ. This is a statement about the container and the installer only — whether the bootloader or the running application validates an image was not established | Verified |
| Plugin loading | The effect-plugin host authenticates nothing. There is exactly one dlopen call site in the whole application binary; the function that reaches it contains no hash, signature, certificate or filesystem-permission check, and the selection of what to load is a filename pattern rather than a name whitelist | Verified |
| Filesystem posture | The root filesystem is mounted read-only by a systemd hook; /yamaha is a separate writable partition, which is what the installer copies into and where the plugin directory lives. Whether any unprivileged or remote path can write there was not examined | Verified |
| Cryptography that is present | The binary's OpenSSL surface is real but belongs to the TLS/Dante paths and to an AES-256-CBC console-settings encryption path. None of it sits on the update or plugin paths | Inferred |
These rows describe how a platform validates a firmware image, because that is a structural fact about its architecture. They are not a vulnerability disclosure and no exploit, bypass or circumvention technique is published here. Licensing and entitlement mechanisms are out of scope throughout — seescope boundaries.
What is programmable
- 1An offline client against the shipped parameter model
The descriptors give types, ranges, array dimensions and packed sizes, so the state layout can be reconstructed and the
datasizearithmetic self-checks without hardware. The SCP and/yosc:command vocabularies are already recovered, which leaves only the transport blank — and the transport is a discovery protocol to be captured, not a port constant to be guessed. - 2The Perseus effect-plugin surface
Plugins are separate loadable objects here rather than statically linked as on the QL, and the load path performs no authentication. What that reaches is the host-side coefficient computation, the parameter model and the GUI — not proven custom SHARC execution, because the SHARC algorithm code is not in the image and a plugin ships coefficients to a kernel that is already resident.
extRAMis absent from all 34 manifests, so no shipping Yamaha plugin uses the SHARC's external SDRAM. - 3The mini-YGDAI (PY) slot
The same route the QL offers — custom processing in the audio path with no console modification — and the image confirms the slots carry their own Cortex-M firmware and, for PY64-MD, a Xilinx bitstream. The DM7's host-side slot interface was not examined, so this is the least investigated of the three.
Traps
Mistakes this analysis actually made, or came close to making. They are recorded because each one produces a plausible-looking wrong answer rather than an obvious failure.
- The container's section alignment is 4 bytes, not 2. A 2-byte assumption walks the first three sections correctly and then desynchronises at the
NABmember onto a plausible-looking wrong magic. Validate the walk by landing exactly on#END, never on the first few hops. var_lenis not the offset to the payload. It is the string-area length plus a constant 8, and the payload begins at the 4-byte-aligned end of the three NUL-terminated strings — a different number whenever those strings are not a multiple of 4. Parse the strings and align; do not do arithmetic on the field.- The payloads look like xz and are zlib. The two
.tar.xzmembers carry the xz magic a few bytes in, behind a zlib header wrapping a deflate stored block, so treating payloads as xz appears to work on exactly those members and fails on every genuinely compressed one. - Regex-scanning for the
#…section magics finds hits inside compressed payloads. The chain has to be walked from0x48, not pattern-matched. - The port hunt's near-misses are worse than its failures. Walking back from the
bindcall sites yields plausible port-shaped immediates — 4096, 3072, 25600 — which are byte-swaps of the small integers 16, 12 and 100. Reading any of them as a port number would have produced a confident, wrong, publishable answer.
Open questions
- The ports for SCP and
/yosc:are not recovered and may not be constants. The real target is theYSDPwire format, and a single broadcast capture from a console would settle it far more cheaply than more disassembly. - Whether anything outside the container validates an update. The container does not and the installer does not; the bootloader and the running application were not examined.
- Where the SHARC algorithm code lives. It is proven absent from the image, and residency on the NAIO board fits the absence of any NAIO update member — but that is not proven.
- The coefficient block format the plugin side emits is documented nowhere in the image, and it is the real ceiling on the plugin route. So is whether a plugin configuration transfer can introduce new SHARC program code or only reconfigure resident kernels.
- The 20-byte archive-header id and the
kindfield (8versus12) are both undecoded;kindcorrelates loosely with unpack-versus-flash but theinstallermember breaks the pattern. - The DSP wire format, the FPGA register maps and the bay synchronisation protocol are untouched.
- No claim here has been checked against a DM7. One pass, one firmware image, no hardware.
- Where the DM7's padding byte sits. The record sums one byte short of its declared size, and until that is located every field beyond it is suspect on this model alone.
- What a DM7 scene looks like. The editor ships 303 presets and no scenes, so the console-wide state — the file a patch list would come from — has not been seen for this model, only for its smaller siblings.
Status of this entry. Substantial findings recorded, but whole subsystems remain unexamined. Nothing on this page has been verified against physical hardware — no unit of this platform has been opened, connected to or modified.