Initially published: 2019-12-26 - Last Modified: 2019-12-26

nRF52 Debug Access Port protection

This post explains some low-level details related to nRF52 Debug Access Port (DAP) protection.

Hardware

Nordic produces a multitude of ARM System-on-Chip (SoC) products. Among those, nRF52 is a popular ARMv7 chip with Bluetooth 5 support, running at 64 MHz.

Debugging with OpenOCD

For this chip, OpenOCD offers support for basic debugging features (nrf52.cpu commands), flash manipulation (nrf5/flash commands), and advanced debugging via the Debug Access Port (nrf52.dap).

Upon starting a debugging session via OpenOCD, it will be identified as such:

$ openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg
[...]
nrf52.cpu: hardware has 6 breakpoints, 4 watchpoints
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc

However, on some chips OpenOCD may instead complain when trying to access the debug port:

Error: Could not find MEM-AP to control the core

The above error means that the vendor have disabled debugging capabilities (and firmware access) when flashing this chip.

Debug protection

nRF52 chips come with (optional) flash read-back protection to prevent firmware dumping (among many other things). Such a feature works by disabling access to the default debug port in the CPU (AHB-AP).

Section 14.1.62 of the nRF52 manual describes the APPROTECT field, which can be written in order to lock access to the debug access port. It is a flash-backed value memory-mapped to address 0x10001208, with the following semantics:

However the chip includes an additional custom Control Access Port (CTRL-AP), which is always available for core debug access.

This can be used in order to unlock R/W access to the flash, as well as full debug features. Unlocking automatically erases all flash and RAM content, and is performed via the ERASEALL field. Its semantics is described in section 16.2.1 of the nRF52 manual, and shown below:

Similarly, AP-protection status can be checked at any time via the the APPROTECTSTATUS field, which is described in the same section.

OpenOCD helpers

OpenOCD can be extended with custom scripts to directly support those operations. The Tcl code below (and submitted as a patch upstream) adds three helper methods:

# Return whether debug access is locked (see manual §16.2)
proc nrf52_is_ap_protected {} {
	if { [using_hla] } {
		return -code error "command not working with hla interfaces"
	}

	set val [[[target current] cget -dap] apreg 1 0x0c]
	return [expr {$val == 0 ? true : false}]
}
add_help_text nrf52_is_ap_protected "return whether nRF52 debug access is locked"

# Erase all content and unlock debug access (see manual §16.2)
proc nrf52_erase_unlock {} {
	if { [using_hla] } {
		return -code error "command not working with hla interfaces"
	}

	poll off
	set target [target current]
	set dap [$target cget -dap]

	# Erase all content
	$dap apreg 1 0x04 1
	# Wait for completion
	while {[$dap apreg 1 0x08] == 1} {
		echo "erase in progress..."
		sleep 150
	}
	echo "erased and unlocked"

	reset halt
	poll on
}
add_help_text nrf52_erase_unlock "erase all nRF52 content and unlock debug access"

# Enable debug access protection (see manual §14.1.62)
proc nrf52_protect_ap {} {
	poll off

	flash fillw 0x10001208 0x00 1

	reset run
	poll on
}
add_help_text nrf52_protect_ap "enable nRF52 debug access protection"