TL;DR: If you’d like to see what your BDM debugger is actually doing under the hood, check out our repo →
The journey of hardware reverse engineering often begins with the eyes. You find a device, rip it out of its shell, and put it under a bright light to inspect the handiwork of another engineer. You look over at the component selection and ask, “I wonder what led to that decision?”
You poke and prod, looking at the interfaces laid out, building a mental map of the traces, as if trying to make sure you can find your way back out of the maze.
On this particular day, you spot a nice array of pins, already populated with headers. Ten pins, and a small silkscreen label, three letters, “BDM”.
Well that’s not JTAG, that’s not UART, definitely not SWD. No, this is a little different. As anyone would do, you hit the search engine. The top result is your old friend,

Your old friend gives you the low-down, what is “BDM”? Why it’s:
“Background debug mode (BDM) interface is an electronic interface that allows debugging of embedded systems. Specifically, it provides in-circuit debugging functionality in microcontrollers. It requires a single wire and specialized electronics in the system being debugged. It appears in many Freescale Semiconductor products.”
You think to yourself, “That almost sounds right.” You can see your processor is an MPC860, an old PowerQUICC III device, which was certainly made by Freescale 2–3 buyouts ago. You look again. “It requires a single wire.” You have 10 pins here, certainly those aren’t just for show.
Let’s go back to the
and figure out what we’re actually looking at.
Sometimes in life, the simplest pleasures can be found in a 1,320-page datasheet, so let’s step back and go to the source. Datasheets are a lovely place where branding and logos are updated, but old technical writing still tells a story like rings on a tree stump. In this case, we have a datasheet with old links to http://www.freescale.com and NXP logos on the headers. A grand ol’ time to be had by all.
So you open your datasheet, scroll down to Chapter 44: System Development and Debugging, continuing to scroll down to Chapter 44.3: Development System Interface, and then you keep scrolling until you see something familiar:

Ah, you sigh in relief, there’s simply TWO BDM interfaces used historically by Freescale. That makes everything extremely clear. (There’s actually even more but that’s for another time.)
Simply using the debug interface with an off-the-shelf debugger was not our end goal. It’s actually quite easy to go out and spend a few thousand on an off the shelf debugging device, and you’re off to the races doing some of your favorite activities, such as breaking, continuing, breaking at your favorite while-loop, reading registers, etc. We wanted to understand this debugging protocol in order to make this device do our bidding without the expensive off-the-shelf debugger in play.
The documentation was helpful. It provided information on the building blocks of this interface. BDM doesn’t use normal op-codes understood by the processor to manipulate processor state. The actual protocol is a mix of PowerPC instructions and debug-specific instructions that are interwoven to directly take control and execute instructions on the processor.

At first glance, some of the signal names may remind the reader of other debugging protocols:
…will evoke the memory of JTAG’s:
These protocols quickly diverge. In addition to the serial data lines and the clock, BDM also makes use of two reset signals: HRESET for hardware reset and SRESET for software reset. While the device being probed is powered and running, these signals assert high, and if brought low, can trigger the appropriate reset of the processor.
Finally, we have two more signals, VLFS0 and VLFS0, the freeze pins used to indicate to the debugger and other off-chip devices that the processor has halted execution.
In conjunction with the physical interface, BDM makes use of four internal registers to facilitate communication. These are:
Keep in mind that DPSR provides double duty, shifting in instructions and data from DSDI, and shifting data and status out of DSDO.
Typically for JTAG, you will shift in some instruction or op-code, then shift some kind of null value as a placeholder to read the response. For BDM, the response from a previous instruction is shifted out while the next instruction is shifted in, cascading through the transaction. Since there is no state machine to delineate between modes, BDM is more or less a stream of layered instructions.

The last aspect of BDM needed to understand the flow is how the command structure interacts with the BDM state machine. DSDI and DSDO carry messages in a similar format. Both can be either 35 bits or 10 bits depending on the command type and mode. For both formats, the first three bits will carry control flow encoding.
In the case of commands shifted into DPSR, the general format will be:
Start (1) | Mode (1) | Control (1) | Data (7 or 32) |For DSDO, you’ll see:
Ready (0) | Status 0 (1) | Status 1 | Data (7 or 32) |In the state machine, when the core is ready for the next command, the DSDO line will be driven low, to set the first “Ready” bit. The debugger will check that DSDO is held low before starting a transmission with the “Start” bit. Once the BDM core detects “Start”, data will begin to be shifted out on DSDO on the falling clock edge, as the debugger shifts in the next command.
One important note: BDM has a few modes which can be controlled at boot by asserting signals with strict timing. In the context of this blog post, the only thing you need to know is we’re detecting BDM in asynchronous mode, where the debugger provides a clock signal. These can be read about in the datasheet if you’re a curious soul who is interested in the minutia.
With that, we have enough information to write an analyzer module to use in conjunction with our Logic Analyzer. Decoding binary messages with our eyes and paper is fun and all, but we have work to do.

In order to get eyes on our signals, we’ll be using a USB Logic Analyzer that comes with a price tag similar to the laptop you plug it into and a name that everyone you meet will say differently.
If you’re new to hardware debugging/reverse engineering, a logic analyzer is a device designed to measure arbitrary analog electrical signals and turn those into discrete digital signals that carry the data we’re actually curious about. These come in many configurations with varying capabilities. In my case, we’re using the Saleae Logic Pro 16.

To pair with the hardware, Saleae also provides a desktop application to use with the device. The Oracle passes on wisdom that the priest must then convey.
Out of the box, it allows you to configure which channels you want to measure, with each capable of capturing in both digital and analog modes, at various sample rates, voltage trigger levels, automatic triggers, filters, etc. It’s a helpful piece of software. Among the most useful parts, though, are the various built-in protocol analyzers that let you go from zero to an exported CSV of data ready to analyze with a script. These are great until you run into a protocol not packaged, or in the extension marketplace. What is there to do?
Why, write our own, of course!
Saleae, with their hardware logic analyzer, and their Logic software, also provide a few APIs for interacting with these tools. Two of which let you make analyzer extensions. They have the High-Level Analyzer and the Low-Level Analyzer. The high-level analyzer Python API relies on the underlying protocol to already be understood. It’s useful in the case where you are trying to decode a protocol encoded on top of another protocol (i.e., a display driver over I2C). The low-level analyzer is there for when you need to start from scratch and define something new from rising and falling edges.
Thankfully for us, Saleae also provides a Sample Analyzer project that can be cloned and modified for your own purposes. This saves us the time of messing with the build system and understanding how Logic needs to be spoken to. The outline of the analyzer is all there, and you only need to worry about implementing your protocol’s logic. They even provide a rename_analyzer.py that will go through all the source and build scripts, replacing “SampleAnalyzer” with the name of your choosing.

This is where we come to our invention: BDMAnalyzer.
A few higher-level components that warrant discussion:
This is where the actual logic of decoding happens. We start in the main WorkerThread, where we have some initialization and a main loop over a switch statement. In writing this tool, I found it unnecessary to implement the various states and used a bit of a shortcut to find the initialization of the debug mode, then move past it to the first instance of the BDM Core announcing ready.
From there, we move to is CollectPackets, where we detect the Mode/Control for DSDI and Status 0/1 for DSDO. This happens first, as the results will determine if we’re reading a 32-bit data sequence or a 7-bit data sequence. With that information in hand, we can continue advancing over the capture, shifting the newest bit into our respective DSDI/DSDO packets.
A few tricks are at play here. With the multiple channels and control flow, we end up using the clock signal to find the next falling edge, then we need to synchronize the current sample across all of the channels to read the correct value. Once synchronized, we can sample the data. Data is technically sampled on the falling edge of the clock, but due to how technicalities live on paper, and we live in a squishy physical plane, signals are not always perfect. Bouncing, glitching, a butterfly flapping its wings can all contribute to that sample being slightly off at that exact point in time. To fix this without thinking too hard about the nature of the universe (don’t forget, we’re trying to debug a PowerPC chip from the mid-90s), we use another trick.
We read the signal on the falling edge, but also peek at a future sample with a user-defined tolerance of n_samples, where n_samples < sample_rate/bit_rate and where the sample rate is the speed at which the Saleae is sampling the signal, and the bitrate is our data speed. In this case, the Saleae is configured to capture at 100 MS/s and DSCK runs at 1 MHz, with 1 bit clocked out on each falling edge. That gives us 1 Mbps. With a little mental math, we get ~100 samples of tolerance. I found that a sweet spot is 10 samples past the sampled edge. This gets us past the occasional 1-2 sample glitch without sampling at the end of the period.
If we find there’s no transition within this tolerance, we accept the original sample’s measurement. If we find a transition within the tolerance, we’ll assume the sample on the falling edge was read too early/late in the rise or fall time of the signal. This isn’t quite scientific, and if these signals were faster, more work and better signal integrity would be needed. Thankfully we’re running at the speed of smell so we can continue on our way.
The rest of the code primarily labels these samples we captured and stores them somewhere for later use in exporting. By properly configuring the AnalyzerResults files, we can define a format for exporting our data. For simplicity’s sake, we export to a CSV table with either a DSDI packet or a DSDO packet per row, with the unused columns left empty and a “Type” field set to tell whatever future decoder what each row contains. We also export the Start timestamp and a Duration value. Duration isn’t as useful, but with Start time, we can keep track of when the last packet was read, and create delineation between transactions of many BDM commands and responses.
name,type,start_time,duration,Mode,Control,Instruction,Status 1,Status 2,Data
BDM,DSDI,1.93935036,0.0000351,0x00,0x00,0x7C769BA6,,,
BDM,DSDO,1.93935036,0.0000351,,,,0x01,0x01,0xFFFFFFFF
BDM,DSDI,1.94076241,0.00003505,0x00,0x00,0x7C969BA6,,,
BDM,DSDO,1.94076241,0.00003505,,,,0x00,0x00,0x00141480
BDM,DSDI,1.94211741,0.00003505,0x00,0x00,0x60000000,,,
BDM,DSDO,1.94211741,0.00003505,,,,0x00,0x00,0x00000000
BDM,DSDI,1.9427804,0.00003505,0x00,0x00,0x60000000,,,
BDM,DSDO,1.9427804,0.00003505,,,,0x01,0x01,0xFFFFFFFF
BDM,DSDI,1.9434584,0.00003505,0x00,0x00,0x60000000,,,With the export defined, using the analyzer is basically complete. You simply build the analyzer, point Logic 2 at it, then capture your signals between your debugger and device under test. The BDM analyzer can be initialized by configuring your Saleae signal lines to the appropriate BDM pins, the Bitrate and Tolerance configured, and exporting the transactions is two clicks away.
Alongside the analyzer, we have also provided a script to decode the CSV into something even more human readable.
Here’s a comparison of the exported CSV data, and the same data decoded:
name,type,start_time,duration,Mode,Control,Instruction,Status 1,Status 2,Data
BDM,DSDI,12.2494536,0.00001005,0×01,0x01,0x0000003F,,,
BDM,DSDO,12.2494536,0.00001005,,,,0×01,0x01,0x0000003F
BDM,DSDI,12.25104359,0.00003505,0×00,0x00,0x7C769BA6,,,
BDM,DSDO,12.25104359,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.25254959,0.00003505,0×00,0x00,0x7C969BA6,,,
BDM,DSDO,12.25254959,0.00003505,,,,0×00,0x00,0x01706F80
BDM,DSDI,12.25389559,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.25389559,0.00003505,,,,0×00,0x00,0x00000000
BDM,DSDI,12.25466259,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.25466259,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.25537958,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.25537958,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.26790855,0.00003505,0×00,0x00,0x7C169BA6,,,
BDM,DSDO,12.26790855,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.26928355,0.00003505,0×00,0x00,0x7C369BA6,,,
BDM,DSDO,12.26928355,0.00003505,,,,0×00,0x00,0x000BBC2C
BDM,DSDI,12.27051155,0.00003505,0×00,0x00,0x7C569BA6,,,
BDM,DSDO,12.27051155,0.00003505,,,,0×00,0x00,0x00783F08
BDM,DSDI,12.27190454,0.00003505,0×00,0x00,0x7C769BA6,,,
BDM,DSDO,12.27190454,0.00003505,,,,0×00,0x00,0x800DB530
BDM,DSDI,12.27320254,0.00003505,0×00,0x00,0x7C969BA6,,,
BDM,DSDO,12.27320254,0.00003505,,,,0×00,0x00,0x01706F80
BDM,DSDI,12.32364441,0.00003505,0×00,0x00,0x7C769BA6,,,
BDM,DSDO,12.32364441,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.32425941,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.32425941,0.00003505,,,,0×00,0x00,0x00001000
BDM,DSDI,12.32563441,0.00003505,0×00,0x00,0x7C600026,,,
BDM,DSDO,12.32563441,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.32625841,0.00003505,0×00,0x00,0x7C769BA6,,,
BDM,DSDO,12.32625841,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.3269354,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.3269354,0.00003505,,,,0×00,0x00,0x24000400
BDM,DSDI,12.3283714,0.00003505,0×00,0x00,0x7C6902A6,,,
BDM,DSDO,12.3283714,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.3290194,0.00003505,0×00,0x00,0x7C769BA6,,,
BDM,DSDO,12.3290194,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.3296354,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.3296354,0.00003505,,,,0×00,0x00,0x00000001
BDM,DSDI,12.33098039,0.00003505,0×00,0x00,0x7C6102A6,,,
BDM,DSDO,12.33098039,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.33163039,0.00003505,0×00,0x00,0x7C769BA6,,,
BDM,DSDO,12.33163039,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.33225139,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.33225139,0.00003505,,,,0×00,0x00,0x20000000
BDM,DSDI,12.33361839,0.00003505,0×00,0x00,0x7C7042A6,,,
BDM,DSDO,12.33361839,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.33427139,0.00003505,0×00,0x00,0x7C769BA6,,,
BDM,DSDO,12.33427139,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.33492738,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.33492738,0.00003505,,,,0×00,0x00,0x800DB530
..
BDM,DSDI,12.37525128,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.37525128,0.00003505,,,,0×00,0x00,0x00000000
BDM,DSDI,12.37677328,0.00003505,0×00,0x00,0x7C769AA6,,,
BDM,DSDO,12.37677328,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.37741728,0.00003505,0×00,0x01,0x01706F80,,,
BDM,DSDO,12.37741728,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.37862927,0.00003505,0×00,0x00,0x7C969AA6,,,
BDM,DSDO,12.37862927,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.37928727,0.00003505,0×00,0x01,0x00000000,,,
BDM,DSDO,12.37928727,0.00003505,,,,0×01,0x01,0xFFFFFFFF
BDM,DSDI,12.38053327,0.00003505,0×00,0x00,0x60000000,,,
BDM,DSDO,12.38053327,0.00003505,,,,0×01,0x01,0xFFFFFFFF
##################################################
##################### BLOCK 1 ####################
LAST: 2.23526979 ____________ THIS: 12.2494536
= PC ===== DSDI ============================= DSDO
———————————————-NULL
0x0114: ASRT_MASK_BREAK 0x0000003F————NULL
0x0115: mtspr DPDR, r3————0x01706F80
0x0116: mtspr DPDR, r4————0x00000000
0x0117: nop——————————–NULL
0x0118: nop——————————–NULL
0x0119: nop——————————–NULL
0x011a: mtspr DPDR, r0————0x000BBC2C
0x011b: mtspr DPDR, r1————0x00783F08
0x011c: mtspr DPDR, r2————0x800DB530
0x011d: mtspr DPDR, r3————0x01706F80
…
0x0143: mfmsr r3————————NULL
0x0144: mtspr DPDR, r3————0x00001000
0x0145: nop——————————–NULL
0x0146: mfspr r3, DPDR——————NULL
0x0147: CORE_DATA: 0x00001000—————–NULL
0x0148: mtmsr r3————————NULL
0x0149: mfmsr r3————————NULL
0x014a: mtspr DPDR, r3————0x00001000
0x014b: nop——————————–NULL
0x014c: mfcr r3————————-NULL
0x014d: mtspr DPDR, r3————0x24000400
0x014e: nop——————————–NULL
0x014f: mfctr r3————————NULL
0x0150: mtspr DPDR, r3————0x00000001
0x0151: nop——————————–NULL
0x0152: mfxer r3————————NULL
0x0153: mtspr DPDR, r3————0x20000000
0x0154: nop——————————–NULL
0x0155: mfspr r3, SPRG0—————–NULL
0x0156: mtspr DPDR, r3————0x800DB530
..
0x0182: mftbu r3————————NULL
0x0183: mtspr DPDR, r3————0x00000000
0x0184: nop——————————–NULL
0x0185: mfspr r3, DPDR——————NULL
0x0186: CORE_DATA: 0x01706F80—————–NULL
0x0187: mfspr r4, DPDR——————NULL
0x0188: CORE_DATA: 0x00000000—————–NULL0x0189: nop————————————
If you made it this far, thanks for reading!
Download BDMAnalyzer from GitHub, and start decoding BDM signals ⇢
And check out more open-source tools by Zetier:
Bungeegum: automates in-memory execution testing for Android cyber tools within real-world SELinux contexts. Read the article →
Lariat: streamlines Android device testing by integrating seamlessly with Device Farmer’s REST API. Read the article →
flaShMASH: designed for analyzing and reconstructing data from multiple flash memory dumps. Read the article →
Illustrations by Rebecca DeField.