All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/5] Add support for K230 board
@ 2026-04-17 15:11 Chao Liu
  2026-04-17 15:11 ` [PATCH v6 1/5] target/riscv: add thead-c908 cpu support Chao Liu
                   ` (4 more replies)
  0 siblings, 5 replies; 20+ messages in thread
From: Chao Liu @ 2026-04-17 15:11 UTC (permalink / raw)
  To: Chao Liu, Pierrick Bouvier, Palmer Dabbelt, Alistair Francis,
	Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier
  Cc: qemu-devel, qemu-riscv

Hi Alistair,

This patch series adds support for U-Boot + OpenSBI + standard Linux kernel on
K230 board. Thanks to Peng Jiang, Mig Yang, Renzao Ren, Yao Zi for their help.

This v6 series has been rebased on Alistair's riscv-to-apply.next branch [1]
and is ready for review.

Test command:

```
$QEMU -M k230 -bios [OpenSBI binary] -m 2G -dtb k230_canmv.dtb -kernel [img]
```

PATCH v6 changelog:
- Rebased on the latest Alistair's riscv-to-apply.next branch.
- Patch 4: Picked up Fabiano's Acked-by.

PATCH v5 changelog:
- Rebased on Alistair's riscv-to-apply.next branch.
- Patch 2: Fixed reset vector ROM jump to trap-handler bug.
  https://lore.kernel.org/qemu-devel/cover.1769757064.git.chao.liu.zevorn@gmail.com/

PATCH v4 changelog:
- Rebased on the latest master branch.
- No functional changes from v3.

PATCH v3 changelog:
- Patch 1: Align T-Head C908 CPU's RISC-V extension with XUANTIE-QEMU.
- Patch 2: Adjust PLIC and CLINT addresses to match K230 datasheet.

PATCH v2 changelog:
- Patch 1: Add Svpbmt extension support for the T-Head C908 CPU.
- Patch 2: Move the k230.rst definition from MAINTAINERS to Patch 5.
- Patch 5: Apply Daniel's bugfix to build the k230 documentation successfully.

PATCH v1 changelog:
- Patch1: Add T-Head C908 and C908v CPU support.
- Patch2: Add K230 board initial support(big core is not supported yet).
- Patch3: Add Programmable Watchdog Timer (WDT) peripheral support.
- Patch4: Add QEMU test for K230 watchdog.
- Patch5: Add documentation for K230 machine.

[1] https://github.com/alistair23/qemu/tree/riscv-to-apply.next

Thanks,
Chao

Chao Liu (5):
  target/riscv: add thead-c908 cpu support
  hw/riscv: add k230 board initial support
  hw/watchdog: add k230 watchdog initial support
  tests/qtest: add test for K230 watchdog
  docs/system/riscv: add documentation for k230 machine

 MAINTAINERS                    |  12 +-
 docs/system/riscv/k230.rst     |  48 ++++
 docs/system/target-riscv.rst   |   1 +
 hw/riscv/Kconfig               |  11 +
 hw/riscv/k230.c                | 502 +++++++++++++++++++++++++++++++++
 hw/riscv/meson.build           |   2 +-
 hw/watchdog/Kconfig            |   4 +
 hw/watchdog/k230_wdt.c         | 307 ++++++++++++++++++++
 hw/watchdog/meson.build        |   1 +
 hw/watchdog/trace-events       |   9 +
 include/hw/riscv/k230.h        | 154 ++++++++++
 include/hw/watchdog/k230_wdt.h | 132 +++++++++
 target/riscv/cpu-qom.h         |   2 +
 target/riscv/cpu.c             |  51 ++++
 target/riscv/th_csr.c          | 380 ++++++++++++++++++++++++-
 tests/qtest/k230-wdt-test.c    | 199 +++++++++++++
 tests/qtest/meson.build        |   3 +-
 17 files changed, 1814 insertions(+), 4 deletions(-)
 create mode 100644 docs/system/riscv/k230.rst
 create mode 100644 hw/riscv/k230.c
 create mode 100644 hw/watchdog/k230_wdt.c
 create mode 100644 include/hw/riscv/k230.h
 create mode 100644 include/hw/watchdog/k230_wdt.h
 create mode 100644 tests/qtest/k230-wdt-test.c

-- 
2.53.0



^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-17 15:11 [PATCH v6 0/5] Add support for K230 board Chao Liu
@ 2026-04-17 15:11 ` Chao Liu
  2026-04-17 19:15   ` Conor Dooley
                     ` (2 more replies)
  2026-04-17 15:11 ` [PATCH v6 2/5] hw/riscv: add k230 board initial support Chao Liu
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 20+ messages in thread
From: Chao Liu @ 2026-04-17 15:11 UTC (permalink / raw)
  To: Chao Liu, Pierrick Bouvier, Palmer Dabbelt, Alistair Francis,
	Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier
  Cc: qemu-devel, qemu-riscv, Chao Liu, Daniel Henrique Barboza,
	Conor Dooley, Peng Jiang

From: Chao Liu <chao.liu@zevorn.cn>

The C908 processor is based on the RV64GCB[V] instruction
set, compatible to RVA22 Profile and implements the XIE
(XuanTie Instruction Extension) technology.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Conor Dooley <conor@kernel.org>
Reported-by: Peng Jiang <3160104094@zju.edu.cn>
---
 target/riscv/cpu-qom.h |   2 +
 target/riscv/cpu.c     |  51 ++++++
 target/riscv/th_csr.c  | 380 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 432 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index 30dcdcfaae..1a28f1369c 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -52,6 +52,8 @@
 #define TYPE_RISCV_CPU_SIFIVE_U34       RISCV_CPU_TYPE_NAME("sifive-u34")
 #define TYPE_RISCV_CPU_SIFIVE_U54       RISCV_CPU_TYPE_NAME("sifive-u54")
 #define TYPE_RISCV_CPU_THEAD_C906       RISCV_CPU_TYPE_NAME("thead-c906")
+#define TYPE_RISCV_CPU_THEAD_C908       RISCV_CPU_TYPE_NAME("thead-c908")
+#define TYPE_RISCV_CPU_THEAD_C908V      RISCV_CPU_TYPE_NAME("thead-c908v")
 #define TYPE_RISCV_CPU_VEYRON_V1        RISCV_CPU_TYPE_NAME("veyron-v1")
 #define TYPE_RISCV_CPU_TT_ASCALON       RISCV_CPU_TYPE_NAME("tt-ascalon")
 #define TYPE_RISCV_CPU_XIANGSHAN_NANHU  RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 72c6f4f0f1..870d0690fe 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -3150,6 +3150,57 @@ static const TypeInfo riscv_cpu_type_infos[] = {
 #endif
     ),
 
+    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908, TYPE_RISCV_VENDOR_CPU,
+        .misa_mxl_max = MXL_RV64,
+        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU,
+        .priv_spec = PRIV_VERSION_1_12_0,
+
+        /* ISA extensions */
+        .cfg.ext_xtheadba = true,
+        .cfg.ext_xtheadbb = true,
+        .cfg.ext_xtheadbs = true,
+        .cfg.ext_xtheadcmo = true,
+        .cfg.ext_xtheadcondmov = true,
+        .cfg.ext_xtheadfmv = true,
+        .cfg.ext_xtheadfmemidx = true,
+        .cfg.ext_xtheadmac = true,
+        .cfg.ext_xtheadmemidx = true,
+        .cfg.ext_xtheadmempair = true,
+        .cfg.ext_xtheadsync = true,
+        .cfg.ext_smepmp = true,
+        .cfg.ext_sscofpmf = true,
+        .cfg.ext_sstc = true,
+        .cfg.ext_svpbmt = true,
+        .cfg.ext_svinval = true,
+        .cfg.ext_svnapot = true,
+        .cfg.ext_zba = true,
+        .cfg.ext_zbb = true,
+        .cfg.ext_zbc = true,
+        .cfg.ext_zbs = true,
+        .cfg.ext_zkt = true,
+        .cfg.ext_zbkc = true,
+        .cfg.ext_zicsr = true,
+        .cfg.ext_zifencei = true,
+        .cfg.ext_zihintpause = true,
+        .cfg.ext_zicbom = true,
+        .cfg.ext_zicboz = true,
+
+        .cfg.pmp = true,
+        .cfg.mmu = true,
+        .cfg.max_satp_mode = VM_1_10_SV48,
+
+        .cfg.marchid = 0x8d143000,
+        .cfg.mvendorid = THEAD_VENDOR_ID,
+#ifndef CONFIG_USER_ONLY
+        .custom_csrs = th_csr_list,
+#endif
+    ),
+
+    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908V, TYPE_RISCV_CPU_THEAD_C908,
+        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU | RVV,
+        .vext_spec = VEXT_VERSION_1_00_0,
+    ),
+
     DEFINE_RISCV_CPU(TYPE_RISCV_CPU_TT_ASCALON, TYPE_RISCV_VENDOR_CPU,
         .misa_mxl_max = MXL_RV64,
         .misa_ext = RVG | RVC | RVS | RVU | RVH | RVV,
diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c
index 49eb7bbab5..e19cab5414 100644
--- a/target/riscv/th_csr.c
+++ b/target/riscv/th_csr.c
@@ -2,6 +2,9 @@
  * T-Head-specific CSRs.
  *
  * Copyright (c) 2024 VRULL GmbH
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * For more information, see XuanTie-C908-UserManual_xrvm_20240530.pdf
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -20,13 +23,88 @@
 #include "cpu.h"
 #include "cpu_vendorid.h"
 
-#define CSR_TH_SXSTATUS 0x5c0
+/* Extended M-mode control registers of T-Head */
+#define CSR_TH_MXSTATUS        0x7c0
+#define CSR_TH_MHCR            0x7c1
+#define CSR_TH_MCOR            0x7c2
+#define CSR_TH_MCCR2           0x7c3
+#define CSR_TH_MHINT           0x7c5
+#define CSR_TH_MRVBR           0x7c7
+#define CSR_TH_MCOUNTERWEN     0x7c9
+#define CSR_TH_MCOUNTERINTEN   0x7ca
+#define CSR_TH_MCOUNTEROF      0x7cb
+#define CSR_TH_MCINS           0x7d2
+#define CSR_TH_MCINDEX         0x7d3
+#define CSR_TH_MCDATA0         0x7d4
+#define CSR_TH_MCDATA1         0x7d5
+#define CSR_TH_MSMPR           0x7f3
+#define CSR_TH_CPUID           0xfc0
+#define CSR_TH_MAPBADDR        0xfc1
+
+/* TH_MXSTATUS bits */
+#define TH_MXSTATUS_UCME        BIT(16)
+#define TH_MXSTATUS_MAEE        BIT(21)
+#define TH_MXSTATUS_THEADISAEE  BIT(22)
+
+/* Extended S-mode control registers of T-Head */
+#define CSR_TH_SXSTATUS        0x5c0
+#define CSR_TH_SHCR            0x5c1
+#define CSR_TH_SCER2           0x5c2
+#define CSR_TH_SCER            0x5c3
+#define CSR_TH_SCOUNTERINTEN   0x5c4
+#define CSR_TH_SCOUNTEROF      0x5c5
+#define CSR_TH_SCYCLE          0x5e0
+#define CSR_TH_SHPMCOUNTER3    0x5e3
+#define CSR_TH_SHPMCOUNTER4    0x5e4
+#define CSR_TH_SHPMCOUNTER5    0x5e5
+#define CSR_TH_SHPMCOUNTER6    0x5e6
+#define CSR_TH_SHPMCOUNTER7    0x5e7
+#define CSR_TH_SHPMCOUNTER8    0x5e8
+#define CSR_TH_SHPMCOUNTER9    0x5e9
+#define CSR_TH_SHPMCOUNTER10   0x5ea
+#define CSR_TH_SHPMCOUNTER11   0x5eb
+#define CSR_TH_SHPMCOUNTER12   0x5ec
+#define CSR_TH_SHPMCOUNTER13   0x5ed
+#define CSR_TH_SHPMCOUNTER14   0x5ee
+#define CSR_TH_SHPMCOUNTER15   0x5ef
+#define CSR_TH_SHPMCOUNTER16   0x5f0
+#define CSR_TH_SHPMCOUNTER17   0x5f1
+#define CSR_TH_SHPMCOUNTER18   0x5f2
+#define CSR_TH_SHPMCOUNTER19   0x5f3
+#define CSR_TH_SHPMCOUNTER20   0x5f4
+#define CSR_TH_SHPMCOUNTER21   0x5f5
+#define CSR_TH_SHPMCOUNTER22   0x5f6
+#define CSR_TH_SHPMCOUNTER23   0x5f7
+#define CSR_TH_SHPMCOUNTER24   0x5f8
+#define CSR_TH_SHPMCOUNTER25   0x5f9
+#define CSR_TH_SHPMCOUNTER26   0x5fa
+#define CSR_TH_SHPMCOUNTER27   0x5fb
+#define CSR_TH_SHPMCOUNTER28   0x5fc
+#define CSR_TH_SHPMCOUNTER29   0x5fd
+#define CSR_TH_SHPMCOUNTER30   0x5fe
+#define CSR_TH_SHPMCOUNTER31   0x5ff
+#define CSR_TH_SMIR            0x9c0
+#define CSR_TH_SMLO0           0x9c1
+#define CSR_TH_SMEH            0x9c2
+#define CSR_TH_SMCIR           0x9c3
+
+/* Extended U-mode control registers of T-Head */
+#define CSR_TH_FXCR            0x800
 
 /* TH_SXSTATUS bits */
 #define TH_SXSTATUS_UCME        BIT(16)
 #define TH_SXSTATUS_MAEE        BIT(21)
 #define TH_SXSTATUS_THEADISAEE  BIT(22)
 
+static RISCVException mmode(CPURISCVState *env, int csrno)
+{
+    if (riscv_has_ext(env, RVM)) {
+        return RISCV_EXCP_NONE;
+    }
+
+    return RISCV_EXCP_ILLEGAL_INST;
+}
+
 static RISCVException smode(CPURISCVState *env, int csrno)
 {
     if (riscv_has_ext(env, RVS)) {
@@ -36,11 +114,31 @@ static RISCVException smode(CPURISCVState *env, int csrno)
     return RISCV_EXCP_ILLEGAL_INST;
 }
 
+static RISCVException any(CPURISCVState *env, int csrno)
+{
+    return RISCV_EXCP_NONE;
+}
+
 static bool test_thead_mvendorid(RISCVCPU *cpu)
 {
     return cpu->cfg.mvendorid == THEAD_VENDOR_ID;
 }
 
+static RISCVException read_th_mxstatus(CPURISCVState *env, int csrno,
+                                       target_ulong *val)
+{
+    /* We don't set MAEE here, because QEMU does not implement MAEE. */
+    *val = TH_MXSTATUS_UCME | TH_MXSTATUS_THEADISAEE;
+    return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_unimp_th_csr(CPURISCVState *env, int csrno,
+                                        target_ulong *val)
+{
+    *val = 0;
+    return RISCV_EXCP_NONE;
+}
+
 static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
                                        target_ulong *val)
 {
@@ -50,10 +148,290 @@ static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
 }
 
 const RISCVCSR th_csr_list[] = {
+    {
+        .csrno = CSR_TH_MXSTATUS,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mxstatus", mmode, read_th_mxstatus }
+    },
+    {
+        .csrno = CSR_TH_MHCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mhcr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcor", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCCR2,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mccr2", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MHINT,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mhint", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MRVBR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mrvbr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTERWEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterwen", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTERINTEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterinten", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCOUNTEROF,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcounterof", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCINS,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcins", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCINDEX,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcindex", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCDATA0,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcdata0", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MCDATA1,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mcdata1", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MSMPR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.msmpr", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_CPUID,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.cpuid", mmode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_MAPBADDR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.mapbaddr", mmode, read_unimp_th_csr }
+    },
     {
         .csrno = CSR_TH_SXSTATUS,
         .insertion_test = test_thead_mvendorid,
         .csr_ops = { "th.sxstatus", smode, read_th_sxstatus }
     },
+    {
+        .csrno = CSR_TH_SHCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shcr", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCER2,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scer2", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCER,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scer", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCOUNTERINTEN,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scounterinten", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCOUNTEROF,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scounterof", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SCYCLE,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.scycle", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER3,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter3", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER4,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter4", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER5,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter5", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER6,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter6", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER7,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter7", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER8,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter8", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER9,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter9", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER10,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter10", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER11,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter11", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER12,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter12", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER13,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter13", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER14,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter14", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER15,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter15", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER16,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter16", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER17,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter17", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER18,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter18", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER19,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter19", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER20,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter20", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER21,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter21", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER22,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter22", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER23,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter23", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER24,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter24", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER25,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter25", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER26,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter26", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER27,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter27", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER28,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter28", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER29,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter29", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER30,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter30", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SHPMCOUNTER31,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.shpmcounter31", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMIR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smir", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMLO0,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smlo0", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMEH,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smeh", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_SMCIR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.smcir", smode, read_unimp_th_csr }
+    },
+    {
+        .csrno = CSR_TH_FXCR,
+        .insertion_test = test_thead_mvendorid,
+        .csr_ops = { "th.fxcr", any, read_unimp_th_csr }
+    },
     { }
 };
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 2/5] hw/riscv: add k230 board initial support
  2026-04-17 15:11 [PATCH v6 0/5] Add support for K230 board Chao Liu
  2026-04-17 15:11 ` [PATCH v6 1/5] target/riscv: add thead-c908 cpu support Chao Liu
@ 2026-04-17 15:11 ` Chao Liu
  2026-05-01  4:09   ` Alistair Francis
  2026-04-17 15:11 ` [PATCH v6 3/5] hw/watchdog: add k230 watchdog " Chao Liu
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 20+ messages in thread
From: Chao Liu @ 2026-04-17 15:11 UTC (permalink / raw)
  To: Chao Liu, Pierrick Bouvier, Palmer Dabbelt, Alistair Francis,
	Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier
  Cc: qemu-devel, qemu-riscv, Chao Liu, Daniel Henrique Barboza,
	Peng Jiang

From: Chao Liu <chao.liu@zevorn.cn>

K230 Board Compatible with kendryte K230 SDK.

Preliminarily supports the C908 small core, which can
run the U-Boot and Linux kernel compiled by the K230 SDK.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reported-by: Peng Jiang <3160104094@zju.edu.cn>
---
 MAINTAINERS             |   8 +-
 hw/riscv/Kconfig        |  10 +
 hw/riscv/k230.c         | 484 ++++++++++++++++++++++++++++++++++++++++
 hw/riscv/meson.build    |   2 +-
 include/hw/riscv/k230.h | 150 +++++++++++++
 5 files changed, 652 insertions(+), 2 deletions(-)
 create mode 100644 hw/riscv/k230.c
 create mode 100644 include/hw/riscv/k230.h

diff --git a/MAINTAINERS b/MAINTAINERS
index aa4267b158..c429c63961 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1773,6 +1773,12 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
 F: hw/riscv/xiangshan_kmh.c
 F: include/hw/riscv/xiangshan_kmh.h
 
+K230 Machines
+M: Chao Liu <chao.liu.zevorn@gmail.com>
+S: Maintained
+F: hw/riscv/k230.c
+F: include/hw/riscv/k230.h
+
 RX Machines
 -----------
 rx-gdbsim
@@ -3620,7 +3626,7 @@ M: Alexander Bulekov <alxndr@bu.edu>
 R: Paolo Bonzini <pbonzini@redhat.com>
 R: Stefan Hajnoczi <stefanha@redhat.com>
 R: Fabiano Rosas <farosas@suse.de>
-R: Darren Kenny <darren.kenny@oracle.com> 
+R: Darren Kenny <darren.kenny@oracle.com>
 R: Qiuhao Li <Qiuhao.Li@outlook.com>
 S: Maintained
 F: tests/qtest/fuzz/
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 0222c93f87..b1a7357866 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -134,3 +134,13 @@ config MIPS_BOSTON_AIA
     default y
     select PCI_EXPRESS
     select PCI_EXPRESS_XILINX
+
+config K230
+    bool
+    default y
+    depends on RISCV64
+    select RISCV_ACLINT
+    select RISCV_APLIC
+    select RISCV_IMSIC
+    select SERIAL_MM
+    select UNIMP
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
new file mode 100644
index 0000000000..2537023a05
--- /dev/null
+++ b/hw/riscv/k230.c
@@ -0,0 +1,484 @@
+/*
+ * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the Kendryte K230 SDK
+ *
+ * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu-qom.h"
+#include "qemu/cutils.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "system/system.h"
+#include "system/memory.h"
+#include "target/riscv/cpu.h"
+#include "chardev/char.h"
+#include "hw/core/loader.h"
+#include "hw/core/sysbus.h"
+#include "hw/riscv/k230.h"
+#include "hw/riscv/boot.h"
+#include "hw/intc/riscv_aclint.h"
+#include "hw/intc/sifive_plic.h"
+#include "hw/char/serial-mm.h"
+#include "hw/misc/unimp.h"
+
+static const MemMapEntry memmap[] = {
+    [K230_DEV_DDRC] =         { 0x00000000,  0x80000000 },
+    [K230_DEV_KPU_L2_CACHE] = { 0x80000000,  0x00200000 },
+    [K230_DEV_SRAM] =         { 0x80200000,  0x00200000 },
+    [K230_DEV_KPU_CFG] =      { 0x80400000,  0x00000800 },
+    [K230_DEV_FFT] =          { 0x80400800,  0x00000400 },
+    [K230_DEV_AI_2D_ENGINE] = { 0x80400C00,  0x00000800 },
+    [K230_DEV_GSDMA] =        { 0x80800000,  0x00004000 },
+    [K230_DEV_DMA] =          { 0x80804000,  0x00004000 },
+    [K230_DEV_DECOMP_GZIP] =  { 0x80808000,  0x00004000 },
+    [K230_DEV_NON_AI_2D] =    { 0x8080C000,  0x00004000 },
+    [K230_DEV_ISP] =          { 0x90000000,  0x00008000 },
+    [K230_DEV_DEWARP] =       { 0x90008000,  0x00001000 },
+    [K230_DEV_RX_CSI] =       { 0x90009000,  0x00002000 },
+    [K230_DEV_H264] =         { 0x90400000,  0x00010000 },
+    [K230_DEV_2P5D] =         { 0x90800000,  0x00040000 },
+    [K230_DEV_VO] =           { 0x90840000,  0x00010000 },
+    [K230_DEV_VO_CFG] =       { 0x90850000,  0x00001000 },
+    [K230_DEV_3D_ENGINE] =    { 0x90A00000,  0x00000800 },
+    [K230_DEV_PMU] =          { 0x91000000,  0x00000C00 },
+    [K230_DEV_RTC] =          { 0x91000C00,  0x00000400 },
+    [K230_DEV_CMU] =          { 0x91100000,  0x00001000 },
+    [K230_DEV_RMU] =          { 0x91101000,  0x00001000 },
+    [K230_DEV_BOOT] =         { 0x91102000,  0x00001000 },
+    [K230_DEV_PWR] =          { 0x91103000,  0x00001000 },
+    [K230_DEV_MAILBOX] =      { 0x91104000,  0x00001000 },
+    [K230_DEV_IOMUX] =        { 0x91105000,  0x00000800 },
+    [K230_DEV_TIMER] =        { 0x91105800,  0x00000800 },
+    [K230_DEV_WDT0] =         { 0x91106000,  0x00000800 },
+    [K230_DEV_WDT1] =         { 0x91106800,  0x00000800 },
+    [K230_DEV_TS] =           { 0x91107000,  0x00000800 },
+    [K230_DEV_HDI] =          { 0x91107800,  0x00000800 },
+    [K230_DEV_STC] =          { 0x91108000,  0x00000800 },
+    [K230_DEV_BOOTROM] =      { 0x91200000,  0x00010000 },
+    [K230_DEV_SECURITY] =     { 0x91210000,  0x00008000 },
+    [K230_DEV_UART0] =        { 0x91400000,  0x00001000 },
+    [K230_DEV_UART1] =        { 0x91401000,  0x00001000 },
+    [K230_DEV_UART2] =        { 0x91402000,  0x00001000 },
+    [K230_DEV_UART3] =        { 0x91403000,  0x00001000 },
+    [K230_DEV_UART4] =        { 0x91404000,  0x00001000 },
+    [K230_DEV_I2C0] =         { 0x91405000,  0x00001000 },
+    [K230_DEV_I2C1] =         { 0x91406000,  0x00001000 },
+    [K230_DEV_I2C2] =         { 0x91407000,  0x00001000 },
+    [K230_DEV_I2C3] =         { 0x91408000,  0x00001000 },
+    [K230_DEV_I2C4] =         { 0x91409000,  0x00001000 },
+    [K230_DEV_PWM] =          { 0x9140A000,  0x00001000 },
+    [K230_DEV_GPIO0] =        { 0x9140B000,  0x00001000 },
+    [K230_DEV_GPIO1] =        { 0x9140C000,  0x00001000 },
+    [K230_DEV_ADC] =          { 0x9140D000,  0x00001000 },
+    [K230_DEV_CODEC] =        { 0x9140E000,  0x00001000 },
+    [K230_DEV_I2S] =          { 0x9140F000,  0x00001000 },
+    [K230_DEV_USB0] =         { 0x91500000,  0x00010000 },
+    [K230_DEV_USB1] =         { 0x91540000,  0x00010000 },
+    [K230_DEV_SD0] =          { 0x91580000,  0x00001000 },
+    [K230_DEV_SD1] =          { 0x91581000,  0x00001000 },
+    [K230_DEV_QSPI0] =        { 0x91582000,  0x00001000 },
+    [K230_DEV_QSPI1] =        { 0x91583000,  0x00001000 },
+    [K230_DEV_SPI] =          { 0x91584000,  0x00001000 },
+    [K230_DEV_HI_SYS_CFG] =   { 0x91585000,  0x00000400 },
+    [K230_DEV_DDRC_CFG] =     { 0x98000000,  0x02000000 },
+    [K230_DEV_FLASH] =        { 0xC0000000,  0x08000000 },
+    [K230_DEV_PLIC] =         { 0xF00000000, 0x00400000 },
+    [K230_DEV_CLINT] =        { 0xF04000000, 0x00400000 },
+};
+
+static void k230_soc_init(Object *obj)
+{
+    K230SoCState *s = RISCV_K230_SOC(obj);
+    RISCVHartArrayState *cpu0 = &s->c908_cpu;
+
+    object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
+    qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
+    qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
+    qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
+                         memmap[K230_DEV_BOOTROM].base);
+}
+
+static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
+{
+    g_autofree char *plic_hart_config = NULL;
+
+    /* Per-socket PLIC hart topology configuration string */
+    plic_hart_config = riscv_plic_hart_config_string(hartid_count);
+
+    /* Per-socket PLIC */
+    return sifive_plic_create(memmap[K230_DEV_PLIC].base,
+                              plic_hart_config, hartid_count, base_hartid,
+                              K230_PLIC_NUM_SOURCES,
+                              K230_PLIC_NUM_PRIORITIES,
+                              K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
+                              K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
+                              K230_PLIC_CONTEXT_BASE,
+                              K230_PLIC_CONTEXT_STRIDE,
+                              memmap[K230_DEV_PLIC].size);
+}
+
+static void k230_soc_realize(DeviceState *dev, Error **errp)
+{
+    K230SoCState *s = RISCV_K230_SOC(dev);
+    MemoryRegion *sys_mem = get_system_memory();
+    int c908_cpus;
+
+    sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
+
+    c908_cpus = s->c908_cpu.num_harts;
+
+    /* SRAM */
+    memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
+                           memmap[K230_DEV_SRAM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
+                                &s->sram);
+
+    /* BootROM */
+    memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
+                           memmap[K230_DEV_BOOTROM].size, &error_fatal);
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
+                                &s->bootrom);
+
+    /* PLIC */
+    s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
+
+    /* CLINT */
+    riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
+                            C908_CPU_HARTID, c908_cpus, false);
+    riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
+                               RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
+                               C908_CPU_HARTID, c908_cpus,
+                               RISCV_ACLINT_DEFAULT_MTIMECMP,
+                               RISCV_ACLINT_DEFAULT_MTIME,
+                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
+
+    /* UART */
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART0].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART0_IRQ),
+                   399193, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART1].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART1_IRQ),
+                   399193, serial_hd(1), DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART2].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART2_IRQ),
+                   399193, serial_hd(2), DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART3].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART3_IRQ),
+                   399193, serial_hd(3), DEVICE_LITTLE_ENDIAN);
+    serial_mm_init(sys_mem, memmap[K230_DEV_UART4].base, 2,
+                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
+                   399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
+
+    /* unimplemented devices */
+    create_unimplemented_device("kpu.l2-cache",
+                                memmap[K230_DEV_KPU_L2_CACHE].base,
+                                memmap[K230_DEV_KPU_L2_CACHE].size);
+
+    create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
+                                memmap[K230_DEV_KPU_CFG].size);
+
+    create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
+                                memmap[K230_DEV_FFT].size);
+
+    create_unimplemented_device("2d-engine.ai",
+                                memmap[K230_DEV_AI_2D_ENGINE].base,
+                                memmap[K230_DEV_AI_2D_ENGINE].size);
+
+    create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
+                                memmap[K230_DEV_GSDMA].size);
+
+    create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
+                                memmap[K230_DEV_DMA].size);
+
+    create_unimplemented_device("decomp-gzip",
+                                memmap[K230_DEV_DECOMP_GZIP].base,
+                                memmap[K230_DEV_DECOMP_GZIP].size);
+
+    create_unimplemented_device("2d-engine.non-ai",
+                                memmap[K230_DEV_NON_AI_2D].base,
+                                memmap[K230_DEV_NON_AI_2D].size);
+
+    create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
+                                memmap[K230_DEV_ISP].size);
+
+    create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
+                                memmap[K230_DEV_DEWARP].size);
+
+    create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
+                                memmap[K230_DEV_RX_CSI].size);
+
+    create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
+                                memmap[K230_DEV_H264].size);
+
+    create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
+                                memmap[K230_DEV_2P5D].size);
+
+    create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
+                                memmap[K230_DEV_VO].size);
+
+    create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
+                                memmap[K230_DEV_VO_CFG].size);
+
+    create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
+                                memmap[K230_DEV_3D_ENGINE].size);
+
+    create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
+                                memmap[K230_DEV_PMU].size);
+
+    create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
+                                memmap[K230_DEV_RTC].size);
+
+    create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
+                                memmap[K230_DEV_CMU].size);
+
+    create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
+                                memmap[K230_DEV_RMU].size);
+
+    create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
+                                memmap[K230_DEV_BOOT].size);
+
+    create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
+                                memmap[K230_DEV_PWR].size);
+
+    create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
+                                memmap[K230_DEV_MAILBOX].size);
+
+    create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
+                                memmap[K230_DEV_IOMUX].size);
+
+    create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
+                                memmap[K230_DEV_TIMER].size);
+
+    create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
+                                memmap[K230_DEV_WDT0].size);
+
+    create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
+                                memmap[K230_DEV_WDT1].size);
+
+    create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
+                                memmap[K230_DEV_TS].size);
+
+    create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
+                                memmap[K230_DEV_HDI].size);
+
+    create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
+                                memmap[K230_DEV_STC].size);
+
+    create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
+                                memmap[K230_DEV_SECURITY].size);
+
+    create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
+                                memmap[K230_DEV_I2C0].size);
+
+    create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
+                                memmap[K230_DEV_I2C1].size);
+
+    create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
+                                memmap[K230_DEV_I2C2].size);
+
+    create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
+                                memmap[K230_DEV_I2C3].size);
+
+    create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
+                                memmap[K230_DEV_I2C4].size);
+
+    create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
+                                memmap[K230_DEV_PWM].size);
+
+    create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
+                                memmap[K230_DEV_GPIO0].size);
+
+    create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
+                                memmap[K230_DEV_GPIO1].size);
+
+    create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
+                                memmap[K230_DEV_ADC].size);
+
+    create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
+                                memmap[K230_DEV_CODEC].size);
+
+    create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
+                                memmap[K230_DEV_I2S].size);
+
+    create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
+                                memmap[K230_DEV_USB0].size);
+
+    create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
+                                memmap[K230_DEV_USB1].size);
+
+    create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
+                                memmap[K230_DEV_SD0].size);
+
+    create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
+                                memmap[K230_DEV_SD1].size);
+
+    create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
+                                memmap[K230_DEV_QSPI0].size);
+
+    create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
+                                memmap[K230_DEV_QSPI1].size);
+
+    create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
+                                memmap[K230_DEV_SPI].size);
+
+    create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
+                                memmap[K230_DEV_HI_SYS_CFG].size);
+
+    create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
+                                memmap[K230_DEV_DDRC_CFG].size);
+
+    create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
+                                memmap[K230_DEV_FLASH].size);
+}
+
+static void k230_soc_class_init(ObjectClass *oc, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = k230_soc_realize;
+}
+
+static const TypeInfo k230_soc_type_info = {
+    .name = TYPE_RISCV_K230_SOC,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(K230SoCState),
+    .instance_init = k230_soc_init,
+    .class_init = k230_soc_class_init,
+};
+
+static void k230_soc_register_types(void)
+{
+    type_register_static(&k230_soc_type_info);
+}
+
+type_init(k230_soc_register_types)
+
+static void k230_machine_done(Notifier *notifier, void *data)
+{
+    K230MachineState *s = container_of(notifier, K230MachineState,
+                                     machine_done);
+    MachineState *machine = MACHINE(s);
+    hwaddr start_addr = memmap[K230_DEV_DDRC].base;
+    target_ulong firmware_end_addr, kernel_start_addr;
+    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
+    uint64_t kernel_entry = 0;
+    RISCVBootInfo boot_info;
+
+    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+                                                     &start_addr, NULL);
+
+    /* Mask ROM reset vector */
+    uint32_t reset_vec[] = {
+        /* 0x91200000: auipc  t0, 0x0              */ 0x00000297,
+        /* 0x91200004: addi   t0, t0, 36 # <trap>  */ 0x03028293,
+        /* 0x91200008: csrw   mtvec, t0            */ 0x30529073,
+        /* 0x9120000C: csrr   a0, misa             */ 0x301012F3,
+        /* 0x91200010: lui    t0, 0x1              */ 0x000012B7,
+        /* 0x91200014: slli   t0, t0, 1            */ 0x00129293,
+        /* 0x91200018: and    t0, a0, t0           */ 0x005572B3,
+        /* 0x9120001C: bnez   t0, loop             */ 0x00511063,
+        /* entry:                                  */
+        /* 0x91200020: addiw  t0, zero, 1          */ 0x0010029b,
+        /* 0x91200024: slli   t0, t0, 0x1b         */ 0x01b29293,
+        /* 0x91200028: jr     t0 # uboot 0x8000000 */ 0x00028067,
+        /* loop:                                   */
+        /* 0x9120002C: j      0x9120002C # <loop>  */ 0x0000006f,
+        /* trap:                                   */
+        /* 0x91200030: j      0x91200030 # <trap>  */ 0x0000006f,
+    };
+
+    /* copy in the reset vector in little_endian byte order */
+    for (int i = 0; i < sizeof(reset_vec) >> 2; i++) {
+        reset_vec[i] = cpu_to_le32(reset_vec[i]);
+    }
+    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
+                          memmap[K230_DEV_BOOTROM].base, &address_space_memory);
+
+    riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
+
+    if (machine->kernel_filename && !kernel_entry) {
+        kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
+                                                         firmware_end_addr);
+        riscv_load_kernel(machine, &boot_info, kernel_start_addr,
+                          true, NULL);
+        kernel_entry = boot_info.image_low_addr;
+    }
+}
+
+static void k230_machine_init(MachineState *machine)
+{
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+
+    K230MachineState *s = RISCV_K230_MACHINE(machine);
+    MemoryRegion *sys_mem = get_system_memory();
+
+    if (machine->ram_size < mc->default_ram_size) {
+        char *sz = size_to_str(mc->default_ram_size);
+        error_report("Invalid RAM size, should be %s", sz);
+        g_free(sz);
+        exit(EXIT_FAILURE);
+    }
+
+    /* Initialize SoC */
+    object_initialize_child(OBJECT(machine), "soc", &s->soc,
+                            TYPE_RISCV_K230_SOC);
+    qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
+
+    /* Data Memory */
+    memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
+                                machine->ram);
+
+    s->machine_done.notify = k230_machine_done;
+    qemu_add_machine_init_done_notifier(&s->machine_done);
+}
+
+static void k230_machine_instance_init(Object *obj)
+{
+}
+
+static void k230_machine_class_init(ObjectClass *oc, const void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
+    mc->init = k230_machine_init;
+    mc->default_cpus = 2;
+    mc->default_ram_id = "riscv.K230.ram"; /* DDR */
+    mc->default_ram_size = memmap[K230_DEV_DDRC].size;
+}
+
+static const TypeInfo k230_machine_typeinfo = {
+    .name       = TYPE_RISCV_K230_MACHINE,
+    .parent     = TYPE_MACHINE,
+    .class_init = k230_machine_class_init,
+    .instance_init = k230_machine_instance_init,
+    .instance_size = sizeof(K230MachineState),
+};
+
+static void k230_machine_init_register_types(void)
+{
+    type_register_static(&k230_machine_typeinfo);
+}
+
+type_init(k230_machine_init_register_types)
diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
index 533472e22a..09cf855984 100644
--- a/hw/riscv/meson.build
+++ b/hw/riscv/meson.build
@@ -14,8 +14,8 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
 	'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
 riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
 riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
-
 riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c'))
 riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c'))
+riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
 
 hw_arch += {'riscv': riscv_ss}
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
new file mode 100644
index 0000000000..830175b756
--- /dev/null
+++ b/include/hw/riscv/k230.h
@@ -0,0 +1,150 @@
+/*
+ * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef HW_K230_H
+#define HW_K230_H
+
+#include "hw/core/boards.h"
+#include "hw/riscv/riscv_hart.h"
+
+#define C908_CPU_HARTID   (0)
+
+#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
+#define RISCV_K230_SOC(obj) \
+    OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
+
+typedef struct K230SoCState {
+    /*< private >*/
+    DeviceState parent_obj;
+
+    /*< public >*/
+    RISCVHartArrayState c908_cpu; /* Small core */
+
+    MemoryRegion sram;
+    MemoryRegion bootrom;
+
+    DeviceState *c908_plic;
+} K230SoCState;
+
+#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
+#define RISCV_K230_MACHINE(obj) \
+    OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
+
+typedef struct K230MachineState {
+    /*< private >*/
+    MachineState parent_obj;
+
+    /*< public >*/
+    K230SoCState soc;
+    Notifier machine_done;
+} K230MachineState;
+
+enum {
+    K230_DEV_DDRC,
+    K230_DEV_KPU_L2_CACHE,
+    K230_DEV_SRAM,
+    K230_DEV_KPU_CFG,
+    K230_DEV_FFT,
+    K230_DEV_AI_2D_ENGINE,
+    K230_DEV_GSDMA,
+    K230_DEV_DMA,
+    K230_DEV_DECOMP_GZIP,
+    K230_DEV_NON_AI_2D,
+    K230_DEV_ISP,
+    K230_DEV_DEWARP,
+    K230_DEV_RX_CSI,
+    K230_DEV_H264,
+    K230_DEV_2P5D,
+    K230_DEV_VO,
+    K230_DEV_VO_CFG,
+    K230_DEV_3D_ENGINE,
+    K230_DEV_PMU,
+    K230_DEV_RTC,
+    K230_DEV_CMU,
+    K230_DEV_RMU,
+    K230_DEV_BOOT,
+    K230_DEV_PWR,
+    K230_DEV_MAILBOX,
+    K230_DEV_IOMUX,
+    K230_DEV_TIMER,
+    K230_DEV_WDT0,
+    K230_DEV_WDT1,
+    K230_DEV_TS,
+    K230_DEV_HDI,
+    K230_DEV_STC,
+    K230_DEV_BOOTROM,
+    K230_DEV_SECURITY,
+    K230_DEV_UART0,
+    K230_DEV_UART1,
+    K230_DEV_UART2,
+    K230_DEV_UART3,
+    K230_DEV_UART4,
+    K230_DEV_I2C0,
+    K230_DEV_I2C1,
+    K230_DEV_I2C2,
+    K230_DEV_I2C3,
+    K230_DEV_I2C4,
+    K230_DEV_PWM,
+    K230_DEV_GPIO0,
+    K230_DEV_GPIO1,
+    K230_DEV_ADC,
+    K230_DEV_CODEC,
+    K230_DEV_I2S,
+    K230_DEV_USB0,
+    K230_DEV_USB1,
+    K230_DEV_SD0,
+    K230_DEV_SD1,
+    K230_DEV_QSPI0,
+    K230_DEV_QSPI1,
+    K230_DEV_SPI,
+    K230_DEV_HI_SYS_CFG,
+    K230_DEV_DDRC_CFG,
+    K230_DEV_FLASH,
+    K230_DEV_PLIC,
+    K230_DEV_CLINT,
+};
+
+enum {
+    K230_UART0_IRQ  = 16,
+    K230_UART1_IRQ  = 17,
+    K230_UART2_IRQ  = 18,
+    K230_UART3_IRQ  = 19,
+    K230_UART4_IRQ  = 20,
+};
+
+/*
+ * Integrates with the interrupt controller (PLIC),
+ * which can process 208 interrupt external sources
+ */
+#define K230_PLIC_NUM_SOURCES 208
+#define K230_PLIC_NUM_PRIORITIES 7
+#define K230_PLIC_PRIORITY_BASE 0x00
+#define K230_PLIC_PENDING_BASE 0x1000
+#define K230_PLIC_ENABLE_BASE 0x2000
+#define K230_PLIC_ENABLE_STRIDE 0x80
+#define K230_PLIC_CONTEXT_BASE 0x200000
+#define K230_PLIC_CONTEXT_STRIDE 0x1000
+
+#endif
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 3/5] hw/watchdog: add k230 watchdog initial support
  2026-04-17 15:11 [PATCH v6 0/5] Add support for K230 board Chao Liu
  2026-04-17 15:11 ` [PATCH v6 1/5] target/riscv: add thead-c908 cpu support Chao Liu
  2026-04-17 15:11 ` [PATCH v6 2/5] hw/riscv: add k230 board initial support Chao Liu
@ 2026-04-17 15:11 ` Chao Liu
  2026-04-17 15:11 ` [PATCH v6 4/5] tests/qtest: add test for K230 watchdog Chao Liu
  2026-04-17 15:11 ` [PATCH v6 5/5] docs/system/riscv: add documentation for k230 machine Chao Liu
  4 siblings, 0 replies; 20+ messages in thread
From: Chao Liu @ 2026-04-17 15:11 UTC (permalink / raw)
  To: Chao Liu, Pierrick Bouvier, Palmer Dabbelt, Alistair Francis,
	Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier
  Cc: qemu-devel, qemu-riscv, Chao Liu, Mig Yang,
	Daniel Henrique Barboza

From: Chao Liu <chao.liu@zevorn.cn>

Add programmable Watchdog Timer (WDT) peripheral for K230 machine.

Signed-off-by: Mig Yang <temashking@foxmail.com>
Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
 MAINTAINERS                    |   2 +
 hw/riscv/Kconfig               |   1 +
 hw/riscv/k230.c                |  18 ++
 hw/watchdog/Kconfig            |   4 +
 hw/watchdog/k230_wdt.c         | 307 +++++++++++++++++++++++++++++++++
 hw/watchdog/meson.build        |   1 +
 hw/watchdog/trace-events       |   9 +
 include/hw/riscv/k230.h        |   4 +
 include/hw/watchdog/k230_wdt.h | 132 ++++++++++++++
 9 files changed, 478 insertions(+)
 create mode 100644 hw/watchdog/k230_wdt.c
 create mode 100644 include/hw/watchdog/k230_wdt.h

diff --git a/MAINTAINERS b/MAINTAINERS
index c429c63961..a2eecca155 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1777,7 +1777,9 @@ K230 Machines
 M: Chao Liu <chao.liu.zevorn@gmail.com>
 S: Maintained
 F: hw/riscv/k230.c
+F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
+F: include/hw/watchdog/k230_wdt.h
 
 RX Machines
 -----------
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index b1a7357866..5f8511cb92 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -144,3 +144,4 @@ config K230
     select RISCV_IMSIC
     select SERIAL_MM
     select UNIMP
+    select K230_WDT
diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
index 2537023a05..7df8a3298c 100644
--- a/hw/riscv/k230.c
+++ b/hw/riscv/k230.c
@@ -113,6 +113,9 @@ static void k230_soc_init(Object *obj)
     RISCVHartArrayState *cpu0 = &s->c908_cpu;
 
     object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
+    object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT);
+    object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT);
+
     qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
     qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
     qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
@@ -190,6 +193,21 @@ static void k230_soc_realize(DeviceState *dev, Error **errp)
                    qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
                    399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
 
+    /* Watchdog */
+    for (int i = 0; i < 2; i++) {
+        if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) {
+            return;
+        }
+    }
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[0]), 0, memmap[K230_DEV_WDT0].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[0]), 0,
+                       qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT0_IRQ));
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt[1]), 0, memmap[K230_DEV_WDT1].base);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->wdt[1]), 0,
+                       qdev_get_gpio_in(DEVICE(s->c908_plic), K230_WDT1_IRQ));
+
     /* unimplemented devices */
     create_unimplemented_device("kpu.l2-cache",
                                 memmap[K230_DEV_KPU_L2_CACHE].base,
diff --git a/hw/watchdog/Kconfig b/hw/watchdog/Kconfig
index 861fd00334..55f77c5c84 100644
--- a/hw/watchdog/Kconfig
+++ b/hw/watchdog/Kconfig
@@ -18,6 +18,10 @@ config WDT_DIAG288
 config WDT_IMX2
     bool
 
+config K230_WDT
+    bool
+    select PTIMER
+
 config WDT_SBSA
     bool
 
diff --git a/hw/watchdog/k230_wdt.c b/hw/watchdog/k230_wdt.c
new file mode 100644
index 0000000000..66df0b738b
--- /dev/null
+++ b/hw/watchdog/k230_wdt.c
@@ -0,0 +1,307 @@
+/*
+ *  * K230 Watchdog Compatible with kendryte K230 SDK
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "qemu/osdep.h"
+#include "qemu/bitops.h"
+#include "qemu/module.h"
+#include "system/watchdog.h"
+#include "migration/vmstate.h"
+#include "hw/core/qdev-properties.h"
+#include "hw/watchdog/k230_wdt.h"
+#include "trace.h"
+
+static void k230_wdt_timeout(void *opaque)
+{
+    K230WdtState *s = K230_WDT(opaque);
+
+    trace_k230_wdt_timeout();
+
+    /* Set interrupt status if in interrupt mode */
+    if (s->cr & K230_WDT_CR_RMOD) {
+        s->stat |= K230_WDT_STAT_INT;
+        s->interrupt_pending = true;
+        qemu_set_irq(s->irq, 1);
+        trace_k230_wdt_interrupt();
+    } else {
+        /* Direct reset mode */
+        trace_k230_wdt_reset();
+        watchdog_perform_action();
+    }
+
+    /* Restart counter */
+    s->current_count = s->timeout_value;
+    ptimer_set_count(s->timer, s->current_count);
+    ptimer_run(s->timer, 1);
+}
+
+static void k230_wdt_reset(DeviceState *dev)
+{
+    K230WdtState *s = K230_WDT(dev);
+
+    trace_k230_wdt_reset_device();
+
+    ptimer_transaction_begin(s->timer);
+    ptimer_stop(s->timer);
+    ptimer_transaction_commit(s->timer);
+
+    /* Reset registers to default values */
+    s->cr = 0;
+    s->torr = 0;
+    s->ccvr = 0xFFFFFFFF;
+    s->stat = 0;
+    s->prot_level = 0x2;
+
+    s->interrupt_pending = false;
+    s->enabled = false;
+    s->timeout_value = 0;
+    s->current_count = 0xFFFFFFFF;
+}
+
+static uint64_t k230_wdt_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    K230WdtState *s = K230_WDT(opaque);
+    uint32_t value = 0;
+
+    switch (addr) {
+    case K230_WDT_CR:
+        value = s->cr;
+        break;
+    case K230_WDT_TORR:
+        value = s->torr;
+        break;
+    case K230_WDT_CCVR:
+        if (s->enabled) {
+            value = ptimer_get_count(s->timer);
+        } else {
+            value = s->current_count;
+        }
+        break;
+    case K230_WDT_STAT:
+        value = s->stat;
+        break;
+    case K230_WDT_PROT_LEVEL:
+        value = s->prot_level;
+        break;
+    case K230_WDT_COMP_PARAM_5:
+        value = 0; /* Upper limit of Timeout Period parameters */
+        break;
+    case K230_WDT_COMP_PARAM_4:
+        value = 0; /* Upper limit of Initial Timeout Period parameters */
+        break;
+    case K230_WDT_COMP_PARAM_3:
+        value = 0; /* Derived from WDT_TOP_RST parameter */
+        break;
+    case K230_WDT_COMP_PARAM_2:
+        value = 0xFFFFFFFF; /* Derived from WDT_RST_CNT parameter */
+        break;
+    case K230_WDT_COMP_PARAM_1:
+        /* Component parameters */
+        value = (32 << K230_WDT_CNT_WIDTH_SHIFT) |  /* 32-bit counter */
+                (0 << K230_WDT_DFLT_TOP_INIT_SHIFT) |
+                (0 << K230_WDT_DFLT_TOP_SHIFT) |
+                (K230_WDT_RPL_16_CYCLES << K230_WDT_DFLT_RPL_SHIFT) |
+                (2 << K230_WDT_APB_DATA_WIDTH_SHIFT) | /* 32-bit APB */
+                K230_WDT_USE_FIX_TOP; /* Use fixed timeout values */
+        break;
+    case K230_WDT_COMP_VERSION:
+        value = K230_WDT_COMP_VERSION_VAL;
+        break;
+    case K230_WDT_COMP_TYPE:
+        value = K230_WDT_COMP_TYPE_VAL;
+        break;
+    default:
+        /* Other registers return 0 */
+        break;
+    }
+
+    trace_k230_wdt_read(addr, value);
+    return value;
+}
+
+static void k230_wdt_update_timer(K230WdtState *s)
+{
+    ptimer_transaction_begin(s->timer);
+
+    if (s->enabled && s->timeout_value > 0) {
+        ptimer_set_count(s->timer, s->current_count);
+        ptimer_run(s->timer, 1);
+    } else {
+        ptimer_stop(s->timer);
+    }
+
+    ptimer_transaction_commit(s->timer);
+}
+
+static uint32_t k230_wdt_calculate_timeout(uint32_t top_value)
+{
+    /* Calculate timeout based on TOP value */
+    /* For fixed timeout mode: 2^(16 + top_value) */
+    if (top_value <= 15) {
+        return 1 << (16 + top_value);
+    }
+    return 1 << 31; /* Maximum value for 32-bit counter */
+}
+
+static void k230_wdt_write(void *opaque, hwaddr addr,
+                           uint64_t value, unsigned int size)
+{
+    K230WdtState *s = K230_WDT(opaque);
+
+    trace_k230_wdt_write(addr, value);
+
+    switch (addr) {
+    case K230_WDT_CR:
+        s->cr = value & (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT |
+                         K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+        /* Update enabled state */
+        s->enabled = (s->cr & K230_WDT_CR_WDT_EN) != 0;
+
+        /* Update timer */
+        k230_wdt_update_timer(s);
+        break;
+
+    case K230_WDT_TORR:
+        s->torr = value & K230_WDT_TORR_TOP_MASK;
+
+        /* Calculate new timeout value */
+        s->timeout_value = k230_wdt_calculate_timeout(s->torr);
+        s->current_count = s->timeout_value;
+
+        /* Update timer if enabled */
+        if (s->enabled) {
+            k230_wdt_update_timer(s);
+        }
+        break;
+
+    case K230_WDT_CRR:
+        /* Restart counter with magic value 0x76 */
+        if ((value & 0xFF) == K230_WDT_CRR_RESTART) {
+            trace_k230_wdt_restart();
+            s->current_count = s->timeout_value;
+
+            /* Clear interrupt if pending */
+            if (s->interrupt_pending) {
+                s->stat &= ~K230_WDT_STAT_INT;
+                s->interrupt_pending = false;
+                qemu_set_irq(s->irq, 0);
+            }
+
+            /* Update timer */
+            k230_wdt_update_timer(s);
+        }
+        break;
+
+    case K230_WDT_EOI:
+        /* Clear interrupt */
+        s->stat &= ~K230_WDT_STAT_INT;
+        s->interrupt_pending = false;
+        qemu_set_irq(s->irq, 0);
+        break;
+
+    case K230_WDT_PROT_LEVEL:
+        s->prot_level = value & 0x7;
+        break;
+
+    default:
+        /* Read-only registers, ignore writes */
+        break;
+    }
+}
+
+static const MemoryRegionOps k230_wdt_ops = {
+    .read  = k230_wdt_read,
+    .write = k230_wdt_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false,
+    },
+};
+
+static const VMStateDescription vmstate_k230_wdt = {
+    .name = "k230.wdt",
+    .fields = (const VMStateField[]) {
+        VMSTATE_PTIMER(timer, K230WdtState),
+        VMSTATE_UINT32(cr, K230WdtState),
+        VMSTATE_UINT32(torr, K230WdtState),
+        VMSTATE_UINT32(ccvr, K230WdtState),
+        VMSTATE_UINT32(stat, K230WdtState),
+        VMSTATE_UINT32(prot_level, K230WdtState),
+        VMSTATE_BOOL(interrupt_pending, K230WdtState),
+        VMSTATE_BOOL(enabled, K230WdtState),
+        VMSTATE_UINT32(timeout_value, K230WdtState),
+        VMSTATE_UINT32(current_count, K230WdtState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void k230_wdt_realize(DeviceState *dev, Error **errp)
+{
+    K230WdtState *s = K230_WDT(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+    memory_region_init_io(&s->mmio, OBJECT(dev),
+                          &k230_wdt_ops, s,
+                          TYPE_K230_WDT,
+                          K230_WDT_MMIO_SIZE);
+    sysbus_init_mmio(sbd, &s->mmio);
+    sysbus_init_irq(sbd, &s->irq);
+
+    s->timer = ptimer_init(k230_wdt_timeout, s,
+                           PTIMER_POLICY_NO_IMMEDIATE_TRIGGER |
+                           PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
+                           PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+
+    ptimer_transaction_begin(s->timer);
+    ptimer_set_freq(s->timer, K230_WDT_DEFAULT_FREQ);
+    ptimer_transaction_commit(s->timer);
+}
+
+static void k230_wdt_class_init(ObjectClass *klass, const void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = k230_wdt_realize;
+    device_class_set_legacy_reset(dc, k230_wdt_reset);
+    dc->vmsd = &vmstate_k230_wdt;
+    dc->desc = "K230 watchdog timer";
+    set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
+}
+
+static const TypeInfo k230_wdt_info = {
+    .name          = TYPE_K230_WDT,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(K230WdtState),
+    .class_init    = k230_wdt_class_init,
+};
+
+static void k230_wdt_register_type(void)
+{
+    type_register_static(&k230_wdt_info);
+}
+type_init(k230_wdt_register_type)
diff --git a/hw/watchdog/meson.build b/hw/watchdog/meson.build
index 15370565bd..5edae65a36 100644
--- a/hw/watchdog/meson.build
+++ b/hw/watchdog/meson.build
@@ -6,5 +6,6 @@ system_ss.add(when: 'CONFIG_WDT_IB700', if_true: files('wdt_ib700.c'))
 system_ss.add(when: 'CONFIG_WDT_DIAG288', if_true: files('wdt_diag288.c'))
 system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('wdt_aspeed.c'))
 system_ss.add(when: 'CONFIG_WDT_IMX2', if_true: files('wdt_imx2.c'))
+system_ss.add(when: 'CONFIG_K230_WDT', if_true: files('k230_wdt.c'))
 system_ss.add(when: 'CONFIG_WDT_SBSA', if_true: files('sbsa_gwdt.c'))
 specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_watchdog.c'))
diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
index ad3be1e9bd..d85b3ca769 100644
--- a/hw/watchdog/trace-events
+++ b/hw/watchdog/trace-events
@@ -33,3 +33,12 @@ spapr_watchdog_expired(uint64_t num, unsigned action) "num=%" PRIu64 " action=%u
 # watchdog.c
 watchdog_perform_action(unsigned int action) "action=%u"
 watchdog_set_action(unsigned int action) "action=%u"
+
+# k230_wdt.c
+k230_wdt_read(uint64_t addr, uint32_t data) "K230 WDT read: [0x%" PRIx64 "] -> 0x%" PRIx32
+k230_wdt_write(uint64_t addr, uint64_t data) "K230 WDT write: [0x%" PRIx64 "] <- 0x%" PRIx64
+k230_wdt_timeout(void) "K230 WDT timeout"
+k230_wdt_interrupt(void) "K230 WDT interrupt"
+k230_wdt_reset(void) "K230 WDT system reset"
+k230_wdt_restart(void) "K230 WDT restart"
+k230_wdt_reset_device(void) "K230 WDT device reset"
diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
index 830175b756..84bd431bc9 100644
--- a/include/hw/riscv/k230.h
+++ b/include/hw/riscv/k230.h
@@ -28,6 +28,7 @@
 
 #include "hw/core/boards.h"
 #include "hw/riscv/riscv_hart.h"
+#include "hw/watchdog/k230_wdt.h"
 
 #define C908_CPU_HARTID   (0)
 
@@ -42,6 +43,7 @@ typedef struct K230SoCState {
     /*< public >*/
     RISCVHartArrayState c908_cpu; /* Small core */
 
+    K230WdtState wdt[2];
     MemoryRegion sram;
     MemoryRegion bootrom;
 
@@ -132,6 +134,8 @@ enum {
     K230_UART2_IRQ  = 18,
     K230_UART3_IRQ  = 19,
     K230_UART4_IRQ  = 20,
+    K230_WDT0_IRQ   = 32,
+    K230_WDT1_IRQ   = 33,
 };
 
 /*
diff --git a/include/hw/watchdog/k230_wdt.h b/include/hw/watchdog/k230_wdt.h
new file mode 100644
index 0000000000..ec80567780
--- /dev/null
+++ b/include/hw/watchdog/k230_wdt.h
@@ -0,0 +1,132 @@
+/*
+ * K230 Watchdog Timer
+ *
+ * Based on K230 technical documentation
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef K230_WDT_H
+#define K230_WDT_H
+
+#include "qemu/bitops.h"
+#include "hw/core/sysbus.h"
+#include "hw/core/irq.h"
+#include "hw/core/ptimer.h"
+#include "qom/object.h"
+
+#define TYPE_K230_WDT "riscv.k230.wdt"
+OBJECT_DECLARE_SIMPLE_TYPE(K230WdtState, K230_WDT)
+
+#define K230_WDT_DEFAULT_FREQ (32768)
+
+/* K230 Watchdog Register Map */
+enum K230WdtRegisters {
+    K230_WDT_CR      = 0x00,  /* Control Register */
+    K230_WDT_TORR    = 0x04,  /* Timeout Range Register */
+    K230_WDT_CCVR    = 0x08,  /* Current Counter Value Register */
+    K230_WDT_CRR     = 0x0c,  /* Counter Restart Register */
+    K230_WDT_STAT    = 0x10,  /* Interrupt Status Register */
+    K230_WDT_EOI     = 0x14,  /* Interrupt Clear Register */
+    K230_WDT_PROT_LEVEL = 0x1c, /* Protection Level Register */
+    K230_WDT_COMP_PARAM_5 = 0xe4, /* Component Parameters Register 5 */
+    K230_WDT_COMP_PARAM_4 = 0xe8, /* Component Parameters Register 4 */
+    K230_WDT_COMP_PARAM_3 = 0xec, /* Component Parameters Register 3 */
+    K230_WDT_COMP_PARAM_2 = 0xf0, /* Component Parameters Register 2 */
+    K230_WDT_COMP_PARAM_1 = 0xf4, /* Component Parameters Register 1 */
+    K230_WDT_COMP_VERSION = 0xf8, /* Component Version Register */
+    K230_WDT_COMP_TYPE = 0xfc, /* Component Type Register */
+};
+
+#define K230_WDT_MMIO_SIZE 0x100
+
+/* Control Register (WDT_CR) definitions */
+#define K230_WDT_CR_RPL_MASK    0x7        /* Reset Pulse Length */
+#define K230_WDT_CR_RPL_SHIFT   2
+#define K230_WDT_CR_RMOD        BIT(1)     /* Response Mode */
+#define K230_WDT_CR_WDT_EN      BIT(0)     /* Watchdog Enable */
+
+/* Reset Pulse Length values */
+#define K230_WDT_RPL_2_CYCLES   0x0
+#define K230_WDT_RPL_4_CYCLES   0x1
+#define K230_WDT_RPL_8_CYCLES   0x2
+#define K230_WDT_RPL_16_CYCLES  0x3
+#define K230_WDT_RPL_32_CYCLES  0x4
+#define K230_WDT_RPL_64_CYCLES  0x5
+#define K230_WDT_RPL_128_CYCLES 0x6
+#define K230_WDT_RPL_256_CYCLES 0x7
+
+/* Timeout Range Register (WDT_TORR) definitions */
+#define K230_WDT_TORR_TOP_MASK  0xf        /* Timeout Period */
+
+/* Interrupt Status Register (WDT_STAT) definitions */
+#define K230_WDT_STAT_INT       BIT(0)     /* Interrupt Status */
+
+/* Counter Restart Register (WDT_CRR) magic value */
+#define K230_WDT_CRR_RESTART    0x76       /* Restart command */
+
+/* Component Parameters Register 1 (WDT_COMP_PARAM_1) definitions */
+#define K230_WDT_CNT_WIDTH_MASK 0x1f000000 /* Counter Width */
+#define K230_WDT_CNT_WIDTH_SHIFT 24
+#define K230_WDT_DFLT_TOP_INIT_MASK 0xf00000 /* Default Initial Timeout */
+#define K230_WDT_DFLT_TOP_INIT_SHIFT 20
+#define K230_WDT_DFLT_TOP_MASK  0xf0000    /* Default Timeout */
+#define K230_WDT_DFLT_TOP_SHIFT 16
+#define K230_WDT_DFLT_RPL_MASK  0x7        /* Default Reset Pulse Length */
+#define K230_WDT_DFLT_RPL_SHIFT 10
+#define K230_WDT_APB_DATA_WIDTH_MASK 0x3   /* APB Data Width */
+#define K230_WDT_APB_DATA_WIDTH_SHIFT 8
+#define K230_WDT_USE_FIX_TOP    BIT(6)     /* Use Fixed Timeout Values */
+#define K230_WDT_HC_TOP         BIT(5)     /* Hard-coded Timeout */
+#define K230_WDT_HC_RPL         BIT(4)     /* Hard-coded Reset Pulse Length */
+#define K230_WDT_HC_RMOD        BIT(3)     /* Hard-coded Response Mode */
+#define K230_WDT_DUAL_TOP       BIT(2)     /* Dual Timeout Period */
+#define K230_WDT_DFLT_RMOD      BIT(1)     /* Default Response Mode */
+#define K230_WDT_ALWAYS_EN      BIT(0)     /* Always Enabled */
+
+/* Component Type Register value */
+#define K230_WDT_COMP_TYPE_VAL  0x44570120
+
+/* Component Version Register value */
+#define K230_WDT_COMP_VERSION_VAL 0x3131302a  /* "110*" */
+
+struct K230WdtState {
+    /* <private> */
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion mmio;
+    qemu_irq irq;
+
+    struct ptimer_state *timer;
+
+    /* Register state */
+    uint32_t cr;           /* Control Register */
+    uint32_t torr;         /* Timeout Range Register */
+    uint32_t ccvr;         /* Current Counter Value Register */
+    uint32_t stat;         /* Interrupt Status Register */
+    uint32_t prot_level;   /* Protection Level Register */
+
+    /* Internal state */
+    bool interrupt_pending;
+    bool enabled;
+    uint32_t timeout_value;
+    uint32_t current_count;
+};
+
+#endif /* K230_WDT_H */
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 4/5] tests/qtest: add test for K230 watchdog
  2026-04-17 15:11 [PATCH v6 0/5] Add support for K230 board Chao Liu
                   ` (2 preceding siblings ...)
  2026-04-17 15:11 ` [PATCH v6 3/5] hw/watchdog: add k230 watchdog " Chao Liu
@ 2026-04-17 15:11 ` Chao Liu
  2026-04-17 15:11 ` [PATCH v6 5/5] docs/system/riscv: add documentation for k230 machine Chao Liu
  4 siblings, 0 replies; 20+ messages in thread
From: Chao Liu @ 2026-04-17 15:11 UTC (permalink / raw)
  To: Chao Liu, Pierrick Bouvier, Palmer Dabbelt, Alistair Francis,
	Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier
  Cc: qemu-devel, qemu-riscv, Chao Liu, Mig Yang,
	Daniel Henrique Barboza

From: Chao Liu <chao.liu@zevorn.cn>

Testing the Basic Functions of K230 WDT:
1. Reset Function
2. Timeout Check
3. Interrupt Function

Signed-off-by: Mig Yang <temashking@foxmail.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Acked-by: Fabiano Rosas <farosas@suse.de>
---
 MAINTAINERS                 |   1 +
 tests/qtest/k230-wdt-test.c | 199 ++++++++++++++++++++++++++++++++++++
 tests/qtest/meson.build     |   3 +-
 3 files changed, 202 insertions(+), 1 deletion(-)
 create mode 100644 tests/qtest/k230-wdt-test.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a2eecca155..b5b4acf6bd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1780,6 +1780,7 @@ F: hw/riscv/k230.c
 F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
 F: include/hw/watchdog/k230_wdt.h
+F: tests/qtest/k230-wdt-test.c
 
 RX Machines
 -----------
diff --git a/tests/qtest/k230-wdt-test.c b/tests/qtest/k230-wdt-test.c
new file mode 100644
index 0000000000..2550cebd10
--- /dev/null
+++ b/tests/qtest/k230-wdt-test.c
@@ -0,0 +1,199 @@
+/*
+ * QTest testcase for K230 Watchdog
+ *
+ * Copyright (c) 2025 Mig Yang <temashking@foxmail.com>
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Provides a board compatible with the kendryte K230 SDK
+ *
+ * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
+ *
+ * For more information, see <https://www.kendryte.com/en/proDetail/230>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "qemu/bitops.h"
+#include "libqtest.h"
+#include "hw/watchdog/k230_wdt.h"
+
+/* K230 WDT0 base address */
+#define K230_WDT0_BASE 0x91106000
+#define K230_WDT1_BASE 0x91106800
+
+/* Test WDT0 by default */
+#define WDT_BASE K230_WDT0_BASE
+
+static void test_register_read_write(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test Control Register (CR) read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_CR), ==,
+                    (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT) |
+                    K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+    /* Test Timeout Range Register (TORR) read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_TORR), ==,
+                    K230_WDT_TORR_TOP_MASK);
+
+    /* Test Protection Level Register read/write */
+    qtest_writel(qts, WDT_BASE + K230_WDT_PROT_LEVEL, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, WDT_BASE + K230_WDT_PROT_LEVEL), ==, 0x7);
+
+    qtest_quit(qts);
+}
+
+static void test_counter_restart(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Enable watchdog and set timeout */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x5); /* TOP = 5 */
+
+    /* Read current counter value */
+    uint32_t initial_count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+    g_assert_cmpuint(initial_count, >, 0);
+
+    /* Restart counter with magic value */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CRR, K230_WDT_CRR_RESTART);
+
+    /* Wait for time */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
+
+    /* Counter should be reset to timeout value */
+    uint32_t new_count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+    g_assert_cmpuint(new_count, >, 0);
+    g_assert_cmpuint(new_count, !=, initial_count);
+
+    qtest_quit(qts);
+}
+
+static void test_interrupt_mode(void)
+{
+    QTestState *qts = qtest_init("-machine k230 --trace k230_*,file=k230.log");
+
+    /* Set interrupt mode and enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR,
+                 K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x1); /* Short timeout */
+
+    /* Wait for timeout to trigger interrupt */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 10);
+
+    /* Check interrupt status */
+    uint32_t stat = qtest_readl(qts, WDT_BASE + K230_WDT_STAT);
+    g_assert_cmphex(stat & K230_WDT_STAT_INT, ==, K230_WDT_STAT_INT);
+
+    /* Clear interrupt */
+    qtest_writel(qts, WDT_BASE + K230_WDT_EOI, 0x1);
+    stat = qtest_readl(qts, WDT_BASE + K230_WDT_STAT);
+    g_assert_cmphex(stat & K230_WDT_STAT_INT, ==, 0);
+
+    qtest_quit(qts);
+}
+
+static void test_reset_mode(void)
+{
+    QTestState *qts = qtest_init("-machine k230 -no-reboot");
+
+    /* Set reset mode and enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    qtest_writel(qts, WDT_BASE + K230_WDT_TORR, 0x1); /* Short timeout */
+
+    /* Wait for timeout to trigger reset */
+    qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
+
+    /* In reset mode, the system should reset */
+    /* This test verifies that reset mode is properly configured */
+
+    qtest_quit(qts);
+}
+
+static void test_timeout_calculation(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test different timeout values */
+    for (uint32_t top = 0; top <= 15; top++) {
+        qtest_writel(qts, WDT_BASE + K230_WDT_TORR, top);
+        qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+
+        /* Read current counter value */
+        uint32_t count = qtest_readl(qts, WDT_BASE + K230_WDT_CCVR);
+        g_assert_cmpuint(count, >, 0);
+
+        /* Disable watchdog for next iteration */
+        qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0);
+    }
+
+    qtest_quit(qts);
+}
+
+static void test_wdt1_registers(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Test WDT1 registers (second watchdog) */
+    qtest_writel(qts, K230_WDT1_BASE + K230_WDT_CR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, K230_WDT1_BASE + K230_WDT_CR), ==,
+                    (K230_WDT_CR_RPL_MASK << K230_WDT_CR_RPL_SHIFT) |
+                    K230_WDT_CR_RMOD | K230_WDT_CR_WDT_EN);
+
+    qtest_writel(qts, K230_WDT1_BASE + K230_WDT_TORR, 0xFFFFFFFF);
+    g_assert_cmphex(qtest_readl(qts, K230_WDT1_BASE + K230_WDT_TORR), ==,
+                    K230_WDT_TORR_TOP_MASK);
+
+    qtest_quit(qts);
+}
+
+static void test_enable_disable(void)
+{
+    QTestState *qts = qtest_init("-machine k230");
+
+    /* Initially disabled */
+    uint32_t cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, 0);
+
+    /* Enable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, K230_WDT_CR_WDT_EN);
+    cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, K230_WDT_CR_WDT_EN);
+
+    /* Disable watchdog */
+    qtest_writel(qts, WDT_BASE + K230_WDT_CR, 0);
+    cr = qtest_readl(qts, WDT_BASE + K230_WDT_CR);
+    g_assert_cmphex(cr & K230_WDT_CR_WDT_EN, ==, 0);
+
+    qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+    g_test_init(&argc, &argv, NULL);
+
+    qtest_add_func("/k230-wdt/register_read_write", test_register_read_write);
+    qtest_add_func("/k230-wdt/counter_restart", test_counter_restart);
+    qtest_add_func("/k230-wdt/interrupt_mode", test_interrupt_mode);
+    qtest_add_func("/k230-wdt/reset_mode", test_reset_mode);
+    qtest_add_func("/k230-wdt/timeout_calculation", test_timeout_calculation);
+    qtest_add_func("/k230-wdt/wdt1_registers", test_wdt1_registers);
+    qtest_add_func("/k230-wdt/enable_disable", test_enable_disable);
+
+    return g_test_run();
+}
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index be4fa627b5..b00e1e1f5d 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -288,7 +288,8 @@ qtests_riscv64 = ['riscv-csr-test'] + \
   (unpack_edk2_blobs ? ['bios-tables-test'] : []) + \
   (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and
    config_all_devices.has_key('CONFIG_RISCV_IOMMU') ?
-   ['iommu-riscv-test'] : [])
+   ['iommu-riscv-test'] : []) + \
+  (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : [])
 
 qos_test_ss = ss.source_set()
 qos_test_ss.add(
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v6 5/5] docs/system/riscv: add documentation for k230 machine
  2026-04-17 15:11 [PATCH v6 0/5] Add support for K230 board Chao Liu
                   ` (3 preceding siblings ...)
  2026-04-17 15:11 ` [PATCH v6 4/5] tests/qtest: add test for K230 watchdog Chao Liu
@ 2026-04-17 15:11 ` Chao Liu
  2026-05-01  4:16   ` Alistair Francis
  4 siblings, 1 reply; 20+ messages in thread
From: Chao Liu @ 2026-04-17 15:11 UTC (permalink / raw)
  To: Chao Liu, Pierrick Bouvier, Palmer Dabbelt, Alistair Francis,
	Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier
  Cc: qemu-devel, qemu-riscv, Chao Liu, Daniel Henrique Barboza

From: Chao Liu <chao.liu@zevorn.cn>

Add documentation for k230 virt reference platform.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
 MAINTAINERS                  |  1 +
 docs/system/riscv/k230.rst   | 48 ++++++++++++++++++++++++++++++++++++
 docs/system/target-riscv.rst |  1 +
 3 files changed, 50 insertions(+)
 create mode 100644 docs/system/riscv/k230.rst

diff --git a/MAINTAINERS b/MAINTAINERS
index b5b4acf6bd..d8d68cc123 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1776,6 +1776,7 @@ F: include/hw/riscv/xiangshan_kmh.h
 K230 Machines
 M: Chao Liu <chao.liu.zevorn@gmail.com>
 S: Maintained
+F: docs/system/riscv/k230.rst
 F: hw/riscv/k230.c
 F: hw/watchdog/k230_wdt.c
 F: include/hw/riscv/k230.h
diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
new file mode 100644
index 0000000000..3e6ca295df
--- /dev/null
+++ b/docs/system/riscv/k230.rst
@@ -0,0 +1,48 @@
+Kendryte K230 virt reference platform (``k230``)
+==========================================================================
+The ``k230`` machine is compatible with with Kendryte K230 SDK.
+
+The K230 is a chip from the AIoT SoC series made by Kendryte ® — a part of
+Canaan Inc. It uses a brand-new multi-heterogeneous unit accelerated computing
+structure.
+
+This chip has 2 RISC-V computing cores and a new-generation KPU (Knowledge
+Process Unit) smart computing unit.
+
+It has multi-precision AI computing ability, works with many common AI computing
+frameworks, and for some typical networks, its usage rate is over 70%. Besides,
+the K230 chip supports many peripheral connections and has several special
+hardware acceleration units (like 2D and 2.5D accelerators). It can speed up
+different tasks (such as image processing, video processing, audio processing
+and AI computing). It also has many good features: low delay, high performance,
+low power use and fast start-up.
+
+For more information, see <https://www.kendryte.com/en/proDetail/230>
+
+Supported devices
+-----------------
+The ``k230`` machine supports the following devices:
+
+* 1 c908 cores
+* Core Local Interruptor (CLINT)
+* Incoming MSI Controller (IMSIC)
+* 2 K230 Watchdog Timer
+* 4 UART
+
+Boot options
+------------
+The ``k230`` machine can start using the standard ``-bios``
+functionality for loading the boot image. You need to compile and link
+the firmware, kernel, and Device Tree (FDT) into a single binary file with
+K230 SDK(k230_canmv_defconfig), such as ``uboot``.
+
+Running
+-------
+Below is an example command line for running the ``k230``
+machine:
+
+.. code-block:: bash
+
+   $ qemu-system-riscv64 -machine k230 \
+      -bios k230_sdk/output/k230_canmv_defconfig/little/uboot/u-boot \
+      -nographic
diff --git a/docs/system/target-riscv.rst b/docs/system/target-riscv.rst
index 3ad5d1ddaf..b0b2f9584f 100644
--- a/docs/system/target-riscv.rst
+++ b/docs/system/target-riscv.rst
@@ -66,6 +66,7 @@ undocumented; you can get a complete list by running
 .. toctree::
    :maxdepth: 1
 
+   riscv/k230
    riscv/microblaze-v-generic
    riscv/microchip-icicle-kit
    riscv/mips
-- 
2.53.0



^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-17 15:11 ` [PATCH v6 1/5] target/riscv: add thead-c908 cpu support Chao Liu
@ 2026-04-17 19:15   ` Conor Dooley
  2026-04-17 23:02     ` Chao Liu
  2026-04-19 23:49   ` Alistair Francis
  2026-05-01  4:02   ` Alistair Francis
  2 siblings, 1 reply; 20+ messages in thread
From: Conor Dooley @ 2026-04-17 19:15 UTC (permalink / raw)
  To: Chao Liu
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Peng Jiang

[-- Attachment #1: Type: text/plain, Size: 713 bytes --]

On Fri, Apr 17, 2026 at 11:11:25PM +0800, Chao Liu wrote:
> From: Chao Liu <chao.liu@zevorn.cn>
> 
> The C908 processor is based on the RV64GCB[V] instruction
> set, compatible to RVA22 Profile and implements the XIE
> (XuanTie Instruction Extension) technology.
> 
> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Reviewed-by: Conor Dooley <conor@kernel.org>

Uhh, I don't recall ever giving a r-b tag for this, never mind the fact
that I never provide tags with this email address.
IIRC I just commented about svpbmt being missing or something along
those lines.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-17 19:15   ` Conor Dooley
@ 2026-04-17 23:02     ` Chao Liu
  2026-04-18 12:18       ` Conor Dooley
  0 siblings, 1 reply; 20+ messages in thread
From: Chao Liu @ 2026-04-17 23:02 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Peng Jiang

Hi Conor,
On Fri, Apr 17, 2026 at 08:15:48PM +0100, Conor Dooley wrote:
> On Fri, Apr 17, 2026 at 11:11:25PM +0800, Chao Liu wrote:
> > From: Chao Liu <chao.liu@zevorn.cn>
> > 
> > The C908 processor is based on the RV64GCB[V] instruction
> > set, compatible to RVA22 Profile and implements the XIE
> > (XuanTie Instruction Extension) technology.
> > 
> > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > Reviewed-by: Conor Dooley <conor@kernel.org>
> 
> Uhh, I don't recall ever giving a r-b tag for this, never mind the fact
> that I never provide tags with this email address.
> IIRC I just commented about svpbmt being missing or something along
> those lines.

Thanks for catching it, that tag shouldn't have been there.
I've dropped it locally and will leave it out next version.

Thanks,
Chao



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-17 23:02     ` Chao Liu
@ 2026-04-18 12:18       ` Conor Dooley
  2026-04-18 12:50         ` Chao Liu
  0 siblings, 1 reply; 20+ messages in thread
From: Conor Dooley @ 2026-04-18 12:18 UTC (permalink / raw)
  To: Chao Liu
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Peng Jiang

[-- Attachment #1: Type: text/plain, Size: 1266 bytes --]

On Sat, Apr 18, 2026 at 07:02:42AM +0800, Chao Liu wrote:
> Hi Conor,
> On Fri, Apr 17, 2026 at 08:15:48PM +0100, Conor Dooley wrote:
> > On Fri, Apr 17, 2026 at 11:11:25PM +0800, Chao Liu wrote:
> > > From: Chao Liu <chao.liu@zevorn.cn>
> > > 
> > > The C908 processor is based on the RV64GCB[V] instruction
> > > set, compatible to RVA22 Profile and implements the XIE
> > > (XuanTie Instruction Extension) technology.
> > > 
> > > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > > Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> > > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > > Reviewed-by: Conor Dooley <conor@kernel.org>
> > 
> > Uhh, I don't recall ever giving a r-b tag for this, never mind the fact
> > that I never provide tags with this email address.
> > IIRC I just commented about svpbmt being missing or something along
> > those lines.
> 
> Thanks for catching it, that tag shouldn't have been there.
> I've dropped it locally and will leave it out next version.

And go double check that the other one is real too.
This isn't the sort of thing that you can get wrong by accident,
since you'll only ever be copy-pasting tags from a mail or using
something like b4 to update them.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-18 12:18       ` Conor Dooley
@ 2026-04-18 12:50         ` Chao Liu
  0 siblings, 0 replies; 20+ messages in thread
From: Chao Liu @ 2026-04-18 12:50 UTC (permalink / raw)
  To: Conor Dooley
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Peng Jiang

On Sat, Apr 18, 2026 at 01:18:54PM +0100, Conor Dooley wrote:
> On Sat, Apr 18, 2026 at 07:02:42AM +0800, Chao Liu wrote:
> > Hi Conor,
> > On Fri, Apr 17, 2026 at 08:15:48PM +0100, Conor Dooley wrote:
> > > On Fri, Apr 17, 2026 at 11:11:25PM +0800, Chao Liu wrote:
> > > > From: Chao Liu <chao.liu@zevorn.cn>
> > > > 
> > > > The C908 processor is based on the RV64GCB[V] instruction
> > > > set, compatible to RVA22 Profile and implements the XIE
> > > > (XuanTie Instruction Extension) technology.
> > > > 
> > > > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > > > Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> > > > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > > > Reviewed-by: Conor Dooley <conor@kernel.org>
> > > 
> > > Uhh, I don't recall ever giving a r-b tag for this, never mind the fact
> > > that I never provide tags with this email address.
> > > IIRC I just commented about svpbmt being missing or something along
> > > those lines.
> > 
> > Thanks for catching it, that tag shouldn't have been there.
> > I've dropped it locally and will leave it out next version.
> 
> And go double check that the other one is real too.
> This isn't the sort of thing that you can get wrong by accident,
> since you'll only ever be copy-pasting tags from a mail or using
> something like b4 to update them.

Good idea, thanks again for the suggestion, it helped me a lot.
When I first started getting involved with email patch communication,
I often couldn't figure out how to add tags, but now I'm very clear
on it. In my last reply, I already accurately verified the tags
across the entire patch set. Which other one are you referring to?

I now understand how to use b4 to update tags, previously I was
still copying them manually...

Thanks,
Chao



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-17 15:11 ` [PATCH v6 1/5] target/riscv: add thead-c908 cpu support Chao Liu
  2026-04-17 19:15   ` Conor Dooley
@ 2026-04-19 23:49   ` Alistair Francis
  2026-04-20  3:37     ` Chao Liu
  2026-05-01  4:02   ` Alistair Francis
  2 siblings, 1 reply; 20+ messages in thread
From: Alistair Francis @ 2026-04-19 23:49 UTC (permalink / raw)
  To: Chao Liu
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Conor Dooley,
	Peng Jiang

On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
>
> From: Chao Liu <chao.liu@zevorn.cn>
>
> The C908 processor is based on the RV64GCB[V] instruction
> set, compatible to RVA22 Profile and implements the XIE
> (XuanTie Instruction Extension) technology.
>
> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Reviewed-by: Conor Dooley <conor@kernel.org>

As Connor pointed out, he didn't add his Reviewed-by, instead he
commented about a missing extension [1]. On top of that I don't see
any instances of `Reviewed-by: Conor Dooley <conor@kernel.org>` in the
QEMU tree, so I assume there are none on the mailing list as well.
Which makes a copy and paste error seem less likely.

I do see that Connor's reply was sent from his conor@kernel.org address,
but manually stitching together a `Reviewed-by` and address seems
unlikely to happen by accident. Although it does seem like the type of
thing an LLM would do (see below).

> Reported-by: Peng Jiang <3160104094@zju.edu.cn>

I'm not sure how this can be Reported-by, it's not a bug fix. What was
reported? It seems like the Reported-by appeared in v3 [2] and wasn't
in v2 [3], yet I don't see anything reported.

The extra and unexplained `Reviewed-by` (especially using an odd
address as mentioned above) really points to this being LLM generated.
Especially considering that your reviews are LLM generated (those are
fine). Unfortunately that means I will need to decline the commits
according to the QEMU Code Provenance rules [4]. Note that it isn't
just the Code Provenance policy, it is also now really difficult to
trust these patches knowing that stray `Reviewed-by` tags could be
hallucinated and not caught before being submitted.

1: https://patchew.org/QEMU/cover.1764493931.git.chao.liu@zevorn.cn/c27edc69ea6642f645d5e194bd5d4cd71e812841.1764493931.git.chao.liu@zevorn.cn/#20251203-squiggle-gentile-f27af704359e@spud
2: https://patchew.org/QEMU/cover.1765811173.git.chao.liu@zevorn.cn/ac82fb9f22366614c2be80d9fe200f1b5ce161ef.1765811173.git.chao.liu@zevorn.cn/
3: https://patchew.org/QEMU/cover.1764830405.git.chao.liu@zevorn.cn/fdd2cb519a91a16c5b6e8931dda8301bf1c23c85.1764830405.git.chao.liu@zevorn.cn/
4: https://www.qemu.org/docs/master/devel/code-provenance.html#use-of-ai-generated-content

Alistair


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-19 23:49   ` Alistair Francis
@ 2026-04-20  3:37     ` Chao Liu
  2026-05-01  4:02       ` Alistair Francis
  0 siblings, 1 reply; 20+ messages in thread
From: Chao Liu @ 2026-04-20  3:37 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Conor Dooley,
	Peng Jiang

On Mon, Apr 20, 2026 at 09:49:50AM +1000, Alistair Francis wrote:
> On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
> >
> > From: Chao Liu <chao.liu@zevorn.cn>
> >
> > The C908 processor is based on the RV64GCB[V] instruction
> > set, compatible to RVA22 Profile and implements the XIE
> > (XuanTie Instruction Extension) technology.
> >
> > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > Reviewed-by: Conor Dooley <conor@kernel.org>
> 
> As Connor pointed out, he didn't add his Reviewed-by, instead he
> commented about a missing extension [1]. On top of that I don't see
> any instances of `Reviewed-by: Conor Dooley <conor@kernel.org>` in the
> QEMU tree, so I assume there are none on the mailing list as well.
> Which makes a copy and paste error seem less likely.
> 
> I do see that Connor's reply was sent from his conor@kernel.org address,
> but manually stitching together a `Reviewed-by` and address seems
> unlikely to happen by accident. Although it does seem like the type of
> thing an LLM would do (see below).
> 
Sorry, when I first started contributing to QEMU, I wasn't familiar with
mailing list conventions. I had been under the impression that whenever a
reviewer left comments, it was appropriate to carry a Reviewed-by tag into
the next revision. No one pointed this out at the time, but that was
clearly my oversight. My apologies to Alistair and Conor for the trouble
caused.

I made the same mistake on earlier patches as well:

https://lore.kernel.org/qemu-devel/8b29b86a9af84edba54cc53aec017224478312bf.1745894489.git.lc00631@tecorigin.com/
https://lore.kernel.org/qemu-devel/501e578a4ef28515ccdefcbc82defc04363855ca.1746001489.git.lc00631@tecorigin.com/

There is also a slightly different case where I added a Reviewed-by tag:

https://lore.kernel.org/qemu-devel/07a97219e3f7e342c668d6772acc4c0a8eb4d4f3.1744709888.git.lc00631@tecorigin.com/

There the R-b came from an internal colleague who reviewed the patch on
our side before it was sent upstream.

Is that also against community convention?

> > Reported-by: Peng Jiang <3160104094@zju.edu.cn>
> 
> I'm not sure how this can be Reported-by, it's not a bug fix. What was
> reported? It seems like the Reported-by appeared in v3 [2] and wasn't
> in v2 [3], yet I don't see anything reported.
> 
This patchset is the project-phase output of a non-profit QEMU open-source
training camp we run in China; so far the camp has trained about 2000
participants. Peng Jiang is one of the members, and his task was bringing
up OpenSBI/RustSBI + Linux on the QEMU k230 board. For the specific
details, see:

https://github.com/rustsbi/rustsbi/issues/160

The Reported-by in v3 was added as a form of encouragement, since he
found several bugs during that bring-up work.

Given this situation, should I also drop Peng Jiang's Reported-by tag?

After the camp concluded, I asked him to report any further issues to the
upstream list directly himself — for example in v4:

https://lore.kernel.org/qemu-devel/651b1d38.63ab7.19be50b4721.Coremail.3160104094@zju.edu.cn/

> The extra and unexplained `Reviewed-by` (especially using an odd
> address as mentioned above) really points to this being LLM generated.
> Especially considering that your reviews are LLM generated (those are
> fine). Unfortunately that means I will need to decline the commits
> according to the QEMU Code Provenance rules [4]. Note that it isn't
> just the Code Provenance policy, it is also now really difficult to
> trust these patches knowing that stray `Reviewed-by` tags could be
> hallucinated and not caught before being submitted.
> 
That said, I should clarify that no LLM assistance was used in developing
this patchset.

Finally, thanks to Alistair for the patient review. I'll be more careful
about these details in future contributions to avoid adding review burden
on maintainers/reviewers.

Reference:
1. learning-QEMU-Camp-2025: https://opencamp.cn/gevico/camp/2025/stage/5
2. QEMU K230 modeling task assignments: https://github.com/gevico/qemu/issues/7

Thanks,
Chao

> 1: https://patchew.org/QEMU/cover.1764493931.git.chao.liu@zevorn.cn/c27edc69ea6642f645d5e194bd5d4cd71e812841.1764493931.git.chao.liu@zevorn.cn/#20251203-squiggle-gentile-f27af704359e@spud
> 2: https://patchew.org/QEMU/cover.1765811173.git.chao.liu@zevorn.cn/ac82fb9f22366614c2be80d9fe200f1b5ce161ef.1765811173.git.chao.liu@zevorn.cn/
> 3: https://patchew.org/QEMU/cover.1764830405.git.chao.liu@zevorn.cn/fdd2cb519a91a16c5b6e8931dda8301bf1c23c85.1764830405.git.chao.liu@zevorn.cn/
> 4: https://www.qemu.org/docs/master/devel/code-provenance.html#use-of-ai-generated-content
> 
> Alistair


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-20  3:37     ` Chao Liu
@ 2026-05-01  4:02       ` Alistair Francis
  2026-05-06  7:43         ` Chao Liu
  0 siblings, 1 reply; 20+ messages in thread
From: Alistair Francis @ 2026-05-01  4:02 UTC (permalink / raw)
  To: Chao Liu
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Conor Dooley,
	Peng Jiang

On Mon, Apr 20, 2026 at 1:38 PM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
>
> On Mon, Apr 20, 2026 at 09:49:50AM +1000, Alistair Francis wrote:
> > On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
> > >
> > > From: Chao Liu <chao.liu@zevorn.cn>
> > >
> > > The C908 processor is based on the RV64GCB[V] instruction
> > > set, compatible to RVA22 Profile and implements the XIE
> > > (XuanTie Instruction Extension) technology.
> > >
> > > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > > Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> > > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > > Reviewed-by: Conor Dooley <conor@kernel.org>
> >
> > As Connor pointed out, he didn't add his Reviewed-by, instead he
> > commented about a missing extension [1]. On top of that I don't see
> > any instances of `Reviewed-by: Conor Dooley <conor@kernel.org>` in the
> > QEMU tree, so I assume there are none on the mailing list as well.
> > Which makes a copy and paste error seem less likely.
> >
> > I do see that Connor's reply was sent from his conor@kernel.org address,
> > but manually stitching together a `Reviewed-by` and address seems
> > unlikely to happen by accident. Although it does seem like the type of
> > thing an LLM would do (see below).
> >
> Sorry, when I first started contributing to QEMU, I wasn't familiar with
> mailing list conventions. I had been under the impression that whenever a
> reviewer left comments, it was appropriate to carry a Reviewed-by tag into
> the next revision. No one pointed this out at the time, but that was
> clearly my oversight. My apologies to Alistair and Conor for the trouble
> caused.

In future, only add tags that people specify. Please copy them
directly or use b4, patchew or a similar tool to apply the tags.

>
> I made the same mistake on earlier patches as well:
>
> https://lore.kernel.org/qemu-devel/8b29b86a9af84edba54cc53aec017224478312bf.1745894489.git.lc00631@tecorigin.com/
> https://lore.kernel.org/qemu-devel/501e578a4ef28515ccdefcbc82defc04363855ca.1746001489.git.lc00631@tecorigin.com/
>
> There is also a slightly different case where I added a Reviewed-by tag:
>
> https://lore.kernel.org/qemu-devel/07a97219e3f7e342c668d6772acc4c0a8eb4d4f3.1744709888.git.lc00631@tecorigin.com/
>
> There the R-b came from an internal colleague who reviewed the patch on
> our side before it was sent upstream.
>
> Is that also against community convention?

No, internal colleagues are ok. Generally they provide little insight
though. Your colleague would be better off engaging with the community
as then the comments can be seen by everyone, that helps build trust
between developers.

>
> > > Reported-by: Peng Jiang <3160104094@zju.edu.cn>
> >
> > I'm not sure how this can be Reported-by, it's not a bug fix. What was
> > reported? It seems like the Reported-by appeared in v3 [2] and wasn't
> > in v2 [3], yet I don't see anything reported.
> >
> This patchset is the project-phase output of a non-profit QEMU open-source
> training camp we run in China; so far the camp has trained about 2000
> participants. Peng Jiang is one of the members, and his task was bringing
> up OpenSBI/RustSBI + Linux on the QEMU k230 board. For the specific
> details, see:
>
> https://github.com/rustsbi/rustsbi/issues/160
>
> The Reported-by in v3 was added as a form of encouragement, since he
> found several bugs during that bring-up work.

A Signed-off-by or Tested-by would probably be more appropriate then.
Reported-by indicates that they found and reported a bug

>
> Given this situation, should I also drop Peng Jiang's Reported-by tag?
>
> After the camp concluded, I asked him to report any further issues to the
> upstream list directly himself — for example in v4:
>
> https://lore.kernel.org/qemu-devel/651b1d38.63ab7.19be50b4721.Coremail.3160104094@zju.edu.cn/
>
> > The extra and unexplained `Reviewed-by` (especially using an odd
> > address as mentioned above) really points to this being LLM generated.
> > Especially considering that your reviews are LLM generated (those are
> > fine). Unfortunately that means I will need to decline the commits
> > according to the QEMU Code Provenance rules [4]. Note that it isn't
> > just the Code Provenance policy, it is also now really difficult to
> > trust these patches knowing that stray `Reviewed-by` tags could be
> > hallucinated and not caught before being submitted.
> >
> That said, I should clarify that no LLM assistance was used in developing
> this patchset.

Ok, good to know :)

>
> Finally, thanks to Alistair for the patient review. I'll be more careful
> about these details in future contributions to avoid adding review burden
> on maintainers/reviewers.

Thank you

Alistair


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-04-17 15:11 ` [PATCH v6 1/5] target/riscv: add thead-c908 cpu support Chao Liu
  2026-04-17 19:15   ` Conor Dooley
  2026-04-19 23:49   ` Alistair Francis
@ 2026-05-01  4:02   ` Alistair Francis
  2 siblings, 0 replies; 20+ messages in thread
From: Alistair Francis @ 2026-05-01  4:02 UTC (permalink / raw)
  To: Chao Liu
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Conor Dooley,
	Peng Jiang

On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
>
> From: Chao Liu <chao.liu@zevorn.cn>
>
> The C908 processor is based on the RV64GCB[V] instruction
> set, compatible to RVA22 Profile and implements the XIE
> (XuanTie Instruction Extension) technology.
>
> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Reviewed-by: Conor Dooley <conor@kernel.org>
> Reported-by: Peng Jiang <3160104094@zju.edu.cn>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/cpu-qom.h |   2 +
>  target/riscv/cpu.c     |  51 ++++++
>  target/riscv/th_csr.c  | 380 ++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 432 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
> index 30dcdcfaae..1a28f1369c 100644
> --- a/target/riscv/cpu-qom.h
> +++ b/target/riscv/cpu-qom.h
> @@ -52,6 +52,8 @@
>  #define TYPE_RISCV_CPU_SIFIVE_U34       RISCV_CPU_TYPE_NAME("sifive-u34")
>  #define TYPE_RISCV_CPU_SIFIVE_U54       RISCV_CPU_TYPE_NAME("sifive-u54")
>  #define TYPE_RISCV_CPU_THEAD_C906       RISCV_CPU_TYPE_NAME("thead-c906")
> +#define TYPE_RISCV_CPU_THEAD_C908       RISCV_CPU_TYPE_NAME("thead-c908")
> +#define TYPE_RISCV_CPU_THEAD_C908V      RISCV_CPU_TYPE_NAME("thead-c908v")
>  #define TYPE_RISCV_CPU_VEYRON_V1        RISCV_CPU_TYPE_NAME("veyron-v1")
>  #define TYPE_RISCV_CPU_TT_ASCALON       RISCV_CPU_TYPE_NAME("tt-ascalon")
>  #define TYPE_RISCV_CPU_XIANGSHAN_NANHU  RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 72c6f4f0f1..870d0690fe 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -3150,6 +3150,57 @@ static const TypeInfo riscv_cpu_type_infos[] = {
>  #endif
>      ),
>
> +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908, TYPE_RISCV_VENDOR_CPU,
> +        .misa_mxl_max = MXL_RV64,
> +        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU,
> +        .priv_spec = PRIV_VERSION_1_12_0,
> +
> +        /* ISA extensions */
> +        .cfg.ext_xtheadba = true,
> +        .cfg.ext_xtheadbb = true,
> +        .cfg.ext_xtheadbs = true,
> +        .cfg.ext_xtheadcmo = true,
> +        .cfg.ext_xtheadcondmov = true,
> +        .cfg.ext_xtheadfmv = true,
> +        .cfg.ext_xtheadfmemidx = true,
> +        .cfg.ext_xtheadmac = true,
> +        .cfg.ext_xtheadmemidx = true,
> +        .cfg.ext_xtheadmempair = true,
> +        .cfg.ext_xtheadsync = true,
> +        .cfg.ext_smepmp = true,
> +        .cfg.ext_sscofpmf = true,
> +        .cfg.ext_sstc = true,
> +        .cfg.ext_svpbmt = true,
> +        .cfg.ext_svinval = true,
> +        .cfg.ext_svnapot = true,
> +        .cfg.ext_zba = true,
> +        .cfg.ext_zbb = true,
> +        .cfg.ext_zbc = true,
> +        .cfg.ext_zbs = true,
> +        .cfg.ext_zkt = true,
> +        .cfg.ext_zbkc = true,
> +        .cfg.ext_zicsr = true,
> +        .cfg.ext_zifencei = true,
> +        .cfg.ext_zihintpause = true,
> +        .cfg.ext_zicbom = true,
> +        .cfg.ext_zicboz = true,
> +
> +        .cfg.pmp = true,
> +        .cfg.mmu = true,
> +        .cfg.max_satp_mode = VM_1_10_SV48,
> +
> +        .cfg.marchid = 0x8d143000,
> +        .cfg.mvendorid = THEAD_VENDOR_ID,
> +#ifndef CONFIG_USER_ONLY
> +        .custom_csrs = th_csr_list,
> +#endif
> +    ),
> +
> +    DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C908V, TYPE_RISCV_CPU_THEAD_C908,
> +        .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU | RVV,
> +        .vext_spec = VEXT_VERSION_1_00_0,
> +    ),
> +
>      DEFINE_RISCV_CPU(TYPE_RISCV_CPU_TT_ASCALON, TYPE_RISCV_VENDOR_CPU,
>          .misa_mxl_max = MXL_RV64,
>          .misa_ext = RVG | RVC | RVS | RVU | RVH | RVV,
> diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c
> index 49eb7bbab5..e19cab5414 100644
> --- a/target/riscv/th_csr.c
> +++ b/target/riscv/th_csr.c
> @@ -2,6 +2,9 @@
>   * T-Head-specific CSRs.
>   *
>   * Copyright (c) 2024 VRULL GmbH
> + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
> + *
> + * For more information, see XuanTie-C908-UserManual_xrvm_20240530.pdf
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms and conditions of the GNU General Public License,
> @@ -20,13 +23,88 @@
>  #include "cpu.h"
>  #include "cpu_vendorid.h"
>
> -#define CSR_TH_SXSTATUS 0x5c0
> +/* Extended M-mode control registers of T-Head */
> +#define CSR_TH_MXSTATUS        0x7c0
> +#define CSR_TH_MHCR            0x7c1
> +#define CSR_TH_MCOR            0x7c2
> +#define CSR_TH_MCCR2           0x7c3
> +#define CSR_TH_MHINT           0x7c5
> +#define CSR_TH_MRVBR           0x7c7
> +#define CSR_TH_MCOUNTERWEN     0x7c9
> +#define CSR_TH_MCOUNTERINTEN   0x7ca
> +#define CSR_TH_MCOUNTEROF      0x7cb
> +#define CSR_TH_MCINS           0x7d2
> +#define CSR_TH_MCINDEX         0x7d3
> +#define CSR_TH_MCDATA0         0x7d4
> +#define CSR_TH_MCDATA1         0x7d5
> +#define CSR_TH_MSMPR           0x7f3
> +#define CSR_TH_CPUID           0xfc0
> +#define CSR_TH_MAPBADDR        0xfc1
> +
> +/* TH_MXSTATUS bits */
> +#define TH_MXSTATUS_UCME        BIT(16)
> +#define TH_MXSTATUS_MAEE        BIT(21)
> +#define TH_MXSTATUS_THEADISAEE  BIT(22)
> +
> +/* Extended S-mode control registers of T-Head */
> +#define CSR_TH_SXSTATUS        0x5c0
> +#define CSR_TH_SHCR            0x5c1
> +#define CSR_TH_SCER2           0x5c2
> +#define CSR_TH_SCER            0x5c3
> +#define CSR_TH_SCOUNTERINTEN   0x5c4
> +#define CSR_TH_SCOUNTEROF      0x5c5
> +#define CSR_TH_SCYCLE          0x5e0
> +#define CSR_TH_SHPMCOUNTER3    0x5e3
> +#define CSR_TH_SHPMCOUNTER4    0x5e4
> +#define CSR_TH_SHPMCOUNTER5    0x5e5
> +#define CSR_TH_SHPMCOUNTER6    0x5e6
> +#define CSR_TH_SHPMCOUNTER7    0x5e7
> +#define CSR_TH_SHPMCOUNTER8    0x5e8
> +#define CSR_TH_SHPMCOUNTER9    0x5e9
> +#define CSR_TH_SHPMCOUNTER10   0x5ea
> +#define CSR_TH_SHPMCOUNTER11   0x5eb
> +#define CSR_TH_SHPMCOUNTER12   0x5ec
> +#define CSR_TH_SHPMCOUNTER13   0x5ed
> +#define CSR_TH_SHPMCOUNTER14   0x5ee
> +#define CSR_TH_SHPMCOUNTER15   0x5ef
> +#define CSR_TH_SHPMCOUNTER16   0x5f0
> +#define CSR_TH_SHPMCOUNTER17   0x5f1
> +#define CSR_TH_SHPMCOUNTER18   0x5f2
> +#define CSR_TH_SHPMCOUNTER19   0x5f3
> +#define CSR_TH_SHPMCOUNTER20   0x5f4
> +#define CSR_TH_SHPMCOUNTER21   0x5f5
> +#define CSR_TH_SHPMCOUNTER22   0x5f6
> +#define CSR_TH_SHPMCOUNTER23   0x5f7
> +#define CSR_TH_SHPMCOUNTER24   0x5f8
> +#define CSR_TH_SHPMCOUNTER25   0x5f9
> +#define CSR_TH_SHPMCOUNTER26   0x5fa
> +#define CSR_TH_SHPMCOUNTER27   0x5fb
> +#define CSR_TH_SHPMCOUNTER28   0x5fc
> +#define CSR_TH_SHPMCOUNTER29   0x5fd
> +#define CSR_TH_SHPMCOUNTER30   0x5fe
> +#define CSR_TH_SHPMCOUNTER31   0x5ff
> +#define CSR_TH_SMIR            0x9c0
> +#define CSR_TH_SMLO0           0x9c1
> +#define CSR_TH_SMEH            0x9c2
> +#define CSR_TH_SMCIR           0x9c3
> +
> +/* Extended U-mode control registers of T-Head */
> +#define CSR_TH_FXCR            0x800
>
>  /* TH_SXSTATUS bits */
>  #define TH_SXSTATUS_UCME        BIT(16)
>  #define TH_SXSTATUS_MAEE        BIT(21)
>  #define TH_SXSTATUS_THEADISAEE  BIT(22)
>
> +static RISCVException mmode(CPURISCVState *env, int csrno)
> +{
> +    if (riscv_has_ext(env, RVM)) {
> +        return RISCV_EXCP_NONE;
> +    }
> +
> +    return RISCV_EXCP_ILLEGAL_INST;
> +}
> +
>  static RISCVException smode(CPURISCVState *env, int csrno)
>  {
>      if (riscv_has_ext(env, RVS)) {
> @@ -36,11 +114,31 @@ static RISCVException smode(CPURISCVState *env, int csrno)
>      return RISCV_EXCP_ILLEGAL_INST;
>  }
>
> +static RISCVException any(CPURISCVState *env, int csrno)
> +{
> +    return RISCV_EXCP_NONE;
> +}
> +
>  static bool test_thead_mvendorid(RISCVCPU *cpu)
>  {
>      return cpu->cfg.mvendorid == THEAD_VENDOR_ID;
>  }
>
> +static RISCVException read_th_mxstatus(CPURISCVState *env, int csrno,
> +                                       target_ulong *val)
> +{
> +    /* We don't set MAEE here, because QEMU does not implement MAEE. */
> +    *val = TH_MXSTATUS_UCME | TH_MXSTATUS_THEADISAEE;
> +    return RISCV_EXCP_NONE;
> +}
> +
> +static RISCVException read_unimp_th_csr(CPURISCVState *env, int csrno,
> +                                        target_ulong *val)
> +{
> +    *val = 0;
> +    return RISCV_EXCP_NONE;
> +}
> +
>  static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
>                                         target_ulong *val)
>  {
> @@ -50,10 +148,290 @@ static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno,
>  }
>
>  const RISCVCSR th_csr_list[] = {
> +    {
> +        .csrno = CSR_TH_MXSTATUS,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mxstatus", mmode, read_th_mxstatus }
> +    },
> +    {
> +        .csrno = CSR_TH_MHCR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mhcr", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCOR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcor", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCCR2,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mccr2", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MHINT,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mhint", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MRVBR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mrvbr", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCOUNTERWEN,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcounterwen", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCOUNTERINTEN,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcounterinten", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCOUNTEROF,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcounterof", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCINS,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcins", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCINDEX,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcindex", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCDATA0,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcdata0", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MCDATA1,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mcdata1", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MSMPR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.msmpr", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_CPUID,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.cpuid", mmode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_MAPBADDR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.mapbaddr", mmode, read_unimp_th_csr }
> +    },
>      {
>          .csrno = CSR_TH_SXSTATUS,
>          .insertion_test = test_thead_mvendorid,
>          .csr_ops = { "th.sxstatus", smode, read_th_sxstatus }
>      },
> +    {
> +        .csrno = CSR_TH_SHCR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shcr", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCER2,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scer2", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCER,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scer", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCOUNTERINTEN,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scounterinten", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCOUNTEROF,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scounterof", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SCYCLE,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.scycle", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER3,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter3", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER4,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter4", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER5,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter5", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER6,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter6", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER7,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter7", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER8,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter8", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER9,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter9", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER10,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter10", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER11,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter11", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER12,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter12", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER13,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter13", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER14,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter14", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER15,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter15", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER16,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter16", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER17,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter17", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER18,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter18", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER19,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter19", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER20,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter20", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER21,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter21", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER22,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter22", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER23,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter23", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER24,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter24", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER25,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter25", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER26,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter26", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER27,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter27", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER28,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter28", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER29,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter29", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER30,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter30", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SHPMCOUNTER31,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.shpmcounter31", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SMIR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.smir", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SMLO0,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.smlo0", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SMEH,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.smeh", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_SMCIR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.smcir", smode, read_unimp_th_csr }
> +    },
> +    {
> +        .csrno = CSR_TH_FXCR,
> +        .insertion_test = test_thead_mvendorid,
> +        .csr_ops = { "th.fxcr", any, read_unimp_th_csr }
> +    },
>      { }
>  };
> --
> 2.53.0
>
>


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 2/5] hw/riscv: add k230 board initial support
  2026-04-17 15:11 ` [PATCH v6 2/5] hw/riscv: add k230 board initial support Chao Liu
@ 2026-05-01  4:09   ` Alistair Francis
  2026-05-06  7:44     ` Chao Liu
  2026-05-06  8:22     ` Chao Liu
  0 siblings, 2 replies; 20+ messages in thread
From: Alistair Francis @ 2026-05-01  4:09 UTC (permalink / raw)
  To: Chao Liu
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Peng Jiang

On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
>
> From: Chao Liu <chao.liu@zevorn.cn>
>
> K230 Board Compatible with kendryte K230 SDK.
>
> Preliminarily supports the C908 small core, which can
> run the U-Boot and Linux kernel compiled by the K230 SDK.
>
> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Reported-by: Peng Jiang <3160104094@zju.edu.cn>

A Signed-off-by or Tested-by would be better here, as it isn't a bug fix patch

> ---
>  MAINTAINERS             |   8 +-
>  hw/riscv/Kconfig        |  10 +
>  hw/riscv/k230.c         | 484 ++++++++++++++++++++++++++++++++++++++++
>  hw/riscv/meson.build    |   2 +-
>  include/hw/riscv/k230.h | 150 +++++++++++++
>  5 files changed, 652 insertions(+), 2 deletions(-)
>  create mode 100644 hw/riscv/k230.c
>  create mode 100644 include/hw/riscv/k230.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index aa4267b158..c429c63961 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1773,6 +1773,12 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
>  F: hw/riscv/xiangshan_kmh.c
>  F: include/hw/riscv/xiangshan_kmh.h
>
> +K230 Machines
> +M: Chao Liu <chao.liu.zevorn@gmail.com>
> +S: Maintained
> +F: hw/riscv/k230.c
> +F: include/hw/riscv/k230.h

I think we generally include the RISC-V mailing list here as well,
just to be clear it's RISC-V

> +
>  RX Machines
>  -----------
>  rx-gdbsim
> @@ -3620,7 +3626,7 @@ M: Alexander Bulekov <alxndr@bu.edu>
>  R: Paolo Bonzini <pbonzini@redhat.com>
>  R: Stefan Hajnoczi <stefanha@redhat.com>
>  R: Fabiano Rosas <farosas@suse.de>
> -R: Darren Kenny <darren.kenny@oracle.com>
> +R: Darren Kenny <darren.kenny@oracle.com>

This doesn't need to be changed

>  R: Qiuhao Li <Qiuhao.Li@outlook.com>
>  S: Maintained
>  F: tests/qtest/fuzz/
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 0222c93f87..b1a7357866 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -134,3 +134,13 @@ config MIPS_BOSTON_AIA
>      default y
>      select PCI_EXPRESS
>      select PCI_EXPRESS_XILINX
> +
> +config K230
> +    bool
> +    default y
> +    depends on RISCV64
> +    select RISCV_ACLINT
> +    select RISCV_APLIC
> +    select RISCV_IMSIC
> +    select SERIAL_MM
> +    select UNIMP
> diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
> new file mode 100644
> index 0000000000..2537023a05
> --- /dev/null
> +++ b/hw/riscv/k230.c
> @@ -0,0 +1,484 @@
> +/*
> + * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
> + *
> + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Provides a board compatible with the Kendryte K230 SDK
> + *
> + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf

Can you link to the manual

> + *
> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "cpu-qom.h"
> +#include "qemu/cutils.h"
> +#include "qemu/error-report.h"
> +#include "qapi/error.h"
> +#include "system/system.h"
> +#include "system/memory.h"
> +#include "target/riscv/cpu.h"
> +#include "chardev/char.h"
> +#include "hw/core/loader.h"
> +#include "hw/core/sysbus.h"
> +#include "hw/riscv/k230.h"
> +#include "hw/riscv/boot.h"
> +#include "hw/intc/riscv_aclint.h"
> +#include "hw/intc/sifive_plic.h"
> +#include "hw/char/serial-mm.h"
> +#include "hw/misc/unimp.h"
> +
> +static const MemMapEntry memmap[] = {
> +    [K230_DEV_DDRC] =         { 0x00000000,  0x80000000 },
> +    [K230_DEV_KPU_L2_CACHE] = { 0x80000000,  0x00200000 },
> +    [K230_DEV_SRAM] =         { 0x80200000,  0x00200000 },
> +    [K230_DEV_KPU_CFG] =      { 0x80400000,  0x00000800 },
> +    [K230_DEV_FFT] =          { 0x80400800,  0x00000400 },
> +    [K230_DEV_AI_2D_ENGINE] = { 0x80400C00,  0x00000800 },
> +    [K230_DEV_GSDMA] =        { 0x80800000,  0x00004000 },
> +    [K230_DEV_DMA] =          { 0x80804000,  0x00004000 },
> +    [K230_DEV_DECOMP_GZIP] =  { 0x80808000,  0x00004000 },
> +    [K230_DEV_NON_AI_2D] =    { 0x8080C000,  0x00004000 },
> +    [K230_DEV_ISP] =          { 0x90000000,  0x00008000 },
> +    [K230_DEV_DEWARP] =       { 0x90008000,  0x00001000 },
> +    [K230_DEV_RX_CSI] =       { 0x90009000,  0x00002000 },
> +    [K230_DEV_H264] =         { 0x90400000,  0x00010000 },
> +    [K230_DEV_2P5D] =         { 0x90800000,  0x00040000 },
> +    [K230_DEV_VO] =           { 0x90840000,  0x00010000 },
> +    [K230_DEV_VO_CFG] =       { 0x90850000,  0x00001000 },
> +    [K230_DEV_3D_ENGINE] =    { 0x90A00000,  0x00000800 },
> +    [K230_DEV_PMU] =          { 0x91000000,  0x00000C00 },
> +    [K230_DEV_RTC] =          { 0x91000C00,  0x00000400 },
> +    [K230_DEV_CMU] =          { 0x91100000,  0x00001000 },
> +    [K230_DEV_RMU] =          { 0x91101000,  0x00001000 },
> +    [K230_DEV_BOOT] =         { 0x91102000,  0x00001000 },
> +    [K230_DEV_PWR] =          { 0x91103000,  0x00001000 },
> +    [K230_DEV_MAILBOX] =      { 0x91104000,  0x00001000 },
> +    [K230_DEV_IOMUX] =        { 0x91105000,  0x00000800 },
> +    [K230_DEV_TIMER] =        { 0x91105800,  0x00000800 },
> +    [K230_DEV_WDT0] =         { 0x91106000,  0x00000800 },
> +    [K230_DEV_WDT1] =         { 0x91106800,  0x00000800 },
> +    [K230_DEV_TS] =           { 0x91107000,  0x00000800 },
> +    [K230_DEV_HDI] =          { 0x91107800,  0x00000800 },
> +    [K230_DEV_STC] =          { 0x91108000,  0x00000800 },
> +    [K230_DEV_BOOTROM] =      { 0x91200000,  0x00010000 },
> +    [K230_DEV_SECURITY] =     { 0x91210000,  0x00008000 },
> +    [K230_DEV_UART0] =        { 0x91400000,  0x00001000 },
> +    [K230_DEV_UART1] =        { 0x91401000,  0x00001000 },
> +    [K230_DEV_UART2] =        { 0x91402000,  0x00001000 },
> +    [K230_DEV_UART3] =        { 0x91403000,  0x00001000 },
> +    [K230_DEV_UART4] =        { 0x91404000,  0x00001000 },
> +    [K230_DEV_I2C0] =         { 0x91405000,  0x00001000 },
> +    [K230_DEV_I2C1] =         { 0x91406000,  0x00001000 },
> +    [K230_DEV_I2C2] =         { 0x91407000,  0x00001000 },
> +    [K230_DEV_I2C3] =         { 0x91408000,  0x00001000 },
> +    [K230_DEV_I2C4] =         { 0x91409000,  0x00001000 },
> +    [K230_DEV_PWM] =          { 0x9140A000,  0x00001000 },
> +    [K230_DEV_GPIO0] =        { 0x9140B000,  0x00001000 },
> +    [K230_DEV_GPIO1] =        { 0x9140C000,  0x00001000 },
> +    [K230_DEV_ADC] =          { 0x9140D000,  0x00001000 },
> +    [K230_DEV_CODEC] =        { 0x9140E000,  0x00001000 },
> +    [K230_DEV_I2S] =          { 0x9140F000,  0x00001000 },
> +    [K230_DEV_USB0] =         { 0x91500000,  0x00010000 },
> +    [K230_DEV_USB1] =         { 0x91540000,  0x00010000 },
> +    [K230_DEV_SD0] =          { 0x91580000,  0x00001000 },
> +    [K230_DEV_SD1] =          { 0x91581000,  0x00001000 },
> +    [K230_DEV_QSPI0] =        { 0x91582000,  0x00001000 },
> +    [K230_DEV_QSPI1] =        { 0x91583000,  0x00001000 },
> +    [K230_DEV_SPI] =          { 0x91584000,  0x00001000 },
> +    [K230_DEV_HI_SYS_CFG] =   { 0x91585000,  0x00000400 },
> +    [K230_DEV_DDRC_CFG] =     { 0x98000000,  0x02000000 },
> +    [K230_DEV_FLASH] =        { 0xC0000000,  0x08000000 },
> +    [K230_DEV_PLIC] =         { 0xF00000000, 0x00400000 },
> +    [K230_DEV_CLINT] =        { 0xF04000000, 0x00400000 },
> +};
> +
> +static void k230_soc_init(Object *obj)
> +{
> +    K230SoCState *s = RISCV_K230_SOC(obj);
> +    RISCVHartArrayState *cpu0 = &s->c908_cpu;
> +
> +    object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
> +    qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
> +    qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
> +    qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
> +                         memmap[K230_DEV_BOOTROM].base);
> +}
> +
> +static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
> +{
> +    g_autofree char *plic_hart_config = NULL;
> +
> +    /* Per-socket PLIC hart topology configuration string */
> +    plic_hart_config = riscv_plic_hart_config_string(hartid_count);
> +
> +    /* Per-socket PLIC */
> +    return sifive_plic_create(memmap[K230_DEV_PLIC].base,
> +                              plic_hart_config, hartid_count, base_hartid,
> +                              K230_PLIC_NUM_SOURCES,
> +                              K230_PLIC_NUM_PRIORITIES,
> +                              K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
> +                              K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
> +                              K230_PLIC_CONTEXT_BASE,
> +                              K230_PLIC_CONTEXT_STRIDE,
> +                              memmap[K230_DEV_PLIC].size);
> +}
> +
> +static void k230_soc_realize(DeviceState *dev, Error **errp)
> +{
> +    K230SoCState *s = RISCV_K230_SOC(dev);
> +    MemoryRegion *sys_mem = get_system_memory();
> +    int c908_cpus;
> +
> +    sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
> +
> +    c908_cpus = s->c908_cpu.num_harts;
> +
> +    /* SRAM */
> +    memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
> +                           memmap[K230_DEV_SRAM].size, &error_fatal);
> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
> +                                &s->sram);
> +
> +    /* BootROM */
> +    memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
> +                           memmap[K230_DEV_BOOTROM].size, &error_fatal);
> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
> +                                &s->bootrom);
> +
> +    /* PLIC */
> +    s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
> +
> +    /* CLINT */
> +    riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
> +                            C908_CPU_HARTID, c908_cpus, false);
> +    riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
> +                               RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
> +                               C908_CPU_HARTID, c908_cpus,
> +                               RISCV_ACLINT_DEFAULT_MTIMECMP,
> +                               RISCV_ACLINT_DEFAULT_MTIME,
> +                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
> +
> +    /* UART */
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART0].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART0_IRQ),
> +                   399193, serial_hd(0), DEVICE_LITTLE_ENDIAN);
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART1].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART1_IRQ),
> +                   399193, serial_hd(1), DEVICE_LITTLE_ENDIAN);
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART2].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART2_IRQ),
> +                   399193, serial_hd(2), DEVICE_LITTLE_ENDIAN);
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART3].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART3_IRQ),
> +                   399193, serial_hd(3), DEVICE_LITTLE_ENDIAN);
> +    serial_mm_init(sys_mem, memmap[K230_DEV_UART4].base, 2,
> +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
> +                   399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
> +
> +    /* unimplemented devices */
> +    create_unimplemented_device("kpu.l2-cache",
> +                                memmap[K230_DEV_KPU_L2_CACHE].base,
> +                                memmap[K230_DEV_KPU_L2_CACHE].size);
> +
> +    create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
> +                                memmap[K230_DEV_KPU_CFG].size);
> +
> +    create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
> +                                memmap[K230_DEV_FFT].size);
> +
> +    create_unimplemented_device("2d-engine.ai",
> +                                memmap[K230_DEV_AI_2D_ENGINE].base,
> +                                memmap[K230_DEV_AI_2D_ENGINE].size);
> +
> +    create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
> +                                memmap[K230_DEV_GSDMA].size);
> +
> +    create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
> +                                memmap[K230_DEV_DMA].size);
> +
> +    create_unimplemented_device("decomp-gzip",
> +                                memmap[K230_DEV_DECOMP_GZIP].base,
> +                                memmap[K230_DEV_DECOMP_GZIP].size);
> +
> +    create_unimplemented_device("2d-engine.non-ai",
> +                                memmap[K230_DEV_NON_AI_2D].base,
> +                                memmap[K230_DEV_NON_AI_2D].size);
> +
> +    create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
> +                                memmap[K230_DEV_ISP].size);
> +
> +    create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
> +                                memmap[K230_DEV_DEWARP].size);
> +
> +    create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
> +                                memmap[K230_DEV_RX_CSI].size);
> +
> +    create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
> +                                memmap[K230_DEV_H264].size);
> +
> +    create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
> +                                memmap[K230_DEV_2P5D].size);
> +
> +    create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
> +                                memmap[K230_DEV_VO].size);
> +
> +    create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
> +                                memmap[K230_DEV_VO_CFG].size);
> +
> +    create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
> +                                memmap[K230_DEV_3D_ENGINE].size);
> +
> +    create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
> +                                memmap[K230_DEV_PMU].size);
> +
> +    create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
> +                                memmap[K230_DEV_RTC].size);
> +
> +    create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
> +                                memmap[K230_DEV_CMU].size);
> +
> +    create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
> +                                memmap[K230_DEV_RMU].size);
> +
> +    create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
> +                                memmap[K230_DEV_BOOT].size);
> +
> +    create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
> +                                memmap[K230_DEV_PWR].size);
> +
> +    create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
> +                                memmap[K230_DEV_MAILBOX].size);
> +
> +    create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
> +                                memmap[K230_DEV_IOMUX].size);
> +
> +    create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
> +                                memmap[K230_DEV_TIMER].size);
> +
> +    create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
> +                                memmap[K230_DEV_WDT0].size);
> +
> +    create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
> +                                memmap[K230_DEV_WDT1].size);
> +
> +    create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
> +                                memmap[K230_DEV_TS].size);
> +
> +    create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
> +                                memmap[K230_DEV_HDI].size);
> +
> +    create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
> +                                memmap[K230_DEV_STC].size);
> +
> +    create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
> +                                memmap[K230_DEV_SECURITY].size);
> +
> +    create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
> +                                memmap[K230_DEV_I2C0].size);
> +
> +    create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
> +                                memmap[K230_DEV_I2C1].size);
> +
> +    create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
> +                                memmap[K230_DEV_I2C2].size);
> +
> +    create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
> +                                memmap[K230_DEV_I2C3].size);
> +
> +    create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
> +                                memmap[K230_DEV_I2C4].size);
> +
> +    create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
> +                                memmap[K230_DEV_PWM].size);
> +
> +    create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
> +                                memmap[K230_DEV_GPIO0].size);
> +
> +    create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
> +                                memmap[K230_DEV_GPIO1].size);
> +
> +    create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
> +                                memmap[K230_DEV_ADC].size);
> +
> +    create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
> +                                memmap[K230_DEV_CODEC].size);
> +
> +    create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
> +                                memmap[K230_DEV_I2S].size);
> +
> +    create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
> +                                memmap[K230_DEV_USB0].size);
> +
> +    create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
> +                                memmap[K230_DEV_USB1].size);
> +
> +    create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
> +                                memmap[K230_DEV_SD0].size);
> +
> +    create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
> +                                memmap[K230_DEV_SD1].size);
> +
> +    create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
> +                                memmap[K230_DEV_QSPI0].size);
> +
> +    create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
> +                                memmap[K230_DEV_QSPI1].size);
> +
> +    create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
> +                                memmap[K230_DEV_SPI].size);
> +
> +    create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
> +                                memmap[K230_DEV_HI_SYS_CFG].size);
> +
> +    create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
> +                                memmap[K230_DEV_DDRC_CFG].size);
> +
> +    create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
> +                                memmap[K230_DEV_FLASH].size);
> +}
> +
> +static void k230_soc_class_init(ObjectClass *oc, const void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(oc);
> +
> +    dc->realize = k230_soc_realize;
> +}
> +
> +static const TypeInfo k230_soc_type_info = {
> +    .name = TYPE_RISCV_K230_SOC,
> +    .parent = TYPE_DEVICE,
> +    .instance_size = sizeof(K230SoCState),
> +    .instance_init = k230_soc_init,
> +    .class_init = k230_soc_class_init,
> +};
> +
> +static void k230_soc_register_types(void)
> +{
> +    type_register_static(&k230_soc_type_info);
> +}
> +
> +type_init(k230_soc_register_types)
> +
> +static void k230_machine_done(Notifier *notifier, void *data)
> +{
> +    K230MachineState *s = container_of(notifier, K230MachineState,
> +                                     machine_done);
> +    MachineState *machine = MACHINE(s);
> +    hwaddr start_addr = memmap[K230_DEV_DDRC].base;
> +    target_ulong firmware_end_addr, kernel_start_addr;
> +    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
> +    uint64_t kernel_entry = 0;
> +    RISCVBootInfo boot_info;
> +
> +    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
> +                                                     &start_addr, NULL);
> +
> +    /* Mask ROM reset vector */
> +    uint32_t reset_vec[] = {
> +        /* 0x91200000: auipc  t0, 0x0              */ 0x00000297,
> +        /* 0x91200004: addi   t0, t0, 36 # <trap>  */ 0x03028293,
> +        /* 0x91200008: csrw   mtvec, t0            */ 0x30529073,
> +        /* 0x9120000C: csrr   a0, misa             */ 0x301012F3,
> +        /* 0x91200010: lui    t0, 0x1              */ 0x000012B7,
> +        /* 0x91200014: slli   t0, t0, 1            */ 0x00129293,
> +        /* 0x91200018: and    t0, a0, t0           */ 0x005572B3,
> +        /* 0x9120001C: bnez   t0, loop             */ 0x00511063,
> +        /* entry:                                  */
> +        /* 0x91200020: addiw  t0, zero, 1          */ 0x0010029b,
> +        /* 0x91200024: slli   t0, t0, 0x1b         */ 0x01b29293,
> +        /* 0x91200028: jr     t0 # uboot 0x8000000 */ 0x00028067,
> +        /* loop:                                   */
> +        /* 0x9120002C: j      0x9120002C # <loop>  */ 0x0000006f,
> +        /* trap:                                   */
> +        /* 0x91200030: j      0x91200030 # <trap>  */ 0x0000006f,
> +    };

Why do we need a custom reset vector?

Can we at least comment why we need this and what it's doing

Alistair

> +
> +    /* copy in the reset vector in little_endian byte order */
> +    for (int i = 0; i < sizeof(reset_vec) >> 2; i++) {
> +        reset_vec[i] = cpu_to_le32(reset_vec[i]);
> +    }
> +    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
> +                          memmap[K230_DEV_BOOTROM].base, &address_space_memory);
> +
> +    riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
> +
> +    if (machine->kernel_filename && !kernel_entry) {
> +        kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
> +                                                         firmware_end_addr);
> +        riscv_load_kernel(machine, &boot_info, kernel_start_addr,
> +                          true, NULL);
> +        kernel_entry = boot_info.image_low_addr;
> +    }
> +}
> +
> +static void k230_machine_init(MachineState *machine)
> +{
> +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> +
> +    K230MachineState *s = RISCV_K230_MACHINE(machine);
> +    MemoryRegion *sys_mem = get_system_memory();
> +
> +    if (machine->ram_size < mc->default_ram_size) {
> +        char *sz = size_to_str(mc->default_ram_size);
> +        error_report("Invalid RAM size, should be %s", sz);
> +        g_free(sz);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    /* Initialize SoC */
> +    object_initialize_child(OBJECT(machine), "soc", &s->soc,
> +                            TYPE_RISCV_K230_SOC);
> +    qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
> +
> +    /* Data Memory */
> +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
> +                                machine->ram);
> +
> +    s->machine_done.notify = k230_machine_done;
> +    qemu_add_machine_init_done_notifier(&s->machine_done);
> +}
> +
> +static void k230_machine_instance_init(Object *obj)
> +{
> +}
> +
> +static void k230_machine_class_init(ObjectClass *oc, const void *data)
> +{
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
> +    mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
> +    mc->init = k230_machine_init;
> +    mc->default_cpus = 2;
> +    mc->default_ram_id = "riscv.K230.ram"; /* DDR */
> +    mc->default_ram_size = memmap[K230_DEV_DDRC].size;
> +}
> +
> +static const TypeInfo k230_machine_typeinfo = {
> +    .name       = TYPE_RISCV_K230_MACHINE,
> +    .parent     = TYPE_MACHINE,
> +    .class_init = k230_machine_class_init,
> +    .instance_init = k230_machine_instance_init,
> +    .instance_size = sizeof(K230MachineState),
> +};
> +
> +static void k230_machine_init_register_types(void)
> +{
> +    type_register_static(&k230_machine_typeinfo);
> +}
> +
> +type_init(k230_machine_init_register_types)
> diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> index 533472e22a..09cf855984 100644
> --- a/hw/riscv/meson.build
> +++ b/hw/riscv/meson.build
> @@ -14,8 +14,8 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
>         'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
>  riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
>  riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
> -
>  riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c'))
>  riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c'))
> +riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
>
>  hw_arch += {'riscv': riscv_ss}
> diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
> new file mode 100644
> index 0000000000..830175b756
> --- /dev/null
> +++ b/include/hw/riscv/k230.h
> @@ -0,0 +1,150 @@
> +/*
> + * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
> + *
> + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Provides a board compatible with the kendryte K230 SDK
> + *
> + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> + *
> + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2 or later, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef HW_K230_H
> +#define HW_K230_H
> +
> +#include "hw/core/boards.h"
> +#include "hw/riscv/riscv_hart.h"
> +
> +#define C908_CPU_HARTID   (0)
> +
> +#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
> +#define RISCV_K230_SOC(obj) \
> +    OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
> +
> +typedef struct K230SoCState {
> +    /*< private >*/
> +    DeviceState parent_obj;
> +
> +    /*< public >*/
> +    RISCVHartArrayState c908_cpu; /* Small core */
> +
> +    MemoryRegion sram;
> +    MemoryRegion bootrom;
> +
> +    DeviceState *c908_plic;
> +} K230SoCState;
> +
> +#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
> +#define RISCV_K230_MACHINE(obj) \
> +    OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
> +
> +typedef struct K230MachineState {
> +    /*< private >*/
> +    MachineState parent_obj;
> +
> +    /*< public >*/
> +    K230SoCState soc;
> +    Notifier machine_done;
> +} K230MachineState;
> +
> +enum {
> +    K230_DEV_DDRC,
> +    K230_DEV_KPU_L2_CACHE,
> +    K230_DEV_SRAM,
> +    K230_DEV_KPU_CFG,
> +    K230_DEV_FFT,
> +    K230_DEV_AI_2D_ENGINE,
> +    K230_DEV_GSDMA,
> +    K230_DEV_DMA,
> +    K230_DEV_DECOMP_GZIP,
> +    K230_DEV_NON_AI_2D,
> +    K230_DEV_ISP,
> +    K230_DEV_DEWARP,
> +    K230_DEV_RX_CSI,
> +    K230_DEV_H264,
> +    K230_DEV_2P5D,
> +    K230_DEV_VO,
> +    K230_DEV_VO_CFG,
> +    K230_DEV_3D_ENGINE,
> +    K230_DEV_PMU,
> +    K230_DEV_RTC,
> +    K230_DEV_CMU,
> +    K230_DEV_RMU,
> +    K230_DEV_BOOT,
> +    K230_DEV_PWR,
> +    K230_DEV_MAILBOX,
> +    K230_DEV_IOMUX,
> +    K230_DEV_TIMER,
> +    K230_DEV_WDT0,
> +    K230_DEV_WDT1,
> +    K230_DEV_TS,
> +    K230_DEV_HDI,
> +    K230_DEV_STC,
> +    K230_DEV_BOOTROM,
> +    K230_DEV_SECURITY,
> +    K230_DEV_UART0,
> +    K230_DEV_UART1,
> +    K230_DEV_UART2,
> +    K230_DEV_UART3,
> +    K230_DEV_UART4,
> +    K230_DEV_I2C0,
> +    K230_DEV_I2C1,
> +    K230_DEV_I2C2,
> +    K230_DEV_I2C3,
> +    K230_DEV_I2C4,
> +    K230_DEV_PWM,
> +    K230_DEV_GPIO0,
> +    K230_DEV_GPIO1,
> +    K230_DEV_ADC,
> +    K230_DEV_CODEC,
> +    K230_DEV_I2S,
> +    K230_DEV_USB0,
> +    K230_DEV_USB1,
> +    K230_DEV_SD0,
> +    K230_DEV_SD1,
> +    K230_DEV_QSPI0,
> +    K230_DEV_QSPI1,
> +    K230_DEV_SPI,
> +    K230_DEV_HI_SYS_CFG,
> +    K230_DEV_DDRC_CFG,
> +    K230_DEV_FLASH,
> +    K230_DEV_PLIC,
> +    K230_DEV_CLINT,
> +};
> +
> +enum {
> +    K230_UART0_IRQ  = 16,
> +    K230_UART1_IRQ  = 17,
> +    K230_UART2_IRQ  = 18,
> +    K230_UART3_IRQ  = 19,
> +    K230_UART4_IRQ  = 20,
> +};
> +
> +/*
> + * Integrates with the interrupt controller (PLIC),
> + * which can process 208 interrupt external sources
> + */
> +#define K230_PLIC_NUM_SOURCES 208
> +#define K230_PLIC_NUM_PRIORITIES 7
> +#define K230_PLIC_PRIORITY_BASE 0x00
> +#define K230_PLIC_PENDING_BASE 0x1000
> +#define K230_PLIC_ENABLE_BASE 0x2000
> +#define K230_PLIC_ENABLE_STRIDE 0x80
> +#define K230_PLIC_CONTEXT_BASE 0x200000
> +#define K230_PLIC_CONTEXT_STRIDE 0x1000
> +
> +#endif
> --
> 2.53.0
>
>


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 5/5] docs/system/riscv: add documentation for k230 machine
  2026-04-17 15:11 ` [PATCH v6 5/5] docs/system/riscv: add documentation for k230 machine Chao Liu
@ 2026-05-01  4:16   ` Alistair Francis
  2026-05-06  8:29     ` Chao Liu
  0 siblings, 1 reply; 20+ messages in thread
From: Alistair Francis @ 2026-05-01  4:16 UTC (permalink / raw)
  To: Chao Liu
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza

On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
>
> From: Chao Liu <chao.liu@zevorn.cn>
>
> Add documentation for k230 virt reference platform.
>
> Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> ---
>  MAINTAINERS                  |  1 +
>  docs/system/riscv/k230.rst   | 48 ++++++++++++++++++++++++++++++++++++
>  docs/system/target-riscv.rst |  1 +
>  3 files changed, 50 insertions(+)
>  create mode 100644 docs/system/riscv/k230.rst
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b5b4acf6bd..d8d68cc123 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1776,6 +1776,7 @@ F: include/hw/riscv/xiangshan_kmh.h
>  K230 Machines
>  M: Chao Liu <chao.liu.zevorn@gmail.com>
>  S: Maintained
> +F: docs/system/riscv/k230.rst
>  F: hw/riscv/k230.c
>  F: hw/watchdog/k230_wdt.c
>  F: include/hw/riscv/k230.h
> diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
> new file mode 100644
> index 0000000000..3e6ca295df
> --- /dev/null
> +++ b/docs/system/riscv/k230.rst
> @@ -0,0 +1,48 @@
> +Kendryte K230 virt reference platform (``k230``)
> +==========================================================================
> +The ``k230`` machine is compatible with with Kendryte K230 SDK.
> +
> +The K230 is a chip from the AIoT SoC series made by Kendryte ® — a part of
> +Canaan Inc. It uses a brand-new multi-heterogeneous unit accelerated computing
> +structure.
> +
> +This chip has 2 RISC-V computing cores and a new-generation KPU (Knowledge
> +Process Unit) smart computing unit.
> +
> +It has multi-precision AI computing ability, works with many common AI computing
> +frameworks, and for some typical networks, its usage rate is over 70%. Besides,
> +the K230 chip supports many peripheral connections and has several special
> +hardware acceleration units (like 2D and 2.5D accelerators). It can speed up
> +different tasks (such as image processing, video processing, audio processing
> +and AI computing). It also has many good features: low delay, high performance,
> +low power use and fast start-up.

This seems like a bit too much marketing, let's remove this paragraph.

> +
> +For more information, see <https://www.kendryte.com/en/proDetail/230>
> +
> +Supported devices
> +-----------------
> +The ``k230`` machine supports the following devices:
> +
> +* 1 c908 cores
> +* Core Local Interruptor (CLINT)
> +* Incoming MSI Controller (IMSIC)
> +* 2 K230 Watchdog Timer
> +* 4 UART
> +
> +Boot options
> +------------
> +The ``k230`` machine can start using the standard ``-bios``
> +functionality for loading the boot image. You need to compile and link
> +the firmware, kernel, and Device Tree (FDT) into a single binary file with
> +K230 SDK(k230_canmv_defconfig), such as ``uboot``.
> +
> +Running
> +-------
> +Below is an example command line for running the ``k230``
> +machine:
> +
> +.. code-block:: bash
> +
> +   $ qemu-system-riscv64 -machine k230 \
> +      -bios k230_sdk/output/k230_canmv_defconfig/little/uboot/u-boot \
> +      -nographic

Does -kernel not work?

Alistair


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 1/5] target/riscv: add thead-c908 cpu support
  2026-05-01  4:02       ` Alistair Francis
@ 2026-05-06  7:43         ` Chao Liu
  0 siblings, 0 replies; 20+ messages in thread
From: Chao Liu @ 2026-05-06  7:43 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Conor Dooley,
	Peng Jiang

On Fri, May 01, 2026 at 02:02:04PM +1000, Alistair Francis wrote:
> On Mon, Apr 20, 2026 at 1:38 PM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
> >
> > On Mon, Apr 20, 2026 at 09:49:50AM +1000, Alistair Francis wrote:
> > > On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
> > > >
> > > > From: Chao Liu <chao.liu@zevorn.cn>
> > > >
> > > > The C908 processor is based on the RV64GCB[V] instruction
> > > > set, compatible to RVA22 Profile and implements the XIE
> > > > (XuanTie Instruction Extension) technology.
> > > >
> > > > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > > > Suggested-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> > > > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > > > Reviewed-by: Conor Dooley <conor@kernel.org>
> > >
> > > As Connor pointed out, he didn't add his Reviewed-by, instead he
> > > commented about a missing extension [1]. On top of that I don't see
> > > any instances of `Reviewed-by: Conor Dooley <conor@kernel.org>` in the
> > > QEMU tree, so I assume there are none on the mailing list as well.
> > > Which makes a copy and paste error seem less likely.
> > >
> > > I do see that Connor's reply was sent from his conor@kernel.org address,
> > > but manually stitching together a `Reviewed-by` and address seems
> > > unlikely to happen by accident. Although it does seem like the type of
> > > thing an LLM would do (see below).
> > >
> > Sorry, when I first started contributing to QEMU, I wasn't familiar with
> > mailing list conventions. I had been under the impression that whenever a
> > reviewer left comments, it was appropriate to carry a Reviewed-by tag into
> > the next revision. No one pointed this out at the time, but that was
> > clearly my oversight. My apologies to Alistair and Conor for the trouble
> > caused.
> 
> In future, only add tags that people specify. Please copy them
> directly or use b4, patchew or a similar tool to apply the tags.

Thanks for the review, way batter than manually tagging people :)

> 
> >
> > I made the same mistake on earlier patches as well:
> >
> > https://lore.kernel.org/qemu-devel/8b29b86a9af84edba54cc53aec017224478312bf.1745894489.git.lc00631@tecorigin.com/
> > https://lore.kernel.org/qemu-devel/501e578a4ef28515ccdefcbc82defc04363855ca.1746001489.git.lc00631@tecorigin.com/
> >
> > There is also a slightly different case where I added a Reviewed-by tag:
> >
> > https://lore.kernel.org/qemu-devel/07a97219e3f7e342c668d6772acc4c0a8eb4d4f3.1744709888.git.lc00631@tecorigin.com/
> >
> > There the R-b came from an internal colleague who reviewed the patch on
> > our side before it was sent upstream.
> >
> > Is that also against community convention?
> 
> No, internal colleagues are ok. Generally they provide little insight
> though. Your colleague would be better off engaging with the community
> as then the comments can be seen by everyone, that helps build trust
> between developers.
> 
You're right, we'll move more internal discussions to community
channels, so other developers can stay informed.

> >
> > > > Reported-by: Peng Jiang <3160104094@zju.edu.cn>
> > >
> > > I'm not sure how this can be Reported-by, it's not a bug fix. What was
> > > reported? It seems like the Reported-by appeared in v3 [2] and wasn't
> > > in v2 [3], yet I don't see anything reported.
> > >
> > This patchset is the project-phase output of a non-profit QEMU open-source
> > training camp we run in China; so far the camp has trained about 2000
> > participants. Peng Jiang is one of the members, and his task was bringing
> > up OpenSBI/RustSBI + Linux on the QEMU k230 board. For the specific
> > details, see:
> >
> > https://github.com/rustsbi/rustsbi/issues/160
> >
> > The Reported-by in v3 was added as a form of encouragement, since he
> > found several bugs during that bring-up work.
> 
> A Signed-off-by or Tested-by would probably be more appropriate then.
> Reported-by indicates that they found and reported a bug
> 
Peng Jiang tested the patchset, so Tested-by fits better. I will fix it
in the next version.

> >
> > Given this situation, should I also drop Peng Jiang's Reported-by tag?
> >
> > After the camp concluded, I asked him to report any further issues to the
> > upstream list directly himself — for example in v4:
> >
> > https://lore.kernel.org/qemu-devel/651b1d38.63ab7.19be50b4721.Coremail.3160104094@zju.edu.cn/
> >
> > > The extra and unexplained `Reviewed-by` (especially using an odd
> > > address as mentioned above) really points to this being LLM generated.
> > > Especially considering that your reviews are LLM generated (those are
> > > fine). Unfortunately that means I will need to decline the commits
> > > according to the QEMU Code Provenance rules [4]. Note that it isn't
> > > just the Code Provenance policy, it is also now really difficult to
> > > trust these patches knowing that stray `Reviewed-by` tags could be
> > > hallucinated and not caught before being submitted.
> > >
> > That said, I should clarify that no LLM assistance was used in developing
> > this patchset.
> 
> Ok, good to know :)
> 
> >
> > Finally, thanks to Alistair for the patient review. I'll be more careful
> > about these details in future contributions to avoid adding review burden
> > on maintainers/reviewers.
> 
> Thank you
> 
> Alistair


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 2/5] hw/riscv: add k230 board initial support
  2026-05-01  4:09   ` Alistair Francis
@ 2026-05-06  7:44     ` Chao Liu
  2026-05-06  8:22     ` Chao Liu
  1 sibling, 0 replies; 20+ messages in thread
From: Chao Liu @ 2026-05-06  7:44 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Peng Jiang

On Fri, May 01, 2026 at 02:09:19PM +1000, Alistair Francis wrote:
> On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
> >
> > From: Chao Liu <chao.liu@zevorn.cn>
> >
> > K230 Board Compatible with kendryte K230 SDK.
> >
> > Preliminarily supports the C908 small core, which can
> > run the U-Boot and Linux kernel compiled by the K230 SDK.
> >
> > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > Reported-by: Peng Jiang <3160104094@zju.edu.cn>
> 
> A Signed-off-by or Tested-by would be better here, as it isn't a bug fix patch
> 
Okay, I will fix it in the next version.

Thanks,
Chao
> > ---
> >  MAINTAINERS             |   8 +-
> >  hw/riscv/Kconfig        |  10 +
> >  hw/riscv/k230.c         | 484 ++++++++++++++++++++++++++++++++++++++++
> >  hw/riscv/meson.build    |   2 +-
> >  include/hw/riscv/k230.h | 150 +++++++++++++
> >  5 files changed, 652 insertions(+), 2 deletions(-)
> >  create mode 100644 hw/riscv/k230.c
> >  create mode 100644 include/hw/riscv/k230.h
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index aa4267b158..c429c63961 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1773,6 +1773,12 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
> >  F: hw/riscv/xiangshan_kmh.c
> >  F: include/hw/riscv/xiangshan_kmh.h
> >
> > +K230 Machines
> > +M: Chao Liu <chao.liu.zevorn@gmail.com>
> > +S: Maintained
> > +F: hw/riscv/k230.c
> > +F: include/hw/riscv/k230.h
> 
> I think we generally include the RISC-V mailing list here as well,
> just to be clear it's RISC-V
> 
> > +
> >  RX Machines
> >  -----------
> >  rx-gdbsim
> > @@ -3620,7 +3626,7 @@ M: Alexander Bulekov <alxndr@bu.edu>
> >  R: Paolo Bonzini <pbonzini@redhat.com>
> >  R: Stefan Hajnoczi <stefanha@redhat.com>
> >  R: Fabiano Rosas <farosas@suse.de>
> > -R: Darren Kenny <darren.kenny@oracle.com>
> > +R: Darren Kenny <darren.kenny@oracle.com>
> 
> This doesn't need to be changed
> 
> >  R: Qiuhao Li <Qiuhao.Li@outlook.com>
> >  S: Maintained
> >  F: tests/qtest/fuzz/
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 0222c93f87..b1a7357866 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -134,3 +134,13 @@ config MIPS_BOSTON_AIA
> >      default y
> >      select PCI_EXPRESS
> >      select PCI_EXPRESS_XILINX
> > +
> > +config K230
> > +    bool
> > +    default y
> > +    depends on RISCV64
> > +    select RISCV_ACLINT
> > +    select RISCV_APLIC
> > +    select RISCV_IMSIC
> > +    select SERIAL_MM
> > +    select UNIMP
> > diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
> > new file mode 100644
> > index 0000000000..2537023a05
> > --- /dev/null
> > +++ b/hw/riscv/k230.c
> > @@ -0,0 +1,484 @@
> > +/*
> > + * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
> > + *
> > + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
> > + *
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + *
> > + * Provides a board compatible with the Kendryte K230 SDK
> > + *
> > + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> 
> Can you link to the manual
> 
> > + *
> > + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "cpu-qom.h"
> > +#include "qemu/cutils.h"
> > +#include "qemu/error-report.h"
> > +#include "qapi/error.h"
> > +#include "system/system.h"
> > +#include "system/memory.h"
> > +#include "target/riscv/cpu.h"
> > +#include "chardev/char.h"
> > +#include "hw/core/loader.h"
> > +#include "hw/core/sysbus.h"
> > +#include "hw/riscv/k230.h"
> > +#include "hw/riscv/boot.h"
> > +#include "hw/intc/riscv_aclint.h"
> > +#include "hw/intc/sifive_plic.h"
> > +#include "hw/char/serial-mm.h"
> > +#include "hw/misc/unimp.h"
> > +
> > +static const MemMapEntry memmap[] = {
> > +    [K230_DEV_DDRC] =         { 0x00000000,  0x80000000 },
> > +    [K230_DEV_KPU_L2_CACHE] = { 0x80000000,  0x00200000 },
> > +    [K230_DEV_SRAM] =         { 0x80200000,  0x00200000 },
> > +    [K230_DEV_KPU_CFG] =      { 0x80400000,  0x00000800 },
> > +    [K230_DEV_FFT] =          { 0x80400800,  0x00000400 },
> > +    [K230_DEV_AI_2D_ENGINE] = { 0x80400C00,  0x00000800 },
> > +    [K230_DEV_GSDMA] =        { 0x80800000,  0x00004000 },
> > +    [K230_DEV_DMA] =          { 0x80804000,  0x00004000 },
> > +    [K230_DEV_DECOMP_GZIP] =  { 0x80808000,  0x00004000 },
> > +    [K230_DEV_NON_AI_2D] =    { 0x8080C000,  0x00004000 },
> > +    [K230_DEV_ISP] =          { 0x90000000,  0x00008000 },
> > +    [K230_DEV_DEWARP] =       { 0x90008000,  0x00001000 },
> > +    [K230_DEV_RX_CSI] =       { 0x90009000,  0x00002000 },
> > +    [K230_DEV_H264] =         { 0x90400000,  0x00010000 },
> > +    [K230_DEV_2P5D] =         { 0x90800000,  0x00040000 },
> > +    [K230_DEV_VO] =           { 0x90840000,  0x00010000 },
> > +    [K230_DEV_VO_CFG] =       { 0x90850000,  0x00001000 },
> > +    [K230_DEV_3D_ENGINE] =    { 0x90A00000,  0x00000800 },
> > +    [K230_DEV_PMU] =          { 0x91000000,  0x00000C00 },
> > +    [K230_DEV_RTC] =          { 0x91000C00,  0x00000400 },
> > +    [K230_DEV_CMU] =          { 0x91100000,  0x00001000 },
> > +    [K230_DEV_RMU] =          { 0x91101000,  0x00001000 },
> > +    [K230_DEV_BOOT] =         { 0x91102000,  0x00001000 },
> > +    [K230_DEV_PWR] =          { 0x91103000,  0x00001000 },
> > +    [K230_DEV_MAILBOX] =      { 0x91104000,  0x00001000 },
> > +    [K230_DEV_IOMUX] =        { 0x91105000,  0x00000800 },
> > +    [K230_DEV_TIMER] =        { 0x91105800,  0x00000800 },
> > +    [K230_DEV_WDT0] =         { 0x91106000,  0x00000800 },
> > +    [K230_DEV_WDT1] =         { 0x91106800,  0x00000800 },
> > +    [K230_DEV_TS] =           { 0x91107000,  0x00000800 },
> > +    [K230_DEV_HDI] =          { 0x91107800,  0x00000800 },
> > +    [K230_DEV_STC] =          { 0x91108000,  0x00000800 },
> > +    [K230_DEV_BOOTROM] =      { 0x91200000,  0x00010000 },
> > +    [K230_DEV_SECURITY] =     { 0x91210000,  0x00008000 },
> > +    [K230_DEV_UART0] =        { 0x91400000,  0x00001000 },
> > +    [K230_DEV_UART1] =        { 0x91401000,  0x00001000 },
> > +    [K230_DEV_UART2] =        { 0x91402000,  0x00001000 },
> > +    [K230_DEV_UART3] =        { 0x91403000,  0x00001000 },
> > +    [K230_DEV_UART4] =        { 0x91404000,  0x00001000 },
> > +    [K230_DEV_I2C0] =         { 0x91405000,  0x00001000 },
> > +    [K230_DEV_I2C1] =         { 0x91406000,  0x00001000 },
> > +    [K230_DEV_I2C2] =         { 0x91407000,  0x00001000 },
> > +    [K230_DEV_I2C3] =         { 0x91408000,  0x00001000 },
> > +    [K230_DEV_I2C4] =         { 0x91409000,  0x00001000 },
> > +    [K230_DEV_PWM] =          { 0x9140A000,  0x00001000 },
> > +    [K230_DEV_GPIO0] =        { 0x9140B000,  0x00001000 },
> > +    [K230_DEV_GPIO1] =        { 0x9140C000,  0x00001000 },
> > +    [K230_DEV_ADC] =          { 0x9140D000,  0x00001000 },
> > +    [K230_DEV_CODEC] =        { 0x9140E000,  0x00001000 },
> > +    [K230_DEV_I2S] =          { 0x9140F000,  0x00001000 },
> > +    [K230_DEV_USB0] =         { 0x91500000,  0x00010000 },
> > +    [K230_DEV_USB1] =         { 0x91540000,  0x00010000 },
> > +    [K230_DEV_SD0] =          { 0x91580000,  0x00001000 },
> > +    [K230_DEV_SD1] =          { 0x91581000,  0x00001000 },
> > +    [K230_DEV_QSPI0] =        { 0x91582000,  0x00001000 },
> > +    [K230_DEV_QSPI1] =        { 0x91583000,  0x00001000 },
> > +    [K230_DEV_SPI] =          { 0x91584000,  0x00001000 },
> > +    [K230_DEV_HI_SYS_CFG] =   { 0x91585000,  0x00000400 },
> > +    [K230_DEV_DDRC_CFG] =     { 0x98000000,  0x02000000 },
> > +    [K230_DEV_FLASH] =        { 0xC0000000,  0x08000000 },
> > +    [K230_DEV_PLIC] =         { 0xF00000000, 0x00400000 },
> > +    [K230_DEV_CLINT] =        { 0xF04000000, 0x00400000 },
> > +};
> > +
> > +static void k230_soc_init(Object *obj)
> > +{
> > +    K230SoCState *s = RISCV_K230_SOC(obj);
> > +    RISCVHartArrayState *cpu0 = &s->c908_cpu;
> > +
> > +    object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
> > +    qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
> > +    qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
> > +    qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
> > +                         memmap[K230_DEV_BOOTROM].base);
> > +}
> > +
> > +static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
> > +{
> > +    g_autofree char *plic_hart_config = NULL;
> > +
> > +    /* Per-socket PLIC hart topology configuration string */
> > +    plic_hart_config = riscv_plic_hart_config_string(hartid_count);
> > +
> > +    /* Per-socket PLIC */
> > +    return sifive_plic_create(memmap[K230_DEV_PLIC].base,
> > +                              plic_hart_config, hartid_count, base_hartid,
> > +                              K230_PLIC_NUM_SOURCES,
> > +                              K230_PLIC_NUM_PRIORITIES,
> > +                              K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
> > +                              K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
> > +                              K230_PLIC_CONTEXT_BASE,
> > +                              K230_PLIC_CONTEXT_STRIDE,
> > +                              memmap[K230_DEV_PLIC].size);
> > +}
> > +
> > +static void k230_soc_realize(DeviceState *dev, Error **errp)
> > +{
> > +    K230SoCState *s = RISCV_K230_SOC(dev);
> > +    MemoryRegion *sys_mem = get_system_memory();
> > +    int c908_cpus;
> > +
> > +    sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
> > +
> > +    c908_cpus = s->c908_cpu.num_harts;
> > +
> > +    /* SRAM */
> > +    memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
> > +                           memmap[K230_DEV_SRAM].size, &error_fatal);
> > +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
> > +                                &s->sram);
> > +
> > +    /* BootROM */
> > +    memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
> > +                           memmap[K230_DEV_BOOTROM].size, &error_fatal);
> > +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
> > +                                &s->bootrom);
> > +
> > +    /* PLIC */
> > +    s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
> > +
> > +    /* CLINT */
> > +    riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
> > +                            C908_CPU_HARTID, c908_cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
> > +                               RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
> > +                               C908_CPU_HARTID, c908_cpus,
> > +                               RISCV_ACLINT_DEFAULT_MTIMECMP,
> > +                               RISCV_ACLINT_DEFAULT_MTIME,
> > +                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
> > +
> > +    /* UART */
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART0].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART0_IRQ),
> > +                   399193, serial_hd(0), DEVICE_LITTLE_ENDIAN);
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART1].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART1_IRQ),
> > +                   399193, serial_hd(1), DEVICE_LITTLE_ENDIAN);
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART2].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART2_IRQ),
> > +                   399193, serial_hd(2), DEVICE_LITTLE_ENDIAN);
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART3].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART3_IRQ),
> > +                   399193, serial_hd(3), DEVICE_LITTLE_ENDIAN);
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART4].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
> > +                   399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
> > +
> > +    /* unimplemented devices */
> > +    create_unimplemented_device("kpu.l2-cache",
> > +                                memmap[K230_DEV_KPU_L2_CACHE].base,
> > +                                memmap[K230_DEV_KPU_L2_CACHE].size);
> > +
> > +    create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
> > +                                memmap[K230_DEV_KPU_CFG].size);
> > +
> > +    create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
> > +                                memmap[K230_DEV_FFT].size);
> > +
> > +    create_unimplemented_device("2d-engine.ai",
> > +                                memmap[K230_DEV_AI_2D_ENGINE].base,
> > +                                memmap[K230_DEV_AI_2D_ENGINE].size);
> > +
> > +    create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
> > +                                memmap[K230_DEV_GSDMA].size);
> > +
> > +    create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
> > +                                memmap[K230_DEV_DMA].size);
> > +
> > +    create_unimplemented_device("decomp-gzip",
> > +                                memmap[K230_DEV_DECOMP_GZIP].base,
> > +                                memmap[K230_DEV_DECOMP_GZIP].size);
> > +
> > +    create_unimplemented_device("2d-engine.non-ai",
> > +                                memmap[K230_DEV_NON_AI_2D].base,
> > +                                memmap[K230_DEV_NON_AI_2D].size);
> > +
> > +    create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
> > +                                memmap[K230_DEV_ISP].size);
> > +
> > +    create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
> > +                                memmap[K230_DEV_DEWARP].size);
> > +
> > +    create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
> > +                                memmap[K230_DEV_RX_CSI].size);
> > +
> > +    create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
> > +                                memmap[K230_DEV_H264].size);
> > +
> > +    create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
> > +                                memmap[K230_DEV_2P5D].size);
> > +
> > +    create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
> > +                                memmap[K230_DEV_VO].size);
> > +
> > +    create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
> > +                                memmap[K230_DEV_VO_CFG].size);
> > +
> > +    create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
> > +                                memmap[K230_DEV_3D_ENGINE].size);
> > +
> > +    create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
> > +                                memmap[K230_DEV_PMU].size);
> > +
> > +    create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
> > +                                memmap[K230_DEV_RTC].size);
> > +
> > +    create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
> > +                                memmap[K230_DEV_CMU].size);
> > +
> > +    create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
> > +                                memmap[K230_DEV_RMU].size);
> > +
> > +    create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
> > +                                memmap[K230_DEV_BOOT].size);
> > +
> > +    create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
> > +                                memmap[K230_DEV_PWR].size);
> > +
> > +    create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
> > +                                memmap[K230_DEV_MAILBOX].size);
> > +
> > +    create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
> > +                                memmap[K230_DEV_IOMUX].size);
> > +
> > +    create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
> > +                                memmap[K230_DEV_TIMER].size);
> > +
> > +    create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
> > +                                memmap[K230_DEV_WDT0].size);
> > +
> > +    create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
> > +                                memmap[K230_DEV_WDT1].size);
> > +
> > +    create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
> > +                                memmap[K230_DEV_TS].size);
> > +
> > +    create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
> > +                                memmap[K230_DEV_HDI].size);
> > +
> > +    create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
> > +                                memmap[K230_DEV_STC].size);
> > +
> > +    create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
> > +                                memmap[K230_DEV_SECURITY].size);
> > +
> > +    create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
> > +                                memmap[K230_DEV_I2C0].size);
> > +
> > +    create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
> > +                                memmap[K230_DEV_I2C1].size);
> > +
> > +    create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
> > +                                memmap[K230_DEV_I2C2].size);
> > +
> > +    create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
> > +                                memmap[K230_DEV_I2C3].size);
> > +
> > +    create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
> > +                                memmap[K230_DEV_I2C4].size);
> > +
> > +    create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
> > +                                memmap[K230_DEV_PWM].size);
> > +
> > +    create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
> > +                                memmap[K230_DEV_GPIO0].size);
> > +
> > +    create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
> > +                                memmap[K230_DEV_GPIO1].size);
> > +
> > +    create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
> > +                                memmap[K230_DEV_ADC].size);
> > +
> > +    create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
> > +                                memmap[K230_DEV_CODEC].size);
> > +
> > +    create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
> > +                                memmap[K230_DEV_I2S].size);
> > +
> > +    create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
> > +                                memmap[K230_DEV_USB0].size);
> > +
> > +    create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
> > +                                memmap[K230_DEV_USB1].size);
> > +
> > +    create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
> > +                                memmap[K230_DEV_SD0].size);
> > +
> > +    create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
> > +                                memmap[K230_DEV_SD1].size);
> > +
> > +    create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
> > +                                memmap[K230_DEV_QSPI0].size);
> > +
> > +    create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
> > +                                memmap[K230_DEV_QSPI1].size);
> > +
> > +    create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
> > +                                memmap[K230_DEV_SPI].size);
> > +
> > +    create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
> > +                                memmap[K230_DEV_HI_SYS_CFG].size);
> > +
> > +    create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
> > +                                memmap[K230_DEV_DDRC_CFG].size);
> > +
> > +    create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
> > +                                memmap[K230_DEV_FLASH].size);
> > +}
> > +
> > +static void k230_soc_class_init(ObjectClass *oc, const void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(oc);
> > +
> > +    dc->realize = k230_soc_realize;
> > +}
> > +
> > +static const TypeInfo k230_soc_type_info = {
> > +    .name = TYPE_RISCV_K230_SOC,
> > +    .parent = TYPE_DEVICE,
> > +    .instance_size = sizeof(K230SoCState),
> > +    .instance_init = k230_soc_init,
> > +    .class_init = k230_soc_class_init,
> > +};
> > +
> > +static void k230_soc_register_types(void)
> > +{
> > +    type_register_static(&k230_soc_type_info);
> > +}
> > +
> > +type_init(k230_soc_register_types)
> > +
> > +static void k230_machine_done(Notifier *notifier, void *data)
> > +{
> > +    K230MachineState *s = container_of(notifier, K230MachineState,
> > +                                     machine_done);
> > +    MachineState *machine = MACHINE(s);
> > +    hwaddr start_addr = memmap[K230_DEV_DDRC].base;
> > +    target_ulong firmware_end_addr, kernel_start_addr;
> > +    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
> > +    uint64_t kernel_entry = 0;
> > +    RISCVBootInfo boot_info;
> > +
> > +    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
> > +                                                     &start_addr, NULL);
> > +
> > +    /* Mask ROM reset vector */
> > +    uint32_t reset_vec[] = {
> > +        /* 0x91200000: auipc  t0, 0x0              */ 0x00000297,
> > +        /* 0x91200004: addi   t0, t0, 36 # <trap>  */ 0x03028293,
> > +        /* 0x91200008: csrw   mtvec, t0            */ 0x30529073,
> > +        /* 0x9120000C: csrr   a0, misa             */ 0x301012F3,
> > +        /* 0x91200010: lui    t0, 0x1              */ 0x000012B7,
> > +        /* 0x91200014: slli   t0, t0, 1            */ 0x00129293,
> > +        /* 0x91200018: and    t0, a0, t0           */ 0x005572B3,
> > +        /* 0x9120001C: bnez   t0, loop             */ 0x00511063,
> > +        /* entry:                                  */
> > +        /* 0x91200020: addiw  t0, zero, 1          */ 0x0010029b,
> > +        /* 0x91200024: slli   t0, t0, 0x1b         */ 0x01b29293,
> > +        /* 0x91200028: jr     t0 # uboot 0x8000000 */ 0x00028067,
> > +        /* loop:                                   */
> > +        /* 0x9120002C: j      0x9120002C # <loop>  */ 0x0000006f,
> > +        /* trap:                                   */
> > +        /* 0x91200030: j      0x91200030 # <trap>  */ 0x0000006f,
> > +    };
> 
> Why do we need a custom reset vector?
> 
> Can we at least comment why we need this and what it's doing
> 
> Alistair
> 
> > +
> > +    /* copy in the reset vector in little_endian byte order */
> > +    for (int i = 0; i < sizeof(reset_vec) >> 2; i++) {
> > +        reset_vec[i] = cpu_to_le32(reset_vec[i]);
> > +    }
> > +    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
> > +                          memmap[K230_DEV_BOOTROM].base, &address_space_memory);
> > +
> > +    riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
> > +
> > +    if (machine->kernel_filename && !kernel_entry) {
> > +        kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
> > +                                                         firmware_end_addr);
> > +        riscv_load_kernel(machine, &boot_info, kernel_start_addr,
> > +                          true, NULL);
> > +        kernel_entry = boot_info.image_low_addr;
> > +    }
> > +}
> > +
> > +static void k230_machine_init(MachineState *machine)
> > +{
> > +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> > +
> > +    K230MachineState *s = RISCV_K230_MACHINE(machine);
> > +    MemoryRegion *sys_mem = get_system_memory();
> > +
> > +    if (machine->ram_size < mc->default_ram_size) {
> > +        char *sz = size_to_str(mc->default_ram_size);
> > +        error_report("Invalid RAM size, should be %s", sz);
> > +        g_free(sz);
> > +        exit(EXIT_FAILURE);
> > +    }
> > +
> > +    /* Initialize SoC */
> > +    object_initialize_child(OBJECT(machine), "soc", &s->soc,
> > +                            TYPE_RISCV_K230_SOC);
> > +    qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
> > +
> > +    /* Data Memory */
> > +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
> > +                                machine->ram);
> > +
> > +    s->machine_done.notify = k230_machine_done;
> > +    qemu_add_machine_init_done_notifier(&s->machine_done);
> > +}
> > +
> > +static void k230_machine_instance_init(Object *obj)
> > +{
> > +}
> > +
> > +static void k230_machine_class_init(ObjectClass *oc, const void *data)
> > +{
> > +    MachineClass *mc = MACHINE_CLASS(oc);
> > +
> > +    mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
> > +    mc->init = k230_machine_init;
> > +    mc->default_cpus = 2;
> > +    mc->default_ram_id = "riscv.K230.ram"; /* DDR */
> > +    mc->default_ram_size = memmap[K230_DEV_DDRC].size;
> > +}
> > +
> > +static const TypeInfo k230_machine_typeinfo = {
> > +    .name       = TYPE_RISCV_K230_MACHINE,
> > +    .parent     = TYPE_MACHINE,
> > +    .class_init = k230_machine_class_init,
> > +    .instance_init = k230_machine_instance_init,
> > +    .instance_size = sizeof(K230MachineState),
> > +};
> > +
> > +static void k230_machine_init_register_types(void)
> > +{
> > +    type_register_static(&k230_machine_typeinfo);
> > +}
> > +
> > +type_init(k230_machine_init_register_types)
> > diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> > index 533472e22a..09cf855984 100644
> > --- a/hw/riscv/meson.build
> > +++ b/hw/riscv/meson.build
> > @@ -14,8 +14,8 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
> >         'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
> >  riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
> >  riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
> > -
> >  riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c'))
> >  riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c'))
> > +riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
> >
> >  hw_arch += {'riscv': riscv_ss}
> > diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
> > new file mode 100644
> > index 0000000000..830175b756
> > --- /dev/null
> > +++ b/include/hw/riscv/k230.h
> > @@ -0,0 +1,150 @@
> > +/*
> > + * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
> > + *
> > + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
> > + *
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + *
> > + * Provides a board compatible with the kendryte K230 SDK
> > + *
> > + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> > + *
> > + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +#ifndef HW_K230_H
> > +#define HW_K230_H
> > +
> > +#include "hw/core/boards.h"
> > +#include "hw/riscv/riscv_hart.h"
> > +
> > +#define C908_CPU_HARTID   (0)
> > +
> > +#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
> > +#define RISCV_K230_SOC(obj) \
> > +    OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
> > +
> > +typedef struct K230SoCState {
> > +    /*< private >*/
> > +    DeviceState parent_obj;
> > +
> > +    /*< public >*/
> > +    RISCVHartArrayState c908_cpu; /* Small core */
> > +
> > +    MemoryRegion sram;
> > +    MemoryRegion bootrom;
> > +
> > +    DeviceState *c908_plic;
> > +} K230SoCState;
> > +
> > +#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
> > +#define RISCV_K230_MACHINE(obj) \
> > +    OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
> > +
> > +typedef struct K230MachineState {
> > +    /*< private >*/
> > +    MachineState parent_obj;
> > +
> > +    /*< public >*/
> > +    K230SoCState soc;
> > +    Notifier machine_done;
> > +} K230MachineState;
> > +
> > +enum {
> > +    K230_DEV_DDRC,
> > +    K230_DEV_KPU_L2_CACHE,
> > +    K230_DEV_SRAM,
> > +    K230_DEV_KPU_CFG,
> > +    K230_DEV_FFT,
> > +    K230_DEV_AI_2D_ENGINE,
> > +    K230_DEV_GSDMA,
> > +    K230_DEV_DMA,
> > +    K230_DEV_DECOMP_GZIP,
> > +    K230_DEV_NON_AI_2D,
> > +    K230_DEV_ISP,
> > +    K230_DEV_DEWARP,
> > +    K230_DEV_RX_CSI,
> > +    K230_DEV_H264,
> > +    K230_DEV_2P5D,
> > +    K230_DEV_VO,
> > +    K230_DEV_VO_CFG,
> > +    K230_DEV_3D_ENGINE,
> > +    K230_DEV_PMU,
> > +    K230_DEV_RTC,
> > +    K230_DEV_CMU,
> > +    K230_DEV_RMU,
> > +    K230_DEV_BOOT,
> > +    K230_DEV_PWR,
> > +    K230_DEV_MAILBOX,
> > +    K230_DEV_IOMUX,
> > +    K230_DEV_TIMER,
> > +    K230_DEV_WDT0,
> > +    K230_DEV_WDT1,
> > +    K230_DEV_TS,
> > +    K230_DEV_HDI,
> > +    K230_DEV_STC,
> > +    K230_DEV_BOOTROM,
> > +    K230_DEV_SECURITY,
> > +    K230_DEV_UART0,
> > +    K230_DEV_UART1,
> > +    K230_DEV_UART2,
> > +    K230_DEV_UART3,
> > +    K230_DEV_UART4,
> > +    K230_DEV_I2C0,
> > +    K230_DEV_I2C1,
> > +    K230_DEV_I2C2,
> > +    K230_DEV_I2C3,
> > +    K230_DEV_I2C4,
> > +    K230_DEV_PWM,
> > +    K230_DEV_GPIO0,
> > +    K230_DEV_GPIO1,
> > +    K230_DEV_ADC,
> > +    K230_DEV_CODEC,
> > +    K230_DEV_I2S,
> > +    K230_DEV_USB0,
> > +    K230_DEV_USB1,
> > +    K230_DEV_SD0,
> > +    K230_DEV_SD1,
> > +    K230_DEV_QSPI0,
> > +    K230_DEV_QSPI1,
> > +    K230_DEV_SPI,
> > +    K230_DEV_HI_SYS_CFG,
> > +    K230_DEV_DDRC_CFG,
> > +    K230_DEV_FLASH,
> > +    K230_DEV_PLIC,
> > +    K230_DEV_CLINT,
> > +};
> > +
> > +enum {
> > +    K230_UART0_IRQ  = 16,
> > +    K230_UART1_IRQ  = 17,
> > +    K230_UART2_IRQ  = 18,
> > +    K230_UART3_IRQ  = 19,
> > +    K230_UART4_IRQ  = 20,
> > +};
> > +
> > +/*
> > + * Integrates with the interrupt controller (PLIC),
> > + * which can process 208 interrupt external sources
> > + */
> > +#define K230_PLIC_NUM_SOURCES 208
> > +#define K230_PLIC_NUM_PRIORITIES 7
> > +#define K230_PLIC_PRIORITY_BASE 0x00
> > +#define K230_PLIC_PENDING_BASE 0x1000
> > +#define K230_PLIC_ENABLE_BASE 0x2000
> > +#define K230_PLIC_ENABLE_STRIDE 0x80
> > +#define K230_PLIC_CONTEXT_BASE 0x200000
> > +#define K230_PLIC_CONTEXT_STRIDE 0x1000
> > +
> > +#endif
> > --
> > 2.53.0
> >
> >


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 2/5] hw/riscv: add k230 board initial support
  2026-05-01  4:09   ` Alistair Francis
  2026-05-06  7:44     ` Chao Liu
@ 2026-05-06  8:22     ` Chao Liu
  1 sibling, 0 replies; 20+ messages in thread
From: Chao Liu @ 2026-05-06  8:22 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza, Peng Jiang

On Fri, May 01, 2026 at 02:09:19PM +1000, Alistair Francis wrote:
> On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
> >
> > From: Chao Liu <chao.liu@zevorn.cn>
> >
> > K230 Board Compatible with kendryte K230 SDK.
> >
> > Preliminarily supports the C908 small core, which can
> > run the U-Boot and Linux kernel compiled by the K230 SDK.
> >
> > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > Reported-by: Peng Jiang <3160104094@zju.edu.cn>
> 
> A Signed-off-by or Tested-by would be better here, as it isn't a bug fix patch
> 
> > ---
> >  MAINTAINERS             |   8 +-
> >  hw/riscv/Kconfig        |  10 +
> >  hw/riscv/k230.c         | 484 ++++++++++++++++++++++++++++++++++++++++
> >  hw/riscv/meson.build    |   2 +-
> >  include/hw/riscv/k230.h | 150 +++++++++++++
> >  5 files changed, 652 insertions(+), 2 deletions(-)
> >  create mode 100644 hw/riscv/k230.c
> >  create mode 100644 include/hw/riscv/k230.h
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index aa4267b158..c429c63961 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1773,6 +1773,12 @@ F: docs/system/riscv/xiangshan-kunminghu.rst
> >  F: hw/riscv/xiangshan_kmh.c
> >  F: include/hw/riscv/xiangshan_kmh.h
> >
> > +K230 Machines
> > +M: Chao Liu <chao.liu.zevorn@gmail.com>
> > +S: Maintained
> > +F: hw/riscv/k230.c
> > +F: include/hw/riscv/k230.h
> 
> I think we generally include the RISC-V mailing list here as well,
> just to be clear it's RISC-V
> 
You're right, I will include the RISC-V mailing list in the next version.

> > +
> >  RX Machines
> >  -----------
> >  rx-gdbsim
> > @@ -3620,7 +3626,7 @@ M: Alexander Bulekov <alxndr@bu.edu>
> >  R: Paolo Bonzini <pbonzini@redhat.com>
> >  R: Stefan Hajnoczi <stefanha@redhat.com>
> >  R: Fabiano Rosas <farosas@suse.de>
> > -R: Darren Kenny <darren.kenny@oracle.com>
> > +R: Darren Kenny <darren.kenny@oracle.com>
> 
> This doesn't need to be changed
> 
Sorry, my IDE auto removed this whitespace. I'll drop this changed in
the next version.

> >  R: Qiuhao Li <Qiuhao.Li@outlook.com>
> >  S: Maintained
> >  F: tests/qtest/fuzz/
> > diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> > index 0222c93f87..b1a7357866 100644
> > --- a/hw/riscv/Kconfig
> > +++ b/hw/riscv/Kconfig
> > @@ -134,3 +134,13 @@ config MIPS_BOSTON_AIA
> >      default y
> >      select PCI_EXPRESS
> >      select PCI_EXPRESS_XILINX
> > +
> > +config K230
> > +    bool
> > +    default y
> > +    depends on RISCV64
> > +    select RISCV_ACLINT
> > +    select RISCV_APLIC
> > +    select RISCV_IMSIC
> > +    select SERIAL_MM
> > +    select UNIMP
> > diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c
> > new file mode 100644
> > index 0000000000..2537023a05
> > --- /dev/null
> > +++ b/hw/riscv/k230.c
> > @@ -0,0 +1,484 @@
> > +/*
> > + * QEMU RISC-V Virt Board Compatible with Kendryte K230 SDK
> > + *
> > + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
> > + *
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + *
> > + * Provides a board compatible with the Kendryte K230 SDK
> > + *
> > + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> 
> Can you link to the manual

Okay.

> 
> > + *
> > + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "cpu-qom.h"
> > +#include "qemu/cutils.h"
> > +#include "qemu/error-report.h"
> > +#include "qapi/error.h"
> > +#include "system/system.h"
> > +#include "system/memory.h"
> > +#include "target/riscv/cpu.h"
> > +#include "chardev/char.h"
> > +#include "hw/core/loader.h"
> > +#include "hw/core/sysbus.h"
> > +#include "hw/riscv/k230.h"
> > +#include "hw/riscv/boot.h"
> > +#include "hw/intc/riscv_aclint.h"
> > +#include "hw/intc/sifive_plic.h"
> > +#include "hw/char/serial-mm.h"
> > +#include "hw/misc/unimp.h"
> > +
> > +static const MemMapEntry memmap[] = {
> > +    [K230_DEV_DDRC] =         { 0x00000000,  0x80000000 },
> > +    [K230_DEV_KPU_L2_CACHE] = { 0x80000000,  0x00200000 },
> > +    [K230_DEV_SRAM] =         { 0x80200000,  0x00200000 },
> > +    [K230_DEV_KPU_CFG] =      { 0x80400000,  0x00000800 },
> > +    [K230_DEV_FFT] =          { 0x80400800,  0x00000400 },
> > +    [K230_DEV_AI_2D_ENGINE] = { 0x80400C00,  0x00000800 },
> > +    [K230_DEV_GSDMA] =        { 0x80800000,  0x00004000 },
> > +    [K230_DEV_DMA] =          { 0x80804000,  0x00004000 },
> > +    [K230_DEV_DECOMP_GZIP] =  { 0x80808000,  0x00004000 },
> > +    [K230_DEV_NON_AI_2D] =    { 0x8080C000,  0x00004000 },
> > +    [K230_DEV_ISP] =          { 0x90000000,  0x00008000 },
> > +    [K230_DEV_DEWARP] =       { 0x90008000,  0x00001000 },
> > +    [K230_DEV_RX_CSI] =       { 0x90009000,  0x00002000 },
> > +    [K230_DEV_H264] =         { 0x90400000,  0x00010000 },
> > +    [K230_DEV_2P5D] =         { 0x90800000,  0x00040000 },
> > +    [K230_DEV_VO] =           { 0x90840000,  0x00010000 },
> > +    [K230_DEV_VO_CFG] =       { 0x90850000,  0x00001000 },
> > +    [K230_DEV_3D_ENGINE] =    { 0x90A00000,  0x00000800 },
> > +    [K230_DEV_PMU] =          { 0x91000000,  0x00000C00 },
> > +    [K230_DEV_RTC] =          { 0x91000C00,  0x00000400 },
> > +    [K230_DEV_CMU] =          { 0x91100000,  0x00001000 },
> > +    [K230_DEV_RMU] =          { 0x91101000,  0x00001000 },
> > +    [K230_DEV_BOOT] =         { 0x91102000,  0x00001000 },
> > +    [K230_DEV_PWR] =          { 0x91103000,  0x00001000 },
> > +    [K230_DEV_MAILBOX] =      { 0x91104000,  0x00001000 },
> > +    [K230_DEV_IOMUX] =        { 0x91105000,  0x00000800 },
> > +    [K230_DEV_TIMER] =        { 0x91105800,  0x00000800 },
> > +    [K230_DEV_WDT0] =         { 0x91106000,  0x00000800 },
> > +    [K230_DEV_WDT1] =         { 0x91106800,  0x00000800 },
> > +    [K230_DEV_TS] =           { 0x91107000,  0x00000800 },
> > +    [K230_DEV_HDI] =          { 0x91107800,  0x00000800 },
> > +    [K230_DEV_STC] =          { 0x91108000,  0x00000800 },
> > +    [K230_DEV_BOOTROM] =      { 0x91200000,  0x00010000 },
> > +    [K230_DEV_SECURITY] =     { 0x91210000,  0x00008000 },
> > +    [K230_DEV_UART0] =        { 0x91400000,  0x00001000 },
> > +    [K230_DEV_UART1] =        { 0x91401000,  0x00001000 },
> > +    [K230_DEV_UART2] =        { 0x91402000,  0x00001000 },
> > +    [K230_DEV_UART3] =        { 0x91403000,  0x00001000 },
> > +    [K230_DEV_UART4] =        { 0x91404000,  0x00001000 },
> > +    [K230_DEV_I2C0] =         { 0x91405000,  0x00001000 },
> > +    [K230_DEV_I2C1] =         { 0x91406000,  0x00001000 },
> > +    [K230_DEV_I2C2] =         { 0x91407000,  0x00001000 },
> > +    [K230_DEV_I2C3] =         { 0x91408000,  0x00001000 },
> > +    [K230_DEV_I2C4] =         { 0x91409000,  0x00001000 },
> > +    [K230_DEV_PWM] =          { 0x9140A000,  0x00001000 },
> > +    [K230_DEV_GPIO0] =        { 0x9140B000,  0x00001000 },
> > +    [K230_DEV_GPIO1] =        { 0x9140C000,  0x00001000 },
> > +    [K230_DEV_ADC] =          { 0x9140D000,  0x00001000 },
> > +    [K230_DEV_CODEC] =        { 0x9140E000,  0x00001000 },
> > +    [K230_DEV_I2S] =          { 0x9140F000,  0x00001000 },
> > +    [K230_DEV_USB0] =         { 0x91500000,  0x00010000 },
> > +    [K230_DEV_USB1] =         { 0x91540000,  0x00010000 },
> > +    [K230_DEV_SD0] =          { 0x91580000,  0x00001000 },
> > +    [K230_DEV_SD1] =          { 0x91581000,  0x00001000 },
> > +    [K230_DEV_QSPI0] =        { 0x91582000,  0x00001000 },
> > +    [K230_DEV_QSPI1] =        { 0x91583000,  0x00001000 },
> > +    [K230_DEV_SPI] =          { 0x91584000,  0x00001000 },
> > +    [K230_DEV_HI_SYS_CFG] =   { 0x91585000,  0x00000400 },
> > +    [K230_DEV_DDRC_CFG] =     { 0x98000000,  0x02000000 },
> > +    [K230_DEV_FLASH] =        { 0xC0000000,  0x08000000 },
> > +    [K230_DEV_PLIC] =         { 0xF00000000, 0x00400000 },
> > +    [K230_DEV_CLINT] =        { 0xF04000000, 0x00400000 },
> > +};
> > +
> > +static void k230_soc_init(Object *obj)
> > +{
> > +    K230SoCState *s = RISCV_K230_SOC(obj);
> > +    RISCVHartArrayState *cpu0 = &s->c908_cpu;
> > +
> > +    object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY);
> > +    qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0);
> > +    qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C908);
> > +    qdev_prop_set_uint64(DEVICE(cpu0), "resetvec",
> > +                         memmap[K230_DEV_BOOTROM].base);
> > +}
> > +
> > +static DeviceState *k230_create_plic(int base_hartid, int hartid_count)
> > +{
> > +    g_autofree char *plic_hart_config = NULL;
> > +
> > +    /* Per-socket PLIC hart topology configuration string */
> > +    plic_hart_config = riscv_plic_hart_config_string(hartid_count);
> > +
> > +    /* Per-socket PLIC */
> > +    return sifive_plic_create(memmap[K230_DEV_PLIC].base,
> > +                              plic_hart_config, hartid_count, base_hartid,
> > +                              K230_PLIC_NUM_SOURCES,
> > +                              K230_PLIC_NUM_PRIORITIES,
> > +                              K230_PLIC_PRIORITY_BASE, K230_PLIC_PENDING_BASE,
> > +                              K230_PLIC_ENABLE_BASE, K230_PLIC_ENABLE_STRIDE,
> > +                              K230_PLIC_CONTEXT_BASE,
> > +                              K230_PLIC_CONTEXT_STRIDE,
> > +                              memmap[K230_DEV_PLIC].size);
> > +}
> > +
> > +static void k230_soc_realize(DeviceState *dev, Error **errp)
> > +{
> > +    K230SoCState *s = RISCV_K230_SOC(dev);
> > +    MemoryRegion *sys_mem = get_system_memory();
> > +    int c908_cpus;
> > +
> > +    sysbus_realize(SYS_BUS_DEVICE(&s->c908_cpu), &error_fatal);
> > +
> > +    c908_cpus = s->c908_cpu.num_harts;
> > +
> > +    /* SRAM */
> > +    memory_region_init_ram(&s->sram, OBJECT(dev), "sram",
> > +                           memmap[K230_DEV_SRAM].size, &error_fatal);
> > +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_SRAM].base,
> > +                                &s->sram);
> > +
> > +    /* BootROM */
> > +    memory_region_init_rom(&s->bootrom, OBJECT(dev), "bootrom",
> > +                           memmap[K230_DEV_BOOTROM].size, &error_fatal);
> > +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_BOOTROM].base,
> > +                                &s->bootrom);
> > +
> > +    /* PLIC */
> > +    s->c908_plic = k230_create_plic(C908_CPU_HARTID, c908_cpus);
> > +
> > +    /* CLINT */
> > +    riscv_aclint_swi_create(memmap[K230_DEV_CLINT].base,
> > +                            C908_CPU_HARTID, c908_cpus, false);
> > +    riscv_aclint_mtimer_create(memmap[K230_DEV_CLINT].base + 0x4000,
> > +                               RISCV_ACLINT_DEFAULT_MTIMER_SIZE,
> > +                               C908_CPU_HARTID, c908_cpus,
> > +                               RISCV_ACLINT_DEFAULT_MTIMECMP,
> > +                               RISCV_ACLINT_DEFAULT_MTIME,
> > +                               RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true);
> > +
> > +    /* UART */
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART0].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART0_IRQ),
> > +                   399193, serial_hd(0), DEVICE_LITTLE_ENDIAN);
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART1].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART1_IRQ),
> > +                   399193, serial_hd(1), DEVICE_LITTLE_ENDIAN);
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART2].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART2_IRQ),
> > +                   399193, serial_hd(2), DEVICE_LITTLE_ENDIAN);
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART3].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART3_IRQ),
> > +                   399193, serial_hd(3), DEVICE_LITTLE_ENDIAN);
> > +    serial_mm_init(sys_mem, memmap[K230_DEV_UART4].base, 2,
> > +                   qdev_get_gpio_in(DEVICE(s->c908_plic), K230_UART4_IRQ),
> > +                   399193, serial_hd(4), DEVICE_LITTLE_ENDIAN);
> > +
> > +    /* unimplemented devices */
> > +    create_unimplemented_device("kpu.l2-cache",
> > +                                memmap[K230_DEV_KPU_L2_CACHE].base,
> > +                                memmap[K230_DEV_KPU_L2_CACHE].size);
> > +
> > +    create_unimplemented_device("kpu_cfg", memmap[K230_DEV_KPU_CFG].base,
> > +                                memmap[K230_DEV_KPU_CFG].size);
> > +
> > +    create_unimplemented_device("fft", memmap[K230_DEV_FFT].base,
> > +                                memmap[K230_DEV_FFT].size);
> > +
> > +    create_unimplemented_device("2d-engine.ai",
> > +                                memmap[K230_DEV_AI_2D_ENGINE].base,
> > +                                memmap[K230_DEV_AI_2D_ENGINE].size);
> > +
> > +    create_unimplemented_device("gsdma", memmap[K230_DEV_GSDMA].base,
> > +                                memmap[K230_DEV_GSDMA].size);
> > +
> > +    create_unimplemented_device("dma", memmap[K230_DEV_DMA].base,
> > +                                memmap[K230_DEV_DMA].size);
> > +
> > +    create_unimplemented_device("decomp-gzip",
> > +                                memmap[K230_DEV_DECOMP_GZIP].base,
> > +                                memmap[K230_DEV_DECOMP_GZIP].size);
> > +
> > +    create_unimplemented_device("2d-engine.non-ai",
> > +                                memmap[K230_DEV_NON_AI_2D].base,
> > +                                memmap[K230_DEV_NON_AI_2D].size);
> > +
> > +    create_unimplemented_device("isp", memmap[K230_DEV_ISP].base,
> > +                                memmap[K230_DEV_ISP].size);
> > +
> > +    create_unimplemented_device("dewarp", memmap[K230_DEV_DEWARP].base,
> > +                                memmap[K230_DEV_DEWARP].size);
> > +
> > +    create_unimplemented_device("rx-csi", memmap[K230_DEV_RX_CSI].base,
> > +                                memmap[K230_DEV_RX_CSI].size);
> > +
> > +    create_unimplemented_device("vpu", memmap[K230_DEV_H264].base,
> > +                                memmap[K230_DEV_H264].size);
> > +
> > +    create_unimplemented_device("gpu", memmap[K230_DEV_2P5D].base,
> > +                                memmap[K230_DEV_2P5D].size);
> > +
> > +    create_unimplemented_device("vo", memmap[K230_DEV_VO].base,
> > +                                memmap[K230_DEV_VO].size);
> > +
> > +    create_unimplemented_device("vo_cfg", memmap[K230_DEV_VO_CFG].base,
> > +                                memmap[K230_DEV_VO_CFG].size);
> > +
> > +    create_unimplemented_device("3d-engine", memmap[K230_DEV_3D_ENGINE].base,
> > +                                memmap[K230_DEV_3D_ENGINE].size);
> > +
> > +    create_unimplemented_device("pmu", memmap[K230_DEV_PMU].base,
> > +                                memmap[K230_DEV_PMU].size);
> > +
> > +    create_unimplemented_device("rtc", memmap[K230_DEV_RTC].base,
> > +                                memmap[K230_DEV_RTC].size);
> > +
> > +    create_unimplemented_device("cmu", memmap[K230_DEV_CMU].base,
> > +                                memmap[K230_DEV_CMU].size);
> > +
> > +    create_unimplemented_device("rmu", memmap[K230_DEV_RMU].base,
> > +                                memmap[K230_DEV_RMU].size);
> > +
> > +    create_unimplemented_device("boot", memmap[K230_DEV_BOOT].base,
> > +                                memmap[K230_DEV_BOOT].size);
> > +
> > +    create_unimplemented_device("pwr", memmap[K230_DEV_PWR].base,
> > +                                memmap[K230_DEV_PWR].size);
> > +
> > +    create_unimplemented_device("ipcm", memmap[K230_DEV_MAILBOX].base,
> > +                                memmap[K230_DEV_MAILBOX].size);
> > +
> > +    create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base,
> > +                                memmap[K230_DEV_IOMUX].size);
> > +
> > +    create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base,
> > +                                memmap[K230_DEV_TIMER].size);
> > +
> > +    create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base,
> > +                                memmap[K230_DEV_WDT0].size);
> > +
> > +    create_unimplemented_device("wdt1", memmap[K230_DEV_WDT1].base,
> > +                                memmap[K230_DEV_WDT1].size);
> > +
> > +    create_unimplemented_device("ts", memmap[K230_DEV_TS].base,
> > +                                memmap[K230_DEV_TS].size);
> > +
> > +    create_unimplemented_device("hdi", memmap[K230_DEV_HDI].base,
> > +                                memmap[K230_DEV_HDI].size);
> > +
> > +    create_unimplemented_device("stc", memmap[K230_DEV_STC].base,
> > +                                memmap[K230_DEV_STC].size);
> > +
> > +    create_unimplemented_device("security", memmap[K230_DEV_SECURITY].base,
> > +                                memmap[K230_DEV_SECURITY].size);
> > +
> > +    create_unimplemented_device("i2c0", memmap[K230_DEV_I2C0].base,
> > +                                memmap[K230_DEV_I2C0].size);
> > +
> > +    create_unimplemented_device("i2c1", memmap[K230_DEV_I2C1].base,
> > +                                memmap[K230_DEV_I2C1].size);
> > +
> > +    create_unimplemented_device("i2c2", memmap[K230_DEV_I2C2].base,
> > +                                memmap[K230_DEV_I2C2].size);
> > +
> > +    create_unimplemented_device("i2c3", memmap[K230_DEV_I2C3].base,
> > +                                memmap[K230_DEV_I2C3].size);
> > +
> > +    create_unimplemented_device("i2c4", memmap[K230_DEV_I2C4].base,
> > +                                memmap[K230_DEV_I2C4].size);
> > +
> > +    create_unimplemented_device("pwm", memmap[K230_DEV_PWM].base,
> > +                                memmap[K230_DEV_PWM].size);
> > +
> > +    create_unimplemented_device("gpio0", memmap[K230_DEV_GPIO0].base,
> > +                                memmap[K230_DEV_GPIO0].size);
> > +
> > +    create_unimplemented_device("gpio1", memmap[K230_DEV_GPIO1].base,
> > +                                memmap[K230_DEV_GPIO1].size);
> > +
> > +    create_unimplemented_device("adc", memmap[K230_DEV_ADC].base,
> > +                                memmap[K230_DEV_ADC].size);
> > +
> > +    create_unimplemented_device("codec", memmap[K230_DEV_CODEC].base,
> > +                                memmap[K230_DEV_CODEC].size);
> > +
> > +    create_unimplemented_device("i2s", memmap[K230_DEV_I2S].base,
> > +                                memmap[K230_DEV_I2S].size);
> > +
> > +    create_unimplemented_device("usb0", memmap[K230_DEV_USB0].base,
> > +                                memmap[K230_DEV_USB0].size);
> > +
> > +    create_unimplemented_device("usb1", memmap[K230_DEV_USB1].base,
> > +                                memmap[K230_DEV_USB1].size);
> > +
> > +    create_unimplemented_device("sd0", memmap[K230_DEV_SD0].base,
> > +                                memmap[K230_DEV_SD0].size);
> > +
> > +    create_unimplemented_device("sd1", memmap[K230_DEV_SD1].base,
> > +                                memmap[K230_DEV_SD1].size);
> > +
> > +    create_unimplemented_device("qspi0", memmap[K230_DEV_QSPI0].base,
> > +                                memmap[K230_DEV_QSPI0].size);
> > +
> > +    create_unimplemented_device("qspi1", memmap[K230_DEV_QSPI1].base,
> > +                                memmap[K230_DEV_QSPI1].size);
> > +
> > +    create_unimplemented_device("spi", memmap[K230_DEV_SPI].base,
> > +                                memmap[K230_DEV_SPI].size);
> > +
> > +    create_unimplemented_device("hi_sys_cfg", memmap[K230_DEV_HI_SYS_CFG].base,
> > +                                memmap[K230_DEV_HI_SYS_CFG].size);
> > +
> > +    create_unimplemented_device("ddrc_cfg", memmap[K230_DEV_DDRC_CFG].base,
> > +                                memmap[K230_DEV_DDRC_CFG].size);
> > +
> > +    create_unimplemented_device("flash", memmap[K230_DEV_FLASH].base,
> > +                                memmap[K230_DEV_FLASH].size);
> > +}
> > +
> > +static void k230_soc_class_init(ObjectClass *oc, const void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(oc);
> > +
> > +    dc->realize = k230_soc_realize;
> > +}
> > +
> > +static const TypeInfo k230_soc_type_info = {
> > +    .name = TYPE_RISCV_K230_SOC,
> > +    .parent = TYPE_DEVICE,
> > +    .instance_size = sizeof(K230SoCState),
> > +    .instance_init = k230_soc_init,
> > +    .class_init = k230_soc_class_init,
> > +};
> > +
> > +static void k230_soc_register_types(void)
> > +{
> > +    type_register_static(&k230_soc_type_info);
> > +}
> > +
> > +type_init(k230_soc_register_types)
> > +
> > +static void k230_machine_done(Notifier *notifier, void *data)
> > +{
> > +    K230MachineState *s = container_of(notifier, K230MachineState,
> > +                                     machine_done);
> > +    MachineState *machine = MACHINE(s);
> > +    hwaddr start_addr = memmap[K230_DEV_DDRC].base;
> > +    target_ulong firmware_end_addr, kernel_start_addr;
> > +    const char *firmware_name = riscv_default_firmware_name(&s->soc.c908_cpu);
> > +    uint64_t kernel_entry = 0;
> > +    RISCVBootInfo boot_info;
> > +
> > +    firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
> > +                                                     &start_addr, NULL);
> > +
> > +    /* Mask ROM reset vector */
> > +    uint32_t reset_vec[] = {
> > +        /* 0x91200000: auipc  t0, 0x0              */ 0x00000297,
> > +        /* 0x91200004: addi   t0, t0, 36 # <trap>  */ 0x03028293,
> > +        /* 0x91200008: csrw   mtvec, t0            */ 0x30529073,
> > +        /* 0x9120000C: csrr   a0, misa             */ 0x301012F3,
> > +        /* 0x91200010: lui    t0, 0x1              */ 0x000012B7,
> > +        /* 0x91200014: slli   t0, t0, 1            */ 0x00129293,
> > +        /* 0x91200018: and    t0, a0, t0           */ 0x005572B3,
> > +        /* 0x9120001C: bnez   t0, loop             */ 0x00511063,
> > +        /* entry:                                  */
> > +        /* 0x91200020: addiw  t0, zero, 1          */ 0x0010029b,
> > +        /* 0x91200024: slli   t0, t0, 0x1b         */ 0x01b29293,
> > +        /* 0x91200028: jr     t0 # uboot 0x8000000 */ 0x00028067,
> > +        /* loop:                                   */
> > +        /* 0x9120002C: j      0x9120002C # <loop>  */ 0x0000006f,
> > +        /* trap:                                   */
> > +        /* 0x91200030: j      0x91200030 # <trap>  */ 0x0000006f,
> > +    };
> 
> Why do we need a custom reset vector?
> 
> Can we at least comment why we need this and what it's doing
> 
The K230 SoC has two CPU cores. The big core has the V extension which
the little core locks, but mhartid is zero on both. To support both
cores going forward, I've customized the reset vector ROM to distinguish
the cores by the V extension. For now, we've only enabled the little
core, which can run Linux.

However, since I don't have plans to support both cores yet, I think
switching to the existing implementation would be the better choice.
Thanks for pointing it out, I will fix it in the next version.

Thanks,
Chao

> Alistair
> 
> > +
> > +    /* copy in the reset vector in little_endian byte order */
> > +    for (int i = 0; i < sizeof(reset_vec) >> 2; i++) {
> > +        reset_vec[i] = cpu_to_le32(reset_vec[i]);
> > +    }
> > +    rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
> > +                          memmap[K230_DEV_BOOTROM].base, &address_space_memory);
> > +
> > +    riscv_boot_info_init(&boot_info, &s->soc.c908_cpu);
> > +
> > +    if (machine->kernel_filename && !kernel_entry) {
> > +        kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
> > +                                                         firmware_end_addr);
> > +        riscv_load_kernel(machine, &boot_info, kernel_start_addr,
> > +                          true, NULL);
> > +        kernel_entry = boot_info.image_low_addr;
> > +    }
> > +}
> > +
> > +static void k230_machine_init(MachineState *machine)
> > +{
> > +    MachineClass *mc = MACHINE_GET_CLASS(machine);
> > +
> > +    K230MachineState *s = RISCV_K230_MACHINE(machine);
> > +    MemoryRegion *sys_mem = get_system_memory();
> > +
> > +    if (machine->ram_size < mc->default_ram_size) {
> > +        char *sz = size_to_str(mc->default_ram_size);
> > +        error_report("Invalid RAM size, should be %s", sz);
> > +        g_free(sz);
> > +        exit(EXIT_FAILURE);
> > +    }
> > +
> > +    /* Initialize SoC */
> > +    object_initialize_child(OBJECT(machine), "soc", &s->soc,
> > +                            TYPE_RISCV_K230_SOC);
> > +    qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
> > +
> > +    /* Data Memory */
> > +    memory_region_add_subregion(sys_mem, memmap[K230_DEV_DDRC].base,
> > +                                machine->ram);
> > +
> > +    s->machine_done.notify = k230_machine_done;
> > +    qemu_add_machine_init_done_notifier(&s->machine_done);
> > +}
> > +
> > +static void k230_machine_instance_init(Object *obj)
> > +{
> > +}
> > +
> > +static void k230_machine_class_init(ObjectClass *oc, const void *data)
> > +{
> > +    MachineClass *mc = MACHINE_CLASS(oc);
> > +
> > +    mc->desc = "RISC-V Board compatible with Kendryte K230 SDK";
> > +    mc->init = k230_machine_init;
> > +    mc->default_cpus = 2;
> > +    mc->default_ram_id = "riscv.K230.ram"; /* DDR */
> > +    mc->default_ram_size = memmap[K230_DEV_DDRC].size;
> > +}
> > +
> > +static const TypeInfo k230_machine_typeinfo = {
> > +    .name       = TYPE_RISCV_K230_MACHINE,
> > +    .parent     = TYPE_MACHINE,
> > +    .class_init = k230_machine_class_init,
> > +    .instance_init = k230_machine_instance_init,
> > +    .instance_size = sizeof(K230MachineState),
> > +};
> > +
> > +static void k230_machine_init_register_types(void)
> > +{
> > +    type_register_static(&k230_machine_typeinfo);
> > +}
> > +
> > +type_init(k230_machine_init_register_types)
> > diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build
> > index 533472e22a..09cf855984 100644
> > --- a/hw/riscv/meson.build
> > +++ b/hw/riscv/meson.build
> > @@ -14,8 +14,8 @@ riscv_ss.add(when: 'CONFIG_RISCV_IOMMU', if_true: files(
> >         'riscv-iommu.c', 'riscv-iommu-pci.c', 'riscv-iommu-sys.c', 'riscv-iommu-hpm.c'))
> >  riscv_ss.add(when: 'CONFIG_MICROBLAZE_V', if_true: files('microblaze-v-generic.c'))
> >  riscv_ss.add(when: 'CONFIG_XIANGSHAN_KUNMINGHU', if_true: files('xiangshan_kmh.c'))
> > -
> >  riscv_ss.add(when: 'CONFIG_RISCV_MIPS_CPS', if_true: files('cps.c'))
> >  riscv_ss.add(when: 'CONFIG_MIPS_BOSTON_AIA', if_true: files('boston-aia.c'))
> > +riscv_ss.add(when: 'CONFIG_K230', if_true: files('k230.c'))
> >
> >  hw_arch += {'riscv': riscv_ss}
> > diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h
> > new file mode 100644
> > index 0000000000..830175b756
> > --- /dev/null
> > +++ b/include/hw/riscv/k230.h
> > @@ -0,0 +1,150 @@
> > +/*
> > + * QEMU RISC-V Virt Board Compatible with kendryte K230 SDK
> > + *
> > + * Copyright (c) 2025 Chao Liu <chao.liu.zevorn@gmail.com>
> > + *
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + *
> > + * Provides a board compatible with the kendryte K230 SDK
> > + *
> > + * Documentation: K230_Technical_Reference_Manual_V0.3.1_20241118.pdf
> > + *
> > + * For more information, see <https://www.kendryte.com/en/proDetail/230>
> > + *
> > + * This program is free software; you can redistribute it and/or modify it
> > + * under the terms and conditions of the GNU General Public License,
> > + * version 2 or later, as published by the Free Software Foundation.
> > + *
> > + * This program is distributed in the hope it will be useful, but WITHOUT
> > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> > + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> > + * more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along with
> > + * this program.  If not, see <http://www.gnu.org/licenses/>.
> > + */
> > +#ifndef HW_K230_H
> > +#define HW_K230_H
> > +
> > +#include "hw/core/boards.h"
> > +#include "hw/riscv/riscv_hart.h"
> > +
> > +#define C908_CPU_HARTID   (0)
> > +
> > +#define TYPE_RISCV_K230_SOC "riscv.k230.soc"
> > +#define RISCV_K230_SOC(obj) \
> > +    OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC)
> > +
> > +typedef struct K230SoCState {
> > +    /*< private >*/
> > +    DeviceState parent_obj;
> > +
> > +    /*< public >*/
> > +    RISCVHartArrayState c908_cpu; /* Small core */
> > +
> > +    MemoryRegion sram;
> > +    MemoryRegion bootrom;
> > +
> > +    DeviceState *c908_plic;
> > +} K230SoCState;
> > +
> > +#define TYPE_RISCV_K230_MACHINE MACHINE_TYPE_NAME("k230")
> > +#define RISCV_K230_MACHINE(obj) \
> > +    OBJECT_CHECK(K230MachineState, (obj), TYPE_RISCV_K230_MACHINE)
> > +
> > +typedef struct K230MachineState {
> > +    /*< private >*/
> > +    MachineState parent_obj;
> > +
> > +    /*< public >*/
> > +    K230SoCState soc;
> > +    Notifier machine_done;
> > +} K230MachineState;
> > +
> > +enum {
> > +    K230_DEV_DDRC,
> > +    K230_DEV_KPU_L2_CACHE,
> > +    K230_DEV_SRAM,
> > +    K230_DEV_KPU_CFG,
> > +    K230_DEV_FFT,
> > +    K230_DEV_AI_2D_ENGINE,
> > +    K230_DEV_GSDMA,
> > +    K230_DEV_DMA,
> > +    K230_DEV_DECOMP_GZIP,
> > +    K230_DEV_NON_AI_2D,
> > +    K230_DEV_ISP,
> > +    K230_DEV_DEWARP,
> > +    K230_DEV_RX_CSI,
> > +    K230_DEV_H264,
> > +    K230_DEV_2P5D,
> > +    K230_DEV_VO,
> > +    K230_DEV_VO_CFG,
> > +    K230_DEV_3D_ENGINE,
> > +    K230_DEV_PMU,
> > +    K230_DEV_RTC,
> > +    K230_DEV_CMU,
> > +    K230_DEV_RMU,
> > +    K230_DEV_BOOT,
> > +    K230_DEV_PWR,
> > +    K230_DEV_MAILBOX,
> > +    K230_DEV_IOMUX,
> > +    K230_DEV_TIMER,
> > +    K230_DEV_WDT0,
> > +    K230_DEV_WDT1,
> > +    K230_DEV_TS,
> > +    K230_DEV_HDI,
> > +    K230_DEV_STC,
> > +    K230_DEV_BOOTROM,
> > +    K230_DEV_SECURITY,
> > +    K230_DEV_UART0,
> > +    K230_DEV_UART1,
> > +    K230_DEV_UART2,
> > +    K230_DEV_UART3,
> > +    K230_DEV_UART4,
> > +    K230_DEV_I2C0,
> > +    K230_DEV_I2C1,
> > +    K230_DEV_I2C2,
> > +    K230_DEV_I2C3,
> > +    K230_DEV_I2C4,
> > +    K230_DEV_PWM,
> > +    K230_DEV_GPIO0,
> > +    K230_DEV_GPIO1,
> > +    K230_DEV_ADC,
> > +    K230_DEV_CODEC,
> > +    K230_DEV_I2S,
> > +    K230_DEV_USB0,
> > +    K230_DEV_USB1,
> > +    K230_DEV_SD0,
> > +    K230_DEV_SD1,
> > +    K230_DEV_QSPI0,
> > +    K230_DEV_QSPI1,
> > +    K230_DEV_SPI,
> > +    K230_DEV_HI_SYS_CFG,
> > +    K230_DEV_DDRC_CFG,
> > +    K230_DEV_FLASH,
> > +    K230_DEV_PLIC,
> > +    K230_DEV_CLINT,
> > +};
> > +
> > +enum {
> > +    K230_UART0_IRQ  = 16,
> > +    K230_UART1_IRQ  = 17,
> > +    K230_UART2_IRQ  = 18,
> > +    K230_UART3_IRQ  = 19,
> > +    K230_UART4_IRQ  = 20,
> > +};
> > +
> > +/*
> > + * Integrates with the interrupt controller (PLIC),
> > + * which can process 208 interrupt external sources
> > + */
> > +#define K230_PLIC_NUM_SOURCES 208
> > +#define K230_PLIC_NUM_PRIORITIES 7
> > +#define K230_PLIC_PRIORITY_BASE 0x00
> > +#define K230_PLIC_PENDING_BASE 0x1000
> > +#define K230_PLIC_ENABLE_BASE 0x2000
> > +#define K230_PLIC_ENABLE_STRIDE 0x80
> > +#define K230_PLIC_CONTEXT_BASE 0x200000
> > +#define K230_PLIC_CONTEXT_STRIDE 0x1000
> > +
> > +#endif
> > --
> > 2.53.0
> >
> >


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v6 5/5] docs/system/riscv: add documentation for k230 machine
  2026-05-01  4:16   ` Alistair Francis
@ 2026-05-06  8:29     ` Chao Liu
  0 siblings, 0 replies; 20+ messages in thread
From: Chao Liu @ 2026-05-06  8:29 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Pierrick Bouvier, Palmer Dabbelt, Alistair Francis, Weiwei Li,
	Daniel Henrique Barboza, Liu Zhiwei, Paolo Bonzini,
	Christoph Muellner, Fabiano Rosas, Laurent Vivier, qemu-devel,
	qemu-riscv, Chao Liu, Daniel Henrique Barboza

On Fri, May 01, 2026 at 02:16:17PM +1000, Alistair Francis wrote:
> On Sat, Apr 18, 2026 at 1:13 AM Chao Liu <chao.liu.zevorn@gmail.com> wrote:
> >
> > From: Chao Liu <chao.liu@zevorn.cn>
> >
> > Add documentation for k230 virt reference platform.
> >
> > Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
> > Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> > ---
> >  MAINTAINERS                  |  1 +
> >  docs/system/riscv/k230.rst   | 48 ++++++++++++++++++++++++++++++++++++
> >  docs/system/target-riscv.rst |  1 +
> >  3 files changed, 50 insertions(+)
> >  create mode 100644 docs/system/riscv/k230.rst
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index b5b4acf6bd..d8d68cc123 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1776,6 +1776,7 @@ F: include/hw/riscv/xiangshan_kmh.h
> >  K230 Machines
> >  M: Chao Liu <chao.liu.zevorn@gmail.com>
> >  S: Maintained
> > +F: docs/system/riscv/k230.rst
> >  F: hw/riscv/k230.c
> >  F: hw/watchdog/k230_wdt.c
> >  F: include/hw/riscv/k230.h
> > diff --git a/docs/system/riscv/k230.rst b/docs/system/riscv/k230.rst
> > new file mode 100644
> > index 0000000000..3e6ca295df
> > --- /dev/null
> > +++ b/docs/system/riscv/k230.rst
> > @@ -0,0 +1,48 @@
> > +Kendryte K230 virt reference platform (``k230``)
> > +==========================================================================
> > +The ``k230`` machine is compatible with with Kendryte K230 SDK.
> > +
> > +The K230 is a chip from the AIoT SoC series made by Kendryte ® — a part of
> > +Canaan Inc. It uses a brand-new multi-heterogeneous unit accelerated computing
> > +structure.
> > +
> > +This chip has 2 RISC-V computing cores and a new-generation KPU (Knowledge
> > +Process Unit) smart computing unit.
> > +
> > +It has multi-precision AI computing ability, works with many common AI computing
> > +frameworks, and for some typical networks, its usage rate is over 70%. Besides,
> > +the K230 chip supports many peripheral connections and has several special
> > +hardware acceleration units (like 2D and 2.5D accelerators). It can speed up
> > +different tasks (such as image processing, video processing, audio processing
> > +and AI computing). It also has many good features: low delay, high performance,
> > +low power use and fast start-up.
> 
> This seems like a bit too much marketing, let's remove this paragraph.
> 
Okay.

> > +
> > +For more information, see <https://www.kendryte.com/en/proDetail/230>
> > +
> > +Supported devices
> > +-----------------
> > +The ``k230`` machine supports the following devices:
> > +
> > +* 1 c908 cores
> > +* Core Local Interruptor (CLINT)
> > +* Incoming MSI Controller (IMSIC)
> > +* 2 K230 Watchdog Timer
> > +* 4 UART
> > +
> > +Boot options
> > +------------
> > +The ``k230`` machine can start using the standard ``-bios``
> > +functionality for loading the boot image. You need to compile and link
> > +the firmware, kernel, and Device Tree (FDT) into a single binary file with
> > +K230 SDK(k230_canmv_defconfig), such as ``uboot``.
> > +
> > +Running
> > +-------
> > +Below is an example command line for running the ``k230``
> > +machine:
> > +
> > +.. code-block:: bash
> > +
> > +   $ qemu-system-riscv64 -machine k230 \
> > +      -bios k230_sdk/output/k230_canmv_defconfig/little/uboot/u-boot \
> > +      -nographic
> 
> Does -kernel not work?
> 
Thanks for the heads-up. I just tested booting Linux via U-Boot, but
ideally we should also support booting Linux with `-kernel`. I'll add
that in next version.

Thanks,
Chao
> Alistair


^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-05-06  8:30 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-17 15:11 [PATCH v6 0/5] Add support for K230 board Chao Liu
2026-04-17 15:11 ` [PATCH v6 1/5] target/riscv: add thead-c908 cpu support Chao Liu
2026-04-17 19:15   ` Conor Dooley
2026-04-17 23:02     ` Chao Liu
2026-04-18 12:18       ` Conor Dooley
2026-04-18 12:50         ` Chao Liu
2026-04-19 23:49   ` Alistair Francis
2026-04-20  3:37     ` Chao Liu
2026-05-01  4:02       ` Alistair Francis
2026-05-06  7:43         ` Chao Liu
2026-05-01  4:02   ` Alistair Francis
2026-04-17 15:11 ` [PATCH v6 2/5] hw/riscv: add k230 board initial support Chao Liu
2026-05-01  4:09   ` Alistair Francis
2026-05-06  7:44     ` Chao Liu
2026-05-06  8:22     ` Chao Liu
2026-04-17 15:11 ` [PATCH v6 3/5] hw/watchdog: add k230 watchdog " Chao Liu
2026-04-17 15:11 ` [PATCH v6 4/5] tests/qtest: add test for K230 watchdog Chao Liu
2026-04-17 15:11 ` [PATCH v6 5/5] docs/system/riscv: add documentation for k230 machine Chao Liu
2026-05-01  4:16   ` Alistair Francis
2026-05-06  8:29     ` Chao Liu

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.