1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
|
---
title: Security and protection
---
Many targets support some way of disabling JTAG/SWD access or protecting the flash from read-back or write.
In the text below, this is called a "locked" target, though each silicon vendor tends to have their
own terminology for this feature.
## Supported Targets
pyOCD currently supports the security features of these target families:
- NXP Kinetis
- Nordic Semiconductor nRF52 families
Both built-in and CMSIS-Pack based targets from these families support security features.
## Connecting to a locked target
If you attempt to run pyOCD Commander against a locked target, you'll encounter a message like this:
``` bash
(venv) ~/devel/contrib/pyocd$ pyocd commander --target nrf52
0000265:WARNING:target_nRF52:NRF52832 APPROTECT enabled: not automatically unlocking
Exception while initing board: No cores were discovered!
Traceback (most recent call last):
File "devel/contrib/pyocd/pyocd/tools/pyocd.py", line 769, in connect
self.session.open(init_board=not self.args.no_init)
File "devel/contrib/pyocd/pyocd/core/session.py", line 371, in open
self._board.init()
File "devel/contrib/pyocd/pyocd/board/board.py", line 83, in init
self.target.init()
File "devel/contrib/pyocd/pyocd/core/coresight_target.py", line 164, in init
seq.invoke()
File "devel/contrib/pyocd/pyocd/utility/sequencer.py", line 208, in invoke
resultSequence = call()
File "devel/contrib/pyocd/pyocd/core/coresight_target.py", line 298, in check_for_cores
raise exceptions.DebugError("No cores were discovered!")
pyocd.core.exceptions.DebugError: No cores were discovered!
```
pyOCD has noticed that the chip is locked. It attempts routine initialization anyway, but fails to find any cores.
For all other pyOCD commands that connect to the target, pyOCD will, by default, attempt to
automatically unlock the target.
Disabling the security features on supported targets is very straight-forward. It typically requires
performing a mass erase of all device memory. For those pyOCD targets with support for security
features, pyOCD can perform this unlock procedure for you.
<div class="alert alert-warning">
Unlocking a locked device will erase all data on the chip!
</div>
You can add the option `auto_unlock` to your [configuration]({% link _docs/configuration.md %}):
```bash
(venv) ~/devel/contrib/pyocd$ pyocd commander --target nrf52 -O auto_unlock
0000264:WARNING:target_nRF52:NRF52832 APPROTECT enabled: will try to unlock via mass erase
Connected to NRF52832 [Halted]: I3FSNZOV
>>>
```
Note that the default for `auto_unlock` is True. Only in pyOCD Commander is this default changed,
because of how Commander is intended to be used for low-level interaction and inspection of the
target.
You can also do this interactively with pyOCD Commander:
```
(venv) $ pyocd commander --target nrf52840 -N
>>> initdp
>>> makeap 1
>>> status
Security: Locked
>>> unlock
>>> status
Security: Unlocked
>>> reinit
>>> status
Security: Unlocked
Core 0 status: Halted
>>>
```
An explanation of some of the commands and options appears below.
## Unsupported targets
If pyOCD doesn't support the security features of your MCU, you can still likely access them with
pyOCD Commander with the `no-init` option. A common pattern is that the security function locks out
the fully-functional AHB-AP, but leaves a second, proprietary AP unlocked. The second AP usually has
very few functions, mostly related to management (reset) or erase/unlock of the chip. Another method
used by some device families is to use only the standard AHB-AP, but when the device is locked the
accessible address range is limited to a small handful of registers.
Starting pyOCD Commander in `--no-init` mode is intended to help in these situations. It intentionally doesn't attempt
to interact with the target on startup. Without initialization, most commands will not work. You'll need to do some
manual initialization.
The usefulness of `--no-init` mode is that it allows Commander to start when initialization would
normally fail due to missing support for the target or security features of the MCU.
### Useful Options
Once you've started Commander `--no-init`, the following commands are most useful.
<dl>
<dt><em>initdp</em></dt>
<dd>Powers on and initializes the on-chip *Debug Port*, allowing Commander to issue commands to the
target</dd>
<dt><em>makeap <ap num></em></dt>
<dd>Targets have at least one, but sometimes more, *Access Ports*. Access port #0 is usually an AHB-AP that allows
debugging of the target. Access port #1, if it exists, is often proprietary to the vendor and allows
for certain functions to proceed *even if AP #0 is locked*.</dd>
<dt><em>readap <APSEL> <address></em></dt>
<dd>Read from an AP register</dd>
<dt><em>writeap <APSEL> <address> <value></em></dt>
<dd>Write to an AP register</dd>
<dt><em>status</em></dt>
<dd>Will show security status for supported targets. If the target is unlocked and the AHB-AP is
initialized, it will also show status for any cores detected (Running, Halted, &c)</dd>
<dt><em>reinit</em></dt>
<dd>This command will attempt to perform the normal initialization steps for the selected target. If you
manually unlock a target, you may want to run `reinit` so that the cores are accessible *without* restarting
Commander in normal mode (without `--no-init`)</dd>
</dl>
### Example
Let's pretend the nRF52 family is unsupported. Here's an example session where we'll use `no-init` mode to manually
unlock the target:
```
(venv) nock@nocko-wired:~/devel/contrib/pyocd$ pyocd commander -N
0000136:WARNING:board:Generic 'cortex_m' target type is selected; is this intentional? You will be able to debug but not program flash. To set the target type use the '--target' argument or 'target_override' option. Use 'pyocd list --targets' to see available targets types.
>>> initdp
```
We use `initdp` to initialize the *Debug Port* and power on the on-chip debug hardware.
The [nRF52 Product Specification](https://infocenter.nordicsemi.com/pdf/nRF52832_PS_v1.1.pdf) says that the chip has a
proprietary *CTRL-AP* at index 1 that supports a few operations even if the main AP is locked.
Let's let pyOCD know about it with `makeap`:
```
>>> makeap 1
AP#1 IDR = 0x02880000
```
The IDR register matches the datasheet! The datasheet says that CTRL-AP (AP #1) has the following registers:
<dl>
<dt><em>RESET</em> (0x000)</dt>
<dd>Writing 1 to this register asserts reset on the chip. Writing 0 takes is out of reset</dd>
<dt><em>ERASEALL</em> (0x004)</dt>
<dd>Writing 1 to this register starts a mass erase of the chip <i>and removes APPROTECT</i> unlocking the chip</dd>
<dt><em>ERASEALLSTATUS</em> (0x008)</dt>
<dd>While the chip is busy doing a mass erase, this register will read 1. When the mass erase is complete, the register
will read 0.</dd>
<dt><em>APPROTECTSTATUS</em> (0x00C)</dt>
<dd>If this register is 0, then APPROTECT is enabled (chip is locked), if 1 the chip is unlocked</dd>
</dl>
We can read the register value with `readap` and write a new value with `writeap`. Let's see if the chip is locked by
reading *APPROTECTSTATUS* on AP #1:
```
>>> readap 1 0x00C
AP register 0x100000c = 0x00000000
```
This chip is locked! Let's unlock it. We need to write a 1 to *ERASEALL* (on AP #1) to start the mass erase:
```
>>> writeap 1 0x004 1
```
Let's see if it has finished, by reading *ERASEALLSTATUS*:
```
>>> readap 1 0x008
AP register 0x1000008 = 0x00000001
>>> readap 1 0x008
AP register 0x1000008 = 0x00000000
```
After the first `readap` it was still erasing, but by the time the second `readap` was issued it was complete.
Let's check the security status by reading *APPROTECTSTATUS* again:
```
>>> readap 1 0x00C
AP register 0x100000c = 0x00000001
```
It's unlocked! Let's check the `status`:
```
>>> status
Security: Unlocked
>>> reinit
>>> status
Security: Unlocked
Core 0 status: Halted
>>>
```
The security was unlocked, but there are no cores (many commands like halt, reset, and so on need a core). It doesn't exist
since we started Commander in `no-init` mode. Running `reinit` from the CLI finishes the initialization that's
possible now that the chip is unlocked.
|