Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Allen & Heath GLD - Reverse engineering

Hardware and software reverse-engineering of the Allen & Heath GLD digital mixer series.

Getting into the firmware

The first step is getting hold of the firmware files, which are available on the Allen & Heath website, by selecting the Legacy Products and GLD-80 options. Luckily, when downloaded, we don't get an encrypted, proprietary file format, but a plain .zip, which when unpacked gives us a complete directory structure:

AllenHeathGLD
  | - Firmware.md5
  | - Firmware
    | - Help
    | - iGL-Firmware
    | - Library
    | - OS
    | - Shows
    | - Translations
    | - Updater

Of these, the iGL-Firmware and OS folders look the most interesting at first glance.

The iGL-Firmware folder contains five key files, plus their version files:

file type role
iGL-Firmware i386 ELF, stripped the main application, this is what runs on the SBC
iGL-Bootloader i386 ELF, not stripped recovery/update screen
iGL-DSPBoard.bin ARM Cortex-M image the DSP board's firmware
iGL-ProcessingBoard.bin ARM Cortex-M image the processing (control surface) board's firmware
iGL-MotorFader.bin ARM Cortex-M image the motor fader board's firmware

The OS folder contains Linux shell scripts, kernel modules, configuration files, an ELF executable, deb packages, and udev rules, which form the userspace around the system.

These findings already confirm what the console's boot screen hinted at: a full Linux system runs on the internal SBC, based on a Debian-derived distro.

In xinitrc we find the state machine that starts up the firmware, and it also turns out there's a debug backdoor: if a USB drive is plugged in at boot with an AllenHeathGLD/ah_debug file on it, the system starts an SSH server for remote login, and opens an xterm session instead of launching the firmware. This is enabled by the start on ah_debug line in /etc/init/ssh.conf, meaning sshd doesn't start at all by default, only this event wakes it up.

If we create this file and try to log in, it naturally asks for a password. Fortunately someone has already cracked it, and it's posted on the Allen & Heath forum: https://forums.allen-heath.com/t/linux-login-password-for-gld-80/23380/2. The username is ubuntu, the password is digital.

It's worth rewriting the xinitrc file so that in debug mode it doesn't open the xterm window, but instead continues on to start the firmware. This way, we have an SSH connection to the machine even while the console is in normal use.

On a running console we can also confirm with lsusb what we already knew from the service manual and the firmware updater: the SBC talks to the individual subsystems over USB. All three boards show up under the same A&H vendor ID (22F0), each with its own product ID and character device file:

USB VID:PID description /dev node
22F0:0002 USB2SPI /dev/ah_usb_dsp
22F0:0003 iLive USB2SPI /dev/ah_usb_proc
22F0:0004 iLive MOTFADS /dev/ah_usb_motor

The descriptor strings are still contain "iLive" - the GLD simply reuses the iLive USB descriptors. The same boards are also matched by the .ko kernel module and .bin firmware we already found in the firmware updater.

The live system yields further interesting finds, such as revealing exactly what operating system and motherboard it's running on. The distro is Ubuntu 11.10 (i386), with its own patched kernel (3.16.1.ah.2), running on a Fujitsu D3003-S1 motherboard with an AMD G-T44R (Bobcat) CPU. Beyond that, we can also find data sitting in the rootfs as plain text that should never have made it onto production hardware, but I won't go into further detail on that here.

Architecture

The service manual and the inspection of the motherboard already outline the structure of the console. The SBC runs the Qt4 UI and controls the fader board, the processing (control surface) board and the DSP board via USB. On each of the three boards, an ARM Cortex-M microcontroller receives USB commands, and dispatches them to the other chips on the board or handles them by itself.

The DSP board is the most interesting one: here, two Spartan-3A FPGAs and eight DSP56300 signal-processing chips do the actual audio processing, while the board's ARM controller is just the intermediate layer. On startup, it uploads the FPGA bitstreams and the DSP code images, and it's the one that receives and dispatches incoming USB commands to the whole audio processing pipeline.

Taking a look at the iGL-Firmware executable with Ghidra reveals a gold mine of information. Although the iGL-Firmware binary is stripped, the __PRETTY_FUNCTION__ and __FILE__ strings left behind in the error-handling branches give away almost the entire source tree. From this, almost a thousand function names and hundreds original source file paths could be recovered. The code decompiled by Ghidra was analyzed with Claude Code, which revealed a lot of useful information about how everything works, essentially the entire source code could be restored this way.

The biggest surprise is that the binary doesn't just control the hardware, it has everything the hardware runs, embedded inside it: all FPGA bitstreams and DSP code images sit right there in the data section, and the SBC uploads them over USB to the boards at power-up. This is fantastic news, since it means we can write our own custom program without ever having to flash anything on the hardware itself.

Searching through the binary, a total of seven bitstreams were found and extracted. The first two are the DSP board's own FPGAs (the IG, presumably responsible for routing, and the AF, the chip that speaks the dSNAKE network protocol), while the other five belong to the various expansion boards (option cards):

id part size role
0x12 XC3S400A 235,820 DSP board IG FPGA - presumably a routing matrix between the DSP chips and the inputs/outputs
0x15 XC3S200A 149,516 dSNAKE FPGA
0x19 XC3S200A 149,516 ACE option card
0x19 XC3S200A 149,516 MADI option card
0x19 XC3S200A 149,516 Mini Multi Out card
0x19 XC3S50A 54,664 option card (id 11, purpose currently unidentified)
0x19 XC3S50A 54,664 Dante / Waves option card (shared carrier board)

The eight DSP chips actually hide 16 logical cores, two per chip, as the silkscreen labeling on the board itself already suggests. Six smaller DSP56725AF chips provide cores 0-11, and two larger DSP56720AG chips provide cores 12-15.

Alongside the two larger 56720AG chips sit a total of four 48LC4M16A2 SDRAM chips on the board, split 2-2 across the two core pairs, while the smaller 56725AF chips have no external memory at all. This is because cores 12-15 run the system's FX engines (reverb, delay, and other long, memory-hungry effects), for which the DSP's internal memory would be too small. Cores 0-11, handle input channel processing and mixing and RTA/metering, where the on-chip memory is enough.

Similarly to the FPGA bitstreams, 4 DSP code images turned up the same way from the firmware, and from these we can also tell exactly how large a program each physical DSP core runs:

cores chip words used
0-5 56725AF 3394
6-10 56725AF 2386
11 56725AF 2572
12-15 56720AG 3077

The FX engine is split across 8 stereo slots on these two chips, 2 slots per core. Each slot gets a 128K-word range from the external SDRAM as its own ringbuffer. A DSP56300 word is 24 bits, so that's 128K × 3 bytes ≈ 384 KB per slot. From this we can already derive the longest available delay time: 131,072 words, at a 48 kHz sample rate that's 131072 / 48000 ≈ 2.73 seconds, which is confirmed by the Stereo Tap Delay FX's help page: "Provides a clean digital delay with a maximum delay time of 2.7 seconds".

The code of the FX programs isn't part of the boot images, but many smaller separate code images that the firmware only loads when a preset is recalled for an FX slot. The 31 code images are located in the binary data section of the iGL-Firmware, similarly to the boot images, each given 1024 words of space, and the firmware delivers them to the right DSP core's FX slot using the same P-memory writing mechanism it used to upload the main program at boot.This dynamic loading is what makes it possible for an FX slot to be reprogrammed to a different effect at any time, over USB, without a DSP reset and thus without any audio dropout, and it also allows a custom-build effect to be placed in a slot instead of the factory 31 code images.

Boot sequence

Running the Qt4 UI without hardware in a Podman container, and replacing the GLD hardware with a Python simulation script that impersonates the otherwise USB-connected subsystems via a PTY, made it possible to capture the boot sequence that had previously only been derived from static reverse engineering as real, live traffic. On the DSP board's USB channel (/dev/ah_usb_dsp), the iGL-Firmware brings the board up live in the following order:

  1. Version request to every board (00 03 01 frame)

    The boards send back an 11-byte response starting with "Version...". If this doesn't come back, the UI immediately switches to a "Boot Failure" screen.

Boot Failure screen when a board doesn't report its version back

  1. Putting the peripherals into an idle state

    A sequence of zeroed-out port pins (SetPortPin on pins 12, 14, 13, 10, 11), with every FPGA and DSP still held in reset.

  2. Identifying the IG FPGA

    A target=0x0A opcode=0x10 frame gets an 'H' or 'I' response from the board, which decides which bitstream variant needs to be uploaded.

  3. Uploading the IG FPGA bitstream

    Port pin reset (5,0 then 5,1), checking the INIT_B signal (GetPortPin(1) == 1), then the bitstream goes out in 235,820 bytes, across 461 blocks of 512 bytes (the bitstream can be found in the extracted fpga_ig_xc3s400a.bin file). The loader waits for the DONE signal (GetPortPin(3)) in a busy-wait loop; if it never becomes 1, the application spins there forever, with a black screen.

  4. DSP reset and code upload

    SetPortPin(9,1), then (15,0)/(15,1) for the DSPs' own reset, followed by uploading the 4×4096-word code image. Each DSP's own internal ROM only loads the first 2048 words to address P:$0000; the image's own stub, starting at $0100, then pulls in the remaining 2048 words to P:$0800 itself.

  5. Handshake

    Y:$12C = 0x555555 (the "go" signal) to every core, then a 200 ms wait on the host side, and finally reading X:$5C: all 16 cores must return 57, which signals that the heartbeat counter is running, i.e. the DSP has actually started up. After 5 failed attempts the firmware gives up, with a "DSP Programming failed" error.

Boot Failure screen when DSP handshake doesn't succeed

The entire chain - IG FPGA upload, DSP reset, code upload, handshake - completes in a live measurement in under 2 seconds (UID Complete in: ~1.8 s). The dSNAKE FPGA and any option card follow the same mechanism, just with different pin assignments and a different bitstream, once the main DSP chain is already up.

It is important that this sequence runs every time the firmware starts, there is no EEPROM in the system, the entire code image and bitstream set comes fresh from the SBC binary every time.

About

Hardware and software reverse-engineering of the Allen & Heath GLD digital mixer series.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors