From nobody Sat Apr 11 23:04:22 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1772954561; cv=none; d=zohomail.com; s=zohoarc; b=LRXCzhKTdXK6ZKDXIHHpIlnBSQQLzzG6bEB9y/4ZOp1+/1CZv16o+qj8Il1VvtP7a2JUT0l8XvnHTsup4gFLYR4J+4U7/eB50WaZGR+wpQRGwNf5P9yZUDje7JyaBARkpCQW+5XAlaUfdWMAXkIA6wVR6Nu23ZyCy4CsQEUgtXM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1772954561; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=pf7Lj7RfCx/IUDSUNJ3d5FggA7Ilj5s8BkMaCOmMuME=; b=JbPyOK7+E/a+mvE5FKOR5u2adcoX8nLzTq1CtVuwQ4IXWxXDNkrb3otd2OMfg3EsG4OjggM9ttaveBfDWnTWlUPP2b4oAcmtQ7rksJCvup2RegDNBn+0n+G9hZK6PNStSh8iNUGIIx7mZz8F44tvbkqVzhJw0NcNRmO8bvL2IfI= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1772954561515109.8100354441599; Sat, 7 Mar 2026 23:22:41 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vz8S2-00030P-J3; Sun, 08 Mar 2026 03:21:26 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1vz8RP-00029h-8o for qemu-devel@nongnu.org; Sun, 08 Mar 2026 03:20:47 -0400 Received: from mail-dy1-x1342.google.com ([2607:f8b0:4864:20::1342]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vz8RL-0002s5-KL for qemu-devel@nongnu.org; Sun, 08 Mar 2026 03:20:43 -0400 Received: by mail-dy1-x1342.google.com with SMTP id 5a478bee46e88-2be1b5fe11cso6989105eec.0 for ; Sat, 07 Mar 2026 23:20:38 -0800 (PST) Received: from ZEVORN-PC.bbrouter ([38.95.120.198]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2be4f984ceasm6014081eec.32.2026.03.07.23.20.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Mar 2026 23:20:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1772954437; x=1773559237; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=pf7Lj7RfCx/IUDSUNJ3d5FggA7Ilj5s8BkMaCOmMuME=; b=MVa5G9IKXGPxheaq2QFWcjUUHlce13sFoqObImIeojbk45/l1DOOeNe3afABqatBna eW9nClaA3gxIFPbLLZq1NKdVEODxSTFHd/Bqu73npg1J90GF+fJgGuJcAqFWWEi3MAPF 0Rn8c0BtAMgDb/kRQqJ7KZVDLnKSpxTxK1n0bXNtruFZlcKDRr2Emcz46CVFyMlaxU7y 59BYq03SU8WnCS/aXqzHjx6NXsdtfJl3eLASP7TqGdWlWqaPJv07Vux+wN0I8OhBh5R6 bqNzeCfs7cnuD1/r1dW6vchtu8qT4SBKPThlkdtAD3CdAZkUWiNjqQOD+SvUH9NY3b5X +bRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772954437; x=1773559237; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=pf7Lj7RfCx/IUDSUNJ3d5FggA7Ilj5s8BkMaCOmMuME=; b=jtmWNmxtzpP/jddA96VB3Nt82VYhsurU1GDnnCAqpZMs1IWVniZbTeYB5ISDf02T6V D9bXUOry4UGti2+GAeKMJI2GfYSjGK2SIWNgFqnU/WlWgrWXfUaC1ErFz/D3wP+b5lGE COmT7KIM12+uI2Px6kTGjrsxXe8JXSGZoGKgYjWox0tqbWHS2UyFDjY5I+CcNjxxtuC9 ow37Jik8TbMPYR5RYWOtOaqqmF4jyklGOlri3iwYC8cjbi0kJyORbEx314Sn6KIxRLQT WPqL8xhAoRenMD5+80Qn/nPbY0wOsmEESLJMdb9hDNBaUi8PuK1b+EWqbCEsM6zu/sN/ RV+w== X-Forwarded-Encrypted: i=1; AJvYcCUp5EgS+6ZzszNrQLx4FpeWCOHCr+97O/d7u41B4sZ6dB/INYokfl+Q5j2at5H/qctO2VuFGi7EkwXA@nongnu.org X-Gm-Message-State: AOJu0YztUKQZwQcQTLJejxXdW9nH0iPBHnSWlY7O/N+dK3jaafQYR4OM 2PooiS2sdNb1WZX3ZWgx9F6NSlKJ0GPx+2IHjwcKrnTDYroZ5abZ8wi1 X-Gm-Gg: ATEYQzy/gN7gCNykSW3hx1OGSrm3UQwPYU8eK/yN0brszJUTVEluEW9iZwq3XKMehpZ Tt4V0eslbsbwNp5Zixt7CBhLDL5JKYoUO3xd8ZXcbnJFfrWEH7+l73AEJjsaDegDqTpJKr+oVOE TucB4Av1IRsMQ5/AfhXhxf1jOXA87E1tQBH4r65F81PUWu4sVWfFb0nQh5D9XtvcBvHp3Fp5agr zyKrxxIyZPi9pu9Sfxld7+mKrFhphRsmaE+henC+OmO3Bl8uF4y6fW2BwRvxO0Ftcc81AvNArjN 8ZLGFTUzkn67sWXcailaMJsOO/zjuPuxfMUAgTO1LxZWOM7NmaNFKGRCGM8AEudwCKiTPZ0XWkc XoMr3/a2SPHA9k+BkM0GUvJ44o7BvcTgf1leEJxzWKuMbns5GLNotL+bGwuByZtdS4ur8n6ChXF OuQKq8L6hULTZWrd+o0OFoyQ/3k2kWdHFl/ApJy6zAQehgGbXkDM6b+8GNPr0zS352rM/D8K19p StQj4nzAoYWWw8jPLgnWbPUOz4= X-Received: by 2002:a05:7022:6892:b0:119:e569:f615 with SMTP id a92af1059eb24-128c2ddc872mr3107220c88.14.1772954437073; Sat, 07 Mar 2026 23:20:37 -0800 (PST) From: Chao Liu To: Paolo Bonzini , Palmer Dabbelt , Alistair Francis , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , Chao Liu , Fabiano Rosas , Laurent Vivier Cc: tangtao1634@phytium.com.cn, qemu-devel@nongnu.org, qemu-riscv@nongnu.org Subject: [PATCH v1 21/28] hw/riscv/dm: add abstract command execution Date: Sun, 8 Mar 2026 15:17:24 +0800 Message-ID: <07fdc457972b18350ba37019370fea56fba70019.1772936778.git.chao.liu.zevorn@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::1342; envelope-from=chao.liu.zevorn@gmail.com; helo=mail-dy1-x1342.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1772954563681158500 Content-Type: text/plain; charset="utf-8" Implement execution-based abstract commands following the pattern described in the RISC-V Debug Specification Appendix A.2. The Access Register command generates RISC-V instructions into the ROM command space for CSR (0x0000-0x0FFF), GPR (0x1000-0x101F), and FPR (0x1020-0x103F) transfers. The hart executes these instructions, and the DM detects completion when the hart returns to the park loop. This also adds the COMMAND and ABSTRACTAUTO register handlers, the autoexec mechanism that re-executes the last command on DATA or PROGBUF access, and the CMDERR sticky error reporting. Signed-off-by: Chao Liu --- hw/riscv/dm.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 3 deletions(-) diff --git a/hw/riscv/dm.c b/hw/riscv/dm.c index 169863c54c..818e48629f 100644 --- a/hw/riscv/dm.c +++ b/hw/riscv/dm.c @@ -336,6 +336,18 @@ static inline bool dm_ndmreset_active(RISCVDMState *s) return ARRAY_FIELD_EX32(s->regs, DMCONTROL, NDMRESET); } =20 +static RISCVCPU *dm_get_cpu(RISCVDMState *s, uint32_t hartsel) +{ + CPUState *cs; + + if (!dm_hart_valid(s, hartsel)) { + return NULL; + } + + cs =3D qemu_get_cpu(hartsel); + return cs ? RISCV_CPU(cs) : NULL; +} + static bool dm_abstract_cmd_completed(RISCVDMState *s, uint32_t hartsel) { uint32_t selected =3D dm_get_hartsel(s); @@ -545,6 +557,185 @@ static inline void dm_set_cmderr(RISCVDMState *s, uin= t32_t err) ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, CMDERR, err); } } +static void dm_execute_access_register(RISCVDMState *s, uint32_t command) +{ + uint32_t regno =3D FIELD_EX32(command, COMMAND, REGNO); + bool write =3D FIELD_EX32(command, COMMAND, WRITE); + bool transfer =3D FIELD_EX32(command, COMMAND, TRANSFER); + bool postexec =3D FIELD_EX32(command, COMMAND, POSTEXEC); + bool aarpostinc =3D FIELD_EX32(command, COMMAND, AARPOSTINCREMENT); + uint32_t aarsize =3D FIELD_EX32(command, COMMAND, AARSIZE); + + uint32_t hartsel =3D dm_get_hartsel(s); + RISCVCPU *cpu =3D dm_get_cpu(s, hartsel); + bool csr_hit =3D (regno <=3D RISCV_DM_REGNO_CSR_END); + bool gpr_hit =3D (regno >=3D RISCV_DM_REGNO_GPR_START && + regno <=3D RISCV_DM_REGNO_GPR_END); + bool fpr_hit =3D (regno >=3D RISCV_DM_REGNO_FPR_START && + regno <=3D RISCV_DM_REGNO_FPR_END); + uint32_t max_aarsize =3D 0; + + /* Hart must be halted */ + if (!dm_hart_valid(s, hartsel) || !s->hart_halted[hartsel]) { + dm_set_cmderr(s, RISCV_DM_CMDERR_HALTRESUME); + trace_riscv_dm_abstract_cmd_rejected("hart_not_halted", + ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR)); + return; + } + + if (!cpu) { + dm_set_cmderr(s, RISCV_DM_CMDERR_HALTRESUME); + trace_riscv_dm_abstract_cmd_rejected("hart_unavailable", + ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR)); + return; + } + + dm_flush_cmd_space(s); + + if (transfer) { + if (csr_hit || gpr_hit) { + max_aarsize =3D riscv_cpu_mxl(&cpu->env) =3D=3D MXL_RV32 ? 2 := 3; + } else if (fpr_hit) { + if (riscv_has_ext(&cpu->env, RVD)) { + max_aarsize =3D 3; + } else if (riscv_has_ext(&cpu->env, RVF)) { + max_aarsize =3D 2; + } + } + + if ((csr_hit || gpr_hit || fpr_hit) && + (aarsize < 2 || aarsize > max_aarsize)) { + dm_set_cmderr(s, RISCV_DM_CMDERR_NOTSUP); + trace_riscv_dm_abstract_cmd_rejected("unsupported_aarsize", + ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR)); + return; + } + + if (!write) { + /* Read: copy register -> data */ + if (csr_hit) { + dm_rom_write32(s, RISCV_DM_ROM_CMD + 2 * 4, + DM_CSRR(regno & 0xFFF)); + dm_rom_write32(s, RISCV_DM_ROM_CMD + 3 * 4, + DM_DATA_STORE(8, aarsize)); + } else if (gpr_hit) { + if ((regno & 0x1F) =3D=3D 8) { + /* + * GPR 8 (s0) is used as a scratch register by the ROM. + * Read the architected x8 value from dscratch0 first. + */ + dm_rom_write32(s, RISCV_DM_ROM_CMD + 2 * 4, + DM_CSRR(0x7b2)); + dm_rom_write32(s, RISCV_DM_ROM_CMD + 3 * 4, + DM_DATA_STORE(8, aarsize)); + } else { + dm_rom_write32(s, RISCV_DM_ROM_CMD + 2 * 4, + DM_DATA_STORE(regno & 0x1F, aarsize)); + } + } else if (fpr_hit) { + dm_rom_write32(s, RISCV_DM_ROM_CMD + 2 * 4, + DM_DATA_FP_STORE(regno & 0x1F, aarsize)); + } else { + dm_set_cmderr(s, RISCV_DM_CMDERR_EXCEPTION); + trace_riscv_dm_abstract_cmd_rejected("unsupported_regno_re= ad", + ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR)); + return; + } + } else { + /* Write: copy data -> register */ + if (csr_hit) { + dm_rom_write32(s, RISCV_DM_ROM_CMD + 2 * 4, + DM_DATA_LOAD(8, aarsize)); + dm_rom_write32(s, RISCV_DM_ROM_CMD + 3 * 4, + DM_CSRW(regno & 0xFFF)); + } else if (gpr_hit) { + if ((regno & 0x1F) =3D=3D 8) { + /* GPR 8 (s0) is saved in dscratch0 */ + dm_rom_write32(s, RISCV_DM_ROM_CMD + 2 * 4, + DM_DATA_LOAD(8, aarsize)); + dm_rom_write32(s, RISCV_DM_ROM_CMD + 3 * 4, + DM_CSRW(0x7b2)); + } else { + dm_rom_write32(s, RISCV_DM_ROM_CMD + 2 * 4, + DM_DATA_LOAD(regno & 0x1F, aarsize)); + } + } else if (fpr_hit) { + dm_rom_write32(s, RISCV_DM_ROM_CMD + 2 * 4, + DM_DATA_FP_LOAD(regno & 0x1F, aarsize)); + } else { + dm_set_cmderr(s, RISCV_DM_CMDERR_EXCEPTION); + trace_riscv_dm_abstract_cmd_rejected("unsupported_regno_wr= ite", + ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR)); + return; + } + } + } + + /* Post-increment */ + if (aarpostinc && transfer) { + s->last_cmd =3D FIELD_DP32(command, COMMAND, REGNO, regno + 1); + } + + if (postexec) { + if (s->progbuf_size =3D=3D 0) { + dm_set_cmderr(s, RISCV_DM_CMDERR_NOTSUP); + trace_riscv_dm_abstract_cmd_rejected("postexec_without_progbuf= ", + ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR)); + return; + } + + /* Restore s0 first, then continue with Program Buffer. */ + dm_rom_write32(s, RISCV_DM_ROM_CMD + 9 * 4, DM_JAL(2)); + } + + dm_invalidate_dynamic_code(s); + + /* Set BUSY */ + ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, BUSY, 1); + + /* Set FLAGS to going and signal hart */ + dm_rom_write8(s, RISCV_DM_ROM_FLAGS + hartsel, RISCV_DM_FLAG_GOING); + + trace_riscv_dm_abstract_cmd_submit( + FIELD_EX32(command, COMMAND, CMDTYPE), regno, transfer, + write, aarpostinc, postexec); +} + +static bool dm_execute_abstract_cmd(RISCVDMState *s, uint32_t command) +{ + uint32_t cmderr =3D ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR); + + /* If cmderr is latched, reject silently */ + if (cmderr !=3D RISCV_DM_CMDERR_NONE) { + trace_riscv_dm_abstract_cmd_rejected("cmderr_latched", cmderr); + return false; + } + + /* If busy, set cmderr=3Dbusy */ + if (ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, BUSY)) { + dm_set_cmderr(s, RISCV_DM_CMDERR_BUSY); + trace_riscv_dm_abstract_cmd_rejected("command_while_busy", + ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR)); + return false; + } + + uint32_t cmdtype =3D FIELD_EX32(command, COMMAND, CMDTYPE); + + switch (cmdtype) { + case RISCV_DM_CMD_ACCESS_REG: + dm_execute_access_register(s, command); + break; + default: + dm_set_cmderr(s, RISCV_DM_CMDERR_NOTSUP); + trace_riscv_dm_abstract_cmd_rejected("unsupported_cmdtype", + ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, CMDERR)); + break; + } + + return true; +} + + =20 static void dm_status_refresh(RISCVDMState *s) { @@ -805,9 +996,13 @@ static uint64_t dm_abstractcs_pre_write(RegisterInfo *= reg, uint64_t val64) static uint64_t dm_command_pre_write(RegisterInfo *reg, uint64_t val64) { RISCVDMState *s =3D RISCV_DM(reg->opaque); + uint32_t command =3D (uint32_t)val64; =20 - /* Stub: abstract command execution added in a follow-on patch. */ - s->last_cmd =3D (uint32_t)val64; + if (dm_execute_abstract_cmd(s, command)) { + s->last_cmd =3D command; + } + + /* COMMAND is WARZ: keep internal state, but reads always return 0. */ return s->regs[R_COMMAND]; } =20 @@ -825,7 +1020,6 @@ static uint64_t dm_abstractauto_pre_write(RegisterInfo= *reg, uint64_t val64) return s->regs[R_ABSTRACTAUTO]; } =20 - /* Stub: autoexec trigger logic added in a follow-on patch. */ uint32_t data_count =3D MIN(s->num_abstract_data, 12); uint32_t pbuf_size =3D MIN(s->progbuf_size, 16); uint32_t data_mask =3D data_count ? ((1u << data_count) - 1u) : 0; @@ -835,6 +1029,27 @@ static uint64_t dm_abstractauto_pre_write(RegisterInf= o *reg, uint64_t val64) return (uint32_t)val64 & mask; } =20 +static void dm_check_autoexec(RISCVDMState *s, bool is_data, int index) +{ + if (ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, BUSY)) { + dm_set_cmderr(s, RISCV_DM_CMDERR_BUSY); + return; + } + + uint32_t autoexec =3D s->regs[R_ABSTRACTAUTO]; + bool trigger; + + if (is_data) { + trigger =3D (autoexec >> index) & 1; + } else { + trigger =3D (autoexec >> (16 + index)) & 1; + } + + if (trigger) { + dm_execute_abstract_cmd(s, s->last_cmd); + } +} + static uint64_t dm_data_pre_write(RegisterInfo *reg, uint64_t val64) { RISCVDMState *s =3D RISCV_DM(reg->opaque); @@ -852,10 +1067,15 @@ static void dm_data_post_write(RegisterInfo *reg, ui= nt64_t val64) int index =3D (reg->access->addr - A_DATA0) / 4; =20 dm_sync_data_to_rom(s, index); + dm_check_autoexec(s, true, index); } =20 static uint64_t dm_data_post_read(RegisterInfo *reg, uint64_t val) { + RISCVDMState *s =3D RISCV_DM(reg->opaque); + int index =3D (reg->access->addr - A_DATA0) / 4; + + dm_check_autoexec(s, true, index); return val; } =20 @@ -876,10 +1096,15 @@ static void dm_progbuf_post_write(RegisterInfo *reg,= uint64_t val64) int index =3D (reg->access->addr - A_PROGBUF0) / 4; =20 dm_sync_progbuf_to_rom(s, index); + dm_check_autoexec(s, false, index); } =20 static uint64_t dm_progbuf_post_read(RegisterInfo *reg, uint64_t val) { + RISCVDMState *s =3D RISCV_DM(reg->opaque); + int index =3D (reg->access->addr - A_PROGBUF0) / 4; + + dm_check_autoexec(s, false, index); return val; } =20 --=20 2.53.0