From nobody Sat Apr 11 23:04:30 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=1772954525; cv=none; d=zohomail.com; s=zohoarc; b=BzV5R/wKTrO+hL2KzmMoQVWGOo21aKvv1p5XTQZjIfZX9mGxXdC4WrXUmVJ7zKrN1+LVs0YhOGAC0mBWQgLNsdFiioVWoTY+cV0FhyAOJCRPnsnVUbFpmzQ5yxXWIlNW8pqmaTT9MRutOyDanl7iEZ+tllT6ADK9Zh+0KOYoaSw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1772954525; 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=hqQ72NnIYBXINuVoG3HiOpoWjjk2RG4TM4kQcZaprKY=; b=dZBtFb2TC5MSPVCdUjGnkQ1HQK8Q04Ss9AY4KbHl/faKeoD/8yuNkpw3jAFoogSA8fZ6bkn+uEWA5XHXzRRXin1+Vkxwa5fM8f24j79z8MGtkEeWKZOY0RW5RhaxVe809OXf9fi0wQOY/fN3MkKo3OrNSmO5biAW2K8lx6GjNiI= 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 177295452555829.296025914160396; Sat, 7 Mar 2026 23:22:05 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1vz8Rg-0002NV-Re; Sun, 08 Mar 2026 03:21:04 -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 1vz8Qz-0001cW-Er for qemu-devel@nongnu.org; Sun, 08 Mar 2026 03:20:19 -0400 Received: from mail-dy1-x1343.google.com ([2607:f8b0:4864:20::1343]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1vz8Qv-0002WX-Dy for qemu-devel@nongnu.org; Sun, 08 Mar 2026 03:20:17 -0400 Received: by mail-dy1-x1343.google.com with SMTP id 5a478bee46e88-2be3bdfda8eso3687281eec.1 for ; Sat, 07 Mar 2026 23:20:12 -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.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 07 Mar 2026 23:20:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1772954412; x=1773559212; 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=hqQ72NnIYBXINuVoG3HiOpoWjjk2RG4TM4kQcZaprKY=; b=ayAdthtSQHM2SDQE+QuwvQ8xL2rBvnljem8OXuzr1KZdmxxhwDDKKIhpC4N6qAHQiW GTMMF0Y9+oe2P+7yzO8e6A0S7bT2ki5ns3GG4wTzk7ZtP+mcl5uI/ae1qrBDXCC2C5ux 3V/sfCP6TJ/x4te35l4ZduWmW4+gmUMySajqxuIIT/mwOse7dfOgG12R+Rqr0ZEcikpi jeGjoC1GKCetaUirGcQYy4ZzuV/vicB6MKHPqszKr8igQNzK8Y1ym2F7n8Q4+1zHOsIs ldfwiC+ugTCFzm8IgZzVlh7exgitY+kaFbfV62TTRTvjAHUx/R4Na5kJunk6nMtzTw2L 0M/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772954412; x=1773559212; 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=hqQ72NnIYBXINuVoG3HiOpoWjjk2RG4TM4kQcZaprKY=; b=FOgEx0TY6gCXROITlxU7jBR0JrHUFDzcWaiI/koO/3xT2lAgGWBXv8M0hxWQtLeBy5 1T6WDT4DKL5P3vm7ETYxZVeNs9gnrA4+8SymBFTsm142mJCcxJVRltMGaJNYTsdOMVSF eSpmD/7z3G7wgbZSIHwoO+9RyXUMWptUXPBUgBoMcShZA0/Jni6aW/M4WtrxjJLiEouq dNwhexf9ICl46Pj6/GrPVf73qHF+I3swrdJoHbi/NwDh/Z1fuNHd1GOqzpyb/Y+iBqAA 6vvq1U0hZwg7K/y7U16GwslmM1+/mpg6gqfFoKdJWpZfO50yjjSDose297mHjC8PfYYU +ESQ== X-Forwarded-Encrypted: i=1; AJvYcCVh+y8tEyMK3Yj+Kc8WFHOuhZg7YfQkOjX+yaccfS4VLYlcDzbezLoNFMUuWkTBpocgYnwSyjA7oVKP@nongnu.org X-Gm-Message-State: AOJu0YzBiDHOcmmpfDdmuMS/hVD2SQocnOx/XIggJsN/Bxxfw7Ail7rT wC5n/qCI0mdNfQX5zamNpAskkkg6kM4mjKcmi0L90IP/FJzEEjYBdvyQKDp4w6xu X-Gm-Gg: ATEYQzw3fGPG3OhnhiW9W7FfOsNQGh7Pb1r8TErI4sGNlvF2FbmPv6qmZAMuD5ZN1sf 7lzMgkaSfd8lZdorOHbHprZ/lIpopST3IZfzEU0UaP59XIrWadZGgqLuiVOHO/uoybjhDKD1J/0 OyByDd9psGsK3LIcxVIaSYxagWDNjmKKlVBzzDVEv1YKzaQmhUHVOCxq6LJMklG69prb8JKrvsH wodqXfWHhokjySkt005KZdEodCXNUM8nFyrUysSsWRDayhRVNtZ2q5e8ZvtbMS8yZH0Dz1LmX+z 6Dn4rTwFtR5uhuRwq8xMS+aod5mVr3+f23kG01QsNK9sCCvdJ/rSbO6/T8xQp9fUPMtP5l8RdDg VCw8n8C6Q9pvJX5ixGnfhptEh3uEv+Xe5xf+PAPi9A+mDU//8q3VQJZ0DWv/o644rWv0CWJFUlO GucH6JOIG3nOdETJzLJBREBoggtclWkvuBMw+JthOSyGCI7u+xhZzx1VNE1k829fqoebI7/6DD8 BfkvaWFYDU5/jxo7iepNP63p10= X-Received: by 2002:a05:693c:3101:b0:2be:aa:9a4a with SMTP id 5a478bee46e88-2be4dd62c65mr2585378eec.0.1772954411647; Sat, 07 Mar 2026 23:20:11 -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 17/28] hw/riscv/dm: add hart run-control operations Date: Sun, 8 Mar 2026 15:17:20 +0800 Message-ID: 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::1343; envelope-from=chao.liu.zevorn@gmail.com; helo=mail-dy1-x1343.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: 1772954526639154101 Content-Type: text/plain; charset="utf-8" Implement the dmcontrol operations that act on the selected hart set and expose the matching summary registers. This adds haltreq, resumereq, hartreset, ndmreset, and reset-haltreq handling, collects selected harts from hartsel, hasel, and hawindow, and computes haltsum0 and haltsum1 from the tracked hart state. It also feeds GOING, RESUME, halt, and resume acknowledgements from the ROM mailbox back into the state machine and adds tracepoints for the new transitions. Signed-off-by: Chao Liu --- hw/riscv/dm.c | 506 +++++++++++++++++++++++++++++++++++++++--- hw/riscv/trace-events | 14 ++ 2 files changed, 485 insertions(+), 35 deletions(-) diff --git a/hw/riscv/dm.c b/hw/riscv/dm.c index fad8e2b2ce..d55b5b827d 100644 --- a/hw/riscv/dm.c +++ b/hw/riscv/dm.c @@ -10,15 +10,28 @@ =20 #include "qemu/osdep.h" #include "qapi/error.h" +#include "hw/core/cpu.h" +#include "hw/core/irq.h" #include "hw/core/qdev-properties.h" #include "hw/riscv/dm.h" +#include "exec/cpu-common.h" #include "migration/vmstate.h" +#include "system/tcg.h" +#include "target/riscv/cpu.h" +#include "trace.h" =20 REG32(DMCONTROL, 0x40) FIELD(DMCONTROL, DMACTIVE, 0, 1) + FIELD(DMCONTROL, NDMRESET, 1, 1) + FIELD(DMCONTROL, CLRRESETHALTREQ, 2, 1) + FIELD(DMCONTROL, SETRESETHALTREQ, 3, 1) FIELD(DMCONTROL, HARTSELLO, 6, 10) FIELD(DMCONTROL, HARTSELHI, 16, 10) FIELD(DMCONTROL, HASEL, 26, 1) + FIELD(DMCONTROL, ACKHAVERESET, 28, 1) + FIELD(DMCONTROL, HARTRESET, 29, 1) + FIELD(DMCONTROL, RESUMEREQ, 30, 1) + FIELD(DMCONTROL, HALTREQ, 31, 1) =20 REG32(DMSTATUS, 0x44) FIELD(DMSTATUS, VERSION, 0, 4) @@ -28,6 +41,8 @@ REG32(DMSTATUS, 0x44) FIELD(DMSTATUS, ALLHALTED, 9, 1) FIELD(DMSTATUS, ANYRUNNING, 10, 1) FIELD(DMSTATUS, ALLRUNNING, 11, 1) + FIELD(DMSTATUS, ANYUNAVAIL, 12, 1) + FIELD(DMSTATUS, ALLUNAVAIL, 13, 1) FIELD(DMSTATUS, ANYNONEXISTENT, 14, 1) FIELD(DMSTATUS, ALLNONEXISTENT, 15, 1) FIELD(DMSTATUS, ANYRESUMEACK, 16, 1) @@ -35,6 +50,7 @@ REG32(DMSTATUS, 0x44) FIELD(DMSTATUS, ANYHAVERESET, 18, 1) FIELD(DMSTATUS, ALLHAVERESET, 19, 1) FIELD(DMSTATUS, IMPEBREAK, 22, 1) + FIELD(DMSTATUS, NDMRESETPENDING, 24, 1) =20 REG32(HARTINFO, 0x48) FIELD(HARTINFO, DATAADDR, 0, 12) @@ -42,12 +58,28 @@ REG32(HARTINFO, 0x48) FIELD(HARTINFO, DATAACCESS, 16, 1) FIELD(HARTINFO, NSCRATCH, 20, 4) =20 +REG32(HALTSUM1, 0x4c) + +REG32(HAWINDOWSEL, 0x50) + FIELD(HAWINDOWSEL, HAWINDOWSEL, 0, 15) + +REG32(HAWINDOW, 0x54) + REG32(ABSTRACTCS, 0x58) FIELD(ABSTRACTCS, DATACOUNT, 0, 4) FIELD(ABSTRACTCS, CMDERR, 8, 3) FIELD(ABSTRACTCS, BUSY, 12, 1) FIELD(ABSTRACTCS, PROGBUFSIZE, 24, 5) =20 +REG32(HALTSUM0, 0x100) + +typedef struct DMHartSelection { + int all[RISCV_DM_HAWINDOW_SIZE + 1]; + int all_count; + int harts[RISCV_DM_HAWINDOW_SIZE + 1]; + int valid_count; +} DMHartSelection; + static inline uint32_t dm_get_hartsel(RISCVDMState *s) { uint32_t hi =3D ARRAY_FIELD_EX32(s->regs, DMCONTROL, HARTSELHI); @@ -61,46 +93,306 @@ static inline bool dm_hart_valid(RISCVDMState *s, uint= 32_t hartsel) return hartsel < s->num_harts; } =20 -static void dm_status_refresh(RISCVDMState *s) +static inline uint32_t dm_rom_read32(RISCVDMState *s, uint32_t offset) +{ + return ldl_le_p(s->rom_ptr + offset); +} + +static inline void dm_rom_write32(RISCVDMState *s, uint32_t offset, + uint32_t val) +{ + stl_le_p(s->rom_ptr + offset, val); +} + +static inline void dm_rom_write8(RISCVDMState *s, uint32_t offset, uint8_t= val) +{ + s->rom_ptr[offset] =3D val; +} + +static void dm_selection_add(RISCVDMState *s, DMHartSelection *sel, int ha= rtsel) +{ + for (int i =3D 0; i < sel->all_count; i++) { + if (sel->all[i] =3D=3D hartsel) { + return; + } + } + + sel->all[sel->all_count++] =3D hartsel; + if (dm_hart_valid(s, hartsel)) { + sel->harts[sel->valid_count++] =3D hartsel; + } +} + +static void dm_collect_selected_harts(RISCVDMState *s, DMHartSelection *se= l) { uint32_t hartsel =3D dm_get_hartsel(s); - bool valid =3D dm_hart_valid(s, hartsel); - bool halted =3D valid && s->hart_halted[hartsel]; - bool running =3D valid && !s->hart_halted[hartsel]; - bool resumeack =3D valid && s->hart_resumeack[hartsel]; - bool havereset =3D valid && s->hart_havereset[hartsel]; - - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYNONEXISTENT, !valid); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLNONEXISTENT, !valid); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYHALTED, halted); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLHALTED, halted); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYRUNNING, running); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLRUNNING, running); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYRESUMEACK, resumeack); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLRESUMEACK, resumeack); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYHAVERESET, havereset); - ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLHAVERESET, havereset); + uint32_t wsel; + uint32_t window; + uint32_t base; + + memset(sel, 0, sizeof(*sel)); + dm_selection_add(s, sel, hartsel); + + if (!ARRAY_FIELD_EX32(s->regs, DMCONTROL, HASEL)) { + return; + } + + wsel =3D ARRAY_FIELD_EX32(s->regs, HAWINDOWSEL, HAWINDOWSEL); + if (wsel >=3D RISCV_DM_MAX_HARTS / RISCV_DM_HAWINDOW_SIZE) { + return; + } + + window =3D s->hawindow[wsel]; + base =3D wsel * RISCV_DM_HAWINDOW_SIZE; + for (int i =3D 0; i < RISCV_DM_HAWINDOW_SIZE; i++) { + if ((window >> i) & 1) { + dm_selection_add(s, sel, base + i); + } + } +} + +static inline bool dm_ndmreset_active(RISCVDMState *s) +{ + return ARRAY_FIELD_EX32(s->regs, DMCONTROL, NDMRESET); +} + +static bool dm_reg_present(RISCVDMState *s, hwaddr addr) +{ + switch (addr) { + case A_HALTSUM1: + return s->num_harts >=3D 33; + default: + return true; + } +} + +static void dm_status_refresh(RISCVDMState *s) +{ + DMHartSelection sel; + bool anyhalted =3D false; + bool allhalted =3D true; + bool anyrunning =3D false; + bool allrunning =3D true; + bool anyunavail =3D false; + bool allunavail =3D true; + bool anyresumeack =3D false; + bool allresumeack =3D true; + bool anyhavereset =3D false; + bool allhavereset =3D true; + bool anynonexistent; + bool allnonexistent; + bool reset_unavail =3D dm_ndmreset_active(s) || + ARRAY_FIELD_EX32(s->regs, DMCONTROL, HARTRESET); + + dm_collect_selected_harts(s, &sel); + + anynonexistent =3D sel.all_count > sel.valid_count; + allnonexistent =3D sel.valid_count =3D=3D 0 && sel.all_count > 0; + + if (sel.valid_count =3D=3D 0) { + allhalted =3D false; + allrunning =3D false; + allunavail =3D false; + allresumeack =3D false; + allhavereset =3D false; + } + + for (int i =3D 0; i < sel.valid_count; i++) { + int h =3D sel.harts[i]; + bool halted =3D s->hart_halted[h]; + bool resumeack =3D s->hart_resumeack[h]; + bool havereset =3D s->hart_havereset[h]; + + if (reset_unavail) { + anyunavail =3D true; + allhalted =3D false; + allrunning =3D false; + } else { + anyhalted |=3D halted; + allhalted &=3D halted; + anyrunning |=3D !halted; + allrunning &=3D !halted; + } + + allunavail &=3D reset_unavail; + anyresumeack |=3D resumeack; + allresumeack &=3D resumeack; + anyhavereset |=3D havereset; + allhavereset &=3D havereset; + } + + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYHALTED, anyhalted); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLHALTED, allhalted); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYRUNNING, anyrunning); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLRUNNING, allrunning); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYUNAVAIL, anyunavail); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLUNAVAIL, allunavail); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYNONEXISTENT, anynonexistent); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLNONEXISTENT, allnonexistent); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYRESUMEACK, anyresumeack); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLRESUMEACK, allresumeack); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ANYHAVERESET, anyhavereset); + ARRAY_FIELD_DP32(s->regs, DMSTATUS, ALLHAVERESET, allhavereset); ARRAY_FIELD_DP32(s->regs, DMSTATUS, HASRESETHALTREQ, 1); } =20 static void dm_debug_reset(RISCVDMState *s); =20 +static void dm_cpu_reset_on_cpu(CPUState *cpu, run_on_cpu_data data) +{ + (void)data; + cpu_reset(cpu); +} + +static void dm_note_hart_reset(RISCVDMState *s, uint32_t hartsel) +{ + CPUState *cs =3D qemu_get_cpu(hartsel); + + s->hart_halted[hartsel] =3D false; + s->hart_resumeack[hartsel] =3D false; + s->hart_havereset[hartsel] =3D true; + dm_rom_write8(s, RISCV_DM_ROM_FLAGS + hartsel, RISCV_DM_FLAG_CLEAR); + + if (cs && s->hart_resethaltreq[hartsel]) { + riscv_cpu_request_dm_halt(RISCV_CPU(cs), DCSR_CAUSE_RESET); + } +} + +static void dm_reset_hart(RISCVDMState *s, uint32_t hartsel) +{ + CPUState *cs; + + if (!dm_hart_valid(s, hartsel)) { + return; + } + + cs =3D qemu_get_cpu(hartsel); + if (cs && tcg_enabled()) { + run_on_cpu(cs, dm_cpu_reset_on_cpu, RUN_ON_CPU_NULL); + } + + dm_note_hart_reset(s, hartsel); +} + +static void dm_reset_selected_harts(RISCVDMState *s, DMHartSelection *sel) +{ + for (int i =3D 0; i < sel->valid_count; i++) { + dm_reset_hart(s, sel->harts[i]); + } +} + +static void dm_reset_all_harts(RISCVDMState *s) +{ + for (uint32_t hartsel =3D 0; hartsel < s->num_harts; hartsel++) { + dm_reset_hart(s, hartsel); + } +} + static uint64_t dm_dmcontrol_pre_write(RegisterInfo *reg, uint64_t val64) { RISCVDMState *s =3D RISCV_DM(reg->opaque); uint32_t val =3D val64; + uint32_t cur_ctl =3D s->regs[R_DMCONTROL]; + bool busy =3D ARRAY_FIELD_EX32(s->regs, ABSTRACTCS, BUSY); + bool ndmreset_was =3D FIELD_EX32(cur_ctl, DMCONTROL, NDMRESET); + bool hartreset_was =3D FIELD_EX32(cur_ctl, DMCONTROL, HARTRESET); + bool dmactive =3D FIELD_EX32(val, DMCONTROL, DMACTIVE); + DMHartSelection sel; + uint32_t stored =3D 0; + + trace_riscv_dm_control_write(s->regs[R_DMCONTROL], val, busy); + + if (busy) { + val =3D FIELD_DP32(val, DMCONTROL, HARTSELHI, + ARRAY_FIELD_EX32(s->regs, DMCONTROL, HARTSELHI)); + val =3D FIELD_DP32(val, DMCONTROL, HARTSELLO, + ARRAY_FIELD_EX32(s->regs, DMCONTROL, HARTSELLO)); + val =3D FIELD_DP32(val, DMCONTROL, HASEL, + ARRAY_FIELD_EX32(s->regs, DMCONTROL, HASEL)); + val =3D FIELD_DP32(val, DMCONTROL, HALTREQ, 0); + val =3D FIELD_DP32(val, DMCONTROL, RESUMEREQ, 0); + val =3D FIELD_DP32(val, DMCONTROL, ACKHAVERESET, 0); + } =20 - if (!FIELD_EX32(val, DMCONTROL, DMACTIVE)) { + if (!dmactive) { dm_debug_reset(s); return 0; } =20 - s->dm_active =3D true; - - val =3D FIELD_DP32(val, DMCONTROL, DMACTIVE, 1); s->regs[R_DMCONTROL] =3D val; + dm_collect_selected_harts(s, &sel); + + if (FIELD_EX32(val, DMCONTROL, NDMRESET) && !ndmreset_was) { + dm_reset_all_harts(s); + } + + if (FIELD_EX32(val, DMCONTROL, HARTRESET) && !hartreset_was) { + dm_reset_selected_harts(s, &sel); + } + + ARRAY_FIELD_DP32(s->regs, DMSTATUS, NDMRESETPENDING, + FIELD_EX32(val, DMCONTROL, NDMRESET)); + + if (!busy && FIELD_EX32(val, DMCONTROL, ACKHAVERESET)) { + for (int i =3D 0; i < sel.valid_count; i++) { + s->hart_havereset[sel.harts[i]] =3D false; + } + } + + if (!busy && FIELD_EX32(val, DMCONTROL, SETRESETHALTREQ)) { + for (int i =3D 0; i < sel.valid_count; i++) { + s->hart_resethaltreq[sel.harts[i]] =3D true; + } + } + + if (!busy && FIELD_EX32(val, DMCONTROL, CLRRESETHALTREQ)) { + for (int i =3D 0; i < sel.valid_count; i++) { + s->hart_resethaltreq[sel.harts[i]] =3D false; + } + } + + if (!busy && FIELD_EX32(val, DMCONTROL, RESUMEREQ) && + !FIELD_EX32(val, DMCONTROL, HALTREQ)) { + for (int i =3D 0; i < sel.valid_count; i++) { + int h =3D sel.harts[i]; + + s->hart_resumeack[h] =3D false; + dm_rom_write8(s, RISCV_DM_ROM_FLAGS + h, RISCV_DM_FLAG_RESUME); + trace_riscv_dm_control_resume(h); + } + } + + if (!busy) { + if (FIELD_EX32(val, DMCONTROL, HALTREQ)) { + for (int i =3D 0; i < sel.valid_count; i++) { + int h =3D sel.harts[i]; + + dm_rom_write8(s, RISCV_DM_ROM_FLAGS + h, RISCV_DM_FLAG_CLE= AR); + qemu_set_irq(s->halt_irqs[h], 1); + trace_riscv_dm_control_halt(h); + } + } else { + for (int i =3D 0; i < sel.valid_count; i++) { + qemu_set_irq(s->halt_irqs[sel.harts[i]], 0); + } + } + } + + stored =3D FIELD_DP32(stored, DMCONTROL, DMACTIVE, 1); + stored =3D FIELD_DP32(stored, DMCONTROL, NDMRESET, + FIELD_EX32(val, DMCONTROL, NDMRESET)); + stored =3D FIELD_DP32(stored, DMCONTROL, HARTSELLO, + FIELD_EX32(val, DMCONTROL, HARTSELLO)); + stored =3D FIELD_DP32(stored, DMCONTROL, HARTSELHI, + FIELD_EX32(val, DMCONTROL, HARTSELHI)); + stored =3D FIELD_DP32(stored, DMCONTROL, HASEL, + FIELD_EX32(val, DMCONTROL, HASEL)); + stored =3D FIELD_DP32(stored, DMCONTROL, HARTRESET, + FIELD_EX32(val, DMCONTROL, HARTRESET)); + + s->dm_active =3D true; dm_status_refresh(s); - return val; + return stored; } =20 static uint64_t dm_dmstatus_post_read(RegisterInfo *reg, uint64_t val) @@ -108,7 +400,7 @@ static uint64_t dm_dmstatus_post_read(RegisterInfo *reg= , uint64_t val) RISCVDMState *s =3D RISCV_DM(reg->opaque); =20 dm_status_refresh(s); - return val; + return s->regs[R_DMSTATUS]; } =20 static uint64_t dm_hartinfo_post_read(RegisterInfo *reg, uint64_t val) @@ -123,6 +415,72 @@ static uint64_t dm_hartinfo_post_read(RegisterInfo *re= g, uint64_t val) return v; } =20 +static uint64_t dm_hawindowsel_pre_write(RegisterInfo *reg, uint64_t val64) +{ + uint32_t max_sel =3D RISCV_DM_MAX_HARTS / RISCV_DM_HAWINDOW_SIZE; + uint32_t val =3D val64 & R_HAWINDOWSEL_HAWINDOWSEL_MASK; + + (void)reg; + if (val >=3D max_sel) { + val =3D max_sel - 1; + } + return val; +} + +static uint64_t dm_hawindow_pre_write(RegisterInfo *reg, uint64_t val64) +{ + RISCVDMState *s =3D RISCV_DM(reg->opaque); + uint32_t wsel =3D ARRAY_FIELD_EX32(s->regs, HAWINDOWSEL, HAWINDOWSEL); + + if (wsel < RISCV_DM_MAX_HARTS / RISCV_DM_HAWINDOW_SIZE) { + s->hawindow[wsel] =3D val64; + } + return (uint32_t)val64; +} + +static uint64_t dm_hawindow_post_read(RegisterInfo *reg, uint64_t val) +{ + RISCVDMState *s =3D RISCV_DM(reg->opaque); + uint32_t wsel =3D ARRAY_FIELD_EX32(s->regs, HAWINDOWSEL, HAWINDOWSEL); + + (void)val; + if (wsel < RISCV_DM_MAX_HARTS / RISCV_DM_HAWINDOW_SIZE) { + return s->hawindow[wsel]; + } + return 0; +} + +static uint64_t dm_haltsum0_post_read(RegisterInfo *reg, uint64_t val) +{ + RISCVDMState *s =3D RISCV_DM(reg->opaque); + uint32_t sum =3D 0; + uint32_t base =3D 0; + uint32_t limit =3D MIN(s->num_harts, 32u); + + (void)val; + for (uint32_t h =3D base; h < limit; h++) { + if (s->hart_halted[h]) { + sum |=3D 1u << (h - base); + } + } + return sum; +} + +static uint64_t dm_haltsum1_post_read(RegisterInfo *reg, uint64_t val) +{ + RISCVDMState *s =3D RISCV_DM(reg->opaque); + uint32_t sum =3D 0; + + (void)reg; + (void)val; + for (uint32_t h =3D 0; h < s->num_harts; h++) { + if (s->hart_halted[h]) { + sum |=3D 1u << (h / 32); + } + } + return sum; +} + static RegisterAccessInfo riscv_dm_regs_info[] =3D { { .name =3D "DMCONTROL", .addr =3D A_DMCONTROL, .pre_write =3D dm_dmcontrol_pre_write, }, @@ -132,8 +490,19 @@ static RegisterAccessInfo riscv_dm_regs_info[] =3D { { .name =3D "HARTINFO", .addr =3D A_HARTINFO, .ro =3D 0xffffffff, .post_read =3D dm_hartinfo_post_read, }, + { .name =3D "HALTSUM1", .addr =3D A_HALTSUM1, + .ro =3D 0xffffffff, + .post_read =3D dm_haltsum1_post_read, }, + { .name =3D "HAWINDOWSEL", .addr =3D A_HAWINDOWSEL, + .pre_write =3D dm_hawindowsel_pre_write, }, + { .name =3D "HAWINDOW", .addr =3D A_HAWINDOW, + .pre_write =3D dm_hawindow_pre_write, + .post_read =3D dm_hawindow_post_read, }, { .name =3D "ABSTRACTCS", .addr =3D A_ABSTRACTCS, .ro =3D 0xffffffff, }, + { .name =3D "HALTSUM0", .addr =3D A_HALTSUM0, + .ro =3D 0xffffffff, + .post_read =3D dm_haltsum0_post_read, }, }; =20 static uint64_t riscv_dm_read(void *opaque, hwaddr addr, unsigned size) @@ -145,6 +514,19 @@ static uint64_t riscv_dm_read(void *opaque, hwaddr add= r, unsigned size) return 0; } =20 + if (dm_ndmreset_active(s)) { + if (addr =3D=3D A_DMSTATUS) { + return s->regs[R_DMSTATUS] & R_DMSTATUS_NDMRESETPENDING_MASK; + } + if (addr !=3D A_DMCONTROL) { + return 0; + } + } + + if (!dm_reg_present(s, addr)) { + return 0; + } + return register_read_memory(opaque, addr, size); } =20 @@ -158,6 +540,14 @@ static void riscv_dm_write(void *opaque, hwaddr addr, return; } =20 + if (dm_ndmreset_active(s) && addr !=3D A_DMCONTROL) { + return; + } + + if (!dm_reg_present(s, addr)) { + return; + } + register_write_memory(opaque, addr, value, size); } =20 @@ -181,29 +571,54 @@ static const MemoryRegionOps riscv_dm_ops =3D { static uint64_t dm_rom_read(void *opaque, hwaddr offset, unsigned size) { RISCVDMState *s =3D opaque; + uint64_t ret; =20 - return ldn_le_p(s->rom_ptr + offset, size); + ret =3D ldn_le_p(s->rom_ptr + offset, size); + trace_riscv_dm_rom_access(offset, ret, size, false); + return ret; } =20 static void dm_rom_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { RISCVDMState *s =3D opaque; + uint32_t hartsel; =20 stn_le_p(s->rom_ptr + offset, size, value); =20 + trace_riscv_dm_rom_access(offset, value, size, true); + if (offset =3D=3D RISCV_DM_ROM_HARTID && size =3D=3D 4) { - riscv_dm_hart_halted(s, value); + hartsel =3D value; + if (dm_hart_valid(s, hartsel)) { + riscv_dm_hart_halted(s, hartsel); + } + return; + } + + if (offset =3D=3D RISCV_DM_ROM_GOING && size =3D=3D 4) { + hartsel =3D dm_rom_read32(s, RISCV_DM_ROM_HARTID); + if (dm_hart_valid(s, hartsel)) { + dm_rom_write8(s, RISCV_DM_ROM_FLAGS + hartsel, + RISCV_DM_FLAG_CLEAR); + trace_riscv_dm_going(hartsel); + } return; } =20 if (offset =3D=3D RISCV_DM_ROM_RESUME && size =3D=3D 4) { - riscv_dm_hart_resumed(s, value); + hartsel =3D value; + if (dm_hart_valid(s, hartsel)) { + riscv_dm_hart_resumed(s, hartsel); + } return; } =20 if (offset =3D=3D RISCV_DM_ROM_EXCP && size =3D=3D 4) { - riscv_dm_abstracts_exception(s, dm_get_hartsel(s)); + hartsel =3D dm_rom_read32(s, RISCV_DM_ROM_HARTID); + if (dm_hart_valid(s, hartsel)) { + riscv_dm_abstracts_exception(s, hartsel); + } } } =20 @@ -250,6 +665,7 @@ void riscv_dm_hart_halted(RISCVDMState *s, uint32_t har= tsel) s->hart_halted[hartsel] =3D true; riscv_dm_abstracts_done(s, hartsel); dm_status_refresh(s); + trace_riscv_dm_hart_halted(hartsel); } =20 void riscv_dm_hart_resumed(RISCVDMState *s, uint32_t hartsel) @@ -260,21 +676,23 @@ void riscv_dm_hart_resumed(RISCVDMState *s, uint32_t = hartsel) =20 s->hart_halted[hartsel] =3D false; s->hart_resumeack[hartsel] =3D true; + dm_rom_write8(s, RISCV_DM_ROM_FLAGS + hartsel, RISCV_DM_FLAG_CLEAR); dm_status_refresh(s); + trace_riscv_dm_hart_resumed(hartsel); } =20 void riscv_dm_abstracts_done(RISCVDMState *s, uint32_t hartsel) { - (void)hartsel; ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, BUSY, 0); + trace_riscv_dm_abstract_cmd_complete(hartsel); } =20 void riscv_dm_abstracts_exception(RISCVDMState *s, uint32_t hartsel) { - (void)hartsel; ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, BUSY, 0); ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, CMDERR, RISCV_DM_CMDERR_EXCEPTION); + trace_riscv_dm_abstract_cmd_exception(hartsel); } =20 static void dm_debug_reset(RISCVDMState *s) @@ -287,11 +705,15 @@ static void dm_debug_reset(RISCVDMState *s) ARRAY_FIELD_DP32(s->regs, ABSTRACTCS, PROGBUFSIZE, s->progbuf_size); =20 if (s->hart_halted) { - memset(s->hart_halted, 0, s->num_harts * sizeof(bool)); - memset(s->hart_resumeack, 0, s->num_harts * sizeof(bool)); - memset(s->hart_havereset, 1, s->num_harts * sizeof(bool)); + for (uint32_t i =3D 0; i < s->num_harts; i++) { + s->hart_halted[i] =3D false; + s->hart_resumeack[i] =3D false; + s->hart_havereset[i] =3D true; + s->hart_resethaltreq[i] =3D false; + } } =20 + memset(s->hawindow, 0, sizeof(s->hawindow)); s->dm_active =3D false; =20 if (s->rom_ptr) { @@ -324,11 +746,21 @@ static void riscv_dm_realize(DeviceState *dev, Error = **errp) return; } =20 - s->hart_halted =3D g_new0(bool, s->num_harts); - s->hart_resumeack =3D g_new0(bool, s->num_harts); - s->hart_havereset =3D g_new0(bool, s->num_harts); + if (s->num_harts > 0) { + s->hart_halted =3D g_new0(bool, s->num_harts); + s->hart_resumeack =3D g_new0(bool, s->num_harts); + s->hart_havereset =3D g_new0(bool, s->num_harts); + s->hart_resethaltreq =3D g_new0(bool, s->num_harts); + s->halt_irqs =3D g_new(qemu_irq, s->num_harts); + qdev_init_gpio_out(dev, s->halt_irqs, s->num_harts); + } =20 if (!dm_rom_realize(s, errp)) { + g_free(s->hart_halted); + g_free(s->hart_resumeack); + g_free(s->hart_havereset); + g_free(s->hart_resethaltreq); + g_free(s->halt_irqs); return; } =20 @@ -348,6 +780,8 @@ static void riscv_dm_unrealize(DeviceState *dev) g_free(s->hart_halted); g_free(s->hart_resumeack); g_free(s->hart_havereset); + g_free(s->hart_resethaltreq); + g_free(s->halt_irqs); } =20 static const Property riscv_dm_props[] =3D { @@ -372,6 +806,8 @@ static const VMStateDescription vmstate_riscv_dm =3D { 0, vmstate_info_bool, bool), VMSTATE_VARRAY_UINT32(hart_havereset, RISCVDMState, num_harts, 0, vmstate_info_bool, bool), + VMSTATE_VARRAY_UINT32(hart_resethaltreq, RISCVDMState, num_harts, + 0, vmstate_info_bool, bool), VMSTATE_END_OF_LIST(), } }; diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events index b50b14a654..020e26607f 100644 --- a/hw/riscv/trace-events +++ b/hw/riscv/trace-events @@ -1,5 +1,19 @@ # See documentation at docs/devel/tracing.rst =20 +# dm.c +riscv_dm_control_write(uint32_t old_val, uint32_t new_val, bool busy) "old= =3D0x%08x new=3D0x%08x busy=3D%d" +riscv_dm_control_halt(uint32_t hartsel) "hartsel=3D%u" +riscv_dm_control_resume(uint32_t hartsel) "hartsel=3D%u" +riscv_dm_hart_halted(uint32_t hartsel) "hartsel=3D%u" +riscv_dm_hart_resumed(uint32_t hartsel) "hartsel=3D%u" +riscv_dm_abstract_cmd_submit(uint32_t cmdtype, uint32_t regno, bool transf= er, bool write, bool aarpostinc, bool postexec) "cmdtype=3D%u regno=3D0x%04= x transfer=3D%d write=3D%d aarpostinc=3D%d postexec=3D%d" +riscv_dm_abstract_cmd_complete(uint32_t hartsel) "hartsel=3D%u" +riscv_dm_abstract_cmd_exception(uint32_t hartsel) "hartsel=3D%u" +riscv_dm_abstract_cmd_rejected(const char *reason, uint32_t cmderr) "reaso= n=3D%s cmderr=3D%u" +riscv_dm_sba_access(uint64_t addr, uint32_t data, int bytes, bool is_write= ) "addr=3D0x%"PRIx64" data=3D0x%08x bytes=3D%d write=3D%d" +riscv_dm_rom_access(uint64_t offset, uint64_t value, unsigned size, bool i= s_write) "offset=3D0x%"PRIx64" value=3D0x%"PRIx64" size=3D%u write=3D%d" +riscv_dm_going(uint32_t hartsel) "hartsel=3D%u" + # riscv-iommu.c riscv_iommu_new(const char *id, unsigned b, unsigned d, unsigned f) "%s: d= evice attached %04x:%02x.%d" riscv_iommu_flt(const char *id, unsigned b, unsigned d, unsigned f, uint64= _t reason, uint64_t iova) "%s: fault %04x:%02x.%u reason: 0x%"PRIx64" iova:= 0x%"PRIx64 --=20 2.53.0