OpenOCD unintendedly interacts with lc_ctrl as if it were a Debug Module
- Dominant language
- SystemVerilog
- Stars
- 3.6k
- Forks
- 1.1k
- Avg merge
- 2d 22h
- Merged PRs (30d)
- 141
Description
### Description
The OpenTitan life cycle controller uses a JTAG <-> DTM <-> DMI <-> TL-UL interface to expose its registers over JTAG. It does this following the RISC-V debug spec 0.13, except that on the bus slave side we have the lc_ctrl's registers instead of the usual Debug Module's registers.
This is very convenient to use with OpenOCD, as we can use it to interact with the lc_ctrl over JTAG using OpenOCD `riscv dmi_read` and `riscv dmi_write` commands.
Unfortunately, when OpenOCD connects to the lc_ctrl's JTAG TAP, it automatically tries to configure the DM it expects to find there. That means it reads and writes to arbitrary lc_ctrl registers, the ones that just so happen to have an offset matching the intended DM's register offsets (after a 1:4 offset adjustment). Namely, it tries to interact with a DM's `dmcontrol` (0x10) and instead interacts with the lc_ctrl's `LC_ID_STATE` (4 x 0x10). If the device's id state is `BLANK` (0x00000000) then it will think it can't initialize the DM (the `dmactive` field of `dmcontrol` doesn't go to 1, despite the attempted write there to make it so). If the device's id state is `PERSONALIZED` (0x55555555) it will think it's active and will continue trying to initialize the "DM", interacting with the `dmstatus` (0x11) / `HW_REVISION0` (0x44) and `hartinfo` (0x12) / `HW_REVISION1` (0x48).
This hasn't been a problem in practice because those reads and writes just so happen to not have any meaningful consequences. But that's just a happy coincidence, so ideally this should be addressed.
I looked into a few OpenOCD configuration options to prevent the automatic examination of the DM, but unfortunately they seemed to break the DMI read and write commands, so that didn't work out.
In the past we (some lowRISC engineers) have considered using the probe-rs Rust library instead of OpenOCD. Presumably that would also solve this problem, so maybe that's worth looking into sometime.
Contributor guide
Research direction
Start by reproducing OpenOCD's connection to the life cycle controller's JTAG TAP and tracing its automatic Debug Module examination, especially accesses to dmcontrol, dmstatus, and hartinfo. Compare configuration options that preserve riscv dmi_read and riscv dmi_write, and consider whether the probe-rs Rust library is a viable alternative; done means avoiding unintended lc_ctrl register interactions without breaking DMI access.
Written by the indexing model from the issue text.
Assessment
- Domain
- devtools, embedded-iot
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 28/100