GNU/Linux Inside!

Disassembling the Wavedrum firmware

September 18, 2014

The Wavedrum’s processing unit is an ADSP-21375 by Analog Devices, a member of the SHARC processor family. The firmware of the Wavedrum, which is stored on a micro SD-card and, more importantly, on the flash memory chip is loaded into the processor during the boot process.

Last time I confirmed by tracing the connections of the two boot pins that the processor is wired to boot from EPROM/Flash (BOOT_CFG1-0 = 10). I’m too lazy to try to verify that the firmware on the micro SD-card is identical to the contents of the flash memory, so I’ll just assume that this is the case.

When the processor is initially powered on, the internal memory is in an undefined state. According to the ADSP hardware reference (section 17-7 Processor Booting), the processor core is put into IDLE mode while loading the boot kernel from an external source (in our case this is the flash memory) into the internal memory at address 0x90000 (IVT_START_ADDR), and finally executes the boot kernel code when a peripheral interrupt signals that the kernel has been loaded. Then the application code is loaded from the memory and finally the application’s Interrupt Vector Table (IVT) is loaded. The boot kernel is 256 48-bit words long, as is the IVT. The application code is of arbitrary length.

Word packing

The boot kernel is exactly 256 48-bit words long (shorter kernels are padded with NOPs), but the words are not transferred as 48-bit words. The boot kernel is transferred from the external memory as a stream of 384 “packed” 32-bit words (see table 17-6 in the hardware reference). To understand packing we have to know that conceptionally the internal memory consists of many rows of four columns, each of which is 16 bit wide. Accessing 48-bit words is often referred to as 3-column access in the reference, whereas accessing 32-bit words is called 2-column access. All of the SHARC instructions are 48 bit wide. This means that any 32-bit wide package never contains the full instruction. Dependent on the order of the packages, the 48-bit words can be reconstructed from a stream of 32-bit words.

Here’s the original explanation in the hardware reference on page 17-27:

During the boot process, word packing (for example 8 to 32-bit) is performed over the SPI. In other words, the kernel is not loaded directly with 256 x 48-bit words, instead it is loaded with 384 x 32-bit ‘packed words’ (2-column access). The same physical memory for instruction boot is loaded via DMA in normal word (NW) 2 column. However, after booting the same physical memory region is fetched by the sequencer in NW 3-column. For example the loader kernel itself has a NW 2 columns count of 256 x 3/2 = 384 words but the kernel is executed with 256 instruction fetches.

When booting from external memory the bus width is set to 8 bits. According to the ADSP hardware reference (section “External Port Booting”), the processor reads a stream of 8-bit words from the data port and packs four of them into 32-bit words (LSB first) before storing them into the internal memory.

Figure 17-5 in the hardware reference visualises this process rather nicely. It shows how streams of different word sizes end up being stored in the internal memory.

word packing

Once I understood that words are transferred from the memory in 8-bit chuncks with the LSB first, writing a disassembler that would translate the binary boot kernel into assembly code was no longer very challenging.

A free disassembler for ADSP-213xx

I implemented a simple tool in Haskell that takes a binary firmware and spits out assembly code for the ADSP. At the moment it only supports a limited set of instructions, just enough so that I could translate the boot kernel. The remainder of the instructions will be implemented later as I happen to encounter them in the application code.

It currently only parses the first 256 words of the firmware, i.e. only the boot kernel. Before I can parse the remainder I need to figure out the memory layout.

The code is freely available under the GPL and can be downloaded from gitorious or Github. See the included instructions for assistance in compiling and using the disassembler.

Next steps

My work isn’t over yet. Next I’ll focus on the following tasks:

If you want to help me, I’d be happy if you could send me a copy of the Global Edition’s firmware. To do this you only need to take out the micro SD-card and create a disk image of it. (On GNU/Linux this can easily be done with dd on the command line; see my first post on hacking the Wavedrum for more detailed instructions.)

I would also be very grateful for code reviews and patches. Translating the various specifications into executable code wasn’t always easy and I’m sure there are bugs in the code here and there.

Read more posts about the Wavedrum here.

← other posts

Click to load Disqus comments