From: Chao Liu <chao.liu.zevorn@gmail.com>
To: Daniel Henrique Barboza <dbarboza@ventanamicro.com>,
Alistair Francis <alistair.francis@wdc.com>,
Palmer Dabbelt <palmer@dabbelt.com>,
Weiwei Li <liwei1518@gmail.com>,
Liu Zhiwei <zhiwei_liu@linux.alibaba.com>
Cc: qemu-devel@nongnu.org, qemu-riscv@nongnu.org,
wangjingwei@iscas.ac.cn, hust-os-kernel-patches@googlegroups.com
Subject: Re: [RFC PATCH v3 2/7] target/riscv: add sdext debug CSRs state
Date: Fri, 30 Jan 2026 14:14:26 +0800 [thread overview]
Message-ID: <a951ffca-9df6-4eef-8a9c-bd0e842564f6@gmail.com> (raw)
In-Reply-To: <b4c0b660-7a06-4b09-9a6e-6e984d54de6c@ventanamicro.com>
Hi Daniel,
On 1/29/2026 3:42 AM, Daniel Henrique Barboza wrote:
>
>
> On 1/27/2026 10:15 AM, Chao Liu wrote:
>> RISC-V Debug Specification:
>> https://github.com/riscv/riscv-debug-spec/releases/tag/1.0
>>
>> Add architectural state for Sdext Debug Mode: debug_mode, dcsr, dpc
>> and dscratch0/1. Wire up CSR access for dcsr/dpc/dscratch and gate
>> them to Debug Mode (or host debugger access).
>>
>> The Sdext is not fully implemented, so it is disabled by default.
>>
>> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
>> ---
>> target/riscv/cpu.c | 10 +++
>> target/riscv/cpu.h | 4 +
>> target/riscv/cpu_bits.h | 33 ++++++++
>> target/riscv/cpu_cfg_fields.h.inc | 1 +
>> target/riscv/csr.c | 126 ++++++++++++++++++++++++++++++
>> target/riscv/machine.c | 20 +++++
>> 6 files changed, 194 insertions(+)
>>
>> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
>> index 0ba98a62e4..ba8fd1557a 100644
>> --- a/target/riscv/cpu.c
>> +++ b/target/riscv/cpu.c
>> @@ -209,6 +209,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
>> ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
>> ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
>> ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
>> + ISA_EXT_DATA_ENTRY(sdext, PRIV_VERSION_1_12_0, ext_sdext),
>> ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, ext_sdtrig),
>> ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, has_priv_1_12),
>> ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha),
>> @@ -779,6 +780,11 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType
>> type)
>> /* Default NaN value: sign bit clear, frac msb set */
>> set_float_default_nan_pattern(0b01000000, &env->fp_status);
>> env->vill = true;
>> + env->debug_mode = false;
>> + env->dcsr = DCSR_DEBUGVER(4);
>> + env->dpc = 0;
>> + env->dscratch[0] = 0;
>> + env->dscratch[1] = 0;
>> #ifndef CONFIG_USER_ONLY
>> if (cpu->cfg.ext_sdtrig) {
>> @@ -1131,6 +1137,9 @@ static void riscv_cpu_init(Object *obj)
>> */
>> cpu->cfg.ext_sdtrig = true;
>> + /* sdext is not fully implemented, so it is disabled by default. */
>> + cpu->cfg.ext_sdext = false;
>> +
>> if (mcc->def->profile) {
>> mcc->def->profile->enabled = true;
>> }
>> @@ -1245,6 +1254,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
>> MULTI_EXT_CFG_BOOL("smcdeleg", ext_smcdeleg, false),
>> MULTI_EXT_CFG_BOOL("sscsrind", ext_sscsrind, false),
>> MULTI_EXT_CFG_BOOL("ssccfg", ext_ssccfg, false),
>> + MULTI_EXT_CFG_BOOL("sdext", ext_sdext, false),
>> MULTI_EXT_CFG_BOOL("sdtrig", ext_sdtrig, true),
>> MULTI_EXT_CFG_BOOL("smctr", ext_smctr, false),
>> MULTI_EXT_CFG_BOOL("ssctr", ext_ssctr, false),
>> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>> index 5c6824f2d3..a474494dff 100644
>> --- a/target/riscv/cpu.h
>> +++ b/target/riscv/cpu.h
>> @@ -476,6 +476,10 @@ struct CPUArchState {
>> /* True if in debugger mode. */
>> bool debugger;
>> + bool debug_mode;
>> + target_ulong dcsr;
>> + target_ulong dpc;
>> + target_ulong dscratch[2];
>
> This patch (and I believe almost every single other patch that follows) won't
> build in the linux-user target. It will throw errors like this:
>
> ../target/riscv/cpu_helper.c: In function ‘riscv_cpu_enter_debug_mode’:
> ../target/riscv/cpu_helper.c:154:8: error: ‘CPURISCVState’ {aka ‘struct
> CPUArchState’} has no member named ‘debug_mode’ 154 | env->debug_mode =
> true; | ^~
> ../target/riscv/cpu_helper.c:155:10: error:
> ‘CPURISCVState’ {aka ‘struct CPUArchState’} has no member named ‘dpc’; did you
> mean ‘pc’? 155 |
> env->dpc = pc & get_xepc_mask(env);
> | ^~~
>
>
> The reason is that the flags you're declaring up above exist only in the system
> emulation mode. If you double check target/riscv/cpu.h you'll notice that the
> flags you're adding are inside a big ifdef around line 270:
>
> #ifndef CONFIG_USER_ONLY
> /* This contains QEMU specific information about the virt state. */
>
>
> So debug_mode, dscr, dpc and dscratch aren't available for user mode. Note that
> this is correct - user mode can't deal with sdext or any other debug trigger
> extension. But you'll have to gate all logic that uses those flags in #ifndef
> CONFIG_USER_ONLY blocks.
>
>
> For example, in patch 3:
>
>
> +void riscv_cpu_enter_debug_mode(CPURISCVState *env, target_ulong pc,
> + uint32_t cause)
> +{
> +#ifndef CONFIG_USER_ONLY
> + if (!riscv_sdext_enabled(env)) {
> + return;
> + }
> +#endif
> + env->debug_mode = true;
> + env->dpc = pc & get_xepc_mask(env);
> + env->dcsr &= ~(DCSR_CAUSE_MASK | DCSR_PRV_MASK | DCSR_V);
> + env->dcsr |= ((target_ulong)(cause & 0x7)) << DCSR_CAUSE_SHIFT;
> + env->dcsr |= env->priv & DCSR_PRV_MASK;
> + if (env->virt_enabled && riscv_has_ext(env, RVH)) {
> + env->dcsr |= DCSR_V;
> + }
> +#ifndef CONFIG_USER_ONLY
> + if (env_archcpu(env)->cfg.ext_zicfilp) {
> + if (env->elp) {
> + env->dcsr |= DCSR_PELP;
> + } else {
> + env->dcsr &= ~DCSR_PELP;
> + }
> + env->elp = false;
> + }
> +#endif
>
>
> We want the whole function body inside an "#ifndef CONFIG_USER_ONLY" because
> everything being done is unavailable in that mode.
>
> You can use the build target 'riscv64-linux-user' to build qemu-riscv64 (i.e.
> user mode) to check if the patches will break it by accident. I usually build
> all riscv targets to catch this type of build errors:
>
>
> ./configure --target-list=riscv64-softmmu,riscv64-linux-user,riscv32-
> softmmu,riscv32-linux-user (...)
>
>
Thanks for catching this! You're right - I missed the linux-user build
target entirely.
I'll fix this in v4 by moving debug_mode/dcsr/dpc/dscratch fields inside
the #ifndef CONFIG_USER_ONLY block in cpu.h, and wrapping all code using
these fields with proper guards.
Thanks,
Chao
>
> Thanks,
> Daniel
>
>
>
>
>> uint64_t mstateen[SMSTATEEN_MAX_COUNT];
>> uint64_t hstateen[SMSTATEEN_MAX_COUNT];
>> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>> index b62dd82fe7..bb59f7ff56 100644
>> --- a/target/riscv/cpu_bits.h
>> +++ b/target/riscv/cpu_bits.h
>> @@ -467,6 +467,39 @@
>> #define CSR_DCSR 0x7b0
>> #define CSR_DPC 0x7b1
>> #define CSR_DSCRATCH 0x7b2
>> +#define CSR_DSCRATCH1 0x7b3
>> +
>> +/* DCSR fields */
>> +#define DCSR_XDEBUGVER_SHIFT 28
>> +#define DCSR_XDEBUGVER_MASK (0xfu << DCSR_XDEBUGVER_SHIFT)
>> +#define DCSR_DEBUGVER(val) ((target_ulong)(val) << DCSR_XDEBUGVER_SHIFT)
>> +#define DCSR_EXTCAUSE_SHIFT 24
>> +#define DCSR_EXTCAUSE_MASK (0x7u << DCSR_EXTCAUSE_SHIFT)
>> +#define DCSR_CETRIG BIT(19)
>> +#define DCSR_PELP BIT(18)
>> +#define DCSR_EBREAKVS BIT(17)
>> +#define DCSR_EBREAKVU BIT(16)
>> +#define DCSR_EBREAKM BIT(15)
>> +#define DCSR_EBREAKS BIT(13)
>> +#define DCSR_EBREAKU BIT(12)
>> +#define DCSR_STEPIE BIT(11)
>> +#define DCSR_STOPCOUNT BIT(10)
>> +#define DCSR_STOPTIME BIT(9)
>> +#define DCSR_CAUSE_SHIFT 6
>> +#define DCSR_CAUSE_MASK (0x7u << DCSR_CAUSE_SHIFT)
>> +#define DCSR_V BIT(5)
>> +#define DCSR_MPRVEN BIT(4)
>> +#define DCSR_NMIP BIT(3)
>> +#define DCSR_STEP BIT(2)
>> +#define DCSR_PRV_MASK 0x3u
>> +
>> +#define DCSR_CAUSE_EBREAK 1
>> +#define DCSR_CAUSE_TRIGGER 2
>> +#define DCSR_CAUSE_HALTREQ 3
>> +#define DCSR_CAUSE_STEP 4
>> +#define DCSR_CAUSE_RESET 5
>> +#define DCSR_CAUSE_GROUP 6
>> +#define DCSR_CAUSE_OTHER 7
>> /* Performance Counters */
>> #define CSR_MHPMCOUNTER3 0xb03
>> diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/
>> cpu_cfg_fields.h.inc
>> index 492fdd1553..4b157ac920 100644
>> --- a/target/riscv/cpu_cfg_fields.h.inc
>> +++ b/target/riscv/cpu_cfg_fields.h.inc
>> @@ -46,6 +46,7 @@ BOOL_FIELD(ext_zilsd)
>> BOOL_FIELD(ext_zimop)
>> BOOL_FIELD(ext_zcmop)
>> BOOL_FIELD(ext_ztso)
>> +BOOL_FIELD(ext_sdext)
>> BOOL_FIELD(ext_sdtrig)
>> BOOL_FIELD(ext_smstateen)
>> BOOL_FIELD(ext_sstc)
>> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>> index 870fad87ac..3e38c943e0 100644
>> --- a/target/riscv/csr.c
>> +++ b/target/riscv/csr.c
>> @@ -3136,6 +3136,126 @@ static RISCVException write_mtval(CPURISCVState *env,
>> int csrno,
>> return RISCV_EXCP_NONE;
>> }
>> +#if !defined(CONFIG_USER_ONLY)
>> +static RISCVException sdext(CPURISCVState *env, int csrno)
>> +{
>> + if (!riscv_cpu_cfg(env)->ext_sdext) {
>> + return RISCV_EXCP_ILLEGAL_INST;
>> + }
>> +
>> + if (!env->debug_mode && !env->debugger) {
>> + return RISCV_EXCP_ILLEGAL_INST;
>> + }
>> +
>> + return RISCV_EXCP_NONE;
>> +}
>> +
>> +static target_ulong dcsr_visible_mask(CPURISCVState *env)
>> +{
>> + target_ulong mask = (target_ulong)-1;
>> + RISCVCPU *cpu = env_archcpu(env);
>> +
>> + if (!riscv_has_ext(env, RVH)) {
>> + mask &= ~(DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V);
>> + }
>> + if (!riscv_has_ext(env, RVS)) {
>> + mask &= ~DCSR_EBREAKS;
>> + }
>> + if (!riscv_has_ext(env, RVU)) {
>> + mask &= ~DCSR_EBREAKU;
>> + }
>> + if (!cpu->cfg.ext_zicfilp) {
>> + mask &= ~DCSR_PELP;
>> + }
>> + if (!cpu->cfg.ext_smdbltrp) {
>> + mask &= ~DCSR_CETRIG;
>> + }
>> +
>> + return mask;
>> +}
>> +
>> +static RISCVException read_dcsr(CPURISCVState *env, int csrno,
>> + target_ulong *val)
>> +{
>> + *val = env->dcsr & dcsr_visible_mask(env);
>> + return RISCV_EXCP_NONE;
>> +}
>> +
>> +static target_ulong dcsr_writable_mask(CPURISCVState *env)
>> +{
>> + target_ulong mask = DCSR_EBREAKM | DCSR_EBREAKS | DCSR_EBREAKU |
>> + DCSR_STEPIE | DCSR_STOPCOUNT | DCSR_STOPTIME |
>> + DCSR_STEP | DCSR_PRV_MASK;
>> + RISCVCPU *cpu = env_archcpu(env);
>> +
>> + mask |= DCSR_MPRVEN;
>> +
>> + if (riscv_has_ext(env, RVH)) {
>> + mask |= DCSR_EBREAKVS | DCSR_EBREAKVU | DCSR_V;
>> + }
>> + if (riscv_has_ext(env, RVS)) {
>> + mask |= DCSR_EBREAKS;
>> + }
>> + if (riscv_has_ext(env, RVU)) {
>> + mask |= DCSR_EBREAKU;
>> + }
>> + if (cpu->cfg.ext_zicfilp) {
>> + mask |= DCSR_PELP;
>> + }
>> + if (cpu->cfg.ext_smdbltrp) {
>> + mask |= DCSR_CETRIG;
>> + }
>> +
>> + return mask;
>> +}
>> +
>> +static RISCVException write_dcsr(CPURISCVState *env, int csrno,
>> + target_ulong val, uintptr_t ra)
>> +{
>> + target_ulong mask = dcsr_writable_mask(env);
>> + target_ulong new_val = env->dcsr;
>> +
>> + new_val &= ~mask;
>> + new_val |= val & mask;
>> + new_val &= ~DCSR_XDEBUGVER_MASK;
>> + new_val |= DCSR_DEBUGVER(4);
>> + env->dcsr = new_val;
>> + return RISCV_EXCP_NONE;
>> +}
>> +
>> +static RISCVException read_dpc(CPURISCVState *env, int csrno,
>> + target_ulong *val)
>> +{
>> + *val = env->dpc & get_xepc_mask(env);
>> + return RISCV_EXCP_NONE;
>> +}
>> +
>> +static RISCVException write_dpc(CPURISCVState *env, int csrno,
>> + target_ulong val, uintptr_t ra)
>> +{
>> + env->dpc = val & get_xepc_mask(env);
>> + return RISCV_EXCP_NONE;
>> +}
>> +
>> +static RISCVException read_dscratch(CPURISCVState *env, int csrno,
>> + target_ulong *val)
>> +{
>> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
>> +
>> + *val = env->dscratch[index];
>> + return RISCV_EXCP_NONE;
>> +}
>> +
>> +static RISCVException write_dscratch(CPURISCVState *env, int csrno,
>> + target_ulong val, uintptr_t ra)
>> +{
>> + int index = (csrno == CSR_DSCRATCH1) ? 1 : 0;
>> +
>> + env->dscratch[index] = val;
>> + return RISCV_EXCP_NONE;
>> +}
>> +#endif /* !CONFIG_USER_ONLY */
>> +
>> /* Execution environment configuration setup */
>> static RISCVException read_menvcfg(CPURISCVState *env, int csrno,
>> target_ulong *val)
>> @@ -6297,6 +6417,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>> [CSR_TDATA3] = { "tdata3", debug, read_tdata, write_tdata },
>> [CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore },
>> [CSR_MCONTEXT] = { "mcontext", debug, read_mcontext, write_mcontext },
>> +#if !defined(CONFIG_USER_ONLY)
>> + [CSR_DCSR] = { "dcsr", sdext, read_dcsr, write_dcsr },
>> + [CSR_DPC] = { "dpc", sdext, read_dpc, write_dpc },
>> + [CSR_DSCRATCH] = { "dscratch0", sdext, read_dscratch, write_dscratch },
>> + [CSR_DSCRATCH1] = { "dscratch1", sdext, read_dscratch, write_dscratch },
>> +#endif
>> [CSR_MCTRCTL] = { "mctrctl", ctr_mmode, NULL, NULL,
>> rmw_xctrctl },
>> [CSR_SCTRCTL] = { "sctrctl", ctr_smode, NULL, NULL,
>> rmw_xctrctl },
>> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
>> index 62c51c8033..52264cf047 100644
>> --- a/target/riscv/machine.c
>> +++ b/target/riscv/machine.c
>> @@ -248,6 +248,25 @@ static const VMStateDescription vmstate_sdtrig = {
>> VMSTATE_UINTTL_ARRAY(env.tdata1, RISCVCPU, RV_MAX_TRIGGERS),
>> VMSTATE_UINTTL_ARRAY(env.tdata2, RISCVCPU, RV_MAX_TRIGGERS),
>> VMSTATE_UINTTL_ARRAY(env.tdata3, RISCVCPU, RV_MAX_TRIGGERS),
>> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
>> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
>> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
>> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static const VMStateDescription vmstate_sdext = {
>> + .name = "cpu/sdext",
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .needed = sdtrig_needed,
>> + .post_load = sdtrig_post_load,
>> + .fields = (const VMStateField[]) {
>> + VMSTATE_BOOL_V(env.debug_mode, RISCVCPU, 3),
>> + VMSTATE_UINTTL_V(env.dcsr, RISCVCPU, 3),
>> + VMSTATE_UINTTL_V(env.dpc, RISCVCPU, 3),
>> + VMSTATE_UINTTL_ARRAY_V(env.dscratch, RISCVCPU, 2, 3),
>> VMSTATE_END_OF_LIST()
>> }
>> };
>> @@ -499,6 +518,7 @@ const VMStateDescription vmstate_riscv_cpu = {
>> &vmstate_ctr,
>> &vmstate_sstc,
>> &vmstate_sdtrig,
>> + &vmstate_sdext,
>> NULL
>> }
>> };
>
next prev parent reply other threads:[~2026-01-30 6:14 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-27 13:15 [RFC PATCH v3 0/7] riscv: add initial sdext support Chao Liu
2026-01-27 13:15 ` [RFC PATCH v3 1/7] target/riscv: deprecate 'debug' CPU property Chao Liu
2026-01-27 13:15 ` [RFC PATCH v3 2/7] target/riscv: add sdext debug CSRs state Chao Liu
2026-01-28 19:42 ` Daniel Henrique Barboza
2026-01-30 6:14 ` Chao Liu [this message]
2026-01-27 13:15 ` [RFC PATCH v3 3/7] target/riscv: add sdext Debug Mode helpers Chao Liu
2026-01-27 13:15 ` [RFC PATCH v3 4/7] target/riscv: add dret instruction Chao Liu
2026-01-27 13:15 ` [RFC PATCH v3 5/7] target/riscv: add sdext enter Debug Mode on ebreak Chao Liu
2026-01-27 13:15 ` [RFC PATCH v3 6/7] target/riscv: add sdext single-step support Chao Liu
2026-01-27 13:15 ` [RFC PATCH v3 7/7] target/riscv: add sdtrig trigger action=debug mode Chao Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a951ffca-9df6-4eef-8a9c-bd0e842564f6@gmail.com \
--to=chao.liu.zevorn@gmail.com \
--cc=alistair.francis@wdc.com \
--cc=dbarboza@ventanamicro.com \
--cc=hust-os-kernel-patches@googlegroups.com \
--cc=liwei1518@gmail.com \
--cc=palmer@dabbelt.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=wangjingwei@iscas.ac.cn \
--cc=zhiwei_liu@linux.alibaba.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.