This series adds a RISC-V Debug Module model and wires it into
target/riscv and the virt machine.
It depends on two earlier patch sets:
- Max's Zvfbfa v5 series, which introduces the EXT_TB flags
mechanism reused here;
- the Sdext debug extension v5 series, which adds the base
debug-mode support that this series builds on.
The architectural reference for this work is the RISC-V Debug
Specification v1.0 (ratified 2025-02-21):
https://github.com/riscv/riscv-debug-spec/releases/tag/1.0
The implementation takes design cues from spike's debug module.
The focus is the Debug Module itself and the execution-based
debug flow around it. In practice, this means:
- target/riscv gains the plumbing needed to keep a hart in Debug
Mode while it executes from a DM ROM, and to route haltreq,
reset-haltreq, single-step completion, ebreak, exceptions, and
trigger-based debug entry through that ROM flow;
- hw/riscv gains a QOM Debug Module device with a DMI-style MMIO
window, a ROM work area, per-hart state tracking, run-control,
abstract register access, and system bus access;
- virt wires CPUs to the DM and exposes a stable layout for the
DMI window and ROM alias;
- qtest adds both protocol-level coverage and TCG-backed
execution tests for the full bring-up path on rv32 and rv64.
The series intentionally focuses on board-visible DM behavior.
It does not add a JTAG DTM frontend, authentication, or other
transport-side pieces. The result is a usable DM model for virt,
with enough target-side support to exercise the main spec-driven
debug flows and enough qtest coverage to keep the behavior
regression-resistant.
Current implementation status:
+-------------------+---------+---------+---------------------------+
| Area | Req/Opt | Status | Notes |
+-------------------+---------+---------+---------------------------+
| Debug entry | req | done | haltreq, reset-haltreq, |
| | | | ebreak, step, exceptions, |
| | | | triggers |
+-------------------+---------+---------+---------------------------+
| DM device | req | done | riscv-dm QOM, DMI MMIO, |
| | | | ROM work area, reset |
+-------------------+---------+---------+---------------------------+
| Hart state | req | done | halted, resumeack, |
| | | | havereset, haltsum0/1, |
| | | | hart selection |
+-------------------+---------+---------+---------------------------+
| Run-control | req | done | haltreq, resumereq, |
| | | | hartreset, ndmreset, |
| | | | reset-haltreq |
+-------------------+---------+---------+---------------------------+
| Abstract cmds | req | done | Access Register |
| | | | (GPR/CSR/FPR), DATA, |
| | | | PROGBUF, ABSTRACTAUTO |
+-------------------+---------+---------+---------------------------+
| SBA | opt | done | SBCS, SBADDRESS, SBDATA, |
| | | | sticky errors, auto-inc |
+-------------------+---------+---------+---------------------------+
| virt wiring | -- | done | DM address map, CPU |
| | | | hookup, ROM propagation |
+-------------------+---------+---------+---------------------------+
| ndmreset scope | req | partial | resets harts only, not |
| | | | other devices |
+-------------------+---------+---------+---------------------------+
| haltsum2/3 | opt | stub | present but read zero; |
| | | | only for >1024 harts |
+-------------------+---------+---------+---------------------------+
| Quick Access | opt | no | cmdtype=1 |
+-------------------+---------+---------+---------------------------+
| Access Memory | opt | no | cmdtype=2 |
+-------------------+---------+---------+---------------------------+
| DTM / JTAG | opt | no | transport-side, outside |
| | | | this series |
+-------------------+---------+---------+---------------------------+
| Authentication | opt | no | authdata absent; |
| | | | authenticated=1 |
+-------------------+---------+---------+---------------------------+
| Hart/resume | opt | no | dmcs2 absent, no group |
| groups | | | halt/resume |
+-------------------+---------+---------+---------------------------+
| External triggers | opt | no | DM ext-trigger I/O not |
| | | | wired |
+-------------------+---------+---------+---------------------------+
| keepalive | opt | no | set/clrkeepalive ignored |
+-------------------+---------+---------+---------------------------+
| ackunavail / | opt | no | sticky unavail not |
| stickyunavail | | | tracked |
+-------------------+---------+---------+---------------------------+
| confstrptr | opt | stub | always 0 |
+-------------------+---------+---------+---------------------------+
| Multi-DM/nextdm | opt | stub | always 0, single DM only |
+-------------------+---------+---------+---------------------------+
| 128-bit access | opt | no | aarsize=4, sbaccess128 |
+-------------------+---------+---------+---------------------------+
| Custom registers | opt | no | regno 0xC000-0xFFFF |
+-------------------+---------+---------+---------------------------+
| Cmds on running | opt | no | abstract cmds require |
| harts | | | halted hart |
+-------------------+---------+---------+---------------------------+
| Sub-word reg | opt | no | aarsize 8/16-bit not |
| access | | | supported |
+-------------------+---------+---------+---------------------------+
The main design choice is to follow the execution-based Debug
Module model described by the spec: the hart stays in Debug Mode,
enters a ROM park loop, and the DM coordinates state changes and
abstract command execution through mailbox words and generated
ROM snippets. This keeps the DM behavior explicit in the machine
model and avoids inventing a separate QEMU-only debug protocol.
The patches are split into three layers:
- patches 1-14 build the target/riscv side of the ROM-based
Debug Mode flow and make trigger-driven stops preserve the
right cause information;
- patches 15-23 add the Debug Module device model, per-hart
state tracking, run-control, register infrastructure, abstract
commands, system bus access, and virt integration;
- patches 24-28 add qtest coverage for the DMI register surface
and the TCG execution paths.
This series is also expected to help advance rvsp-ref machine
support, since Sdext is a required instruction extension for
rvsp-soc.
Thanks Tao Tang for running CI on this series:
https://gitlab.com/TaoTang/qemu/-/pipelines/2370872174
The resulting series has been validated with:
- `TMPDIR=/tmp QTEST_QEMU_BINARY=./build/qemu-system-riscv32 \
./build/tests/qtest/riscv-dm-test`
- `TMPDIR=/tmp QTEST_QEMU_BINARY=./build/qemu-system-riscv64 \
./build/tests/qtest/riscv-dm-test`
Thanks,
Chao
Chao Liu (28):
target/riscv: track pending Debug Module halt requests
target/riscv: keep Debug Mode active when a DM ROM is present
target/riscv: enter Debug Mode from pending DM halt requests
target/riscv: route in-debug exceptions back to the DM ROM
target/riscv: re-enter the DM ROM after single-step completion
target/riscv: let ebreak enter the DM ROM
target/riscv: restart the DM ROM on debug-mode ebreak
target/riscv: track the exact breakpoint trigger hit
target/riscv: track the exact watchpoint trigger hit
target/riscv: send trigger debug-mode actions to the DM ROM
target/riscv: suppress itrigger TB state in Debug Mode
target/riscv: tighten itrigger privilege and count checks
target/riscv: allow debug-mode actions for itrigger
target/riscv: stop consuming itrigger counts in Debug Mode
hw/riscv: add an initial Debug Module device model
hw/riscv/dm: track per-hart debug state
hw/riscv/dm: add hart run-control operations
hw/riscv/dm: queue reset halts from the reset work item
hw/riscv/dm: add DMI register declarations and ROM entry program
hw/riscv/dm: add register handlers and update state management
hw/riscv/dm: add abstract command execution
hw/riscv/dm: add system bus access
hw/riscv/virt: integrate the Debug Module
tests/qtest: add initial RISC-V Debug Module tests
tests/qtest: extend DM register semantics coverage
tests/qtest: add DM abstract command and halt/resume tests
tests/qtest: add DM TCG halt and register access tests
tests/qtest: add DM TCG single-step and trigger tests
MAINTAINERS | 1 +
hw/riscv/Kconfig | 5 +
hw/riscv/dm.c | 2017 +++++++++++++++++++++++++++++++++++
hw/riscv/meson.build | 2 +
hw/riscv/trace-events | 14 +
hw/riscv/virt.c | 21 +-
include/hw/riscv/dm.h | 139 +++
target/riscv/cpu.c | 68 ++
target/riscv/cpu.h | 8 +
target/riscv/cpu_bits.h | 1 +
target/riscv/cpu_helper.c | 60 +-
target/riscv/debug.c | 249 ++---
target/riscv/machine.c | 2 +
target/riscv/op_helper.c | 15 +
target/riscv/tcg/tcg-cpu.c | 12 +-
tests/qtest/meson.build | 7 +-
tests/qtest/riscv-dm-test.c | 1914 +++++++++++++++++++++++++++++++++
17 files changed, 4410 insertions(+), 125 deletions(-)
create mode 100644 hw/riscv/dm.c
create mode 100644 include/hw/riscv/dm.h
create mode 100644 tests/qtest/riscv-dm-test.c
--
2.53.0