Overview
JTAG (Joint Test Action Group) is an industry standard (IEEE 1149.1) originally designed for testing printed circuit board connections via boundary scan, but now widely used for in-system programming, hardware debugging, and reverse engineering of embedded devices. The JTAG interface provides direct access to a chip’s internal registers, memory, and debug capabilities through a simple 4-5 wire serial interface. Nearly all modern microcontrollers, CPUs, FPGAs, and SoCs include JTAG ports, making it the primary interface for firmware development, production testing, and security research.
JTAG uses a Test Access Port (TAP) with four mandatory signals: TDI (Test Data In), TDO (Test Data Out), TMS (Test Mode Select), and TCK (Test Clock), plus an optional TRST (Test Reset). Multiple devices can be daisy-chained on a single JTAG bus. Through JTAG, you can halt the processor, read and write memory, set breakpoints, single-step code execution, dump firmware, program flash memory, and perform boundary scan testing of I/O pins. Tools like OpenOCD, SEGGER J-Link, and various low-cost adapters (FTDI-based, Bus Pirate) provide JTAG connectivity from a PC.
JTAG Signals
| Signal | Direction | Description |
|---|
| TCK | Input | Test Clock - synchronizes operations |
| TMS | Input | Test Mode Select - controls TAP FSM |
| TDI | Input | Test Data In - serial data input |
| TDO | Output | Test Data Out - serial data output |
| TRST | Input | Test Reset (optional) - resets TAP |
| VCC | Power | Reference voltage |
| GND | Ground | Ground reference |
Common JTAG Pinouts
| Connector | Pins | Standards |
|---|
| ARM 20-pin | 20 | ARM standard JTAG |
| ARM 10-pin | 10 | Compact ARM JTAG |
| MIPS EJTAG | 14 | MIPS processors |
| Intel 60-pin | 60 | Intel XDP |
| AVR 6-pin | 6 | Atmel/Microchip ISP |
| TI 14-pin | 14 | Texas Instruments |
| Custom headers | Var | Varies by vendor |
ARM 20-Pin Standard
Pin 1: VCC Pin 2: TMS
Pin 3: GND Pin 4: TCK
Pin 5: GND Pin 6: TDO
Pin 7: - Pin 8: TDI
Pin 9: GND Pin 10: nRESET
Pin 11: GND Pin 12: -
Pin 13: GND Pin 14: -
Pin 15: GND Pin 16: -
Pin 17: GND Pin 18: -
Pin 19: GND Pin 20: -
JTAG Adapters
Popular Hardware
| Adapter | Interface | Speed | Price |
|---|
| SEGGER J-Link | USB | Very fast | $$$$ |
| SEGGER J-Link EDU | USB | Very fast | $$ |
| ST-LINK V2 | USB | Fast | $ |
| FTDI FT2232H | USB | Medium | $ |
| Bus Pirate | USB | Slow | $ |
| Raspberry Pi GPIO | GPIO | Slow | $ |
| Black Magic Probe | USB | Fast | $$ |
| Tigard | USB | Medium | $$ |
FTDI-Based Adapter Setup
# Install FTDI drivers
sudo apt install libftdi1-dev
# Check FTDI device
lsusb | grep -i ftdi
# Common FTDI JTAG pinout (FT2232H)
# ADBUS0 = TCK
# ADBUS1 = TDI
# ADBUS2 = TDO
# ADBUS3 = TMS
JTAG TAP State Machine
┌─────────────────┐
│ Test-Logic-Reset │
└────────┬─────────┘
│ TMS=0
┌────────▼─────────┐
┌──────►│ Run-Test/Idle │◄──────┐
│ └────────┬─────────┘ │
│ │ TMS=1 │
│ ┌────────▼─────────┐ │
│ │ Select-DR-Scan │ │
│ └───┬──────────┬───┘ │
│ TMS=0 │ │ TMS=1 │
│ ┌────────▼──┐ ┌───▼─────────┐ │
│ │ Capture-DR │ │Select-IR-Scan│ │
│ └────┬───────┘ └───┬─────────┘ │
│ │ │ │
│ (DR chain) (IR chain) │
│ │ │ │
└───────┴──────────────┘ │
│ TMS=1 (Update-xR) │
└─────────────────────────────┘
Finding JTAG Pins
Manual Identification
# Look for:
# - Unpopulated headers (4-20 pins in a row)
# - Labeled pads: TCK, TMS, TDI, TDO, TRST, SRST
# - Test points near CPU/SoC
# - Grouped vias near processor
# Use multimeter to identify:
# - GND: continuity to ground plane/shield
# - VCC: steady 3.3V or 1.8V
# - TCK: may have pull-down resistor
# - TMS: may have pull-up resistor
# - TDI: may have pull-up resistor
JTAGulator (Automated Discovery)
# JTAGulator finds JTAG pins automatically
# Connect all candidate pins to JTAGulator channels
# In JTAGulator terminal:
> u # Set target voltage
> Enter voltage: 3.3
> b # BYPASS scan (find JTAG)
> Enter start channel: 0
> Enter end channel: 7
# Tries all pin combinations
> i # IDCODE scan
> Enter start channel: 0
> Enter end channel: 7
# Reads JTAG device IDs
Using OpenOCD for Discovery
# Boundary scan with unknown device
openocd -f interface/ftdi/tigard.cfg \
-c "transport select jtag" \
-c "adapter speed 1000" \
-c "jtag newtap auto0 tap -irlen 4 -expected-id 0" \
-c "init" \
-c "scan_chain" \
-c "shutdown"
OpenOCD Usage
Basic Commands
# Start OpenOCD with specific target
openocd -f interface/jlink.cfg -f target/stm32f4x.cfg
# Start with FTDI adapter
openocd -f interface/ftdi/tigard.cfg -f target/stm32f1x.cfg
# Custom configuration
openocd -f my_target.cfg
# Connect GDB to OpenOCD
arm-none-eabi-gdb firmware.elf
(gdb) target remote localhost:3333
(gdb) monitor reset halt
(gdb) load
(gdb) continue
OpenOCD Telnet Commands
# Connect to OpenOCD telnet
telnet localhost 4444
# Halt processor
> halt
# Resume execution
> resume
# Reset target
> reset
> reset halt
> reset init
# Read memory
> mdw 0x08000000 16 # Read 16 words from flash
> mdb 0x20000000 64 # Read 64 bytes from RAM
> mdh 0x40000000 8 # Read 8 halfwords
# Write memory
> mww 0x20000000 0xDEADBEEF # Write word
> mwb 0x20000000 0x42 # Write byte
# Dump memory to file
> dump_image firmware.bin 0x08000000 0x100000
# Load binary to memory
> load_image firmware.bin 0x08000000
# Flash programming
> flash write_image erase firmware.bin 0x08000000
> flash verify_image firmware.bin 0x08000000
# Flash info
> flash info 0
> flash banks
# Set breakpoints
> bp 0x08001234 4 hw # Hardware breakpoint
> rbp 0x08001234 # Remove breakpoint
# Single step
> step
# Register access
> reg # Show all registers
> reg pc # Show program counter
> reg r0 0x12345678 # Set register value
# JTAG chain info
> scan_chain
> jtag names
OpenOCD Configuration Files
# my_target.cfg
source [find interface/ftdi/tigard.cfg]
transport select jtag
adapter speed 1000
source [find target/stm32f4x.cfg]
# Custom JTAG settings
jtag newtap mytarget cpu -irlen 4 -expected-id 0x2ba01477
# Reset configuration
reset_config srst_only srst_nogate
# Flash configuration
flash bank myflash stm32f2x 0x08000000 0 0 0 mytarget.cpu
Dump Flash Memory
# Using OpenOCD
openocd -f interface/jlink.cfg -f target/stm32f4x.cfg \
-c "init" \
-c "reset halt" \
-c "flash read_image firmware.bin 0x08000000 0x100000" \
-c "shutdown"
# Using J-Link Commander
JLinkExe -device STM32F407VG -if JTAG -speed 4000
J-Link> connect
J-Link> halt
J-Link> savebin firmware.bin 0x08000000 0x100000
J-Link> exit
Analyze Dumped Firmware
# Basic analysis
file firmware.bin
strings firmware.bin | head -50
hexdump -C firmware.bin | head -100
binwalk firmware.bin
# Look for file systems
binwalk -e firmware.bin
# Entropy analysis (find encrypted/compressed sections)
binwalk -E firmware.bin
Advanced Usage
Boundary Scan
# Boundary scan tests I/O pin connectivity
# Using OpenOCD
openocd -f interface/jlink.cfg -f target/stm32f4x.cfg \
-c "init" \
-c "jtag_reset 0 0" \
-c "irscan stm32f4x.cpu 0x00" \
-c "drscan stm32f4x.cpu 32 0x00000000" \
-c "shutdown"
# Using BSDL files for pin mapping
# BSDL (Boundary Scan Description Language) files
# describe pin functions for boundary scan
JTAG Daisy Chain
# Multiple devices on JTAG chain
# my_chain.cfg
jtag newtap fpga tap -irlen 6 -expected-id 0x0123abcd
jtag newtap mcu tap -irlen 4 -expected-id 0x2ba01477
# The first device in chain (closest to TDO) is listed first
SWD Alternative (ARM)
# SWD uses only 2 wires (SWDIO + SWCLK) instead of 4
# Most ARM Cortex-M devices support SWD
openocd -f interface/jlink.cfg \
-c "transport select swd" \
-f target/stm32f4x.cfg
# SWD pinout:
# SWDIO = TMS (bidirectional data)
# SWCLK = TCK (clock)
Troubleshooting
| Issue | Solution |
|---|
| No JTAG device found | Verify wiring, check voltage levels |
| IDCODE all zeros/ones | Wrong pin assignment, check TCK/TMS |
| Can’t halt processor | Try TRST/SRST reset, check JTAG lock fuses |
| Flash read protection | Device may have RDP enabled (read protection) |
| Slow JTAG speed | Reduce adapter speed, shorten wires |
| OpenOCD connection fails | Check adapter driver, verify config files |
| GDB can’t connect | Verify OpenOCD is running, check port 3333 |
| Daisy chain detection fails | Verify IR lengths, check device order |
Common Error Messages
# "JTAG scan chain interrogation failed"
# -> Wrong wiring or no target power
# "Timeout waiting for SYSCOMP"
# -> Target is in low-power mode, add reset
# "Could not find MEM-AP to control the core"
# -> Device may use SWD instead of JTAG
# "Error: flash write failed"
# -> Flash may be locked, check protection bits
JTAG Security Countermeasures
# Some devices disable JTAG:
# - Fuse bits (OTP) that permanently disable JTAG
# - Software JTAG lock (sometimes reversible)
# - Debug authentication required (ARM CoreSight)
# - JTAG pins repurposed as GPIO
# Bypass techniques (for security research):
# - Voltage glitching during boot
# - UV exposure to clear OTP fuses (older devices)
# - Microprobing internal test pads
# - Exploiting boot ROM vulnerabilities