qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far)
@ 2023-06-26 23:19 Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 01/16] target/riscv: Remove unused 'instmap.h' header in translate.c Philippe Mathieu-Daudé
                   ` (16 more replies)
  0 siblings, 17 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Hi,

this series reorder TCG specific code in order to easily
build a KVM-only binary. sysemu specific code is also
moved around, to help noticing invalid uses from user
emulation. Last patch adds a new job to our CI to avoid
this to bitrot.

Please review,

Phil.

Philippe Mathieu-Daudé (16):
  target/riscv: Remove unused 'instmap.h' header in translate.c
  target/riscv: Restrict KVM-specific fields from ArchCPU
  target/riscv: Restrict sysemu specific header to user emulation
  target/riscv: Restrict 'rv128' machine to TCG accelerator
  target/riscv: Move sysemu-specific files to target/riscv/sysemu/
  target/riscv: Restrict riscv_cpu_do_interrupt() to sysemu
  target/riscv: Move TCG-specific files to target/riscv/tcg/
  target/riscv: Move TCG-specific cpu_get_tb_cpu_state() to tcg/cpu.c
  target/riscv: Expose some 'trigger' prototypes from debug.c
  target/riscv: Extract TCG-specific code from debug.c
  target/riscv: Move sysemu-specific debug files to target/riscv/sysemu/
  target/riscv: Expose riscv_cpu_pending_to_irq() from cpu_helper.c
  target/riscv: Move TCG/sysemu-specific code to tcg/sysemu/cpu_helper.c
  target/riscv: Move sysemu-specific code to sysemu/cpu_helper.c
  target/riscv: Restrict TCG-specific prototype declarations
  gitlab-ci.d/crossbuilds: Add KVM riscv64 cross-build jobs

 target/riscv/cpu.h                            |   29 +-
 target/riscv/internals.h                      |    4 +
 target/riscv/{ => sysemu}/debug.h             |    6 +
 target/riscv/{ => sysemu}/instmap.h           |    0
 target/riscv/{ => sysemu}/kvm_riscv.h         |    0
 target/riscv/{ => sysemu}/pmp.h               |    0
 target/riscv/{ => sysemu}/pmu.h               |    0
 target/riscv/{ => sysemu}/time_helper.h       |    0
 target/riscv/{ => tcg}/XVentanaCondOps.decode |    0
 target/riscv/{ => tcg}/insn16.decode          |    0
 target/riscv/{ => tcg}/insn32.decode          |    0
 target/riscv/{ => tcg}/xthead.decode          |    0
 hw/riscv/virt.c                               |    2 +-
 target/riscv/cpu.c                            |   35 +-
 target/riscv/cpu_helper.c                     | 1692 +----------------
 target/riscv/csr.c                            |    6 +-
 target/riscv/{ => sysemu}/arch_dump.c         |    0
 target/riscv/sysemu/cpu_helper.c              |  863 +++++++++
 target/riscv/{ => sysemu}/debug.c             |  153 +-
 target/riscv/{ => sysemu}/kvm-stub.c          |    0
 target/riscv/{ => sysemu}/kvm.c               |    0
 target/riscv/{ => sysemu}/machine.c           |    8 +-
 target/riscv/{ => sysemu}/monitor.c           |    0
 target/riscv/{ => sysemu}/pmp.c               |    0
 target/riscv/{ => sysemu}/pmu.c               |    0
 target/riscv/{ => sysemu}/riscv-qmp-cmds.c    |    0
 target/riscv/{ => sysemu}/time_helper.c       |    0
 target/riscv/{ => tcg}/bitmanip_helper.c      |    0
 target/riscv/tcg/cpu.c                        |   97 +
 target/riscv/{ => tcg}/crypto_helper.c        |    0
 target/riscv/{ => tcg}/fpu_helper.c           |    0
 target/riscv/{ => tcg}/m128_helper.c          |    0
 target/riscv/{ => tcg}/op_helper.c            |    0
 target/riscv/tcg/sysemu/cpu_helper.c          |  766 ++++++++
 target/riscv/tcg/sysemu/debug.c               |  165 ++
 target/riscv/tcg/tcg-stub.c                   |   31 +
 target/riscv/{ => tcg}/translate.c            |    1 -
 target/riscv/{ => tcg}/vector_helper.c        |    0
 target/riscv/{ => tcg}/zce_helper.c           |    0
 .gitlab-ci.d/crossbuilds.yml                  |    8 +
 target/riscv/meson.build                      |   33 +-
 target/riscv/sysemu/meson.build               |   14 +
 target/riscv/tcg/meson.build                  |   22 +
 target/riscv/tcg/sysemu/meson.build           |    4 +
 44 files changed, 2046 insertions(+), 1893 deletions(-)
 rename target/riscv/{ => sysemu}/debug.h (96%)
 rename target/riscv/{ => sysemu}/instmap.h (100%)
 rename target/riscv/{ => sysemu}/kvm_riscv.h (100%)
 rename target/riscv/{ => sysemu}/pmp.h (100%)
 rename target/riscv/{ => sysemu}/pmu.h (100%)
 rename target/riscv/{ => sysemu}/time_helper.h (100%)
 rename target/riscv/{ => tcg}/XVentanaCondOps.decode (100%)
 rename target/riscv/{ => tcg}/insn16.decode (100%)
 rename target/riscv/{ => tcg}/insn32.decode (100%)
 rename target/riscv/{ => tcg}/xthead.decode (100%)
 rename target/riscv/{ => sysemu}/arch_dump.c (100%)
 create mode 100644 target/riscv/sysemu/cpu_helper.c
 rename target/riscv/{ => sysemu}/debug.c (83%)
 rename target/riscv/{ => sysemu}/kvm-stub.c (100%)
 rename target/riscv/{ => sysemu}/kvm.c (100%)
 rename target/riscv/{ => sysemu}/machine.c (98%)
 rename target/riscv/{ => sysemu}/monitor.c (100%)
 rename target/riscv/{ => sysemu}/pmp.c (100%)
 rename target/riscv/{ => sysemu}/pmu.c (100%)
 rename target/riscv/{ => sysemu}/riscv-qmp-cmds.c (100%)
 rename target/riscv/{ => sysemu}/time_helper.c (100%)
 rename target/riscv/{ => tcg}/bitmanip_helper.c (100%)
 create mode 100644 target/riscv/tcg/cpu.c
 rename target/riscv/{ => tcg}/crypto_helper.c (100%)
 rename target/riscv/{ => tcg}/fpu_helper.c (100%)
 rename target/riscv/{ => tcg}/m128_helper.c (100%)
 rename target/riscv/{ => tcg}/op_helper.c (100%)
 create mode 100644 target/riscv/tcg/sysemu/cpu_helper.c
 create mode 100644 target/riscv/tcg/sysemu/debug.c
 create mode 100644 target/riscv/tcg/tcg-stub.c
 rename target/riscv/{ => tcg}/translate.c (99%)
 rename target/riscv/{ => tcg}/vector_helper.c (100%)
 rename target/riscv/{ => tcg}/zce_helper.c (100%)
 create mode 100644 target/riscv/sysemu/meson.build
 create mode 100644 target/riscv/tcg/meson.build
 create mode 100644 target/riscv/tcg/sysemu/meson.build

-- 
2.38.1



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

* [PATCH 01/16] target/riscv: Remove unused 'instmap.h' header in translate.c
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
@ 2023-06-26 23:19 ` Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 02/16] target/riscv: Restrict KVM-specific fields from ArchCPU Philippe Mathieu-Daudé
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/translate.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 8a33da811e..bd33bc3f51 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -30,7 +30,6 @@
 #include "exec/log.h"
 #include "semihosting/semihost.h"
 
-#include "instmap.h"
 #include "internals.h"
 
 #define HELPER_H "helper.h"
-- 
2.38.1



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

* [PATCH 02/16] target/riscv: Restrict KVM-specific fields from ArchCPU
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 01/16] target/riscv: Remove unused 'instmap.h' header in translate.c Philippe Mathieu-Daudé
@ 2023-06-26 23:19 ` Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 03/16] target/riscv: Restrict sysemu specific header to user emulation Philippe Mathieu-Daudé
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

These fields shouldn't be accessed when KVM is not available.

Restrict the KVM timer migration state. Rename the KVM timer
post_load() handler accordingly, because cpu_post_load() is
too generic.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
---
 target/riscv/cpu.h     | 2 ++
 target/riscv/cpu.c     | 2 +-
 target/riscv/machine.c | 8 ++++++--
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index e3e08d315f..b1b56aa29e 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -363,12 +363,14 @@ struct CPUArchState {
     hwaddr kernel_addr;
     hwaddr fdt_addr;
 
+#ifdef CONFIG_KVM
     /* kvm timer */
     bool kvm_timer_dirty;
     uint64_t kvm_timer_time;
     uint64_t kvm_timer_compare;
     uint64_t kvm_timer_state;
     uint64_t kvm_timer_frequency;
+#endif /* CONFIG_KVM */
 };
 
 /*
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 881bddf393..4035fe0e62 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -584,7 +584,7 @@ static void riscv_host_cpu_init(Object *obj)
 #endif
     riscv_cpu_add_user_properties(obj);
 }
-#endif
+#endif /* CONFIG_KVM */
 
 static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model)
 {
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 3ce2970785..c7c862cdd3 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -194,12 +194,13 @@ static const VMStateDescription vmstate_rv128 = {
     }
 };
 
+#ifdef CONFIG_KVM
 static bool kvmtimer_needed(void *opaque)
 {
     return kvm_enabled();
 }
 
-static int cpu_post_load(void *opaque, int version_id)
+static int cpu_kvmtimer_post_load(void *opaque, int version_id)
 {
     RISCVCPU *cpu = opaque;
     CPURISCVState *env = &cpu->env;
@@ -213,7 +214,7 @@ static const VMStateDescription vmstate_kvmtimer = {
     .version_id = 1,
     .minimum_version_id = 1,
     .needed = kvmtimer_needed,
-    .post_load = cpu_post_load,
+    .post_load = cpu_kvmtimer_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_UINT64(env.kvm_timer_time, RISCVCPU),
         VMSTATE_UINT64(env.kvm_timer_compare, RISCVCPU),
@@ -221,6 +222,7 @@ static const VMStateDescription vmstate_kvmtimer = {
         VMSTATE_END_OF_LIST()
     }
 };
+#endif
 
 static bool debug_needed(void *opaque)
 {
@@ -409,7 +411,9 @@ const VMStateDescription vmstate_riscv_cpu = {
         &vmstate_vector,
         &vmstate_pointermasking,
         &vmstate_rv128,
+#ifdef CONFIG_KVM
         &vmstate_kvmtimer,
+#endif
         &vmstate_envcfg,
         &vmstate_debug,
         &vmstate_smstateen,
-- 
2.38.1



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

* [PATCH 03/16] target/riscv: Restrict sysemu specific header to user emulation
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 01/16] target/riscv: Remove unused 'instmap.h' header in translate.c Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 02/16] target/riscv: Restrict KVM-specific fields from ArchCPU Philippe Mathieu-Daudé
@ 2023-06-26 23:19 ` Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 04/16] target/riscv: Restrict 'rv128' machine to TCG accelerator Philippe Mathieu-Daudé
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/cpu.c        | 8 +++++---
 target/riscv/cpu_helper.c | 2 ++
 target/riscv/csr.c        | 2 ++
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 4035fe0e62..175dbc9826 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -23,9 +23,13 @@
 #include "qemu/log.h"
 #include "cpu.h"
 #include "cpu_vendorid.h"
+#ifndef CONFIG_USER_ONLY
 #include "pmu.h"
-#include "internals.h"
 #include "time_helper.h"
+#include "sysemu/kvm.h"
+#include "kvm_riscv.h"
+#endif
+#include "internals.h"
 #include "exec/exec-all.h"
 #include "qapi/error.h"
 #include "qapi/visitor.h"
@@ -33,8 +37,6 @@
 #include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
 #include "fpu/softfloat-helpers.h"
-#include "sysemu/kvm.h"
-#include "kvm_riscv.h"
 #include "tcg/tcg.h"
 
 /* RISC-V CPU definitions */
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 90cef9856d..d871718e5d 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -28,7 +28,9 @@
 #include "tcg/tcg-op.h"
 #include "trace.h"
 #include "semihosting/common-semi.h"
+#ifndef CONFIG_USER_ONLY
 #include "sysemu/cpu-timers.h"
+#endif
 #include "cpu_bits.h"
 #include "debug.h"
 #include "tcg/oversized-guest.h"
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 58499b5afc..936ba2be24 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -21,8 +21,10 @@
 #include "qemu/log.h"
 #include "qemu/timer.h"
 #include "cpu.h"
+#ifndef CONFIG_USER_ONLY
 #include "pmu.h"
 #include "time_helper.h"
+#endif
 #include "qemu/main-loop.h"
 #include "exec/exec-all.h"
 #include "exec/tb-flush.h"
-- 
2.38.1



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

* [PATCH 04/16] target/riscv: Restrict 'rv128' machine to TCG accelerator
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (2 preceding siblings ...)
  2023-06-26 23:19 ` [PATCH 03/16] target/riscv: Restrict sysemu specific header to user emulation Philippe Mathieu-Daudé
@ 2023-06-26 23:19 ` Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 05/16] target/riscv: Move sysemu-specific files to target/riscv/sysemu/ Philippe Mathieu-Daudé
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

We only build for 32/64-bit hosts, so TCG is required for
128-bit targets.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/cpu.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 175dbc9826..7f281cdcf6 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -473,6 +473,7 @@ static void rv64_veyron_v1_cpu_init(Object *obj)
 #endif
 }
 
+#ifdef CONFIG_TCG
 static void rv128_base_cpu_init(Object *obj)
 {
     if (qemu_tcg_mttcg_enabled()) {
@@ -491,7 +492,10 @@ static void rv128_base_cpu_init(Object *obj)
     set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57);
 #endif
 }
-#else
+#endif
+
+#else /* !TARGET_RISCV64 */
+
 static void rv32_base_cpu_init(Object *obj)
 {
     CPURISCVState *env = &RISCV_CPU(obj)->env;
@@ -573,7 +577,7 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
     cpu->cfg.ext_icsr = true;
     cpu->cfg.pmp = true;
 }
-#endif
+#endif /* !TARGET_RISCV64 */
 
 #if defined(CONFIG_KVM)
 static void riscv_host_cpu_init(Object *obj)
@@ -1947,8 +1951,10 @@ static const TypeInfo riscv_cpu_type_infos[] = {
     DEFINE_CPU(TYPE_RISCV_CPU_SHAKTI_C,         rv64_sifive_u_cpu_init),
     DEFINE_CPU(TYPE_RISCV_CPU_THEAD_C906,       rv64_thead_c906_cpu_init),
     DEFINE_CPU(TYPE_RISCV_CPU_VEYRON_V1,        rv64_veyron_v1_cpu_init),
+#ifdef CONFIG_TCG
     DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128,  rv128_base_cpu_init),
-#endif
+#endif /* CONFIG_TCG */
+#endif /* TARGET_RISCV64 */
 };
 
 DEFINE_TYPES(riscv_cpu_type_infos)
-- 
2.38.1



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

* [PATCH 05/16] target/riscv: Move sysemu-specific files to target/riscv/sysemu/
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (3 preceding siblings ...)
  2023-06-26 23:19 ` [PATCH 04/16] target/riscv: Restrict 'rv128' machine to TCG accelerator Philippe Mathieu-Daudé
@ 2023-06-26 23:19 ` Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 06/16] target/riscv: Restrict riscv_cpu_do_interrupt() to sysemu Philippe Mathieu-Daudé
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Move sysemu-specific files to the a new 'sysemu' sub-directory,
adapt meson rules.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/cpu.h                         |  2 +-
 target/riscv/{ => sysemu}/instmap.h        |  0
 target/riscv/{ => sysemu}/kvm_riscv.h      |  0
 target/riscv/{ => sysemu}/pmp.h            |  0
 target/riscv/{ => sysemu}/pmu.h            |  0
 target/riscv/{ => sysemu}/time_helper.h    |  0
 hw/riscv/virt.c                            |  2 +-
 target/riscv/cpu.c                         |  6 +++---
 target/riscv/cpu_helper.c                  |  4 ++--
 target/riscv/csr.c                         |  4 ++--
 target/riscv/{ => sysemu}/arch_dump.c      |  0
 target/riscv/{ => sysemu}/kvm-stub.c       |  0
 target/riscv/{ => sysemu}/kvm.c            |  0
 target/riscv/{ => sysemu}/machine.c        |  0
 target/riscv/{ => sysemu}/monitor.c        |  0
 target/riscv/{ => sysemu}/pmp.c            |  0
 target/riscv/{ => sysemu}/pmu.c            |  0
 target/riscv/{ => sysemu}/riscv-qmp-cmds.c |  0
 target/riscv/{ => sysemu}/time_helper.c    |  0
 target/riscv/meson.build                   | 13 ++++---------
 target/riscv/sysemu/meson.build            | 12 ++++++++++++
 21 files changed, 25 insertions(+), 18 deletions(-)
 rename target/riscv/{ => sysemu}/instmap.h (100%)
 rename target/riscv/{ => sysemu}/kvm_riscv.h (100%)
 rename target/riscv/{ => sysemu}/pmp.h (100%)
 rename target/riscv/{ => sysemu}/pmu.h (100%)
 rename target/riscv/{ => sysemu}/time_helper.h (100%)
 rename target/riscv/{ => sysemu}/arch_dump.c (100%)
 rename target/riscv/{ => sysemu}/kvm-stub.c (100%)
 rename target/riscv/{ => sysemu}/kvm.c (100%)
 rename target/riscv/{ => sysemu}/machine.c (100%)
 rename target/riscv/{ => sysemu}/monitor.c (100%)
 rename target/riscv/{ => sysemu}/pmp.c (100%)
 rename target/riscv/{ => sysemu}/pmu.c (100%)
 rename target/riscv/{ => sysemu}/riscv-qmp-cmds.c (100%)
 rename target/riscv/{ => sysemu}/time_helper.c (100%)
 create mode 100644 target/riscv/sysemu/meson.build

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index b1b56aa29e..83a9a965d1 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -88,7 +88,7 @@ typedef enum {
 #define MAX_RISCV_PMPS (16)
 
 #if !defined(CONFIG_USER_ONLY)
-#include "pmp.h"
+#include "sysemu/pmp.h"
 #include "debug.h"
 #endif
 
diff --git a/target/riscv/instmap.h b/target/riscv/sysemu/instmap.h
similarity index 100%
rename from target/riscv/instmap.h
rename to target/riscv/sysemu/instmap.h
diff --git a/target/riscv/kvm_riscv.h b/target/riscv/sysemu/kvm_riscv.h
similarity index 100%
rename from target/riscv/kvm_riscv.h
rename to target/riscv/sysemu/kvm_riscv.h
diff --git a/target/riscv/pmp.h b/target/riscv/sysemu/pmp.h
similarity index 100%
rename from target/riscv/pmp.h
rename to target/riscv/sysemu/pmp.h
diff --git a/target/riscv/pmu.h b/target/riscv/sysemu/pmu.h
similarity index 100%
rename from target/riscv/pmu.h
rename to target/riscv/sysemu/pmu.h
diff --git a/target/riscv/time_helper.h b/target/riscv/sysemu/time_helper.h
similarity index 100%
rename from target/riscv/time_helper.h
rename to target/riscv/sysemu/time_helper.h
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index 95708d890e..11f9577004 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -30,7 +30,7 @@
 #include "hw/char/serial.h"
 #include "target/riscv/cpu.h"
 #include "hw/core/sysbus-fdt.h"
-#include "target/riscv/pmu.h"
+#include "target/riscv/sysemu/pmu.h"
 #include "hw/riscv/riscv_hart.h"
 #include "hw/riscv/virt.h"
 #include "hw/riscv/boot.h"
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7f281cdcf6..a1513bf5cc 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -24,10 +24,10 @@
 #include "cpu.h"
 #include "cpu_vendorid.h"
 #ifndef CONFIG_USER_ONLY
-#include "pmu.h"
-#include "time_helper.h"
+#include "sysemu/pmu.h"
+#include "sysemu/time_helper.h"
 #include "sysemu/kvm.h"
-#include "kvm_riscv.h"
+#include "sysemu/kvm_riscv.h"
 #endif
 #include "internals.h"
 #include "exec/exec-all.h"
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index d871718e5d..5ff48be561 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -22,9 +22,9 @@
 #include "qemu/main-loop.h"
 #include "cpu.h"
 #include "internals.h"
-#include "pmu.h"
+#include "sysemu/pmu.h"
 #include "exec/exec-all.h"
-#include "instmap.h"
+#include "sysemu/instmap.h"
 #include "tcg/tcg-op.h"
 #include "trace.h"
 #include "semihosting/common-semi.h"
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 936ba2be24..788d169502 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -22,8 +22,8 @@
 #include "qemu/timer.h"
 #include "cpu.h"
 #ifndef CONFIG_USER_ONLY
-#include "pmu.h"
-#include "time_helper.h"
+#include "sysemu/pmu.h"
+#include "sysemu/time_helper.h"
 #endif
 #include "qemu/main-loop.h"
 #include "exec/exec-all.h"
diff --git a/target/riscv/arch_dump.c b/target/riscv/sysemu/arch_dump.c
similarity index 100%
rename from target/riscv/arch_dump.c
rename to target/riscv/sysemu/arch_dump.c
diff --git a/target/riscv/kvm-stub.c b/target/riscv/sysemu/kvm-stub.c
similarity index 100%
rename from target/riscv/kvm-stub.c
rename to target/riscv/sysemu/kvm-stub.c
diff --git a/target/riscv/kvm.c b/target/riscv/sysemu/kvm.c
similarity index 100%
rename from target/riscv/kvm.c
rename to target/riscv/sysemu/kvm.c
diff --git a/target/riscv/machine.c b/target/riscv/sysemu/machine.c
similarity index 100%
rename from target/riscv/machine.c
rename to target/riscv/sysemu/machine.c
diff --git a/target/riscv/monitor.c b/target/riscv/sysemu/monitor.c
similarity index 100%
rename from target/riscv/monitor.c
rename to target/riscv/sysemu/monitor.c
diff --git a/target/riscv/pmp.c b/target/riscv/sysemu/pmp.c
similarity index 100%
rename from target/riscv/pmp.c
rename to target/riscv/sysemu/pmp.c
diff --git a/target/riscv/pmu.c b/target/riscv/sysemu/pmu.c
similarity index 100%
rename from target/riscv/pmu.c
rename to target/riscv/sysemu/pmu.c
diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/sysemu/riscv-qmp-cmds.c
similarity index 100%
rename from target/riscv/riscv-qmp-cmds.c
rename to target/riscv/sysemu/riscv-qmp-cmds.c
diff --git a/target/riscv/time_helper.c b/target/riscv/sysemu/time_helper.c
similarity index 100%
rename from target/riscv/time_helper.c
rename to target/riscv/sysemu/time_helper.c
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 7f56c5f88d..8967dfaded 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -7,6 +7,8 @@ gen = [
 ]
 
 riscv_ss = ss.source_set()
+riscv_system_ss = ss.source_set()
+
 riscv_ss.add(gen)
 riscv_ss.add(files(
   'cpu.c',
@@ -22,19 +24,12 @@ riscv_ss.add(files(
   'crypto_helper.c',
   'zce_helper.c'
 ))
-riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'), if_false: files('kvm-stub.c'))
 
-riscv_system_ss = ss.source_set()
 riscv_system_ss.add(files(
-  'arch_dump.c',
-  'pmp.c',
   'debug.c',
-  'monitor.c',
-  'machine.c',
-  'pmu.c',
-  'time_helper.c',
-  'riscv-qmp-cmds.c',
 ))
 
+subdir('sysemu')
+
 target_arch += {'riscv': riscv_ss}
 target_softmmu_arch += {'riscv': riscv_system_ss}
diff --git a/target/riscv/sysemu/meson.build b/target/riscv/sysemu/meson.build
new file mode 100644
index 0000000000..5f8e1edcf2
--- /dev/null
+++ b/target/riscv/sysemu/meson.build
@@ -0,0 +1,12 @@
+riscv_system_ss.add(files(
+  'arch_dump.c',
+  'machine.c',
+  'monitor.c',
+  'pmp.c',
+  'pmu.c',
+  'riscv-qmp-cmds.c',
+  'time_helper.c',
+))
+
+riscv_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'),
+                                 if_false: files('kvm-stub.c'))
-- 
2.38.1



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

* [PATCH 06/16] target/riscv: Restrict riscv_cpu_do_interrupt() to sysemu
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (4 preceding siblings ...)
  2023-06-26 23:19 ` [PATCH 05/16] target/riscv: Move sysemu-specific files to target/riscv/sysemu/ Philippe Mathieu-Daudé
@ 2023-06-26 23:19 ` Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 07/16] target/riscv: Move TCG-specific files to target/riscv/tcg/ Philippe Mathieu-Daudé
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

riscv_cpu_do_interrupt() is not reachable on user emulation.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/cpu.h        | 5 +++--
 target/riscv/cpu_helper.c | 7 ++-----
 2 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 83a9a965d1..288df4c2b1 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -411,7 +411,6 @@ extern const char * const riscv_int_regnamesh[];
 extern const char * const riscv_fpr_regnames[];
 
 const char *riscv_cpu_get_trap_name(target_ulong cause, bool async);
-void riscv_cpu_do_interrupt(CPUState *cpu);
 int riscv_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
                                int cpuid, DumpState *s);
 int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
@@ -444,6 +443,7 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
 #define cpu_mmu_index riscv_cpu_mmu_index
 
 #ifndef CONFIG_USER_ONLY
+void riscv_cpu_do_interrupt(CPUState *cpu);
 void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
                                      vaddr addr, unsigned size,
                                      MMUAccessType access_type,
@@ -467,7 +467,8 @@ void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
                                    void *rmw_fn_arg);
 
 RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
-#endif
+#endif /* !CONFIG_USER_ONLY */
+
 void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
 
 void riscv_translate_init(void);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 5ff48be561..cc0050d110 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1575,7 +1575,6 @@ static target_ulong riscv_transformed_insn(CPURISCVState *env,
 
     return xinsn;
 }
-#endif /* !CONFIG_USER_ONLY */
 
 /*
  * Handle Traps
@@ -1585,8 +1584,6 @@ static target_ulong riscv_transformed_insn(CPURISCVState *env,
  */
 void riscv_cpu_do_interrupt(CPUState *cs)
 {
-#if !defined(CONFIG_USER_ONLY)
-
     RISCVCPU *cpu = RISCV_CPU(cs);
     CPURISCVState *env = &cpu->env;
     bool write_gva = false;
@@ -1779,6 +1776,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 
     env->two_stage_lookup = false;
     env->two_stage_indirect_lookup = false;
-#endif
-    cs->exception_index = RISCV_EXCP_NONE; /* mark handled to qemu */
 }
+
+#endif /* !CONFIG_USER_ONLY */
-- 
2.38.1



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

* [PATCH 07/16] target/riscv: Move TCG-specific files to target/riscv/tcg/
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (5 preceding siblings ...)
  2023-06-26 23:19 ` [PATCH 06/16] target/riscv: Restrict riscv_cpu_do_interrupt() to sysemu Philippe Mathieu-Daudé
@ 2023-06-26 23:19 ` Philippe Mathieu-Daudé
  2023-06-26 23:19 ` [PATCH 08/16] target/riscv: Move TCG-specific cpu_get_tb_cpu_state() to tcg/cpu.c Philippe Mathieu-Daudé
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Move TCG-specific files to the a new 'tcg' sub-directory. Add
stubs for riscv_cpu_[get/set]_fflags and riscv_raise_exception().
Adapt meson rules.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/{ => tcg}/XVentanaCondOps.decode |  0
 target/riscv/{ => tcg}/insn16.decode          |  0
 target/riscv/{ => tcg}/insn32.decode          |  0
 target/riscv/{ => tcg}/xthead.decode          |  0
 target/riscv/{ => tcg}/bitmanip_helper.c      |  0
 target/riscv/{ => tcg}/crypto_helper.c        |  0
 target/riscv/{ => tcg}/fpu_helper.c           |  0
 target/riscv/{ => tcg}/m128_helper.c          |  0
 target/riscv/{ => tcg}/op_helper.c            |  0
 target/riscv/tcg/tcg-stub.c                   | 25 +++++++++++++++++++
 target/riscv/{ => tcg}/translate.c            |  0
 target/riscv/{ => tcg}/vector_helper.c        |  0
 target/riscv/{ => tcg}/zce_helper.c           |  0
 target/riscv/meson.build                      | 18 +------------
 target/riscv/tcg/meson.build                  | 19 ++++++++++++++
 15 files changed, 45 insertions(+), 17 deletions(-)
 rename target/riscv/{ => tcg}/XVentanaCondOps.decode (100%)
 rename target/riscv/{ => tcg}/insn16.decode (100%)
 rename target/riscv/{ => tcg}/insn32.decode (100%)
 rename target/riscv/{ => tcg}/xthead.decode (100%)
 rename target/riscv/{ => tcg}/bitmanip_helper.c (100%)
 rename target/riscv/{ => tcg}/crypto_helper.c (100%)
 rename target/riscv/{ => tcg}/fpu_helper.c (100%)
 rename target/riscv/{ => tcg}/m128_helper.c (100%)
 rename target/riscv/{ => tcg}/op_helper.c (100%)
 create mode 100644 target/riscv/tcg/tcg-stub.c
 rename target/riscv/{ => tcg}/translate.c (100%)
 rename target/riscv/{ => tcg}/vector_helper.c (100%)
 rename target/riscv/{ => tcg}/zce_helper.c (100%)
 create mode 100644 target/riscv/tcg/meson.build

diff --git a/target/riscv/XVentanaCondOps.decode b/target/riscv/tcg/XVentanaCondOps.decode
similarity index 100%
rename from target/riscv/XVentanaCondOps.decode
rename to target/riscv/tcg/XVentanaCondOps.decode
diff --git a/target/riscv/insn16.decode b/target/riscv/tcg/insn16.decode
similarity index 100%
rename from target/riscv/insn16.decode
rename to target/riscv/tcg/insn16.decode
diff --git a/target/riscv/insn32.decode b/target/riscv/tcg/insn32.decode
similarity index 100%
rename from target/riscv/insn32.decode
rename to target/riscv/tcg/insn32.decode
diff --git a/target/riscv/xthead.decode b/target/riscv/tcg/xthead.decode
similarity index 100%
rename from target/riscv/xthead.decode
rename to target/riscv/tcg/xthead.decode
diff --git a/target/riscv/bitmanip_helper.c b/target/riscv/tcg/bitmanip_helper.c
similarity index 100%
rename from target/riscv/bitmanip_helper.c
rename to target/riscv/tcg/bitmanip_helper.c
diff --git a/target/riscv/crypto_helper.c b/target/riscv/tcg/crypto_helper.c
similarity index 100%
rename from target/riscv/crypto_helper.c
rename to target/riscv/tcg/crypto_helper.c
diff --git a/target/riscv/fpu_helper.c b/target/riscv/tcg/fpu_helper.c
similarity index 100%
rename from target/riscv/fpu_helper.c
rename to target/riscv/tcg/fpu_helper.c
diff --git a/target/riscv/m128_helper.c b/target/riscv/tcg/m128_helper.c
similarity index 100%
rename from target/riscv/m128_helper.c
rename to target/riscv/tcg/m128_helper.c
diff --git a/target/riscv/op_helper.c b/target/riscv/tcg/op_helper.c
similarity index 100%
rename from target/riscv/op_helper.c
rename to target/riscv/tcg/op_helper.c
diff --git a/target/riscv/tcg/tcg-stub.c b/target/riscv/tcg/tcg-stub.c
new file mode 100644
index 0000000000..dfe42ae2ac
--- /dev/null
+++ b/target/riscv/tcg/tcg-stub.c
@@ -0,0 +1,25 @@
+/*
+ * QEMU RISC-V TCG stubs
+ *
+ * Copyright (c) 2023 Linaro
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+#include "cpu.h"
+
+target_ulong riscv_cpu_get_fflags(CPURISCVState *env)
+{
+    g_assert_not_reached();
+}
+
+void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong)
+{
+    g_assert_not_reached();
+}
+
+G_NORETURN void riscv_raise_exception(CPURISCVState *env,
+                                      uint32_t exception, uintptr_t pc)
+{
+    g_assert_not_reached();
+}
diff --git a/target/riscv/translate.c b/target/riscv/tcg/translate.c
similarity index 100%
rename from target/riscv/translate.c
rename to target/riscv/tcg/translate.c
diff --git a/target/riscv/vector_helper.c b/target/riscv/tcg/vector_helper.c
similarity index 100%
rename from target/riscv/vector_helper.c
rename to target/riscv/tcg/vector_helper.c
diff --git a/target/riscv/zce_helper.c b/target/riscv/tcg/zce_helper.c
similarity index 100%
rename from target/riscv/zce_helper.c
rename to target/riscv/tcg/zce_helper.c
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 8967dfaded..8ef47f43f9 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -1,34 +1,18 @@
-# FIXME extra_args should accept files()
-gen = [
-  decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']),
-  decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'),
-  decodetree.process('xthead.decode', extra_args: '--static-decode=decode_xthead'),
-  decodetree.process('XVentanaCondOps.decode', extra_args: '--static-decode=decode_XVentanaCodeOps'),
-]
-
 riscv_ss = ss.source_set()
 riscv_system_ss = ss.source_set()
 
-riscv_ss.add(gen)
 riscv_ss.add(files(
   'cpu.c',
   'cpu_helper.c',
   'csr.c',
-  'fpu_helper.c',
   'gdbstub.c',
-  'op_helper.c',
-  'vector_helper.c',
-  'bitmanip_helper.c',
-  'translate.c',
-  'm128_helper.c',
-  'crypto_helper.c',
-  'zce_helper.c'
 ))
 
 riscv_system_ss.add(files(
   'debug.c',
 ))
 
+subdir('tcg')
 subdir('sysemu')
 
 target_arch += {'riscv': riscv_ss}
diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
new file mode 100644
index 0000000000..65670493b1
--- /dev/null
+++ b/target/riscv/tcg/meson.build
@@ -0,0 +1,19 @@
+# FIXME extra_args should accept files()
+gen = [
+  decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']),
+  decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'),
+  decodetree.process('xthead.decode', extra_args: '--static-decode=decode_xthead'),
+  decodetree.process('XVentanaCondOps.decode', extra_args: '--static-decode=decode_XVentanaCodeOps'),
+]
+riscv_ss.add(when: 'CONFIG_TCG', if_true: gen)
+
+riscv_ss.add(when: 'CONFIG_TCG', if_true: files(
+  'fpu_helper.c',
+  'op_helper.c',
+  'vector_helper.c',
+  'bitmanip_helper.c',
+  'translate.c',
+  'm128_helper.c',
+  'crypto_helper.c',
+  'zce_helper.c',
+), if_false: files('tcg-stub.c'))
-- 
2.38.1



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

* [PATCH 08/16] target/riscv: Move TCG-specific cpu_get_tb_cpu_state() to tcg/cpu.c
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (6 preceding siblings ...)
  2023-06-26 23:19 ` [PATCH 07/16] target/riscv: Move TCG-specific files to target/riscv/tcg/ Philippe Mathieu-Daudé
@ 2023-06-26 23:19 ` Philippe Mathieu-Daudé
  2023-06-26 23:20 ` [PATCH 09/16] target/riscv: Expose some 'trigger' prototypes from debug.c Philippe Mathieu-Daudé
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:19 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/cpu_helper.c    | 83 ------------------------------
 target/riscv/tcg/cpu.c       | 97 ++++++++++++++++++++++++++++++++++++
 target/riscv/tcg/meson.build |  1 +
 3 files changed, 98 insertions(+), 83 deletions(-)
 create mode 100644 target/riscv/tcg/cpu.c

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index cc0050d110..a1501fea76 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -63,89 +63,6 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
 #endif
 }
 
-void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
-                          target_ulong *cs_base, uint32_t *pflags)
-{
-    CPUState *cs = env_cpu(env);
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    RISCVExtStatus fs, vs;
-    uint32_t flags = 0;
-
-    *pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc;
-    *cs_base = 0;
-
-    if (cpu->cfg.ext_zve32f) {
-        /*
-         * If env->vl equals to VLMAX, we can use generic vector operation
-         * expanders (GVEC) to accerlate the vector operations.
-         * However, as LMUL could be a fractional number. The maximum
-         * vector size can be operated might be less than 8 bytes,
-         * which is not supported by GVEC. So we set vl_eq_vlmax flag to true
-         * only when maxsz >= 8 bytes.
-         */
-        uint32_t vlmax = vext_get_vlmax(cpu, env->vtype);
-        uint32_t sew = FIELD_EX64(env->vtype, VTYPE, VSEW);
-        uint32_t maxsz = vlmax << sew;
-        bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) &&
-                           (maxsz >= 8);
-        flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill);
-        flags = FIELD_DP32(flags, TB_FLAGS, SEW, sew);
-        flags = FIELD_DP32(flags, TB_FLAGS, LMUL,
-                           FIELD_EX64(env->vtype, VTYPE, VLMUL));
-        flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax);
-        flags = FIELD_DP32(flags, TB_FLAGS, VTA,
-                           FIELD_EX64(env->vtype, VTYPE, VTA));
-        flags = FIELD_DP32(flags, TB_FLAGS, VMA,
-                           FIELD_EX64(env->vtype, VTYPE, VMA));
-        flags = FIELD_DP32(flags, TB_FLAGS, VSTART_EQ_ZERO, env->vstart == 0);
-    } else {
-        flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1);
-    }
-
-#ifdef CONFIG_USER_ONLY
-    fs = EXT_STATUS_DIRTY;
-    vs = EXT_STATUS_DIRTY;
-#else
-    flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
-
-    flags |= cpu_mmu_index(env, 0);
-    fs = get_field(env->mstatus, MSTATUS_FS);
-    vs = get_field(env->mstatus, MSTATUS_VS);
-
-    if (env->virt_enabled) {
-        flags = FIELD_DP32(flags, TB_FLAGS, VIRT_ENABLED, 1);
-        /*
-         * Merge DISABLED and !DIRTY states using MIN.
-         * We will set both fields when dirtying.
-         */
-        fs = MIN(fs, get_field(env->mstatus_hs, MSTATUS_FS));
-        vs = MIN(vs, get_field(env->mstatus_hs, MSTATUS_VS));
-    }
-
-    /* With Zfinx, floating point is enabled/disabled by Smstateen. */
-    if (!riscv_has_ext(env, RVF)) {
-        fs = (smstateen_acc_ok(env, 0, SMSTATEEN0_FCSR) == RISCV_EXCP_NONE)
-             ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
-    }
-
-    if (cpu->cfg.debug && !icount_enabled()) {
-        flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
-    }
-#endif
-
-    flags = FIELD_DP32(flags, TB_FLAGS, FS, fs);
-    flags = FIELD_DP32(flags, TB_FLAGS, VS, vs);
-    flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl);
-    if (env->cur_pmmask != 0) {
-        flags = FIELD_DP32(flags, TB_FLAGS, PM_MASK_ENABLED, 1);
-    }
-    if (env->cur_pmbase != 0) {
-        flags = FIELD_DP32(flags, TB_FLAGS, PM_BASE_ENABLED, 1);
-    }
-
-    *pflags = flags;
-}
-
 void riscv_cpu_update_mask(CPURISCVState *env)
 {
     target_ulong mask = 0, base = 0;
diff --git a/target/riscv/tcg/cpu.c b/target/riscv/tcg/cpu.c
new file mode 100644
index 0000000000..b5d32729f2
--- /dev/null
+++ b/target/riscv/tcg/cpu.c
@@ -0,0 +1,97 @@
+/*
+ * RISC-V CPU helpers (TCG specific)
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#ifndef CONFIG_USER_ONLY
+#include "sysemu/cpu-timers.h"
+#endif
+
+void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
+                          target_ulong *cs_base, uint32_t *pflags)
+{
+    CPUState *cs = env_cpu(env);
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    RISCVExtStatus fs, vs;
+    uint32_t flags = 0;
+
+    *pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc;
+    *cs_base = 0;
+
+    if (cpu->cfg.ext_zve32f) {
+        /*
+         * If env->vl equals to VLMAX, we can use generic vector operation
+         * expanders (GVEC) to accerlate the vector operations.
+         * However, as LMUL could be a fractional number. The maximum
+         * vector size can be operated might be less than 8 bytes,
+         * which is not supported by GVEC. So we set vl_eq_vlmax flag to true
+         * only when maxsz >= 8 bytes.
+         */
+        uint32_t vlmax = vext_get_vlmax(cpu, env->vtype);
+        uint32_t sew = FIELD_EX64(env->vtype, VTYPE, VSEW);
+        uint32_t maxsz = vlmax << sew;
+        bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) &&
+                           (maxsz >= 8);
+        flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill);
+        flags = FIELD_DP32(flags, TB_FLAGS, SEW, sew);
+        flags = FIELD_DP32(flags, TB_FLAGS, LMUL,
+                           FIELD_EX64(env->vtype, VTYPE, VLMUL));
+        flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax);
+        flags = FIELD_DP32(flags, TB_FLAGS, VTA,
+                           FIELD_EX64(env->vtype, VTYPE, VTA));
+        flags = FIELD_DP32(flags, TB_FLAGS, VMA,
+                           FIELD_EX64(env->vtype, VTYPE, VMA));
+        flags = FIELD_DP32(flags, TB_FLAGS, VSTART_EQ_ZERO, env->vstart == 0);
+    } else {
+        flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1);
+    }
+
+#ifdef CONFIG_USER_ONLY
+    fs = EXT_STATUS_DIRTY;
+    vs = EXT_STATUS_DIRTY;
+#else
+    flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv);
+
+    flags |= cpu_mmu_index(env, 0);
+    fs = get_field(env->mstatus, MSTATUS_FS);
+    vs = get_field(env->mstatus, MSTATUS_VS);
+
+    if (env->virt_enabled) {
+        flags = FIELD_DP32(flags, TB_FLAGS, VIRT_ENABLED, 1);
+        /*
+         * Merge DISABLED and !DIRTY states using MIN.
+         * We will set both fields when dirtying.
+         */
+        fs = MIN(fs, get_field(env->mstatus_hs, MSTATUS_FS));
+        vs = MIN(vs, get_field(env->mstatus_hs, MSTATUS_VS));
+    }
+
+    /* With Zfinx, floating point is enabled/disabled by Smstateen. */
+    if (!riscv_has_ext(env, RVF)) {
+        fs = (smstateen_acc_ok(env, 0, SMSTATEEN0_FCSR) == RISCV_EXCP_NONE)
+             ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED;
+    }
+
+    if (cpu->cfg.debug && !icount_enabled()) {
+        flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled);
+    }
+#endif
+
+    flags = FIELD_DP32(flags, TB_FLAGS, FS, fs);
+    flags = FIELD_DP32(flags, TB_FLAGS, VS, vs);
+    flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl);
+    if (env->cur_pmmask != 0) {
+        flags = FIELD_DP32(flags, TB_FLAGS, PM_MASK_ENABLED, 1);
+    }
+    if (env->cur_pmbase != 0) {
+        flags = FIELD_DP32(flags, TB_FLAGS, PM_BASE_ENABLED, 1);
+    }
+
+    *pflags = flags;
+}
diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
index 65670493b1..a615aafd9a 100644
--- a/target/riscv/tcg/meson.build
+++ b/target/riscv/tcg/meson.build
@@ -8,6 +8,7 @@ gen = [
 riscv_ss.add(when: 'CONFIG_TCG', if_true: gen)
 
 riscv_ss.add(when: 'CONFIG_TCG', if_true: files(
+  'cpu.c',
   'fpu_helper.c',
   'op_helper.c',
   'vector_helper.c',
-- 
2.38.1



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

* [PATCH 09/16] target/riscv: Expose some 'trigger' prototypes from debug.c
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (7 preceding siblings ...)
  2023-06-26 23:19 ` [PATCH 08/16] target/riscv: Move TCG-specific cpu_get_tb_cpu_state() to tcg/cpu.c Philippe Mathieu-Daudé
@ 2023-06-26 23:20 ` Philippe Mathieu-Daudé
  2023-06-26 23:20 ` [PATCH 10/16] target/riscv: Extract TCG-specific code " Philippe Mathieu-Daudé
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

We want to extract TCG-specific code from debug.c, but some
functions call get_trigger_type() / do_trigger_action().
Expose these prototypes in "debug.h".

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/debug.h | 4 ++++
 target/riscv/debug.c | 5 ++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/target/riscv/debug.h b/target/riscv/debug.h
index c471748d5a..65cd45b8f3 100644
--- a/target/riscv/debug.h
+++ b/target/riscv/debug.h
@@ -147,4 +147,8 @@ void riscv_trigger_init(CPURISCVState *env);
 
 bool riscv_itrigger_enabled(CPURISCVState *env);
 void riscv_itrigger_update_priv(CPURISCVState *env);
+
+target_ulong get_trigger_type(CPURISCVState *env, target_ulong trigger_index);
+void do_trigger_action(CPURISCVState *env, target_ulong trigger_index);
+
 #endif /* RISCV_DEBUG_H */
diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 75ee1c4971..5676f2c57e 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -88,8 +88,7 @@ static inline target_ulong extract_trigger_type(CPURISCVState *env,
     }
 }
 
-static inline target_ulong get_trigger_type(CPURISCVState *env,
-                                            target_ulong trigger_index)
+target_ulong get_trigger_type(CPURISCVState *env, target_ulong trigger_index)
 {
     return extract_trigger_type(env, env->tdata1[trigger_index]);
 }
@@ -217,7 +216,7 @@ static inline void warn_always_zero_bit(target_ulong val, target_ulong mask,
     }
 }
 
-static void do_trigger_action(CPURISCVState *env, target_ulong trigger_index)
+void do_trigger_action(CPURISCVState *env, target_ulong trigger_index)
 {
     trigger_action_t action = get_trigger_action(env, trigger_index);
 
-- 
2.38.1



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

* [PATCH 10/16] target/riscv: Extract TCG-specific code from debug.c
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (8 preceding siblings ...)
  2023-06-26 23:20 ` [PATCH 09/16] target/riscv: Expose some 'trigger' prototypes from debug.c Philippe Mathieu-Daudé
@ 2023-06-26 23:20 ` Philippe Mathieu-Daudé
  2023-06-26 23:20 ` [PATCH 11/16] target/riscv: Move sysemu-specific debug files to target/riscv/sysemu/ Philippe Mathieu-Daudé
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Extract TCG-specific code from debug.c to tcg/sysemu/debug.c,
restrict the prototypes to TCG, adapt meson rules.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/debug.h                |   2 +
 target/riscv/debug.c                | 148 -------------------------
 target/riscv/tcg/sysemu/debug.c     | 165 ++++++++++++++++++++++++++++
 target/riscv/tcg/meson.build        |   2 +
 target/riscv/tcg/sysemu/meson.build |   3 +
 5 files changed, 172 insertions(+), 148 deletions(-)
 create mode 100644 target/riscv/tcg/sysemu/debug.c
 create mode 100644 target/riscv/tcg/sysemu/meson.build

diff --git a/target/riscv/debug.h b/target/riscv/debug.h
index 65cd45b8f3..0b3bdd5be1 100644
--- a/target/riscv/debug.h
+++ b/target/riscv/debug.h
@@ -139,9 +139,11 @@ void tdata_csr_write(CPURISCVState *env, int tdata_index, target_ulong val);
 
 target_ulong tinfo_csr_read(CPURISCVState *env);
 
+#ifdef CONFIG_TCG
 void riscv_cpu_debug_excp_handler(CPUState *cs);
 bool riscv_cpu_debug_check_breakpoint(CPUState *cs);
 bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp);
+#endif
 
 void riscv_trigger_init(CPURISCVState *env);
 
diff --git a/target/riscv/debug.c b/target/riscv/debug.c
index 5676f2c57e..45a2605d8a 100644
--- a/target/riscv/debug.c
+++ b/target/riscv/debug.c
@@ -754,154 +754,6 @@ target_ulong tinfo_csr_read(CPURISCVState *env)
            BIT(TRIGGER_TYPE_AD_MATCH6);
 }
 
-void riscv_cpu_debug_excp_handler(CPUState *cs)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-
-    if (cs->watchpoint_hit) {
-        if (cs->watchpoint_hit->flags & BP_CPU) {
-            do_trigger_action(env, DBG_ACTION_BP);
-        }
-    } else {
-        if (cpu_breakpoint_test(cs, env->pc, BP_CPU)) {
-            do_trigger_action(env, DBG_ACTION_BP);
-        }
-    }
-}
-
-bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    CPUBreakpoint *bp;
-    target_ulong ctrl;
-    target_ulong pc;
-    int trigger_type;
-    int i;
-
-    QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
-        for (i = 0; i < RV_MAX_TRIGGERS; i++) {
-            trigger_type = get_trigger_type(env, i);
-
-            switch (trigger_type) {
-            case TRIGGER_TYPE_AD_MATCH:
-                /* type 2 trigger cannot be fired in VU/VS mode */
-                if (env->virt_enabled) {
-                    return false;
-                }
-
-                ctrl = env->tdata1[i];
-                pc = env->tdata2[i];
-
-                if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) {
-                    /* check U/S/M bit against current privilege level */
-                    if ((ctrl >> 3) & BIT(env->priv)) {
-                        return true;
-                    }
-                }
-                break;
-            case TRIGGER_TYPE_AD_MATCH6:
-                ctrl = env->tdata1[i];
-                pc = env->tdata2[i];
-
-                if ((ctrl & TYPE6_EXEC) && (bp->pc == pc)) {
-                    if (env->virt_enabled) {
-                        /* check VU/VS bit against current privilege level */
-                        if ((ctrl >> 23) & BIT(env->priv)) {
-                            return true;
-                        }
-                    } else {
-                        /* check U/S/M bit against current privilege level */
-                        if ((ctrl >> 3) & BIT(env->priv)) {
-                            return true;
-                        }
-                    }
-                }
-                break;
-            default:
-                /* other trigger types are not supported or irrelevant */
-                break;
-            }
-        }
-    }
-
-    return false;
-}
-
-bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    target_ulong ctrl;
-    target_ulong addr;
-    int trigger_type;
-    int flags;
-    int i;
-
-    for (i = 0; i < RV_MAX_TRIGGERS; i++) {
-        trigger_type = get_trigger_type(env, i);
-
-        switch (trigger_type) {
-        case TRIGGER_TYPE_AD_MATCH:
-            /* type 2 trigger cannot be fired in VU/VS mode */
-            if (env->virt_enabled) {
-                return false;
-            }
-
-            ctrl = env->tdata1[i];
-            addr = env->tdata2[i];
-            flags = 0;
-
-            if (ctrl & TYPE2_LOAD) {
-                flags |= BP_MEM_READ;
-            }
-            if (ctrl & TYPE2_STORE) {
-                flags |= BP_MEM_WRITE;
-            }
-
-            if ((wp->flags & flags) && (wp->vaddr == addr)) {
-                /* check U/S/M bit against current privilege level */
-                if ((ctrl >> 3) & BIT(env->priv)) {
-                    return true;
-                }
-            }
-            break;
-        case TRIGGER_TYPE_AD_MATCH6:
-            ctrl = env->tdata1[i];
-            addr = env->tdata2[i];
-            flags = 0;
-
-            if (ctrl & TYPE6_LOAD) {
-                flags |= BP_MEM_READ;
-            }
-            if (ctrl & TYPE6_STORE) {
-                flags |= BP_MEM_WRITE;
-            }
-
-            if ((wp->flags & flags) && (wp->vaddr == addr)) {
-                if (env->virt_enabled) {
-                    /* check VU/VS bit against current privilege level */
-                    if ((ctrl >> 23) & BIT(env->priv)) {
-                        return true;
-                    }
-                } else {
-                    /* check U/S/M bit against current privilege level */
-                    if ((ctrl >> 3) & BIT(env->priv)) {
-                        return true;
-                    }
-                }
-            }
-            break;
-        default:
-            /* other trigger types are not supported */
-            break;
-        }
-    }
-
-    return false;
-}
-
 void riscv_trigger_init(CPURISCVState *env)
 {
     target_ulong tdata1 = build_tdata1(env, TRIGGER_TYPE_AD_MATCH, 0, 0);
diff --git a/target/riscv/tcg/sysemu/debug.c b/target/riscv/tcg/sysemu/debug.c
new file mode 100644
index 0000000000..cdd6744b3a
--- /dev/null
+++ b/target/riscv/tcg/sysemu/debug.c
@@ -0,0 +1,165 @@
+/*
+ * QEMU RISC-V Native Debug Support (TCG specific)
+ *
+ * Copyright (c) 2022 Wind River Systems, Inc.
+ *
+ * Author:
+ *   Bin Meng <bin.meng@windriver.com>
+ *
+ * This provides the native debug support via the Trigger Module, as defined
+ * in the RISC-V Debug Specification:
+ * https://github.com/riscv/riscv-debug-spec/raw/master/riscv-debug-stable.pdf
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+
+void riscv_cpu_debug_excp_handler(CPUState *cs)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+
+    if (cs->watchpoint_hit) {
+        if (cs->watchpoint_hit->flags & BP_CPU) {
+            do_trigger_action(env, DBG_ACTION_BP);
+        }
+    } else {
+        if (cpu_breakpoint_test(cs, env->pc, BP_CPU)) {
+            do_trigger_action(env, DBG_ACTION_BP);
+        }
+    }
+}
+
+bool riscv_cpu_debug_check_breakpoint(CPUState *cs)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    CPUBreakpoint *bp;
+    target_ulong ctrl;
+    target_ulong pc;
+    int trigger_type;
+    int i;
+
+    QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
+        for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+            trigger_type = get_trigger_type(env, i);
+
+            switch (trigger_type) {
+            case TRIGGER_TYPE_AD_MATCH:
+                /* type 2 trigger cannot be fired in VU/VS mode */
+                if (env->virt_enabled) {
+                    return false;
+                }
+
+                ctrl = env->tdata1[i];
+                pc = env->tdata2[i];
+
+                if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) {
+                    /* check U/S/M bit against current privilege level */
+                    if ((ctrl >> 3) & BIT(env->priv)) {
+                        return true;
+                    }
+                }
+                break;
+            case TRIGGER_TYPE_AD_MATCH6:
+                ctrl = env->tdata1[i];
+                pc = env->tdata2[i];
+
+                if ((ctrl & TYPE6_EXEC) && (bp->pc == pc)) {
+                    if (env->virt_enabled) {
+                        /* check VU/VS bit against current privilege level */
+                        if ((ctrl >> 23) & BIT(env->priv)) {
+                            return true;
+                        }
+                    } else {
+                        /* check U/S/M bit against current privilege level */
+                        if ((ctrl >> 3) & BIT(env->priv)) {
+                            return true;
+                        }
+                    }
+                }
+                break;
+            default:
+                /* other trigger types are not supported or irrelevant */
+                break;
+            }
+        }
+    }
+
+    return false;
+}
+
+bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    target_ulong ctrl;
+    target_ulong addr;
+    int trigger_type;
+    int flags;
+    int i;
+
+    for (i = 0; i < RV_MAX_TRIGGERS; i++) {
+        trigger_type = get_trigger_type(env, i);
+
+        switch (trigger_type) {
+        case TRIGGER_TYPE_AD_MATCH:
+            /* type 2 trigger cannot be fired in VU/VS mode */
+            if (env->virt_enabled) {
+                return false;
+            }
+
+            ctrl = env->tdata1[i];
+            addr = env->tdata2[i];
+            flags = 0;
+
+            if (ctrl & TYPE2_LOAD) {
+                flags |= BP_MEM_READ;
+            }
+            if (ctrl & TYPE2_STORE) {
+                flags |= BP_MEM_WRITE;
+            }
+
+            if ((wp->flags & flags) && (wp->vaddr == addr)) {
+                /* check U/S/M bit against current privilege level */
+                if ((ctrl >> 3) & BIT(env->priv)) {
+                    return true;
+                }
+            }
+            break;
+        case TRIGGER_TYPE_AD_MATCH6:
+            ctrl = env->tdata1[i];
+            addr = env->tdata2[i];
+            flags = 0;
+
+            if (ctrl & TYPE6_LOAD) {
+                flags |= BP_MEM_READ;
+            }
+            if (ctrl & TYPE6_STORE) {
+                flags |= BP_MEM_WRITE;
+            }
+
+            if ((wp->flags & flags) && (wp->vaddr == addr)) {
+                if (env->virt_enabled) {
+                    /* check VU/VS bit against current privilege level */
+                    if ((ctrl >> 23) & BIT(env->priv)) {
+                        return true;
+                    }
+                } else {
+                    /* check U/S/M bit against current privilege level */
+                    if ((ctrl >> 3) & BIT(env->priv)) {
+                        return true;
+                    }
+                }
+            }
+            break;
+        default:
+            /* other trigger types are not supported */
+            break;
+        }
+    }
+
+    return false;
+}
diff --git a/target/riscv/tcg/meson.build b/target/riscv/tcg/meson.build
index a615aafd9a..933d340799 100644
--- a/target/riscv/tcg/meson.build
+++ b/target/riscv/tcg/meson.build
@@ -18,3 +18,5 @@ riscv_ss.add(when: 'CONFIG_TCG', if_true: files(
   'crypto_helper.c',
   'zce_helper.c',
 ), if_false: files('tcg-stub.c'))
+
+subdir('sysemu')
diff --git a/target/riscv/tcg/sysemu/meson.build b/target/riscv/tcg/sysemu/meson.build
new file mode 100644
index 0000000000..e8e61e5784
--- /dev/null
+++ b/target/riscv/tcg/sysemu/meson.build
@@ -0,0 +1,3 @@
+riscv_system_ss.add(when: 'CONFIG_TCG', if_true: files(
+  'debug.c',
+))
-- 
2.38.1



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

* [PATCH 11/16] target/riscv: Move sysemu-specific debug files to target/riscv/sysemu/
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (9 preceding siblings ...)
  2023-06-26 23:20 ` [PATCH 10/16] target/riscv: Extract TCG-specific code " Philippe Mathieu-Daudé
@ 2023-06-26 23:20 ` Philippe Mathieu-Daudé
  2023-06-26 23:20 ` [PATCH 12/16] target/riscv: Expose riscv_cpu_pending_to_irq() from cpu_helper.c Philippe Mathieu-Daudé
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/cpu.h                | 2 +-
 target/riscv/{ => sysemu}/debug.h | 0
 target/riscv/cpu_helper.c         | 2 +-
 target/riscv/{ => sysemu}/debug.c | 0
 target/riscv/meson.build          | 4 ----
 target/riscv/sysemu/meson.build   | 1 +
 6 files changed, 3 insertions(+), 6 deletions(-)
 rename target/riscv/{ => sysemu}/debug.h (100%)
 rename target/riscv/{ => sysemu}/debug.c (100%)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 288df4c2b1..6908dc395c 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -89,7 +89,7 @@ typedef enum {
 
 #if !defined(CONFIG_USER_ONLY)
 #include "sysemu/pmp.h"
-#include "debug.h"
+#include "sysemu/debug.h"
 #endif
 
 #define RV_VLEN_MAX 1024
diff --git a/target/riscv/debug.h b/target/riscv/sysemu/debug.h
similarity index 100%
rename from target/riscv/debug.h
rename to target/riscv/sysemu/debug.h
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index a1501fea76..88760248c0 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -32,7 +32,7 @@
 #include "sysemu/cpu-timers.h"
 #endif
 #include "cpu_bits.h"
-#include "debug.h"
+#include "sysemu/debug.h"
 #include "tcg/oversized-guest.h"
 
 int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
diff --git a/target/riscv/debug.c b/target/riscv/sysemu/debug.c
similarity index 100%
rename from target/riscv/debug.c
rename to target/riscv/sysemu/debug.c
diff --git a/target/riscv/meson.build b/target/riscv/meson.build
index 8ef47f43f9..49cdcde679 100644
--- a/target/riscv/meson.build
+++ b/target/riscv/meson.build
@@ -8,10 +8,6 @@ riscv_ss.add(files(
   'gdbstub.c',
 ))
 
-riscv_system_ss.add(files(
-  'debug.c',
-))
-
 subdir('tcg')
 subdir('sysemu')
 
diff --git a/target/riscv/sysemu/meson.build b/target/riscv/sysemu/meson.build
index 5f8e1edcf2..33fec8f11e 100644
--- a/target/riscv/sysemu/meson.build
+++ b/target/riscv/sysemu/meson.build
@@ -1,5 +1,6 @@
 riscv_system_ss.add(files(
   'arch_dump.c',
+  'debug.c',
   'machine.c',
   'monitor.c',
   'pmp.c',
-- 
2.38.1



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

* [PATCH 12/16] target/riscv: Expose riscv_cpu_pending_to_irq() from cpu_helper.c
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (10 preceding siblings ...)
  2023-06-26 23:20 ` [PATCH 11/16] target/riscv: Move sysemu-specific debug files to target/riscv/sysemu/ Philippe Mathieu-Daudé
@ 2023-06-26 23:20 ` Philippe Mathieu-Daudé
  2023-06-26 23:20 ` [RFC PATCH 13/16] target/riscv: Move TCG/sysemu-specific code to tcg/sysemu/cpu_helper.c Philippe Mathieu-Daudé
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

We want to extract TCG/sysemu-specific code from cpu_helper.c,
but some functions call riscv_cpu_pending_to_irq(). Expose the
prototype in "internals.h".

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/internals.h  | 4 ++++
 target/riscv/cpu_helper.c | 6 +++---
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/target/riscv/internals.h b/target/riscv/internals.h
index b5f823c7ec..b6881b4815 100644
--- a/target/riscv/internals.h
+++ b/target/riscv/internals.h
@@ -72,6 +72,10 @@ target_ulong fclass_d(uint64_t frs1);
 
 #ifndef CONFIG_USER_ONLY
 extern const VMStateDescription vmstate_riscv_cpu;
+
+int riscv_cpu_pending_to_irq(CPURISCVState *env,
+                             int extirq, unsigned int extirq_def_prio,
+                             uint64_t pending, uint8_t *iprio);
 #endif
 
 enum {
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 88760248c0..5620e5d7ba 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -252,9 +252,9 @@ uint8_t riscv_cpu_default_priority(int irq)
     return default_iprio[irq] ? default_iprio[irq] : IPRIO_MMAXIPRIO;
 };
 
-static int riscv_cpu_pending_to_irq(CPURISCVState *env,
-                                    int extirq, unsigned int extirq_def_prio,
-                                    uint64_t pending, uint8_t *iprio)
+int riscv_cpu_pending_to_irq(CPURISCVState *env,
+                             int extirq, unsigned int extirq_def_prio,
+                             uint64_t pending, uint8_t *iprio)
 {
     int irq, best_irq = RISCV_EXCP_NONE;
     unsigned int prio, best_prio = UINT_MAX;
-- 
2.38.1



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

* [RFC PATCH 13/16] target/riscv: Move TCG/sysemu-specific code to tcg/sysemu/cpu_helper.c
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (11 preceding siblings ...)
  2023-06-26 23:20 ` [PATCH 12/16] target/riscv: Expose riscv_cpu_pending_to_irq() from cpu_helper.c Philippe Mathieu-Daudé
@ 2023-06-26 23:20 ` Philippe Mathieu-Daudé
  2023-06-26 23:20 ` [PATCH 14/16] target/riscv: Move sysemu-specific code to sysemu/cpu_helper.c Philippe Mathieu-Daudé
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Move TCG/sysemu-specific code and restrict the corresponding
prototypes to TCG, adapting meson rules.

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
RFC due to riscv_cpu_get_phys_page_debug()

 target/riscv/cpu.h                   |  15 +-
 target/riscv/cpu_helper.c            | 745 --------------------------
 target/riscv/tcg/sysemu/cpu_helper.c | 766 +++++++++++++++++++++++++++
 target/riscv/tcg/tcg-stub.c          |   6 +
 target/riscv/tcg/sysemu/meson.build  |   1 +
 5 files changed, 782 insertions(+), 751 deletions(-)
 create mode 100644 target/riscv/tcg/sysemu/cpu_helper.c

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 6908dc395c..5945e13fe0 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -429,12 +429,6 @@ void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen);
 bool riscv_cpu_vector_enabled(CPURISCVState *env);
 void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
 int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
-G_NORETURN void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
-                                               MMUAccessType access_type,
-                                               int mmu_idx, uintptr_t retaddr);
-bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
-                        MMUAccessType access_type, int mmu_idx,
-                        bool probe, uintptr_t retaddr);
 char *riscv_isa_string(RISCVCPU *cpu);
 void riscv_cpu_list(void);
 void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
@@ -444,11 +438,20 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
 
 #ifndef CONFIG_USER_ONLY
 void riscv_cpu_do_interrupt(CPUState *cpu);
+#ifdef CONFIG_TCG
+bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                        MMUAccessType access_type, int mmu_idx,
+                        bool probe, uintptr_t retaddr);
 void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
                                      vaddr addr, unsigned size,
                                      MMUAccessType access_type,
                                      int mmu_idx, MemTxAttrs attrs,
                                      MemTxResult response, uintptr_t retaddr);
+G_NORETURN void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+                                               MMUAccessType access_type,
+                                               int mmu_idx, uintptr_t retaddr);
+#endif /* CONFIG_TCG */
+
 hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
 void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 5620e5d7ba..ded1fee489 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -327,69 +327,6 @@ int riscv_cpu_vsirq_pending(CPURISCVState *env)
                                     irqs >> 1, env->hviprio);
 }
 
-static int riscv_cpu_local_irq_pending(CPURISCVState *env)
-{
-    int virq;
-    uint64_t irqs, pending, mie, hsie, vsie;
-
-    /* Determine interrupt enable state of all privilege modes */
-    if (env->virt_enabled) {
-        mie = 1;
-        hsie = 1;
-        vsie = (env->priv < PRV_S) ||
-               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
-    } else {
-        mie = (env->priv < PRV_M) ||
-              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
-        hsie = (env->priv < PRV_S) ||
-               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
-        vsie = 0;
-    }
-
-    /* Determine all pending interrupts */
-    pending = riscv_cpu_all_pending(env);
-
-    /* Check M-mode interrupts */
-    irqs = pending & ~env->mideleg & -mie;
-    if (irqs) {
-        return riscv_cpu_pending_to_irq(env, IRQ_M_EXT, IPRIO_DEFAULT_M,
-                                        irqs, env->miprio);
-    }
-
-    /* Check HS-mode interrupts */
-    irqs = pending & env->mideleg & ~env->hideleg & -hsie;
-    if (irqs) {
-        return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-                                        irqs, env->siprio);
-    }
-
-    /* Check VS-mode interrupts */
-    irqs = pending & env->mideleg & env->hideleg & -vsie;
-    if (irqs) {
-        virq = riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-                                        irqs >> 1, env->hviprio);
-        return (virq <= 0) ? virq : virq + 1;
-    }
-
-    /* Indicate no pending interrupt */
-    return RISCV_EXCP_NONE;
-}
-
-bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
-{
-    if (interrupt_request & CPU_INTERRUPT_HARD) {
-        RISCVCPU *cpu = RISCV_CPU(cs);
-        CPURISCVState *env = &cpu->env;
-        int interruptno = riscv_cpu_local_irq_pending(env);
-        if (interruptno >= 0) {
-            cs->exception_index = RISCV_EXCP_INT_FLAG | interruptno;
-            riscv_cpu_do_interrupt(cs);
-            return true;
-        }
-    }
-    return false;
-}
-
 /* Return true is floating point support is currently enabled */
 bool riscv_cpu_fp_enabled(CPURISCVState *env)
 {
@@ -605,688 +542,6 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
     env->load_res = -1;
 }
 
-/*
- * get_physical_address_pmp - check PMP permission for this physical address
- *
- * Match the PMP region and check permission for this physical address and it's
- * TLB page. Returns 0 if the permission checking was successful
- *
- * @env: CPURISCVState
- * @prot: The returned protection attributes
- * @addr: The physical address to be checked permission
- * @access_type: The type of MMU access
- * @mode: Indicates current privilege level.
- */
-static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
-                                    int size, MMUAccessType access_type,
-                                    int mode)
-{
-    pmp_priv_t pmp_priv;
-    bool pmp_has_privs;
-
-    if (!riscv_cpu_cfg(env)->pmp) {
-        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        return TRANSLATE_SUCCESS;
-    }
-
-    pmp_has_privs = pmp_hart_has_privs(env, addr, size, 1 << access_type,
-                                       &pmp_priv, mode);
-    if (!pmp_has_privs) {
-        *prot = 0;
-        return TRANSLATE_PMP_FAIL;
-    }
-
-    *prot = pmp_priv_to_page_prot(pmp_priv);
-
-    return TRANSLATE_SUCCESS;
-}
-
-/*
- * get_physical_address - get the physical address for this virtual address
- *
- * Do a page table walk to obtain the physical address corresponding to a
- * virtual address. Returns 0 if the translation was successful
- *
- * Adapted from Spike's mmu_t::translate and mmu_t::walk
- *
- * @env: CPURISCVState
- * @physical: This will be set to the calculated physical address
- * @prot: The returned protection attributes
- * @addr: The virtual address or guest physical address to be translated
- * @fault_pte_addr: If not NULL, this will be set to fault pte address
- *                  when a error occurs on pte address translation.
- *                  This will already be shifted to match htval.
- * @access_type: The type of MMU access
- * @mmu_idx: Indicates current privilege level
- * @first_stage: Are we in first stage translation?
- *               Second stage is used for hypervisor guest translation
- * @two_stage: Are we going to perform two stage translation
- * @is_debug: Is this access from a debugger or the monitor?
- */
-static int get_physical_address(CPURISCVState *env, hwaddr *physical,
-                                int *ret_prot, vaddr addr,
-                                target_ulong *fault_pte_addr,
-                                int access_type, int mmu_idx,
-                                bool first_stage, bool two_stage,
-                                bool is_debug)
-{
-    /*
-     * NOTE: the env->pc value visible here will not be
-     * correct, but the value visible to the exception handler
-     * (riscv_cpu_do_interrupt) is correct
-     */
-    MemTxResult res;
-    MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
-    int mode = mmuidx_priv(mmu_idx);
-    bool use_background = false;
-    hwaddr ppn;
-    int napot_bits = 0;
-    target_ulong napot_mask;
-
-    /*
-     * Check if we should use the background registers for the two
-     * stage translation. We don't need to check if we actually need
-     * two stage translation as that happened before this function
-     * was called. Background registers will be used if the guest has
-     * forced a two stage translation to be on (in HS or M mode).
-     */
-    if (!env->virt_enabled && two_stage) {
-        use_background = true;
-    }
-
-    if (mode == PRV_M || !riscv_cpu_cfg(env)->mmu) {
-        *physical = addr;
-        *ret_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        return TRANSLATE_SUCCESS;
-    }
-
-    *ret_prot = 0;
-
-    hwaddr base;
-    int levels, ptidxbits, ptesize, vm, widened;
-
-    if (first_stage == true) {
-        if (use_background) {
-            if (riscv_cpu_mxl(env) == MXL_RV32) {
-                base = (hwaddr)get_field(env->vsatp, SATP32_PPN) << PGSHIFT;
-                vm = get_field(env->vsatp, SATP32_MODE);
-            } else {
-                base = (hwaddr)get_field(env->vsatp, SATP64_PPN) << PGSHIFT;
-                vm = get_field(env->vsatp, SATP64_MODE);
-            }
-        } else {
-            if (riscv_cpu_mxl(env) == MXL_RV32) {
-                base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
-                vm = get_field(env->satp, SATP32_MODE);
-            } else {
-                base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
-                vm = get_field(env->satp, SATP64_MODE);
-            }
-        }
-        widened = 0;
-    } else {
-        if (riscv_cpu_mxl(env) == MXL_RV32) {
-            base = (hwaddr)get_field(env->hgatp, SATP32_PPN) << PGSHIFT;
-            vm = get_field(env->hgatp, SATP32_MODE);
-        } else {
-            base = (hwaddr)get_field(env->hgatp, SATP64_PPN) << PGSHIFT;
-            vm = get_field(env->hgatp, SATP64_MODE);
-        }
-        widened = 2;
-    }
-
-    switch (vm) {
-    case VM_1_10_SV32:
-      levels = 2; ptidxbits = 10; ptesize = 4; break;
-    case VM_1_10_SV39:
-      levels = 3; ptidxbits = 9; ptesize = 8; break;
-    case VM_1_10_SV48:
-      levels = 4; ptidxbits = 9; ptesize = 8; break;
-    case VM_1_10_SV57:
-      levels = 5; ptidxbits = 9; ptesize = 8; break;
-    case VM_1_10_MBARE:
-        *physical = addr;
-        *ret_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
-        return TRANSLATE_SUCCESS;
-    default:
-      g_assert_not_reached();
-    }
-
-    CPUState *cs = env_cpu(env);
-    int va_bits = PGSHIFT + levels * ptidxbits + widened;
-
-    if (first_stage == true) {
-        target_ulong mask, masked_msbs;
-
-        if (TARGET_LONG_BITS > (va_bits - 1)) {
-            mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
-        } else {
-            mask = 0;
-        }
-        masked_msbs = (addr >> (va_bits - 1)) & mask;
-
-        if (masked_msbs != 0 && masked_msbs != mask) {
-            return TRANSLATE_FAIL;
-        }
-    } else {
-        if (vm != VM_1_10_SV32 && addr >> va_bits != 0) {
-            return TRANSLATE_FAIL;
-        }
-    }
-
-    bool pbmte = env->menvcfg & MENVCFG_PBMTE;
-    bool hade = env->menvcfg & MENVCFG_HADE;
-
-    if (first_stage && two_stage && env->virt_enabled) {
-        pbmte = pbmte && (env->henvcfg & HENVCFG_PBMTE);
-        hade = hade && (env->henvcfg & HENVCFG_HADE);
-    }
-
-    int ptshift = (levels - 1) * ptidxbits;
-    target_ulong pte;
-    hwaddr pte_addr;
-    int i;
-
-#if !TCG_OVERSIZED_GUEST
-restart:
-#endif
-    for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
-        target_ulong idx;
-        if (i == 0) {
-            idx = (addr >> (PGSHIFT + ptshift)) &
-                           ((1 << (ptidxbits + widened)) - 1);
-        } else {
-            idx = (addr >> (PGSHIFT + ptshift)) &
-                           ((1 << ptidxbits) - 1);
-        }
-
-        /* check that physical address of PTE is legal */
-
-        if (two_stage && first_stage) {
-            int vbase_prot;
-            hwaddr vbase;
-
-            /* Do the second stage translation on the base PTE address. */
-            int vbase_ret = get_physical_address(env, &vbase, &vbase_prot,
-                                                 base, NULL, MMU_DATA_LOAD,
-                                                 MMUIdx_U, false, true,
-                                                 is_debug);
-
-            if (vbase_ret != TRANSLATE_SUCCESS) {
-                if (fault_pte_addr) {
-                    *fault_pte_addr = (base + idx * ptesize) >> 2;
-                }
-                return TRANSLATE_G_STAGE_FAIL;
-            }
-
-            pte_addr = vbase + idx * ptesize;
-        } else {
-            pte_addr = base + idx * ptesize;
-        }
-
-        int pmp_prot;
-        int pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
-                                               sizeof(target_ulong),
-                                               MMU_DATA_LOAD, PRV_S);
-        if (pmp_ret != TRANSLATE_SUCCESS) {
-            return TRANSLATE_PMP_FAIL;
-        }
-
-        if (riscv_cpu_mxl(env) == MXL_RV32) {
-            pte = address_space_ldl(cs->as, pte_addr, attrs, &res);
-        } else {
-            pte = address_space_ldq(cs->as, pte_addr, attrs, &res);
-        }
-
-        if (res != MEMTX_OK) {
-            return TRANSLATE_FAIL;
-        }
-
-        if (riscv_cpu_sxl(env) == MXL_RV32) {
-            ppn = pte >> PTE_PPN_SHIFT;
-        } else {
-            if (pte & PTE_RESERVED) {
-                return TRANSLATE_FAIL;
-            }
-
-            if (!pbmte && (pte & PTE_PBMT)) {
-                return TRANSLATE_FAIL;
-            }
-
-            if (!riscv_cpu_cfg(env)->ext_svnapot && (pte & PTE_N)) {
-                return TRANSLATE_FAIL;
-            }
-
-            ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT;
-        }
-
-        if (!(pte & PTE_V)) {
-            /* Invalid PTE */
-            return TRANSLATE_FAIL;
-        }
-        if (pte & (PTE_R | PTE_W | PTE_X)) {
-            goto leaf;
-        }
-
-        /* Inner PTE, continue walking */
-        if (pte & (PTE_D | PTE_A | PTE_U | PTE_ATTR)) {
-            return TRANSLATE_FAIL;
-        }
-        base = ppn << PGSHIFT;
-    }
-
-    /* No leaf pte at any translation level. */
-    return TRANSLATE_FAIL;
-
- leaf:
-    if (ppn & ((1ULL << ptshift) - 1)) {
-        /* Misaligned PPN */
-        return TRANSLATE_FAIL;
-    }
-    if (!pbmte && (pte & PTE_PBMT)) {
-        /* Reserved without Svpbmt. */
-        return TRANSLATE_FAIL;
-    }
-
-    /* Check for reserved combinations of RWX flags. */
-    switch (pte & (PTE_R | PTE_W | PTE_X)) {
-    case PTE_W:
-    case PTE_W | PTE_X:
-        return TRANSLATE_FAIL;
-    }
-
-    int prot = 0;
-    if (pte & PTE_R) {
-        prot |= PAGE_READ;
-    }
-    if (pte & PTE_W) {
-        prot |= PAGE_WRITE;
-    }
-    if (pte & PTE_X) {
-        bool mxr;
-
-        if (first_stage == true) {
-            mxr = get_field(env->mstatus, MSTATUS_MXR);
-        } else {
-            mxr = get_field(env->vsstatus, MSTATUS_MXR);
-        }
-        if (mxr) {
-            prot |= PAGE_READ;
-        }
-        prot |= PAGE_EXEC;
-    }
-
-    if (pte & PTE_U) {
-        if (mode != PRV_U) {
-            if (!mmuidx_sum(mmu_idx)) {
-                return TRANSLATE_FAIL;
-            }
-            /* SUM allows only read+write, not execute. */
-            prot &= PAGE_READ | PAGE_WRITE;
-        }
-    } else if (mode != PRV_S) {
-        /* Supervisor PTE flags when not S mode */
-        return TRANSLATE_FAIL;
-    }
-
-    if (!((prot >> access_type) & 1)) {
-        /* Access check failed */
-        return TRANSLATE_FAIL;
-    }
-
-    /* If necessary, set accessed and dirty bits. */
-    target_ulong updated_pte = pte | PTE_A |
-                (access_type == MMU_DATA_STORE ? PTE_D : 0);
-
-    /* Page table updates need to be atomic with MTTCG enabled */
-    if (updated_pte != pte && !is_debug) {
-        if (!hade) {
-            return TRANSLATE_FAIL;
-        }
-
-        /*
-         * - if accessed or dirty bits need updating, and the PTE is
-         *   in RAM, then we do so atomically with a compare and swap.
-         * - if the PTE is in IO space or ROM, then it can't be updated
-         *   and we return TRANSLATE_FAIL.
-         * - if the PTE changed by the time we went to update it, then
-         *   it is no longer valid and we must re-walk the page table.
-         */
-        MemoryRegion *mr;
-        hwaddr l = sizeof(target_ulong), addr1;
-        mr = address_space_translate(cs->as, pte_addr, &addr1, &l,
-                                     false, MEMTXATTRS_UNSPECIFIED);
-        if (memory_region_is_ram(mr)) {
-            target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
-#if TCG_OVERSIZED_GUEST
-            /*
-             * MTTCG is not enabled on oversized TCG guests so
-             * page table updates do not need to be atomic
-             */
-            *pte_pa = pte = updated_pte;
-#else
-            target_ulong old_pte = qatomic_cmpxchg(pte_pa, pte, updated_pte);
-            if (old_pte != pte) {
-                goto restart;
-            }
-            pte = updated_pte;
-#endif
-        } else {
-            /*
-             * Misconfigured PTE in ROM (AD bits are not preset) or
-             * PTE is in IO space and can't be updated atomically.
-             */
-            return TRANSLATE_FAIL;
-        }
-    }
-
-    /* For superpage mappings, make a fake leaf PTE for the TLB's benefit. */
-    target_ulong vpn = addr >> PGSHIFT;
-
-    if (riscv_cpu_cfg(env)->ext_svnapot && (pte & PTE_N)) {
-        napot_bits = ctzl(ppn) + 1;
-        if ((i != (levels - 1)) || (napot_bits != 4)) {
-            return TRANSLATE_FAIL;
-        }
-    }
-
-    napot_mask = (1 << napot_bits) - 1;
-    *physical = (((ppn & ~napot_mask) | (vpn & napot_mask) |
-                  (vpn & (((target_ulong)1 << ptshift) - 1))
-                 ) << PGSHIFT) | (addr & ~TARGET_PAGE_MASK);
-
-    /*
-     * Remove write permission unless this is a store, or the page is
-     * already dirty, so that we TLB miss on later writes to update
-     * the dirty bit.
-     */
-    if (access_type != MMU_DATA_STORE && !(pte & PTE_D)) {
-        prot &= ~PAGE_WRITE;
-    }
-    *ret_prot = prot;
-
-    return TRANSLATE_SUCCESS;
-}
-
-static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
-                                MMUAccessType access_type, bool pmp_violation,
-                                bool first_stage, bool two_stage,
-                                bool two_stage_indirect)
-{
-    CPUState *cs = env_cpu(env);
-    int page_fault_exceptions, vm;
-    uint64_t stap_mode;
-
-    if (riscv_cpu_mxl(env) == MXL_RV32) {
-        stap_mode = SATP32_MODE;
-    } else {
-        stap_mode = SATP64_MODE;
-    }
-
-    if (first_stage) {
-        vm = get_field(env->satp, stap_mode);
-    } else {
-        vm = get_field(env->hgatp, stap_mode);
-    }
-
-    page_fault_exceptions = vm != VM_1_10_MBARE && !pmp_violation;
-
-    switch (access_type) {
-    case MMU_INST_FETCH:
-        if (env->virt_enabled && !first_stage) {
-            cs->exception_index = RISCV_EXCP_INST_GUEST_PAGE_FAULT;
-        } else {
-            cs->exception_index = page_fault_exceptions ?
-                RISCV_EXCP_INST_PAGE_FAULT : RISCV_EXCP_INST_ACCESS_FAULT;
-        }
-        break;
-    case MMU_DATA_LOAD:
-        if (two_stage && !first_stage) {
-            cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT;
-        } else {
-            cs->exception_index = page_fault_exceptions ?
-                RISCV_EXCP_LOAD_PAGE_FAULT : RISCV_EXCP_LOAD_ACCESS_FAULT;
-        }
-        break;
-    case MMU_DATA_STORE:
-        if (two_stage && !first_stage) {
-            cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT;
-        } else {
-            cs->exception_index = page_fault_exceptions ?
-                RISCV_EXCP_STORE_PAGE_FAULT :
-                RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
-        }
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    env->badaddr = address;
-    env->two_stage_lookup = two_stage;
-    env->two_stage_indirect_lookup = two_stage_indirect;
-}
-
-hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    hwaddr phys_addr;
-    int prot;
-    int mmu_idx = cpu_mmu_index(&cpu->env, false);
-
-    if (get_physical_address(env, &phys_addr, &prot, addr, NULL, 0, mmu_idx,
-                             true, env->virt_enabled, true)) {
-        return -1;
-    }
-
-    if (env->virt_enabled) {
-        if (get_physical_address(env, &phys_addr, &prot, phys_addr, NULL,
-                                 0, mmu_idx, false, true, true)) {
-            return -1;
-        }
-    }
-
-    return phys_addr & TARGET_PAGE_MASK;
-}
-
-void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
-                                     vaddr addr, unsigned size,
-                                     MMUAccessType access_type,
-                                     int mmu_idx, MemTxAttrs attrs,
-                                     MemTxResult response, uintptr_t retaddr)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-
-    if (access_type == MMU_DATA_STORE) {
-        cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
-    } else if (access_type == MMU_DATA_LOAD) {
-        cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT;
-    } else {
-        cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT;
-    }
-
-    env->badaddr = addr;
-    env->two_stage_lookup = mmuidx_2stage(mmu_idx);
-    env->two_stage_indirect_lookup = false;
-    cpu_loop_exit_restore(cs, retaddr);
-}
-
-void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
-                                   MMUAccessType access_type, int mmu_idx,
-                                   uintptr_t retaddr)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    switch (access_type) {
-    case MMU_INST_FETCH:
-        cs->exception_index = RISCV_EXCP_INST_ADDR_MIS;
-        break;
-    case MMU_DATA_LOAD:
-        cs->exception_index = RISCV_EXCP_LOAD_ADDR_MIS;
-        break;
-    case MMU_DATA_STORE:
-        cs->exception_index = RISCV_EXCP_STORE_AMO_ADDR_MIS;
-        break;
-    default:
-        g_assert_not_reached();
-    }
-    env->badaddr = addr;
-    env->two_stage_lookup = mmuidx_2stage(mmu_idx);
-    env->two_stage_indirect_lookup = false;
-    cpu_loop_exit_restore(cs, retaddr);
-}
-
-
-static void pmu_tlb_fill_incr_ctr(RISCVCPU *cpu, MMUAccessType access_type)
-{
-    enum riscv_pmu_event_idx pmu_event_type;
-
-    switch (access_type) {
-    case MMU_INST_FETCH:
-        pmu_event_type = RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS;
-        break;
-    case MMU_DATA_LOAD:
-        pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS;
-        break;
-    case MMU_DATA_STORE:
-        pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS;
-        break;
-    default:
-        return;
-    }
-
-    riscv_pmu_incr_ctr(cpu, pmu_event_type);
-}
-
-bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
-                        MMUAccessType access_type, int mmu_idx,
-                        bool probe, uintptr_t retaddr)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    vaddr im_address;
-    hwaddr pa = 0;
-    int prot, prot2, prot_pmp;
-    bool pmp_violation = false;
-    bool first_stage_error = true;
-    bool two_stage_lookup = mmuidx_2stage(mmu_idx);
-    bool two_stage_indirect_error = false;
-    int ret = TRANSLATE_FAIL;
-    int mode = mmu_idx;
-    /* default TLB page size */
-    target_ulong tlb_size = TARGET_PAGE_SIZE;
-
-    env->guest_phys_fault_addr = 0;
-
-    qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
-                  __func__, address, access_type, mmu_idx);
-
-    pmu_tlb_fill_incr_ctr(cpu, access_type);
-    if (two_stage_lookup) {
-        /* Two stage lookup */
-        ret = get_physical_address(env, &pa, &prot, address,
-                                   &env->guest_phys_fault_addr, access_type,
-                                   mmu_idx, true, true, false);
-
-        /*
-         * A G-stage exception may be triggered during two state lookup.
-         * And the env->guest_phys_fault_addr has already been set in
-         * get_physical_address().
-         */
-        if (ret == TRANSLATE_G_STAGE_FAIL) {
-            first_stage_error = false;
-            two_stage_indirect_error = true;
-            access_type = MMU_DATA_LOAD;
-        }
-
-        qemu_log_mask(CPU_LOG_MMU,
-                      "%s 1st-stage address=%" VADDR_PRIx " ret %d physical "
-                      HWADDR_FMT_plx " prot %d\n",
-                      __func__, address, ret, pa, prot);
-
-        if (ret == TRANSLATE_SUCCESS) {
-            /* Second stage lookup */
-            im_address = pa;
-
-            ret = get_physical_address(env, &pa, &prot2, im_address, NULL,
-                                       access_type, MMUIdx_U, false, true,
-                                       false);
-
-            qemu_log_mask(CPU_LOG_MMU,
-                          "%s 2nd-stage address=%" VADDR_PRIx
-                          " ret %d physical "
-                          HWADDR_FMT_plx " prot %d\n",
-                          __func__, im_address, ret, pa, prot2);
-
-            prot &= prot2;
-
-            if (ret == TRANSLATE_SUCCESS) {
-                ret = get_physical_address_pmp(env, &prot_pmp, pa,
-                                               size, access_type, mode);
-                tlb_size = pmp_get_tlb_size(env, pa);
-
-                qemu_log_mask(CPU_LOG_MMU,
-                              "%s PMP address=" HWADDR_FMT_plx " ret %d prot"
-                              " %d tlb_size " TARGET_FMT_lu "\n",
-                              __func__, pa, ret, prot_pmp, tlb_size);
-
-                prot &= prot_pmp;
-            }
-
-            if (ret != TRANSLATE_SUCCESS) {
-                /*
-                 * Guest physical address translation failed, this is a HS
-                 * level exception
-                 */
-                first_stage_error = false;
-                env->guest_phys_fault_addr = (im_address |
-                                              (address &
-                                               (TARGET_PAGE_SIZE - 1))) >> 2;
-            }
-        }
-    } else {
-        /* Single stage lookup */
-        ret = get_physical_address(env, &pa, &prot, address, NULL,
-                                   access_type, mmu_idx, true, false, false);
-
-        qemu_log_mask(CPU_LOG_MMU,
-                      "%s address=%" VADDR_PRIx " ret %d physical "
-                      HWADDR_FMT_plx " prot %d\n",
-                      __func__, address, ret, pa, prot);
-
-        if (ret == TRANSLATE_SUCCESS) {
-            ret = get_physical_address_pmp(env, &prot_pmp, pa,
-                                           size, access_type, mode);
-            tlb_size = pmp_get_tlb_size(env, pa);
-
-            qemu_log_mask(CPU_LOG_MMU,
-                          "%s PMP address=" HWADDR_FMT_plx " ret %d prot"
-                          " %d tlb_size " TARGET_FMT_lu "\n",
-                          __func__, pa, ret, prot_pmp, tlb_size);
-
-            prot &= prot_pmp;
-        }
-    }
-
-    if (ret == TRANSLATE_PMP_FAIL) {
-        pmp_violation = true;
-    }
-
-    if (ret == TRANSLATE_SUCCESS) {
-        tlb_set_page(cs, address & ~(tlb_size - 1), pa & ~(tlb_size - 1),
-                     prot, mmu_idx, tlb_size);
-        return true;
-    } else if (probe) {
-        return false;
-    } else {
-        raise_mmu_exception(env, address, access_type, pmp_violation,
-                            first_stage_error, two_stage_lookup,
-                            two_stage_indirect_error);
-        cpu_loop_exit_restore(cs, retaddr);
-    }
-
-    return true;
-}
 
 static target_ulong riscv_transformed_insn(CPURISCVState *env,
                                            target_ulong insn,
diff --git a/target/riscv/tcg/sysemu/cpu_helper.c b/target/riscv/tcg/sysemu/cpu_helper.c
new file mode 100644
index 0000000000..57b04eb2ce
--- /dev/null
+++ b/target/riscv/tcg/sysemu/cpu_helper.c
@@ -0,0 +1,766 @@
+/*
+ * RISC-V CPU system helpers (TCG specific)
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "exec/exec-all.h"
+#include "cpu.h"
+#include "internals.h"
+#include "sysemu/cpu-timers.h"
+#include "sysemu/pmu.h"
+#include "sysemu/instmap.h"
+#include "semihosting/common-semi.h"
+#include "trace.h"
+
+
+static int riscv_cpu_local_irq_pending(CPURISCVState *env)
+{
+    int virq;
+    uint64_t irqs, pending, mie, hsie, vsie;
+
+    /* Determine interrupt enable state of all privilege modes */
+    if (env->virt_enabled) {
+        mie = 1;
+        hsie = 1;
+        vsie = (env->priv < PRV_S) ||
+               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
+    } else {
+        mie = (env->priv < PRV_M) ||
+              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
+        hsie = (env->priv < PRV_S) ||
+               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
+        vsie = 0;
+    }
+
+    /* Determine all pending interrupts */
+    pending = riscv_cpu_all_pending(env);
+
+    /* Check M-mode interrupts */
+    irqs = pending & ~env->mideleg & -mie;
+    if (irqs) {
+        return riscv_cpu_pending_to_irq(env, IRQ_M_EXT, IPRIO_DEFAULT_M,
+                                        irqs, env->miprio);
+    }
+
+    /* Check HS-mode interrupts */
+    irqs = pending & env->mideleg & ~env->hideleg & -hsie;
+    if (irqs) {
+        return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
+                                        irqs, env->siprio);
+    }
+
+    /* Check VS-mode interrupts */
+    irqs = pending & env->mideleg & env->hideleg & -vsie;
+    if (irqs) {
+        virq = riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
+                                        irqs >> 1, env->hviprio);
+        return (virq <= 0) ? virq : virq + 1;
+    }
+
+    /* Indicate no pending interrupt */
+    return RISCV_EXCP_NONE;
+}
+
+bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+    if (interrupt_request & CPU_INTERRUPT_HARD) {
+        RISCVCPU *cpu = RISCV_CPU(cs);
+        CPURISCVState *env = &cpu->env;
+        int interruptno = riscv_cpu_local_irq_pending(env);
+        if (interruptno >= 0) {
+            cs->exception_index = RISCV_EXCP_INT_FLAG | interruptno;
+            riscv_cpu_do_interrupt(cs);
+            return true;
+        }
+    }
+    return false;
+}
+
+/*
+ * get_physical_address_pmp - check PMP permission for this physical address
+ *
+ * Match the PMP region and check permission for this physical address and it's
+ * TLB page. Returns 0 if the permission checking was successful
+ *
+ * @env: CPURISCVState
+ * @prot: The returned protection attributes
+ * @addr: The physical address to be checked permission
+ * @access_type: The type of MMU access
+ * @mode: Indicates current privilege level.
+ */
+static int get_physical_address_pmp(CPURISCVState *env, int *prot, hwaddr addr,
+                                    int size, MMUAccessType access_type,
+                                    int mode)
+{
+    pmp_priv_t pmp_priv;
+    bool pmp_has_privs;
+
+    if (!riscv_cpu_cfg(env)->pmp) {
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return TRANSLATE_SUCCESS;
+    }
+
+    pmp_has_privs = pmp_hart_has_privs(env, addr, size, 1 << access_type,
+                                       &pmp_priv, mode);
+    if (!pmp_has_privs) {
+        *prot = 0;
+        return TRANSLATE_PMP_FAIL;
+    }
+
+    *prot = pmp_priv_to_page_prot(pmp_priv);
+
+    return TRANSLATE_SUCCESS;
+}
+
+/*
+ * get_physical_address - get the physical address for this virtual address
+ *
+ * Do a page table walk to obtain the physical address corresponding to a
+ * virtual address. Returns 0 if the translation was successful
+ *
+ * Adapted from Spike's mmu_t::translate and mmu_t::walk
+ *
+ * @env: CPURISCVState
+ * @physical: This will be set to the calculated physical address
+ * @prot: The returned protection attributes
+ * @addr: The virtual address or guest physical address to be translated
+ * @fault_pte_addr: If not NULL, this will be set to fault pte address
+ *                  when a error occurs on pte address translation.
+ *                  This will already be shifted to match htval.
+ * @access_type: The type of MMU access
+ * @mmu_idx: Indicates current privilege level
+ * @first_stage: Are we in first stage translation?
+ *               Second stage is used for hypervisor guest translation
+ * @two_stage: Are we going to perform two stage translation
+ * @is_debug: Is this access from a debugger or the monitor?
+ */
+static int get_physical_address(CPURISCVState *env, hwaddr *physical,
+                                int *ret_prot, vaddr addr,
+                                target_ulong *fault_pte_addr,
+                                int access_type, int mmu_idx,
+                                bool first_stage, bool two_stage,
+                                bool is_debug)
+{
+    /*
+     * NOTE: the env->pc value visible here will not be
+     * correct, but the value visible to the exception handler
+     * (riscv_cpu_do_interrupt) is correct
+     */
+    MemTxResult res;
+    MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
+    int mode = mmuidx_priv(mmu_idx);
+    bool use_background = false;
+    hwaddr ppn;
+    int napot_bits = 0;
+    target_ulong napot_mask;
+
+    /*
+     * Check if we should use the background registers for the two
+     * stage translation. We don't need to check if we actually need
+     * two stage translation as that happened before this function
+     * was called. Background registers will be used if the guest has
+     * forced a two stage translation to be on (in HS or M mode).
+     */
+    if (!env->virt_enabled && two_stage) {
+        use_background = true;
+    }
+
+    if (mode == PRV_M || !riscv_cpu_cfg(env)->mmu) {
+        *physical = addr;
+        *ret_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return TRANSLATE_SUCCESS;
+    }
+
+    *ret_prot = 0;
+
+    hwaddr base;
+    int levels, ptidxbits, ptesize, vm, widened;
+
+    if (first_stage == true) {
+        if (use_background) {
+            if (riscv_cpu_mxl(env) == MXL_RV32) {
+                base = (hwaddr)get_field(env->vsatp, SATP32_PPN) << PGSHIFT;
+                vm = get_field(env->vsatp, SATP32_MODE);
+            } else {
+                base = (hwaddr)get_field(env->vsatp, SATP64_PPN) << PGSHIFT;
+                vm = get_field(env->vsatp, SATP64_MODE);
+            }
+        } else {
+            if (riscv_cpu_mxl(env) == MXL_RV32) {
+                base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
+                vm = get_field(env->satp, SATP32_MODE);
+            } else {
+                base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
+                vm = get_field(env->satp, SATP64_MODE);
+            }
+        }
+        widened = 0;
+    } else {
+        if (riscv_cpu_mxl(env) == MXL_RV32) {
+            base = (hwaddr)get_field(env->hgatp, SATP32_PPN) << PGSHIFT;
+            vm = get_field(env->hgatp, SATP32_MODE);
+        } else {
+            base = (hwaddr)get_field(env->hgatp, SATP64_PPN) << PGSHIFT;
+            vm = get_field(env->hgatp, SATP64_MODE);
+        }
+        widened = 2;
+    }
+
+    switch (vm) {
+    case VM_1_10_SV32:
+      levels = 2; ptidxbits = 10; ptesize = 4; break;
+    case VM_1_10_SV39:
+      levels = 3; ptidxbits = 9; ptesize = 8; break;
+    case VM_1_10_SV48:
+      levels = 4; ptidxbits = 9; ptesize = 8; break;
+    case VM_1_10_SV57:
+      levels = 5; ptidxbits = 9; ptesize = 8; break;
+    case VM_1_10_MBARE:
+        *physical = addr;
+        *ret_prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        return TRANSLATE_SUCCESS;
+    default:
+      g_assert_not_reached();
+    }
+
+    CPUState *cs = env_cpu(env);
+    int va_bits = PGSHIFT + levels * ptidxbits + widened;
+
+    if (first_stage == true) {
+        target_ulong mask, masked_msbs;
+
+        if (TARGET_LONG_BITS > (va_bits - 1)) {
+            mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
+        } else {
+            mask = 0;
+        }
+        masked_msbs = (addr >> (va_bits - 1)) & mask;
+
+        if (masked_msbs != 0 && masked_msbs != mask) {
+            return TRANSLATE_FAIL;
+        }
+    } else {
+        if (vm != VM_1_10_SV32 && addr >> va_bits != 0) {
+            return TRANSLATE_FAIL;
+        }
+    }
+
+    bool pbmte = env->menvcfg & MENVCFG_PBMTE;
+    bool hade = env->menvcfg & MENVCFG_HADE;
+
+    if (first_stage && two_stage && env->virt_enabled) {
+        pbmte = pbmte && (env->henvcfg & HENVCFG_PBMTE);
+        hade = hade && (env->henvcfg & HENVCFG_HADE);
+    }
+
+    int ptshift = (levels - 1) * ptidxbits;
+    target_ulong pte;
+    hwaddr pte_addr;
+    int i;
+
+#if !TCG_OVERSIZED_GUEST
+restart:
+#endif
+    for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
+        target_ulong idx;
+        if (i == 0) {
+            idx = (addr >> (PGSHIFT + ptshift)) &
+                           ((1 << (ptidxbits + widened)) - 1);
+        } else {
+            idx = (addr >> (PGSHIFT + ptshift)) &
+                           ((1 << ptidxbits) - 1);
+        }
+
+        /* check that physical address of PTE is legal */
+
+        if (two_stage && first_stage) {
+            int vbase_prot;
+            hwaddr vbase;
+
+            /* Do the second stage translation on the base PTE address. */
+            int vbase_ret = get_physical_address(env, &vbase, &vbase_prot,
+                                                 base, NULL, MMU_DATA_LOAD,
+                                                 MMUIdx_U, false, true,
+                                                 is_debug);
+
+            if (vbase_ret != TRANSLATE_SUCCESS) {
+                if (fault_pte_addr) {
+                    *fault_pte_addr = (base + idx * ptesize) >> 2;
+                }
+                return TRANSLATE_G_STAGE_FAIL;
+            }
+
+            pte_addr = vbase + idx * ptesize;
+        } else {
+            pte_addr = base + idx * ptesize;
+        }
+
+        int pmp_prot;
+        int pmp_ret = get_physical_address_pmp(env, &pmp_prot, pte_addr,
+                                               sizeof(target_ulong),
+                                               MMU_DATA_LOAD, PRV_S);
+        if (pmp_ret != TRANSLATE_SUCCESS) {
+            return TRANSLATE_PMP_FAIL;
+        }
+
+        if (riscv_cpu_mxl(env) == MXL_RV32) {
+            pte = address_space_ldl(cs->as, pte_addr, attrs, &res);
+        } else {
+            pte = address_space_ldq(cs->as, pte_addr, attrs, &res);
+        }
+
+        if (res != MEMTX_OK) {
+            return TRANSLATE_FAIL;
+        }
+
+        if (riscv_cpu_sxl(env) == MXL_RV32) {
+            ppn = pte >> PTE_PPN_SHIFT;
+        } else {
+            if (pte & PTE_RESERVED) {
+                return TRANSLATE_FAIL;
+            }
+
+            if (!pbmte && (pte & PTE_PBMT)) {
+                return TRANSLATE_FAIL;
+            }
+
+            if (!riscv_cpu_cfg(env)->ext_svnapot && (pte & PTE_N)) {
+                return TRANSLATE_FAIL;
+            }
+
+            ppn = (pte & (target_ulong)PTE_PPN_MASK) >> PTE_PPN_SHIFT;
+        }
+
+        if (!(pte & PTE_V)) {
+            /* Invalid PTE */
+            return TRANSLATE_FAIL;
+        }
+        if (pte & (PTE_R | PTE_W | PTE_X)) {
+            goto leaf;
+        }
+
+        /* Inner PTE, continue walking */
+        if (pte & (PTE_D | PTE_A | PTE_U | PTE_ATTR)) {
+            return TRANSLATE_FAIL;
+        }
+        base = ppn << PGSHIFT;
+    }
+
+    /* No leaf pte at any translation level. */
+    return TRANSLATE_FAIL;
+
+ leaf:
+    if (ppn & ((1ULL << ptshift) - 1)) {
+        /* Misaligned PPN */
+        return TRANSLATE_FAIL;
+    }
+    if (!pbmte && (pte & PTE_PBMT)) {
+        /* Reserved without Svpbmt. */
+        return TRANSLATE_FAIL;
+    }
+
+    /* Check for reserved combinations of RWX flags. */
+    switch (pte & (PTE_R | PTE_W | PTE_X)) {
+    case PTE_W:
+    case PTE_W | PTE_X:
+        return TRANSLATE_FAIL;
+    }
+
+    int prot = 0;
+    if (pte & PTE_R) {
+        prot |= PAGE_READ;
+    }
+    if (pte & PTE_W) {
+        prot |= PAGE_WRITE;
+    }
+    if (pte & PTE_X) {
+        bool mxr;
+
+        if (first_stage == true) {
+            mxr = get_field(env->mstatus, MSTATUS_MXR);
+        } else {
+            mxr = get_field(env->vsstatus, MSTATUS_MXR);
+        }
+        if (mxr) {
+            prot |= PAGE_READ;
+        }
+        prot |= PAGE_EXEC;
+    }
+
+    if (pte & PTE_U) {
+        if (mode != PRV_U) {
+            if (!mmuidx_sum(mmu_idx)) {
+                return TRANSLATE_FAIL;
+            }
+            /* SUM allows only read+write, not execute. */
+            prot &= PAGE_READ | PAGE_WRITE;
+        }
+    } else if (mode != PRV_S) {
+        /* Supervisor PTE flags when not S mode */
+        return TRANSLATE_FAIL;
+    }
+
+    if (!((prot >> access_type) & 1)) {
+        /* Access check failed */
+        return TRANSLATE_FAIL;
+    }
+
+    /* If necessary, set accessed and dirty bits. */
+    target_ulong updated_pte = pte | PTE_A |
+                (access_type == MMU_DATA_STORE ? PTE_D : 0);
+
+    /* Page table updates need to be atomic with MTTCG enabled */
+    if (updated_pte != pte && !is_debug) {
+        if (!hade) {
+            return TRANSLATE_FAIL;
+        }
+
+        /*
+         * - if accessed or dirty bits need updating, and the PTE is
+         *   in RAM, then we do so atomically with a compare and swap.
+         * - if the PTE is in IO space or ROM, then it can't be updated
+         *   and we return TRANSLATE_FAIL.
+         * - if the PTE changed by the time we went to update it, then
+         *   it is no longer valid and we must re-walk the page table.
+         */
+        MemoryRegion *mr;
+        hwaddr l = sizeof(target_ulong), addr1;
+        mr = address_space_translate(cs->as, pte_addr, &addr1, &l,
+                                     false, MEMTXATTRS_UNSPECIFIED);
+        if (memory_region_is_ram(mr)) {
+            target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
+#if TCG_OVERSIZED_GUEST
+            /*
+             * MTTCG is not enabled on oversized TCG guests so
+             * page table updates do not need to be atomic
+             */
+            *pte_pa = pte = updated_pte;
+#else
+            target_ulong old_pte = qatomic_cmpxchg(pte_pa, pte, updated_pte);
+            if (old_pte != pte) {
+                goto restart;
+            }
+            pte = updated_pte;
+#endif
+        } else {
+            /*
+             * Misconfigured PTE in ROM (AD bits are not preset) or
+             * PTE is in IO space and can't be updated atomically.
+             */
+            return TRANSLATE_FAIL;
+        }
+    }
+
+    /* For superpage mappings, make a fake leaf PTE for the TLB's benefit. */
+    target_ulong vpn = addr >> PGSHIFT;
+
+    if (riscv_cpu_cfg(env)->ext_svnapot && (pte & PTE_N)) {
+        napot_bits = ctzl(ppn) + 1;
+        if ((i != (levels - 1)) || (napot_bits != 4)) {
+            return TRANSLATE_FAIL;
+        }
+    }
+
+    napot_mask = (1 << napot_bits) - 1;
+    *physical = (((ppn & ~napot_mask) | (vpn & napot_mask) |
+                  (vpn & (((target_ulong)1 << ptshift) - 1))
+                 ) << PGSHIFT) | (addr & ~TARGET_PAGE_MASK);
+
+    /*
+     * Remove write permission unless this is a store, or the page is
+     * already dirty, so that we TLB miss on later writes to update
+     * the dirty bit.
+     */
+    if (access_type != MMU_DATA_STORE && !(pte & PTE_D)) {
+        prot &= ~PAGE_WRITE;
+    }
+    *ret_prot = prot;
+
+    return TRANSLATE_SUCCESS;
+}
+
+static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
+                                MMUAccessType access_type, bool pmp_violation,
+                                bool first_stage, bool two_stage,
+                                bool two_stage_indirect)
+{
+    CPUState *cs = env_cpu(env);
+    int page_fault_exceptions, vm;
+    uint64_t stap_mode;
+
+    if (riscv_cpu_mxl(env) == MXL_RV32) {
+        stap_mode = SATP32_MODE;
+    } else {
+        stap_mode = SATP64_MODE;
+    }
+
+    if (first_stage) {
+        vm = get_field(env->satp, stap_mode);
+    } else {
+        vm = get_field(env->hgatp, stap_mode);
+    }
+
+    page_fault_exceptions = vm != VM_1_10_MBARE && !pmp_violation;
+
+    switch (access_type) {
+    case MMU_INST_FETCH:
+        if (env->virt_enabled && !first_stage) {
+            cs->exception_index = RISCV_EXCP_INST_GUEST_PAGE_FAULT;
+        } else {
+            cs->exception_index = page_fault_exceptions ?
+                RISCV_EXCP_INST_PAGE_FAULT : RISCV_EXCP_INST_ACCESS_FAULT;
+        }
+        break;
+    case MMU_DATA_LOAD:
+        if (two_stage && !first_stage) {
+            cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT;
+        } else {
+            cs->exception_index = page_fault_exceptions ?
+                RISCV_EXCP_LOAD_PAGE_FAULT : RISCV_EXCP_LOAD_ACCESS_FAULT;
+        }
+        break;
+    case MMU_DATA_STORE:
+        if (two_stage && !first_stage) {
+            cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT;
+        } else {
+            cs->exception_index = page_fault_exceptions ?
+                RISCV_EXCP_STORE_PAGE_FAULT :
+                RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
+        }
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    env->badaddr = address;
+    env->two_stage_lookup = two_stage;
+    env->two_stage_indirect_lookup = two_stage_indirect;
+}
+
+hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    hwaddr phys_addr;
+    int prot;
+    int mmu_idx = cpu_mmu_index(&cpu->env, false);
+
+    if (get_physical_address(env, &phys_addr, &prot, addr, NULL, 0, mmu_idx,
+                             true, env->virt_enabled, true)) {
+        return -1;
+    }
+
+    if (env->virt_enabled) {
+        if (get_physical_address(env, &phys_addr, &prot, phys_addr, NULL,
+                                 0, mmu_idx, false, true, true)) {
+            return -1;
+        }
+    }
+
+    return phys_addr & TARGET_PAGE_MASK;
+}
+
+void riscv_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+                                     vaddr addr, unsigned size,
+                                     MMUAccessType access_type,
+                                     int mmu_idx, MemTxAttrs attrs,
+                                     MemTxResult response, uintptr_t retaddr)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+
+    if (access_type == MMU_DATA_STORE) {
+        cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT;
+    } else if (access_type == MMU_DATA_LOAD) {
+        cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT;
+    } else {
+        cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT;
+    }
+
+    env->badaddr = addr;
+    env->two_stage_lookup = mmuidx_2stage(mmu_idx);
+    env->two_stage_indirect_lookup = false;
+    cpu_loop_exit_restore(cs, retaddr);
+}
+
+void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
+                                   MMUAccessType access_type, int mmu_idx,
+                                   uintptr_t retaddr)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    switch (access_type) {
+    case MMU_INST_FETCH:
+        cs->exception_index = RISCV_EXCP_INST_ADDR_MIS;
+        break;
+    case MMU_DATA_LOAD:
+        cs->exception_index = RISCV_EXCP_LOAD_ADDR_MIS;
+        break;
+    case MMU_DATA_STORE:
+        cs->exception_index = RISCV_EXCP_STORE_AMO_ADDR_MIS;
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    env->badaddr = addr;
+    env->two_stage_lookup = mmuidx_2stage(mmu_idx);
+    env->two_stage_indirect_lookup = false;
+    cpu_loop_exit_restore(cs, retaddr);
+}
+
+static void pmu_tlb_fill_incr_ctr(RISCVCPU *cpu, MMUAccessType access_type)
+{
+    enum riscv_pmu_event_idx pmu_event_type;
+
+    switch (access_type) {
+    case MMU_INST_FETCH:
+        pmu_event_type = RISCV_PMU_EVENT_CACHE_ITLB_PREFETCH_MISS;
+        break;
+    case MMU_DATA_LOAD:
+        pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_READ_MISS;
+        break;
+    case MMU_DATA_STORE:
+        pmu_event_type = RISCV_PMU_EVENT_CACHE_DTLB_WRITE_MISS;
+        break;
+    default:
+        return;
+    }
+
+    riscv_pmu_incr_ctr(cpu, pmu_event_type);
+}
+
+bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+                        MMUAccessType access_type, int mmu_idx,
+                        bool probe, uintptr_t retaddr)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    vaddr im_address;
+    hwaddr pa = 0;
+    int prot, prot2, prot_pmp;
+    bool pmp_violation = false;
+    bool first_stage_error = true;
+    bool two_stage_lookup = mmuidx_2stage(mmu_idx);
+    bool two_stage_indirect_error = false;
+    int ret = TRANSLATE_FAIL;
+    int mode = mmu_idx;
+    /* default TLB page size */
+    target_ulong tlb_size = TARGET_PAGE_SIZE;
+
+    env->guest_phys_fault_addr = 0;
+
+    qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
+                  __func__, address, access_type, mmu_idx);
+
+    pmu_tlb_fill_incr_ctr(cpu, access_type);
+    if (two_stage_lookup) {
+        /* Two stage lookup */
+        ret = get_physical_address(env, &pa, &prot, address,
+                                   &env->guest_phys_fault_addr, access_type,
+                                   mmu_idx, true, true, false);
+
+        /*
+         * A G-stage exception may be triggered during two state lookup.
+         * And the env->guest_phys_fault_addr has already been set in
+         * get_physical_address().
+         */
+        if (ret == TRANSLATE_G_STAGE_FAIL) {
+            first_stage_error = false;
+            two_stage_indirect_error = true;
+            access_type = MMU_DATA_LOAD;
+        }
+
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s 1st-stage address=%" VADDR_PRIx " ret %d physical "
+                      HWADDR_FMT_plx " prot %d\n",
+                      __func__, address, ret, pa, prot);
+
+        if (ret == TRANSLATE_SUCCESS) {
+            /* Second stage lookup */
+            im_address = pa;
+
+            ret = get_physical_address(env, &pa, &prot2, im_address, NULL,
+                                       access_type, MMUIdx_U, false, true,
+                                       false);
+
+            qemu_log_mask(CPU_LOG_MMU,
+                          "%s 2nd-stage address=%" VADDR_PRIx
+                          " ret %d physical "
+                          HWADDR_FMT_plx " prot %d\n",
+                          __func__, im_address, ret, pa, prot2);
+
+            prot &= prot2;
+
+            if (ret == TRANSLATE_SUCCESS) {
+                ret = get_physical_address_pmp(env, &prot_pmp, pa,
+                                               size, access_type, mode);
+                tlb_size = pmp_get_tlb_size(env, pa);
+
+                qemu_log_mask(CPU_LOG_MMU,
+                              "%s PMP address=" HWADDR_FMT_plx " ret %d prot"
+                              " %d tlb_size " TARGET_FMT_lu "\n",
+                              __func__, pa, ret, prot_pmp, tlb_size);
+
+                prot &= prot_pmp;
+            }
+
+            if (ret != TRANSLATE_SUCCESS) {
+                /*
+                 * Guest physical address translation failed, this is a HS
+                 * level exception
+                 */
+                first_stage_error = false;
+                env->guest_phys_fault_addr = (im_address |
+                                              (address &
+                                               (TARGET_PAGE_SIZE - 1))) >> 2;
+            }
+        }
+    } else {
+        /* Single stage lookup */
+        ret = get_physical_address(env, &pa, &prot, address, NULL,
+                                   access_type, mmu_idx, true, false, false);
+
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s address=%" VADDR_PRIx " ret %d physical "
+                      HWADDR_FMT_plx " prot %d\n",
+                      __func__, address, ret, pa, prot);
+
+        if (ret == TRANSLATE_SUCCESS) {
+            ret = get_physical_address_pmp(env, &prot_pmp, pa,
+                                           size, access_type, mode);
+            tlb_size = pmp_get_tlb_size(env, pa);
+
+            qemu_log_mask(CPU_LOG_MMU,
+                          "%s PMP address=" HWADDR_FMT_plx " ret %d prot"
+                          " %d tlb_size " TARGET_FMT_lu "\n",
+                          __func__, pa, ret, prot_pmp, tlb_size);
+
+            prot &= prot_pmp;
+        }
+    }
+
+    if (ret == TRANSLATE_PMP_FAIL) {
+        pmp_violation = true;
+    }
+
+    if (ret == TRANSLATE_SUCCESS) {
+        tlb_set_page(cs, address & ~(tlb_size - 1), pa & ~(tlb_size - 1),
+                     prot, mmu_idx, tlb_size);
+        return true;
+    } else if (probe) {
+        return false;
+    } else {
+        raise_mmu_exception(env, address, access_type, pmp_violation,
+                            first_stage_error, two_stage_lookup,
+                            two_stage_indirect_error);
+        cpu_loop_exit_restore(cs, retaddr);
+    }
+
+    return true;
+}
diff --git a/target/riscv/tcg/tcg-stub.c b/target/riscv/tcg/tcg-stub.c
index dfe42ae2ac..e329d25355 100644
--- a/target/riscv/tcg/tcg-stub.c
+++ b/target/riscv/tcg/tcg-stub.c
@@ -23,3 +23,9 @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env,
 {
     g_assert_not_reached();
 }
+
+hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+    /* XXX too many TCG code in the real riscv_cpu_get_phys_page_debug() */
+    return -1;
+}
diff --git a/target/riscv/tcg/sysemu/meson.build b/target/riscv/tcg/sysemu/meson.build
index e8e61e5784..a549e497ce 100644
--- a/target/riscv/tcg/sysemu/meson.build
+++ b/target/riscv/tcg/sysemu/meson.build
@@ -1,3 +1,4 @@
 riscv_system_ss.add(when: 'CONFIG_TCG', if_true: files(
+  'cpu_helper.c',
   'debug.c',
 ))
-- 
2.38.1



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

* [PATCH 14/16] target/riscv: Move sysemu-specific code to sysemu/cpu_helper.c
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (12 preceding siblings ...)
  2023-06-26 23:20 ` [RFC PATCH 13/16] target/riscv: Move TCG/sysemu-specific code to tcg/sysemu/cpu_helper.c Philippe Mathieu-Daudé
@ 2023-06-26 23:20 ` Philippe Mathieu-Daudé
  2023-06-26 23:20 ` [PATCH 15/16] target/riscv: Restrict TCG-specific prototype declarations Philippe Mathieu-Daudé
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/cpu_helper.c        | 859 +-----------------------------
 target/riscv/sysemu/cpu_helper.c | 863 +++++++++++++++++++++++++++++++
 target/riscv/sysemu/meson.build  |   1 +
 3 files changed, 865 insertions(+), 858 deletions(-)
 create mode 100644 target/riscv/sysemu/cpu_helper.c

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index ded1fee489..075b1ae068 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -18,22 +18,12 @@
  */
 
 #include "qemu/osdep.h"
-#include "qemu/log.h"
-#include "qemu/main-loop.h"
 #include "cpu.h"
 #include "internals.h"
-#include "sysemu/pmu.h"
-#include "exec/exec-all.h"
-#include "sysemu/instmap.h"
-#include "tcg/tcg-op.h"
-#include "trace.h"
-#include "semihosting/common-semi.h"
 #ifndef CONFIG_USER_ONLY
 #include "sysemu/cpu-timers.h"
 #endif
-#include "cpu_bits.h"
-#include "sysemu/debug.h"
-#include "tcg/oversized-guest.h"
+
 
 int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
 {
@@ -104,850 +94,3 @@ void riscv_cpu_update_mask(CPURISCVState *env)
         env->cur_pmbase = base;
     }
 }
-
-#ifndef CONFIG_USER_ONLY
-
-/*
- * The HS-mode is allowed to configure priority only for the
- * following VS-mode local interrupts:
- *
- * 0  (Reserved interrupt, reads as zero)
- * 1  Supervisor software interrupt
- * 4  (Reserved interrupt, reads as zero)
- * 5  Supervisor timer interrupt
- * 8  (Reserved interrupt, reads as zero)
- * 13 (Reserved interrupt)
- * 14 "
- * 15 "
- * 16 "
- * 17 "
- * 18 "
- * 19 "
- * 20 "
- * 21 "
- * 22 "
- * 23 "
- */
-
-static const int hviprio_index2irq[] = {
-    0, 1, 4, 5, 8, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
-static const int hviprio_index2rdzero[] = {
-    1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
-{
-    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
-        return -EINVAL;
-    }
-
-    if (out_irq) {
-        *out_irq = hviprio_index2irq[index];
-    }
-
-    if (out_rdzero) {
-        *out_rdzero = hviprio_index2rdzero[index];
-    }
-
-    return 0;
-}
-
-/*
- * Default priorities of local interrupts are defined in the
- * RISC-V Advanced Interrupt Architecture specification.
- *
- * ----------------------------------------------------------------
- *  Default  |
- *  Priority | Major Interrupt Numbers
- * ----------------------------------------------------------------
- *  Highest  | 47, 23, 46, 45, 22, 44,
- *           | 43, 21, 42, 41, 20, 40
- *           |
- *           | 11 (0b),  3 (03),  7 (07)
- *           |  9 (09),  1 (01),  5 (05)
- *           | 12 (0c)
- *           | 10 (0a),  2 (02),  6 (06)
- *           |
- *           | 39, 19, 38, 37, 18, 36,
- *  Lowest   | 35, 17, 34, 33, 16, 32
- * ----------------------------------------------------------------
- */
-static const uint8_t default_iprio[64] = {
-    /* Custom interrupts 48 to 63 */
-    [63] = IPRIO_MMAXIPRIO,
-    [62] = IPRIO_MMAXIPRIO,
-    [61] = IPRIO_MMAXIPRIO,
-    [60] = IPRIO_MMAXIPRIO,
-    [59] = IPRIO_MMAXIPRIO,
-    [58] = IPRIO_MMAXIPRIO,
-    [57] = IPRIO_MMAXIPRIO,
-    [56] = IPRIO_MMAXIPRIO,
-    [55] = IPRIO_MMAXIPRIO,
-    [54] = IPRIO_MMAXIPRIO,
-    [53] = IPRIO_MMAXIPRIO,
-    [52] = IPRIO_MMAXIPRIO,
-    [51] = IPRIO_MMAXIPRIO,
-    [50] = IPRIO_MMAXIPRIO,
-    [49] = IPRIO_MMAXIPRIO,
-    [48] = IPRIO_MMAXIPRIO,
-
-    /* Custom interrupts 24 to 31 */
-    [31] = IPRIO_MMAXIPRIO,
-    [30] = IPRIO_MMAXIPRIO,
-    [29] = IPRIO_MMAXIPRIO,
-    [28] = IPRIO_MMAXIPRIO,
-    [27] = IPRIO_MMAXIPRIO,
-    [26] = IPRIO_MMAXIPRIO,
-    [25] = IPRIO_MMAXIPRIO,
-    [24] = IPRIO_MMAXIPRIO,
-
-    [47] = IPRIO_DEFAULT_UPPER,
-    [23] = IPRIO_DEFAULT_UPPER + 1,
-    [46] = IPRIO_DEFAULT_UPPER + 2,
-    [45] = IPRIO_DEFAULT_UPPER + 3,
-    [22] = IPRIO_DEFAULT_UPPER + 4,
-    [44] = IPRIO_DEFAULT_UPPER + 5,
-
-    [43] = IPRIO_DEFAULT_UPPER + 6,
-    [21] = IPRIO_DEFAULT_UPPER + 7,
-    [42] = IPRIO_DEFAULT_UPPER + 8,
-    [41] = IPRIO_DEFAULT_UPPER + 9,
-    [20] = IPRIO_DEFAULT_UPPER + 10,
-    [40] = IPRIO_DEFAULT_UPPER + 11,
-
-    [11] = IPRIO_DEFAULT_M,
-    [3]  = IPRIO_DEFAULT_M + 1,
-    [7]  = IPRIO_DEFAULT_M + 2,
-
-    [9]  = IPRIO_DEFAULT_S,
-    [1]  = IPRIO_DEFAULT_S + 1,
-    [5]  = IPRIO_DEFAULT_S + 2,
-
-    [12] = IPRIO_DEFAULT_SGEXT,
-
-    [10] = IPRIO_DEFAULT_VS,
-    [2]  = IPRIO_DEFAULT_VS + 1,
-    [6]  = IPRIO_DEFAULT_VS + 2,
-
-    [39] = IPRIO_DEFAULT_LOWER,
-    [19] = IPRIO_DEFAULT_LOWER + 1,
-    [38] = IPRIO_DEFAULT_LOWER + 2,
-    [37] = IPRIO_DEFAULT_LOWER + 3,
-    [18] = IPRIO_DEFAULT_LOWER + 4,
-    [36] = IPRIO_DEFAULT_LOWER + 5,
-
-    [35] = IPRIO_DEFAULT_LOWER + 6,
-    [17] = IPRIO_DEFAULT_LOWER + 7,
-    [34] = IPRIO_DEFAULT_LOWER + 8,
-    [33] = IPRIO_DEFAULT_LOWER + 9,
-    [16] = IPRIO_DEFAULT_LOWER + 10,
-    [32] = IPRIO_DEFAULT_LOWER + 11,
-};
-
-uint8_t riscv_cpu_default_priority(int irq)
-{
-    if (irq < 0 || irq > 63) {
-        return IPRIO_MMAXIPRIO;
-    }
-
-    return default_iprio[irq] ? default_iprio[irq] : IPRIO_MMAXIPRIO;
-};
-
-int riscv_cpu_pending_to_irq(CPURISCVState *env,
-                             int extirq, unsigned int extirq_def_prio,
-                             uint64_t pending, uint8_t *iprio)
-{
-    int irq, best_irq = RISCV_EXCP_NONE;
-    unsigned int prio, best_prio = UINT_MAX;
-
-    if (!pending) {
-        return RISCV_EXCP_NONE;
-    }
-
-    irq = ctz64(pending);
-    if (!((extirq == IRQ_M_EXT) ? riscv_cpu_cfg(env)->ext_smaia :
-                                  riscv_cpu_cfg(env)->ext_ssaia)) {
-        return irq;
-    }
-
-    pending = pending >> irq;
-    while (pending) {
-        prio = iprio[irq];
-        if (!prio) {
-            if (irq == extirq) {
-                prio = extirq_def_prio;
-            } else {
-                prio = (riscv_cpu_default_priority(irq) < extirq_def_prio) ?
-                       1 : IPRIO_MMAXIPRIO;
-            }
-        }
-        if ((pending & 0x1) && (prio <= best_prio)) {
-            best_irq = irq;
-            best_prio = prio;
-        }
-        irq++;
-        pending = pending >> 1;
-    }
-
-    return best_irq;
-}
-
-uint64_t riscv_cpu_all_pending(CPURISCVState *env)
-{
-    uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
-    uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
-    uint64_t vstip = (env->vstime_irq) ? MIP_VSTIP : 0;
-
-    return (env->mip | vsgein | vstip) & env->mie;
-}
-
-int riscv_cpu_mirq_pending(CPURISCVState *env)
-{
-    uint64_t irqs = riscv_cpu_all_pending(env) & ~env->mideleg &
-                    ~(MIP_SGEIP | MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
-
-    return riscv_cpu_pending_to_irq(env, IRQ_M_EXT, IPRIO_DEFAULT_M,
-                                    irqs, env->miprio);
-}
-
-int riscv_cpu_sirq_pending(CPURISCVState *env)
-{
-    uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
-                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
-
-    return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-                                    irqs, env->siprio);
-}
-
-int riscv_cpu_vsirq_pending(CPURISCVState *env)
-{
-    uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
-                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
-
-    return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
-                                    irqs >> 1, env->hviprio);
-}
-
-/* Return true is floating point support is currently enabled */
-bool riscv_cpu_fp_enabled(CPURISCVState *env)
-{
-    if (env->mstatus & MSTATUS_FS) {
-        if (env->virt_enabled && !(env->mstatus_hs & MSTATUS_FS)) {
-            return false;
-        }
-        return true;
-    }
-
-    return false;
-}
-
-/* Return true is vector support is currently enabled */
-bool riscv_cpu_vector_enabled(CPURISCVState *env)
-{
-    if (env->mstatus & MSTATUS_VS) {
-        if (env->virt_enabled && !(env->mstatus_hs & MSTATUS_VS)) {
-            return false;
-        }
-        return true;
-    }
-
-    return false;
-}
-
-void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
-{
-    uint64_t mstatus_mask = MSTATUS_MXR | MSTATUS_SUM |
-                            MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE |
-                            MSTATUS64_UXL | MSTATUS_VS;
-
-    if (riscv_has_ext(env, RVF)) {
-        mstatus_mask |= MSTATUS_FS;
-    }
-    bool current_virt = env->virt_enabled;
-
-    g_assert(riscv_has_ext(env, RVH));
-
-    if (current_virt) {
-        /* Current V=1 and we are about to change to V=0 */
-        env->vsstatus = env->mstatus & mstatus_mask;
-        env->mstatus &= ~mstatus_mask;
-        env->mstatus |= env->mstatus_hs;
-
-        env->vstvec = env->stvec;
-        env->stvec = env->stvec_hs;
-
-        env->vsscratch = env->sscratch;
-        env->sscratch = env->sscratch_hs;
-
-        env->vsepc = env->sepc;
-        env->sepc = env->sepc_hs;
-
-        env->vscause = env->scause;
-        env->scause = env->scause_hs;
-
-        env->vstval = env->stval;
-        env->stval = env->stval_hs;
-
-        env->vsatp = env->satp;
-        env->satp = env->satp_hs;
-    } else {
-        /* Current V=0 and we are about to change to V=1 */
-        env->mstatus_hs = env->mstatus & mstatus_mask;
-        env->mstatus &= ~mstatus_mask;
-        env->mstatus |= env->vsstatus;
-
-        env->stvec_hs = env->stvec;
-        env->stvec = env->vstvec;
-
-        env->sscratch_hs = env->sscratch;
-        env->sscratch = env->vsscratch;
-
-        env->sepc_hs = env->sepc;
-        env->sepc = env->vsepc;
-
-        env->scause_hs = env->scause;
-        env->scause = env->vscause;
-
-        env->stval_hs = env->stval;
-        env->stval = env->vstval;
-
-        env->satp_hs = env->satp;
-        env->satp = env->vsatp;
-    }
-}
-
-target_ulong riscv_cpu_get_geilen(CPURISCVState *env)
-{
-    if (!riscv_has_ext(env, RVH)) {
-        return 0;
-    }
-
-    return env->geilen;
-}
-
-void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen)
-{
-    if (!riscv_has_ext(env, RVH)) {
-        return;
-    }
-
-    if (geilen > (TARGET_LONG_BITS - 1)) {
-        return;
-    }
-
-    env->geilen = geilen;
-}
-
-/* This function can only be called to set virt when RVH is enabled */
-void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
-{
-    /* Flush the TLB on all virt mode changes. */
-    if (env->virt_enabled != enable) {
-        tlb_flush(env_cpu(env));
-    }
-
-    env->virt_enabled = enable;
-
-    if (enable) {
-        /*
-         * The guest external interrupts from an interrupt controller are
-         * delivered only when the Guest/VM is running (i.e. V=1). This means
-         * any guest external interrupt which is triggered while the Guest/VM
-         * is not running (i.e. V=0) will be missed on QEMU resulting in guest
-         * with sluggish response to serial console input and other I/O events.
-         *
-         * To solve this, we check and inject interrupt after setting V=1.
-         */
-        riscv_cpu_update_mip(env, 0, 0);
-    }
-}
-
-int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
-{
-    CPURISCVState *env = &cpu->env;
-    if (env->miclaim & interrupts) {
-        return -1;
-    } else {
-        env->miclaim |= interrupts;
-        return 0;
-    }
-}
-
-uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask,
-                              uint64_t value)
-{
-    CPUState *cs = env_cpu(env);
-    uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
-
-    if (env->virt_enabled) {
-        gein = get_field(env->hstatus, HSTATUS_VGEIN);
-        vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
-    }
-
-    vstip = env->vstime_irq ? MIP_VSTIP : 0;
-
-    QEMU_IOTHREAD_LOCK_GUARD();
-
-    env->mip = (env->mip & ~mask) | (value & mask);
-
-    if (env->mip | vsgein | vstip) {
-        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
-    } else {
-        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
-    }
-
-    return old;
-}
-
-void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
-                             void *arg)
-{
-    env->rdtime_fn = fn;
-    env->rdtime_fn_arg = arg;
-}
-
-void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
-                                   int (*rmw_fn)(void *arg,
-                                                 target_ulong reg,
-                                                 target_ulong *val,
-                                                 target_ulong new_val,
-                                                 target_ulong write_mask),
-                                   void *rmw_fn_arg)
-{
-    if (priv <= PRV_M) {
-        env->aia_ireg_rmw_fn[priv] = rmw_fn;
-        env->aia_ireg_rmw_fn_arg[priv] = rmw_fn_arg;
-    }
-}
-
-void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
-{
-    g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED);
-
-    if (icount_enabled() && newpriv != env->priv) {
-        riscv_itrigger_update_priv(env);
-    }
-    /* tlb_flush is unnecessary as mode is contained in mmu_idx */
-    env->priv = newpriv;
-    env->xl = cpu_recompute_xl(env);
-    riscv_cpu_update_mask(env);
-
-    /*
-     * Clear the load reservation - otherwise a reservation placed in one
-     * context/process can be used by another, resulting in an SC succeeding
-     * incorrectly. Version 2.2 of the ISA specification explicitly requires
-     * this behaviour, while later revisions say that the kernel "should" use
-     * an SC instruction to force the yielding of a load reservation on a
-     * preemptive context switch. As a result, do both.
-     */
-    env->load_res = -1;
-}
-
-
-static target_ulong riscv_transformed_insn(CPURISCVState *env,
-                                           target_ulong insn,
-                                           target_ulong taddr)
-{
-    target_ulong xinsn = 0;
-    target_ulong access_rs1 = 0, access_imm = 0, access_size = 0;
-
-    /*
-     * Only Quadrant 0 and Quadrant 2 of RVC instruction space need to
-     * be uncompressed. The Quadrant 1 of RVC instruction space need
-     * not be transformed because these instructions won't generate
-     * any load/store trap.
-     */
-
-    if ((insn & 0x3) != 0x3) {
-        /* Transform 16bit instruction into 32bit instruction */
-        switch (GET_C_OP(insn)) {
-        case OPC_RISC_C_OP_QUAD0: /* Quadrant 0 */
-            switch (GET_C_FUNC(insn)) {
-            case OPC_RISC_C_FUNC_FLD_LQ:
-                if (riscv_cpu_xlen(env) != 128) { /* C.FLD (RV32/64) */
-                    xinsn = OPC_RISC_FLD;
-                    xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
-                    access_rs1 = GET_C_RS1S(insn);
-                    access_imm = GET_C_LD_IMM(insn);
-                    access_size = 8;
-                }
-                break;
-            case OPC_RISC_C_FUNC_LW: /* C.LW */
-                xinsn = OPC_RISC_LW;
-                xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
-                access_rs1 = GET_C_RS1S(insn);
-                access_imm = GET_C_LW_IMM(insn);
-                access_size = 4;
-                break;
-            case OPC_RISC_C_FUNC_FLW_LD:
-                if (riscv_cpu_xlen(env) == 32) { /* C.FLW (RV32) */
-                    xinsn = OPC_RISC_FLW;
-                    xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
-                    access_rs1 = GET_C_RS1S(insn);
-                    access_imm = GET_C_LW_IMM(insn);
-                    access_size = 4;
-                } else { /* C.LD (RV64/RV128) */
-                    xinsn = OPC_RISC_LD;
-                    xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
-                    access_rs1 = GET_C_RS1S(insn);
-                    access_imm = GET_C_LD_IMM(insn);
-                    access_size = 8;
-                }
-                break;
-            case OPC_RISC_C_FUNC_FSD_SQ:
-                if (riscv_cpu_xlen(env) != 128) { /* C.FSD (RV32/64) */
-                    xinsn = OPC_RISC_FSD;
-                    xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
-                    access_rs1 = GET_C_RS1S(insn);
-                    access_imm = GET_C_SD_IMM(insn);
-                    access_size = 8;
-                }
-                break;
-            case OPC_RISC_C_FUNC_SW: /* C.SW */
-                xinsn = OPC_RISC_SW;
-                xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
-                access_rs1 = GET_C_RS1S(insn);
-                access_imm = GET_C_SW_IMM(insn);
-                access_size = 4;
-                break;
-            case OPC_RISC_C_FUNC_FSW_SD:
-                if (riscv_cpu_xlen(env) == 32) { /* C.FSW (RV32) */
-                    xinsn = OPC_RISC_FSW;
-                    xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
-                    access_rs1 = GET_C_RS1S(insn);
-                    access_imm = GET_C_SW_IMM(insn);
-                    access_size = 4;
-                } else { /* C.SD (RV64/RV128) */
-                    xinsn = OPC_RISC_SD;
-                    xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
-                    access_rs1 = GET_C_RS1S(insn);
-                    access_imm = GET_C_SD_IMM(insn);
-                    access_size = 8;
-                }
-                break;
-            default:
-                break;
-            }
-            break;
-        case OPC_RISC_C_OP_QUAD2: /* Quadrant 2 */
-            switch (GET_C_FUNC(insn)) {
-            case OPC_RISC_C_FUNC_FLDSP_LQSP:
-                if (riscv_cpu_xlen(env) != 128) { /* C.FLDSP (RV32/64) */
-                    xinsn = OPC_RISC_FLD;
-                    xinsn = SET_RD(xinsn, GET_C_RD(insn));
-                    access_rs1 = 2;
-                    access_imm = GET_C_LDSP_IMM(insn);
-                    access_size = 8;
-                }
-                break;
-            case OPC_RISC_C_FUNC_LWSP: /* C.LWSP */
-                xinsn = OPC_RISC_LW;
-                xinsn = SET_RD(xinsn, GET_C_RD(insn));
-                access_rs1 = 2;
-                access_imm = GET_C_LWSP_IMM(insn);
-                access_size = 4;
-                break;
-            case OPC_RISC_C_FUNC_FLWSP_LDSP:
-                if (riscv_cpu_xlen(env) == 32) { /* C.FLWSP (RV32) */
-                    xinsn = OPC_RISC_FLW;
-                    xinsn = SET_RD(xinsn, GET_C_RD(insn));
-                    access_rs1 = 2;
-                    access_imm = GET_C_LWSP_IMM(insn);
-                    access_size = 4;
-                } else { /* C.LDSP (RV64/RV128) */
-                    xinsn = OPC_RISC_LD;
-                    xinsn = SET_RD(xinsn, GET_C_RD(insn));
-                    access_rs1 = 2;
-                    access_imm = GET_C_LDSP_IMM(insn);
-                    access_size = 8;
-                }
-                break;
-            case OPC_RISC_C_FUNC_FSDSP_SQSP:
-                if (riscv_cpu_xlen(env) != 128) { /* C.FSDSP (RV32/64) */
-                    xinsn = OPC_RISC_FSD;
-                    xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
-                    access_rs1 = 2;
-                    access_imm = GET_C_SDSP_IMM(insn);
-                    access_size = 8;
-                }
-                break;
-            case OPC_RISC_C_FUNC_SWSP: /* C.SWSP */
-                xinsn = OPC_RISC_SW;
-                xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
-                access_rs1 = 2;
-                access_imm = GET_C_SWSP_IMM(insn);
-                access_size = 4;
-                break;
-            case 7:
-                if (riscv_cpu_xlen(env) == 32) { /* C.FSWSP (RV32) */
-                    xinsn = OPC_RISC_FSW;
-                    xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
-                    access_rs1 = 2;
-                    access_imm = GET_C_SWSP_IMM(insn);
-                    access_size = 4;
-                } else { /* C.SDSP (RV64/RV128) */
-                    xinsn = OPC_RISC_SD;
-                    xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
-                    access_rs1 = 2;
-                    access_imm = GET_C_SDSP_IMM(insn);
-                    access_size = 8;
-                }
-                break;
-            default:
-                break;
-            }
-            break;
-        default:
-            break;
-        }
-
-        /*
-         * Clear Bit1 of transformed instruction to indicate that
-         * original insruction was a 16bit instruction
-         */
-        xinsn &= ~((target_ulong)0x2);
-    } else {
-        /* Transform 32bit (or wider) instructions */
-        switch (MASK_OP_MAJOR(insn)) {
-        case OPC_RISC_ATOMIC:
-            xinsn = insn;
-            access_rs1 = GET_RS1(insn);
-            access_size = 1 << GET_FUNCT3(insn);
-            break;
-        case OPC_RISC_LOAD:
-        case OPC_RISC_FP_LOAD:
-            xinsn = SET_I_IMM(insn, 0);
-            access_rs1 = GET_RS1(insn);
-            access_imm = GET_IMM(insn);
-            access_size = 1 << GET_FUNCT3(insn);
-            break;
-        case OPC_RISC_STORE:
-        case OPC_RISC_FP_STORE:
-            xinsn = SET_S_IMM(insn, 0);
-            access_rs1 = GET_RS1(insn);
-            access_imm = GET_STORE_IMM(insn);
-            access_size = 1 << GET_FUNCT3(insn);
-            break;
-        case OPC_RISC_SYSTEM:
-            if (MASK_OP_SYSTEM(insn) == OPC_RISC_HLVHSV) {
-                xinsn = insn;
-                access_rs1 = GET_RS1(insn);
-                access_size = 1 << ((GET_FUNCT7(insn) >> 1) & 0x3);
-                access_size = 1 << access_size;
-            }
-            break;
-        default:
-            break;
-        }
-    }
-
-    if (access_size) {
-        xinsn = SET_RS1(xinsn, (taddr - (env->gpr[access_rs1] + access_imm)) &
-                               (access_size - 1));
-    }
-
-    return xinsn;
-}
-
-/*
- * Handle Traps
- *
- * Adapted from Spike's processor_t::take_trap.
- *
- */
-void riscv_cpu_do_interrupt(CPUState *cs)
-{
-    RISCVCPU *cpu = RISCV_CPU(cs);
-    CPURISCVState *env = &cpu->env;
-    bool write_gva = false;
-    uint64_t s;
-
-    /*
-     * cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
-     * so we mask off the MSB and separate into trap type and cause.
-     */
-    bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
-    target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
-    uint64_t deleg = async ? env->mideleg : env->medeleg;
-    target_ulong tval = 0;
-    target_ulong tinst = 0;
-    target_ulong htval = 0;
-    target_ulong mtval2 = 0;
-
-    if  (cause == RISCV_EXCP_SEMIHOST) {
-        do_common_semihosting(cs);
-        env->pc += 4;
-        return;
-    }
-
-    if (!async) {
-        /* set tval to badaddr for traps with address information */
-        switch (cause) {
-        case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
-        case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
-        case RISCV_EXCP_LOAD_ADDR_MIS:
-        case RISCV_EXCP_STORE_AMO_ADDR_MIS:
-        case RISCV_EXCP_LOAD_ACCESS_FAULT:
-        case RISCV_EXCP_STORE_AMO_ACCESS_FAULT:
-        case RISCV_EXCP_LOAD_PAGE_FAULT:
-        case RISCV_EXCP_STORE_PAGE_FAULT:
-            write_gva = env->two_stage_lookup;
-            tval = env->badaddr;
-            if (env->two_stage_indirect_lookup) {
-                /*
-                 * special pseudoinstruction for G-stage fault taken while
-                 * doing VS-stage page table walk.
-                 */
-                tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
-            } else {
-                /*
-                 * The "Addr. Offset" field in transformed instruction is
-                 * non-zero only for misaligned access.
-                 */
-                tinst = riscv_transformed_insn(env, env->bins, tval);
-            }
-            break;
-        case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
-        case RISCV_EXCP_INST_ADDR_MIS:
-        case RISCV_EXCP_INST_ACCESS_FAULT:
-        case RISCV_EXCP_INST_PAGE_FAULT:
-            write_gva = env->two_stage_lookup;
-            tval = env->badaddr;
-            if (env->two_stage_indirect_lookup) {
-                /*
-                 * special pseudoinstruction for G-stage fault taken while
-                 * doing VS-stage page table walk.
-                 */
-                tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
-            }
-            break;
-        case RISCV_EXCP_ILLEGAL_INST:
-        case RISCV_EXCP_VIRT_INSTRUCTION_FAULT:
-            tval = env->bins;
-            break;
-        case RISCV_EXCP_BREAKPOINT:
-            if (cs->watchpoint_hit) {
-                tval = cs->watchpoint_hit->hitaddr;
-                cs->watchpoint_hit = NULL;
-            }
-            break;
-        default:
-            break;
-        }
-        /* ecall is dispatched as one cause so translate based on mode */
-        if (cause == RISCV_EXCP_U_ECALL) {
-            assert(env->priv <= 3);
-
-            if (env->priv == PRV_M) {
-                cause = RISCV_EXCP_M_ECALL;
-            } else if (env->priv == PRV_S && env->virt_enabled) {
-                cause = RISCV_EXCP_VS_ECALL;
-            } else if (env->priv == PRV_S && !env->virt_enabled) {
-                cause = RISCV_EXCP_S_ECALL;
-            } else if (env->priv == PRV_U) {
-                cause = RISCV_EXCP_U_ECALL;
-            }
-        }
-    }
-
-    trace_riscv_trap(env->mhartid, async, cause, env->pc, tval,
-                     riscv_cpu_get_trap_name(cause, async));
-
-    qemu_log_mask(CPU_LOG_INT,
-                  "%s: hart:"TARGET_FMT_ld", async:%d, cause:"TARGET_FMT_lx", "
-                  "epc:0x"TARGET_FMT_lx", tval:0x"TARGET_FMT_lx", desc=%s\n",
-                  __func__, env->mhartid, async, cause, env->pc, tval,
-                  riscv_cpu_get_trap_name(cause, async));
-
-    if (env->priv <= PRV_S &&
-            cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
-        /* handle the trap in S-mode */
-        if (riscv_has_ext(env, RVH)) {
-            uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
-
-            if (env->virt_enabled && ((hdeleg >> cause) & 1)) {
-                /* Trap to VS mode */
-                /*
-                 * See if we need to adjust cause. Yes if its VS mode interrupt
-                 * no if hypervisor has delegated one of hs mode's interrupt
-                 */
-                if (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
-                    cause == IRQ_VS_EXT) {
-                    cause = cause - 1;
-                }
-                write_gva = false;
-            } else if (env->virt_enabled) {
-                /* Trap into HS mode, from virt */
-                riscv_cpu_swap_hypervisor_regs(env);
-                env->hstatus = set_field(env->hstatus, HSTATUS_SPVP,
-                                         env->priv);
-                env->hstatus = set_field(env->hstatus, HSTATUS_SPV, true);
-
-                htval = env->guest_phys_fault_addr;
-
-                riscv_cpu_set_virt_enabled(env, 0);
-            } else {
-                /* Trap into HS mode */
-                env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
-                htval = env->guest_phys_fault_addr;
-            }
-            env->hstatus = set_field(env->hstatus, HSTATUS_GVA, write_gva);
-        }
-
-        s = env->mstatus;
-        s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
-        s = set_field(s, MSTATUS_SPP, env->priv);
-        s = set_field(s, MSTATUS_SIE, 0);
-        env->mstatus = s;
-        env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
-        env->sepc = env->pc;
-        env->stval = tval;
-        env->htval = htval;
-        env->htinst = tinst;
-        env->pc = (env->stvec >> 2 << 2) +
-                  ((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
-        riscv_cpu_set_mode(env, PRV_S);
-    } else {
-        /* handle the trap in M-mode */
-        if (riscv_has_ext(env, RVH)) {
-            if (env->virt_enabled) {
-                riscv_cpu_swap_hypervisor_regs(env);
-            }
-            env->mstatus = set_field(env->mstatus, MSTATUS_MPV,
-                                     env->virt_enabled);
-            if (env->virt_enabled && tval) {
-                env->mstatus = set_field(env->mstatus, MSTATUS_GVA, 1);
-            }
-
-            mtval2 = env->guest_phys_fault_addr;
-
-            /* Trapping to M mode, virt is disabled */
-            riscv_cpu_set_virt_enabled(env, 0);
-        }
-
-        s = env->mstatus;
-        s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
-        s = set_field(s, MSTATUS_MPP, env->priv);
-        s = set_field(s, MSTATUS_MIE, 0);
-        env->mstatus = s;
-        env->mcause = cause | ~(((target_ulong)-1) >> async);
-        env->mepc = env->pc;
-        env->mtval = tval;
-        env->mtval2 = mtval2;
-        env->mtinst = tinst;
-        env->pc = (env->mtvec >> 2 << 2) +
-                  ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
-        riscv_cpu_set_mode(env, PRV_M);
-    }
-
-    /*
-     * NOTE: it is not necessary to yield load reservations here. It is only
-     * necessary for an SC from "another hart" to cause a load reservation
-     * to be yielded. Refer to the memory consistency model section of the
-     * RISC-V ISA Specification.
-     */
-
-    env->two_stage_lookup = false;
-    env->two_stage_indirect_lookup = false;
-}
-
-#endif /* !CONFIG_USER_ONLY */
diff --git a/target/riscv/sysemu/cpu_helper.c b/target/riscv/sysemu/cpu_helper.c
new file mode 100644
index 0000000000..05a6b834fa
--- /dev/null
+++ b/target/riscv/sysemu/cpu_helper.c
@@ -0,0 +1,863 @@
+/*
+ * RISC-V CPU system helpers for QEMU.
+ *
+ * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
+ * Copyright (c) 2017-2018 SiFive, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "exec/exec-all.h"
+#include "cpu.h"
+#include "internals.h"
+#include "sysemu/cpu-timers.h"
+#include "sysemu/pmu.h"
+#include "sysemu/instmap.h"
+#include "semihosting/common-semi.h"
+#include "trace.h"
+
+
+/*
+ * The HS-mode is allowed to configure priority only for the
+ * following VS-mode local interrupts:
+ *
+ * 0  (Reserved interrupt, reads as zero)
+ * 1  Supervisor software interrupt
+ * 4  (Reserved interrupt, reads as zero)
+ * 5  Supervisor timer interrupt
+ * 8  (Reserved interrupt, reads as zero)
+ * 13 (Reserved interrupt)
+ * 14 "
+ * 15 "
+ * 16 "
+ * 17 "
+ * 18 "
+ * 19 "
+ * 20 "
+ * 21 "
+ * 22 "
+ * 23 "
+ */
+
+static const int hviprio_index2irq[] = {
+    0, 1, 4, 5, 8, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };
+static const int hviprio_index2rdzero[] = {
+    1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
+{
+    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
+        return -EINVAL;
+    }
+
+    if (out_irq) {
+        *out_irq = hviprio_index2irq[index];
+    }
+
+    if (out_rdzero) {
+        *out_rdzero = hviprio_index2rdzero[index];
+    }
+
+    return 0;
+}
+
+/*
+ * Default priorities of local interrupts are defined in the
+ * RISC-V Advanced Interrupt Architecture specification.
+ *
+ * ----------------------------------------------------------------
+ *  Default  |
+ *  Priority | Major Interrupt Numbers
+ * ----------------------------------------------------------------
+ *  Highest  | 47, 23, 46, 45, 22, 44,
+ *           | 43, 21, 42, 41, 20, 40
+ *           |
+ *           | 11 (0b),  3 (03),  7 (07)
+ *           |  9 (09),  1 (01),  5 (05)
+ *           | 12 (0c)
+ *           | 10 (0a),  2 (02),  6 (06)
+ *           |
+ *           | 39, 19, 38, 37, 18, 36,
+ *  Lowest   | 35, 17, 34, 33, 16, 32
+ * ----------------------------------------------------------------
+ */
+static const uint8_t default_iprio[64] = {
+    /* Custom interrupts 48 to 63 */
+    [63] = IPRIO_MMAXIPRIO,
+    [62] = IPRIO_MMAXIPRIO,
+    [61] = IPRIO_MMAXIPRIO,
+    [60] = IPRIO_MMAXIPRIO,
+    [59] = IPRIO_MMAXIPRIO,
+    [58] = IPRIO_MMAXIPRIO,
+    [57] = IPRIO_MMAXIPRIO,
+    [56] = IPRIO_MMAXIPRIO,
+    [55] = IPRIO_MMAXIPRIO,
+    [54] = IPRIO_MMAXIPRIO,
+    [53] = IPRIO_MMAXIPRIO,
+    [52] = IPRIO_MMAXIPRIO,
+    [51] = IPRIO_MMAXIPRIO,
+    [50] = IPRIO_MMAXIPRIO,
+    [49] = IPRIO_MMAXIPRIO,
+    [48] = IPRIO_MMAXIPRIO,
+
+    /* Custom interrupts 24 to 31 */
+    [31] = IPRIO_MMAXIPRIO,
+    [30] = IPRIO_MMAXIPRIO,
+    [29] = IPRIO_MMAXIPRIO,
+    [28] = IPRIO_MMAXIPRIO,
+    [27] = IPRIO_MMAXIPRIO,
+    [26] = IPRIO_MMAXIPRIO,
+    [25] = IPRIO_MMAXIPRIO,
+    [24] = IPRIO_MMAXIPRIO,
+
+    [47] = IPRIO_DEFAULT_UPPER,
+    [23] = IPRIO_DEFAULT_UPPER + 1,
+    [46] = IPRIO_DEFAULT_UPPER + 2,
+    [45] = IPRIO_DEFAULT_UPPER + 3,
+    [22] = IPRIO_DEFAULT_UPPER + 4,
+    [44] = IPRIO_DEFAULT_UPPER + 5,
+
+    [43] = IPRIO_DEFAULT_UPPER + 6,
+    [21] = IPRIO_DEFAULT_UPPER + 7,
+    [42] = IPRIO_DEFAULT_UPPER + 8,
+    [41] = IPRIO_DEFAULT_UPPER + 9,
+    [20] = IPRIO_DEFAULT_UPPER + 10,
+    [40] = IPRIO_DEFAULT_UPPER + 11,
+
+    [11] = IPRIO_DEFAULT_M,
+    [3]  = IPRIO_DEFAULT_M + 1,
+    [7]  = IPRIO_DEFAULT_M + 2,
+
+    [9]  = IPRIO_DEFAULT_S,
+    [1]  = IPRIO_DEFAULT_S + 1,
+    [5]  = IPRIO_DEFAULT_S + 2,
+
+    [12] = IPRIO_DEFAULT_SGEXT,
+
+    [10] = IPRIO_DEFAULT_VS,
+    [2]  = IPRIO_DEFAULT_VS + 1,
+    [6]  = IPRIO_DEFAULT_VS + 2,
+
+    [39] = IPRIO_DEFAULT_LOWER,
+    [19] = IPRIO_DEFAULT_LOWER + 1,
+    [38] = IPRIO_DEFAULT_LOWER + 2,
+    [37] = IPRIO_DEFAULT_LOWER + 3,
+    [18] = IPRIO_DEFAULT_LOWER + 4,
+    [36] = IPRIO_DEFAULT_LOWER + 5,
+
+    [35] = IPRIO_DEFAULT_LOWER + 6,
+    [17] = IPRIO_DEFAULT_LOWER + 7,
+    [34] = IPRIO_DEFAULT_LOWER + 8,
+    [33] = IPRIO_DEFAULT_LOWER + 9,
+    [16] = IPRIO_DEFAULT_LOWER + 10,
+    [32] = IPRIO_DEFAULT_LOWER + 11,
+};
+
+uint8_t riscv_cpu_default_priority(int irq)
+{
+    if (irq < 0 || irq > 63) {
+        return IPRIO_MMAXIPRIO;
+    }
+
+    return default_iprio[irq] ? default_iprio[irq] : IPRIO_MMAXIPRIO;
+};
+
+int riscv_cpu_pending_to_irq(CPURISCVState *env,
+                             int extirq, unsigned int extirq_def_prio,
+                             uint64_t pending, uint8_t *iprio)
+{
+    int irq, best_irq = RISCV_EXCP_NONE;
+    unsigned int prio, best_prio = UINT_MAX;
+
+    if (!pending) {
+        return RISCV_EXCP_NONE;
+    }
+
+    irq = ctz64(pending);
+    if (!((extirq == IRQ_M_EXT) ? riscv_cpu_cfg(env)->ext_smaia :
+                                  riscv_cpu_cfg(env)->ext_ssaia)) {
+        return irq;
+    }
+
+    pending = pending >> irq;
+    while (pending) {
+        prio = iprio[irq];
+        if (!prio) {
+            if (irq == extirq) {
+                prio = extirq_def_prio;
+            } else {
+                prio = (riscv_cpu_default_priority(irq) < extirq_def_prio) ?
+                       1 : IPRIO_MMAXIPRIO;
+            }
+        }
+        if ((pending & 0x1) && (prio <= best_prio)) {
+            best_irq = irq;
+            best_prio = prio;
+        }
+        irq++;
+        pending = pending >> 1;
+    }
+
+    return best_irq;
+}
+
+uint64_t riscv_cpu_all_pending(CPURISCVState *env)
+{
+    uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
+    uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
+    uint64_t vstip = (env->vstime_irq) ? MIP_VSTIP : 0;
+
+    return (env->mip | vsgein | vstip) & env->mie;
+}
+
+int riscv_cpu_mirq_pending(CPURISCVState *env)
+{
+    uint64_t irqs = riscv_cpu_all_pending(env) & ~env->mideleg &
+                    ~(MIP_SGEIP | MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+
+    return riscv_cpu_pending_to_irq(env, IRQ_M_EXT, IPRIO_DEFAULT_M,
+                                    irqs, env->miprio);
+}
+
+int riscv_cpu_sirq_pending(CPURISCVState *env)
+{
+    uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
+                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+
+    return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
+                                    irqs, env->siprio);
+}
+
+int riscv_cpu_vsirq_pending(CPURISCVState *env)
+{
+    uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
+                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+
+    return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
+                                    irqs >> 1, env->hviprio);
+}
+
+/* Return true is floating point support is currently enabled */
+bool riscv_cpu_fp_enabled(CPURISCVState *env)
+{
+    if (env->mstatus & MSTATUS_FS) {
+        if (env->virt_enabled && !(env->mstatus_hs & MSTATUS_FS)) {
+            return false;
+        }
+        return true;
+    }
+
+    return false;
+}
+
+/* Return true is vector support is currently enabled */
+bool riscv_cpu_vector_enabled(CPURISCVState *env)
+{
+    if (env->mstatus & MSTATUS_VS) {
+        if (env->virt_enabled && !(env->mstatus_hs & MSTATUS_VS)) {
+            return false;
+        }
+        return true;
+    }
+
+    return false;
+}
+
+void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
+{
+    uint64_t mstatus_mask = MSTATUS_MXR | MSTATUS_SUM |
+                            MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE |
+                            MSTATUS64_UXL | MSTATUS_VS;
+
+    if (riscv_has_ext(env, RVF)) {
+        mstatus_mask |= MSTATUS_FS;
+    }
+    bool current_virt = env->virt_enabled;
+
+    g_assert(riscv_has_ext(env, RVH));
+
+    if (current_virt) {
+        /* Current V=1 and we are about to change to V=0 */
+        env->vsstatus = env->mstatus & mstatus_mask;
+        env->mstatus &= ~mstatus_mask;
+        env->mstatus |= env->mstatus_hs;
+
+        env->vstvec = env->stvec;
+        env->stvec = env->stvec_hs;
+
+        env->vsscratch = env->sscratch;
+        env->sscratch = env->sscratch_hs;
+
+        env->vsepc = env->sepc;
+        env->sepc = env->sepc_hs;
+
+        env->vscause = env->scause;
+        env->scause = env->scause_hs;
+
+        env->vstval = env->stval;
+        env->stval = env->stval_hs;
+
+        env->vsatp = env->satp;
+        env->satp = env->satp_hs;
+    } else {
+        /* Current V=0 and we are about to change to V=1 */
+        env->mstatus_hs = env->mstatus & mstatus_mask;
+        env->mstatus &= ~mstatus_mask;
+        env->mstatus |= env->vsstatus;
+
+        env->stvec_hs = env->stvec;
+        env->stvec = env->vstvec;
+
+        env->sscratch_hs = env->sscratch;
+        env->sscratch = env->vsscratch;
+
+        env->sepc_hs = env->sepc;
+        env->sepc = env->vsepc;
+
+        env->scause_hs = env->scause;
+        env->scause = env->vscause;
+
+        env->stval_hs = env->stval;
+        env->stval = env->vstval;
+
+        env->satp_hs = env->satp;
+        env->satp = env->vsatp;
+    }
+}
+
+target_ulong riscv_cpu_get_geilen(CPURISCVState *env)
+{
+    if (!riscv_has_ext(env, RVH)) {
+        return 0;
+    }
+
+    return env->geilen;
+}
+
+void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen)
+{
+    if (!riscv_has_ext(env, RVH)) {
+        return;
+    }
+
+    if (geilen > (TARGET_LONG_BITS - 1)) {
+        return;
+    }
+
+    env->geilen = geilen;
+}
+
+/* This function can only be called to set virt when RVH is enabled */
+void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
+{
+    /* Flush the TLB on all virt mode changes. */
+    if (env->virt_enabled != enable) {
+        tlb_flush(env_cpu(env));
+    }
+
+    env->virt_enabled = enable;
+
+    if (enable) {
+        /*
+         * The guest external interrupts from an interrupt controller are
+         * delivered only when the Guest/VM is running (i.e. V=1). This means
+         * any guest external interrupt which is triggered while the Guest/VM
+         * is not running (i.e. V=0) will be missed on QEMU resulting in guest
+         * with sluggish response to serial console input and other I/O events.
+         *
+         * To solve this, we check and inject interrupt after setting V=1.
+         */
+        riscv_cpu_update_mip(env, 0, 0);
+    }
+}
+
+int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
+{
+    CPURISCVState *env = &cpu->env;
+    if (env->miclaim & interrupts) {
+        return -1;
+    } else {
+        env->miclaim |= interrupts;
+        return 0;
+    }
+}
+
+uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask,
+                              uint64_t value)
+{
+    CPUState *cs = env_cpu(env);
+    uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
+
+    if (env->virt_enabled) {
+        gein = get_field(env->hstatus, HSTATUS_VGEIN);
+        vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
+    }
+
+    vstip = env->vstime_irq ? MIP_VSTIP : 0;
+
+    QEMU_IOTHREAD_LOCK_GUARD();
+
+    env->mip = (env->mip & ~mask) | (value & mask);
+
+    if (env->mip | vsgein | vstip) {
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+    }
+
+    return old;
+}
+
+void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
+                             void *arg)
+{
+    env->rdtime_fn = fn;
+    env->rdtime_fn_arg = arg;
+}
+
+void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
+                                   int (*rmw_fn)(void *arg,
+                                                 target_ulong reg,
+                                                 target_ulong *val,
+                                                 target_ulong new_val,
+                                                 target_ulong write_mask),
+                                   void *rmw_fn_arg)
+{
+    if (priv <= PRV_M) {
+        env->aia_ireg_rmw_fn[priv] = rmw_fn;
+        env->aia_ireg_rmw_fn_arg[priv] = rmw_fn_arg;
+    }
+}
+
+void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
+{
+    g_assert(newpriv <= PRV_M && newpriv != PRV_RESERVED);
+
+    if (icount_enabled() && newpriv != env->priv) {
+        riscv_itrigger_update_priv(env);
+    }
+    /* tlb_flush is unnecessary as mode is contained in mmu_idx */
+    env->priv = newpriv;
+    env->xl = cpu_recompute_xl(env);
+    riscv_cpu_update_mask(env);
+
+    /*
+     * Clear the load reservation - otherwise a reservation placed in one
+     * context/process can be used by another, resulting in an SC succeeding
+     * incorrectly. Version 2.2 of the ISA specification explicitly requires
+     * this behaviour, while later revisions say that the kernel "should" use
+     * an SC instruction to force the yielding of a load reservation on a
+     * preemptive context switch. As a result, do both.
+     */
+    env->load_res = -1;
+}
+
+static target_ulong riscv_transformed_insn(CPURISCVState *env,
+                                           target_ulong insn,
+                                           target_ulong taddr)
+{
+    target_ulong xinsn = 0;
+    target_ulong access_rs1 = 0, access_imm = 0, access_size = 0;
+
+    /*
+     * Only Quadrant 0 and Quadrant 2 of RVC instruction space need to
+     * be uncompressed. The Quadrant 1 of RVC instruction space need
+     * not be transformed because these instructions won't generate
+     * any load/store trap.
+     */
+
+    if ((insn & 0x3) != 0x3) {
+        /* Transform 16bit instruction into 32bit instruction */
+        switch (GET_C_OP(insn)) {
+        case OPC_RISC_C_OP_QUAD0: /* Quadrant 0 */
+            switch (GET_C_FUNC(insn)) {
+            case OPC_RISC_C_FUNC_FLD_LQ:
+                if (riscv_cpu_xlen(env) != 128) { /* C.FLD (RV32/64) */
+                    xinsn = OPC_RISC_FLD;
+                    xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+                    access_rs1 = GET_C_RS1S(insn);
+                    access_imm = GET_C_LD_IMM(insn);
+                    access_size = 8;
+                }
+                break;
+            case OPC_RISC_C_FUNC_LW: /* C.LW */
+                xinsn = OPC_RISC_LW;
+                xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+                access_rs1 = GET_C_RS1S(insn);
+                access_imm = GET_C_LW_IMM(insn);
+                access_size = 4;
+                break;
+            case OPC_RISC_C_FUNC_FLW_LD:
+                if (riscv_cpu_xlen(env) == 32) { /* C.FLW (RV32) */
+                    xinsn = OPC_RISC_FLW;
+                    xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+                    access_rs1 = GET_C_RS1S(insn);
+                    access_imm = GET_C_LW_IMM(insn);
+                    access_size = 4;
+                } else { /* C.LD (RV64/RV128) */
+                    xinsn = OPC_RISC_LD;
+                    xinsn = SET_RD(xinsn, GET_C_RS2S(insn));
+                    access_rs1 = GET_C_RS1S(insn);
+                    access_imm = GET_C_LD_IMM(insn);
+                    access_size = 8;
+                }
+                break;
+            case OPC_RISC_C_FUNC_FSD_SQ:
+                if (riscv_cpu_xlen(env) != 128) { /* C.FSD (RV32/64) */
+                    xinsn = OPC_RISC_FSD;
+                    xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
+                    access_rs1 = GET_C_RS1S(insn);
+                    access_imm = GET_C_SD_IMM(insn);
+                    access_size = 8;
+                }
+                break;
+            case OPC_RISC_C_FUNC_SW: /* C.SW */
+                xinsn = OPC_RISC_SW;
+                xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
+                access_rs1 = GET_C_RS1S(insn);
+                access_imm = GET_C_SW_IMM(insn);
+                access_size = 4;
+                break;
+            case OPC_RISC_C_FUNC_FSW_SD:
+                if (riscv_cpu_xlen(env) == 32) { /* C.FSW (RV32) */
+                    xinsn = OPC_RISC_FSW;
+                    xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
+                    access_rs1 = GET_C_RS1S(insn);
+                    access_imm = GET_C_SW_IMM(insn);
+                    access_size = 4;
+                } else { /* C.SD (RV64/RV128) */
+                    xinsn = OPC_RISC_SD;
+                    xinsn = SET_RS2(xinsn, GET_C_RS2S(insn));
+                    access_rs1 = GET_C_RS1S(insn);
+                    access_imm = GET_C_SD_IMM(insn);
+                    access_size = 8;
+                }
+                break;
+            default:
+                break;
+            }
+            break;
+        case OPC_RISC_C_OP_QUAD2: /* Quadrant 2 */
+            switch (GET_C_FUNC(insn)) {
+            case OPC_RISC_C_FUNC_FLDSP_LQSP:
+                if (riscv_cpu_xlen(env) != 128) { /* C.FLDSP (RV32/64) */
+                    xinsn = OPC_RISC_FLD;
+                    xinsn = SET_RD(xinsn, GET_C_RD(insn));
+                    access_rs1 = 2;
+                    access_imm = GET_C_LDSP_IMM(insn);
+                    access_size = 8;
+                }
+                break;
+            case OPC_RISC_C_FUNC_LWSP: /* C.LWSP */
+                xinsn = OPC_RISC_LW;
+                xinsn = SET_RD(xinsn, GET_C_RD(insn));
+                access_rs1 = 2;
+                access_imm = GET_C_LWSP_IMM(insn);
+                access_size = 4;
+                break;
+            case OPC_RISC_C_FUNC_FLWSP_LDSP:
+                if (riscv_cpu_xlen(env) == 32) { /* C.FLWSP (RV32) */
+                    xinsn = OPC_RISC_FLW;
+                    xinsn = SET_RD(xinsn, GET_C_RD(insn));
+                    access_rs1 = 2;
+                    access_imm = GET_C_LWSP_IMM(insn);
+                    access_size = 4;
+                } else { /* C.LDSP (RV64/RV128) */
+                    xinsn = OPC_RISC_LD;
+                    xinsn = SET_RD(xinsn, GET_C_RD(insn));
+                    access_rs1 = 2;
+                    access_imm = GET_C_LDSP_IMM(insn);
+                    access_size = 8;
+                }
+                break;
+            case OPC_RISC_C_FUNC_FSDSP_SQSP:
+                if (riscv_cpu_xlen(env) != 128) { /* C.FSDSP (RV32/64) */
+                    xinsn = OPC_RISC_FSD;
+                    xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
+                    access_rs1 = 2;
+                    access_imm = GET_C_SDSP_IMM(insn);
+                    access_size = 8;
+                }
+                break;
+            case OPC_RISC_C_FUNC_SWSP: /* C.SWSP */
+                xinsn = OPC_RISC_SW;
+                xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
+                access_rs1 = 2;
+                access_imm = GET_C_SWSP_IMM(insn);
+                access_size = 4;
+                break;
+            case 7:
+                if (riscv_cpu_xlen(env) == 32) { /* C.FSWSP (RV32) */
+                    xinsn = OPC_RISC_FSW;
+                    xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
+                    access_rs1 = 2;
+                    access_imm = GET_C_SWSP_IMM(insn);
+                    access_size = 4;
+                } else { /* C.SDSP (RV64/RV128) */
+                    xinsn = OPC_RISC_SD;
+                    xinsn = SET_RS2(xinsn, GET_C_RS2(insn));
+                    access_rs1 = 2;
+                    access_imm = GET_C_SDSP_IMM(insn);
+                    access_size = 8;
+                }
+                break;
+            default:
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+
+        /*
+         * Clear Bit1 of transformed instruction to indicate that
+         * original insruction was a 16bit instruction
+         */
+        xinsn &= ~((target_ulong)0x2);
+    } else {
+        /* Transform 32bit (or wider) instructions */
+        switch (MASK_OP_MAJOR(insn)) {
+        case OPC_RISC_ATOMIC:
+            xinsn = insn;
+            access_rs1 = GET_RS1(insn);
+            access_size = 1 << GET_FUNCT3(insn);
+            break;
+        case OPC_RISC_LOAD:
+        case OPC_RISC_FP_LOAD:
+            xinsn = SET_I_IMM(insn, 0);
+            access_rs1 = GET_RS1(insn);
+            access_imm = GET_IMM(insn);
+            access_size = 1 << GET_FUNCT3(insn);
+            break;
+        case OPC_RISC_STORE:
+        case OPC_RISC_FP_STORE:
+            xinsn = SET_S_IMM(insn, 0);
+            access_rs1 = GET_RS1(insn);
+            access_imm = GET_STORE_IMM(insn);
+            access_size = 1 << GET_FUNCT3(insn);
+            break;
+        case OPC_RISC_SYSTEM:
+            if (MASK_OP_SYSTEM(insn) == OPC_RISC_HLVHSV) {
+                xinsn = insn;
+                access_rs1 = GET_RS1(insn);
+                access_size = 1 << ((GET_FUNCT7(insn) >> 1) & 0x3);
+                access_size = 1 << access_size;
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    if (access_size) {
+        xinsn = SET_RS1(xinsn, (taddr - (env->gpr[access_rs1] + access_imm)) &
+                               (access_size - 1));
+    }
+
+    return xinsn;
+}
+
+/*
+ * Handle Traps
+ *
+ * Adapted from Spike's processor_t::take_trap.
+ *
+ */
+void riscv_cpu_do_interrupt(CPUState *cs)
+{
+    RISCVCPU *cpu = RISCV_CPU(cs);
+    CPURISCVState *env = &cpu->env;
+    bool write_gva = false;
+    uint64_t s;
+
+    /*
+     * cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
+     * so we mask off the MSB and separate into trap type and cause.
+     */
+    bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
+    target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
+    uint64_t deleg = async ? env->mideleg : env->medeleg;
+    target_ulong tval = 0;
+    target_ulong tinst = 0;
+    target_ulong htval = 0;
+    target_ulong mtval2 = 0;
+
+    if  (cause == RISCV_EXCP_SEMIHOST) {
+        do_common_semihosting(cs);
+        env->pc += 4;
+        return;
+    }
+
+    if (!async) {
+        /* set tval to badaddr for traps with address information */
+        switch (cause) {
+        case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
+        case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
+        case RISCV_EXCP_LOAD_ADDR_MIS:
+        case RISCV_EXCP_STORE_AMO_ADDR_MIS:
+        case RISCV_EXCP_LOAD_ACCESS_FAULT:
+        case RISCV_EXCP_STORE_AMO_ACCESS_FAULT:
+        case RISCV_EXCP_LOAD_PAGE_FAULT:
+        case RISCV_EXCP_STORE_PAGE_FAULT:
+            write_gva = env->two_stage_lookup;
+            tval = env->badaddr;
+            if (env->two_stage_indirect_lookup) {
+                /*
+                 * special pseudoinstruction for G-stage fault taken while
+                 * doing VS-stage page table walk.
+                 */
+                tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
+            } else {
+                /*
+                 * The "Addr. Offset" field in transformed instruction is
+                 * non-zero only for misaligned access.
+                 */
+                tinst = riscv_transformed_insn(env, env->bins, tval);
+            }
+            break;
+        case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
+        case RISCV_EXCP_INST_ADDR_MIS:
+        case RISCV_EXCP_INST_ACCESS_FAULT:
+        case RISCV_EXCP_INST_PAGE_FAULT:
+            write_gva = env->two_stage_lookup;
+            tval = env->badaddr;
+            if (env->two_stage_indirect_lookup) {
+                /*
+                 * special pseudoinstruction for G-stage fault taken while
+                 * doing VS-stage page table walk.
+                 */
+                tinst = (riscv_cpu_xlen(env) == 32) ? 0x00002000 : 0x00003000;
+            }
+            break;
+        case RISCV_EXCP_ILLEGAL_INST:
+        case RISCV_EXCP_VIRT_INSTRUCTION_FAULT:
+            tval = env->bins;
+            break;
+        case RISCV_EXCP_BREAKPOINT:
+            if (cs->watchpoint_hit) {
+                tval = cs->watchpoint_hit->hitaddr;
+                cs->watchpoint_hit = NULL;
+            }
+            break;
+        default:
+            break;
+        }
+        /* ecall is dispatched as one cause so translate based on mode */
+        if (cause == RISCV_EXCP_U_ECALL) {
+            assert(env->priv <= 3);
+
+            if (env->priv == PRV_M) {
+                cause = RISCV_EXCP_M_ECALL;
+            } else if (env->priv == PRV_S && env->virt_enabled) {
+                cause = RISCV_EXCP_VS_ECALL;
+            } else if (env->priv == PRV_S && !env->virt_enabled) {
+                cause = RISCV_EXCP_S_ECALL;
+            } else if (env->priv == PRV_U) {
+                cause = RISCV_EXCP_U_ECALL;
+            }
+        }
+    }
+
+    trace_riscv_trap(env->mhartid, async, cause, env->pc, tval,
+                     riscv_cpu_get_trap_name(cause, async));
+
+    qemu_log_mask(CPU_LOG_INT,
+                  "%s: hart:"TARGET_FMT_ld", async:%d, cause:"TARGET_FMT_lx", "
+                  "epc:0x"TARGET_FMT_lx", tval:0x"TARGET_FMT_lx", desc=%s\n",
+                  __func__, env->mhartid, async, cause, env->pc, tval,
+                  riscv_cpu_get_trap_name(cause, async));
+
+    if (env->priv <= PRV_S &&
+            cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
+        /* handle the trap in S-mode */
+        if (riscv_has_ext(env, RVH)) {
+            uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
+
+            if (env->virt_enabled && ((hdeleg >> cause) & 1)) {
+                /* Trap to VS mode */
+                /*
+                 * See if we need to adjust cause. Yes if its VS mode interrupt
+                 * no if hypervisor has delegated one of hs mode's interrupt
+                 */
+                if (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
+                    cause == IRQ_VS_EXT) {
+                    cause = cause - 1;
+                }
+                write_gva = false;
+            } else if (env->virt_enabled) {
+                /* Trap into HS mode, from virt */
+                riscv_cpu_swap_hypervisor_regs(env);
+                env->hstatus = set_field(env->hstatus, HSTATUS_SPVP,
+                                         env->priv);
+                env->hstatus = set_field(env->hstatus, HSTATUS_SPV, true);
+
+                htval = env->guest_phys_fault_addr;
+
+                riscv_cpu_set_virt_enabled(env, 0);
+            } else {
+                /* Trap into HS mode */
+                env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
+                htval = env->guest_phys_fault_addr;
+            }
+            env->hstatus = set_field(env->hstatus, HSTATUS_GVA, write_gva);
+        }
+
+        s = env->mstatus;
+        s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
+        s = set_field(s, MSTATUS_SPP, env->priv);
+        s = set_field(s, MSTATUS_SIE, 0);
+        env->mstatus = s;
+        env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
+        env->sepc = env->pc;
+        env->stval = tval;
+        env->htval = htval;
+        env->htinst = tinst;
+        env->pc = (env->stvec >> 2 << 2) +
+                  ((async && (env->stvec & 3) == 1) ? cause * 4 : 0);
+        riscv_cpu_set_mode(env, PRV_S);
+    } else {
+        /* handle the trap in M-mode */
+        if (riscv_has_ext(env, RVH)) {
+            if (env->virt_enabled) {
+                riscv_cpu_swap_hypervisor_regs(env);
+            }
+            env->mstatus = set_field(env->mstatus, MSTATUS_MPV,
+                                     env->virt_enabled);
+            if (env->virt_enabled && tval) {
+                env->mstatus = set_field(env->mstatus, MSTATUS_GVA, 1);
+            }
+
+            mtval2 = env->guest_phys_fault_addr;
+
+            /* Trapping to M mode, virt is disabled */
+            riscv_cpu_set_virt_enabled(env, 0);
+        }
+
+        s = env->mstatus;
+        s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
+        s = set_field(s, MSTATUS_MPP, env->priv);
+        s = set_field(s, MSTATUS_MIE, 0);
+        env->mstatus = s;
+        env->mcause = cause | ~(((target_ulong)-1) >> async);
+        env->mepc = env->pc;
+        env->mtval = tval;
+        env->mtval2 = mtval2;
+        env->mtinst = tinst;
+        env->pc = (env->mtvec >> 2 << 2) +
+                  ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0);
+        riscv_cpu_set_mode(env, PRV_M);
+    }
+
+    /*
+     * NOTE: it is not necessary to yield load reservations here. It is only
+     * necessary for an SC from "another hart" to cause a load reservation
+     * to be yielded. Refer to the memory consistency model section of the
+     * RISC-V ISA Specification.
+     */
+
+    env->two_stage_lookup = false;
+    env->two_stage_indirect_lookup = false;
+}
diff --git a/target/riscv/sysemu/meson.build b/target/riscv/sysemu/meson.build
index 33fec8f11e..d5d8ad17a0 100644
--- a/target/riscv/sysemu/meson.build
+++ b/target/riscv/sysemu/meson.build
@@ -1,5 +1,6 @@
 riscv_system_ss.add(files(
   'arch_dump.c',
+  'cpu_helper.c',
   'debug.c',
   'machine.c',
   'monitor.c',
-- 
2.38.1



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

* [PATCH 15/16] target/riscv: Restrict TCG-specific prototype declarations
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (13 preceding siblings ...)
  2023-06-26 23:20 ` [PATCH 14/16] target/riscv: Move sysemu-specific code to sysemu/cpu_helper.c Philippe Mathieu-Daudé
@ 2023-06-26 23:20 ` Philippe Mathieu-Daudé
  2023-06-26 23:20 ` [PATCH 16/16] gitlab-ci.d/crossbuilds: Add KVM riscv64 cross-build jobs Philippe Mathieu-Daudé
  2023-06-27 18:54 ` [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Daniel Henrique Barboza
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 target/riscv/cpu.h |  3 +++
 target/riscv/cpu.c | 11 +++++++++++
 2 files changed, 14 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 5945e13fe0..8f16655041 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -474,7 +474,10 @@ RISCVException smstateen_acc_ok(CPURISCVState *env, int index, uint64_t bit);
 
 void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
 
+#ifdef CONFIG_TCG
 void riscv_translate_init(void);
+#endif
+
 G_NORETURN void riscv_raise_exception(CPURISCVState *env,
                                       uint32_t exception, uintptr_t pc);
 
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index a1513bf5cc..2371bdd68a 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -37,7 +37,9 @@
 #include "hw/qdev-properties.h"
 #include "migration/vmstate.h"
 #include "fpu/softfloat-helpers.h"
+#ifdef CONFIG_TCG
 #include "tcg/tcg.h"
+#endif
 
 /* RISC-V CPU definitions */
 
@@ -724,6 +726,7 @@ static vaddr riscv_cpu_get_pc(CPUState *cs)
     return env->pc;
 }
 
+#ifdef CONFIG_TCG
 static void riscv_cpu_synchronize_from_tb(CPUState *cs,
                                           const TranslationBlock *tb)
 {
@@ -741,6 +744,7 @@ static void riscv_cpu_synchronize_from_tb(CPUState *cs,
         }
     }
 }
+#endif
 
 static bool riscv_cpu_has_work(CPUState *cs)
 {
@@ -757,6 +761,7 @@ static bool riscv_cpu_has_work(CPUState *cs)
 #endif
 }
 
+#ifdef CONFIG_TCG
 static void riscv_restore_state_to_opc(CPUState *cs,
                                        const TranslationBlock *tb,
                                        const uint64_t *data)
@@ -779,6 +784,7 @@ static void riscv_restore_state_to_opc(CPUState *cs,
     }
     env->bins = data[1];
 }
+#endif
 
 static void riscv_cpu_reset_hold(Object *obj)
 {
@@ -1785,6 +1791,8 @@ static const struct SysemuCPUOps riscv_sysemu_ops = {
 };
 #endif
 
+#ifdef CONFIG_TCG
+
 #include "hw/core/tcg-cpu-ops.h"
 
 static const struct TCGCPUOps riscv_tcg_ops = {
@@ -1803,6 +1811,7 @@ static const struct TCGCPUOps riscv_tcg_ops = {
     .debug_check_watchpoint = riscv_cpu_debug_check_watchpoint,
 #endif /* !CONFIG_USER_ONLY */
 };
+#endif /* CONFIG_TCG */
 
 static void riscv_cpu_class_init(ObjectClass *c, void *data)
 {
@@ -1833,7 +1842,9 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
 #endif
     cc->gdb_arch_name = riscv_gdb_arch_name;
     cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml;
+#ifdef CONFIG_TCG
     cc->tcg_ops = &riscv_tcg_ops;
+#endif /* CONFIG_TCG */
 
     device_class_set_props(dc, riscv_cpu_properties);
 }
-- 
2.38.1



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

* [PATCH 16/16] gitlab-ci.d/crossbuilds: Add KVM riscv64 cross-build jobs
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (14 preceding siblings ...)
  2023-06-26 23:20 ` [PATCH 15/16] target/riscv: Restrict TCG-specific prototype declarations Philippe Mathieu-Daudé
@ 2023-06-26 23:20 ` Philippe Mathieu-Daudé
  2023-06-27 18:54 ` [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Daniel Henrique Barboza
  16 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-26 23:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Philippe Mathieu-Daudé, Palmer Dabbelt,
	Wainer dos Santos Moschetta, Daniel Henrique Barboza, Weiwei Li,
	qemu-riscv

Add a new job to cross-build the riscv64 target without
the TCG accelerator (IOW: only KVM accelerator enabled).

Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 .gitlab-ci.d/crossbuilds.yml | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/.gitlab-ci.d/crossbuilds.yml b/.gitlab-ci.d/crossbuilds.yml
index 1e0e6c7f2c..5b72df4090 100644
--- a/.gitlab-ci.d/crossbuilds.yml
+++ b/.gitlab-ci.d/crossbuilds.yml
@@ -129,6 +129,14 @@ cross-riscv64-user:
   variables:
     IMAGE: debian-riscv64-cross
 
+cross-riscv64-kvm-only:
+  extends: .cross_accel_build_job
+  needs:
+    job: riscv64-debian-cross-container
+  variables:
+    IMAGE: debian-riscv64-cross
+    EXTRA_CONFIGURE_OPTS: --disable-tcg --without-default-features
+
 cross-s390x-system:
   extends: .cross_system_build_job
   needs:
-- 
2.38.1



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

* Re: [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far)
  2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
                   ` (15 preceding siblings ...)
  2023-06-26 23:20 ` [PATCH 16/16] gitlab-ci.d/crossbuilds: Add KVM riscv64 cross-build jobs Philippe Mathieu-Daudé
@ 2023-06-27 18:54 ` Daniel Henrique Barboza
  2023-06-27 22:32   ` Philippe Mathieu-Daudé
  16 siblings, 1 reply; 19+ messages in thread
From: Daniel Henrique Barboza @ 2023-06-27 18:54 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Palmer Dabbelt, Wainer dos Santos Moschetta,
	Weiwei Li, qemu-riscv

Phil,

Can you rebase this on top of Alistair's riscv-to-apply.next?

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

There's a trivial conflict in patch 8 and a not so trivial conflict in patch 14
that I'd rather let you deal with it.

Also, can you take a look at these KVM patches to see if there's a potential
design conflict with what you're doing here?

"[PATCH v5 00/19] target/riscv, KVM: fixes and enhancements"

We're missing a few details in one of the patches and it seems good to go. I am
doing some stuff there that I'm unsure if it will compromise the work you're
doing here (e.g. creating kvm user properties by using TCG user properties). In
a quick glance at your series I think we'll be fine, but better safe than sorry.

I guess I'll wait for you to send a rebased version of this series and apply
mine on top of it to see what happens. That would be a good test.


Thanks,


Daniel


On 6/26/23 20:19, Philippe Mathieu-Daudé wrote:
> Hi,
> 
> this series reorder TCG specific code in order to easily
> build a KVM-only binary. sysemu specific code is also
> moved around, to help noticing invalid uses from user
> emulation. Last patch adds a new job to our CI to avoid
> this to bitrot.
> 
> Please review,
> 
> Phil.
> 
> Philippe Mathieu-Daudé (16):
>    target/riscv: Remove unused 'instmap.h' header in translate.c
>    target/riscv: Restrict KVM-specific fields from ArchCPU
>    target/riscv: Restrict sysemu specific header to user emulation
>    target/riscv: Restrict 'rv128' machine to TCG accelerator
>    target/riscv: Move sysemu-specific files to target/riscv/sysemu/
>    target/riscv: Restrict riscv_cpu_do_interrupt() to sysemu
>    target/riscv: Move TCG-specific files to target/riscv/tcg/
>    target/riscv: Move TCG-specific cpu_get_tb_cpu_state() to tcg/cpu.c
>    target/riscv: Expose some 'trigger' prototypes from debug.c
>    target/riscv: Extract TCG-specific code from debug.c
>    target/riscv: Move sysemu-specific debug files to target/riscv/sysemu/
>    target/riscv: Expose riscv_cpu_pending_to_irq() from cpu_helper.c
>    target/riscv: Move TCG/sysemu-specific code to tcg/sysemu/cpu_helper.c
>    target/riscv: Move sysemu-specific code to sysemu/cpu_helper.c
>    target/riscv: Restrict TCG-specific prototype declarations
>    gitlab-ci.d/crossbuilds: Add KVM riscv64 cross-build jobs
> 
>   target/riscv/cpu.h                            |   29 +-
>   target/riscv/internals.h                      |    4 +
>   target/riscv/{ => sysemu}/debug.h             |    6 +
>   target/riscv/{ => sysemu}/instmap.h           |    0
>   target/riscv/{ => sysemu}/kvm_riscv.h         |    0
>   target/riscv/{ => sysemu}/pmp.h               |    0
>   target/riscv/{ => sysemu}/pmu.h               |    0
>   target/riscv/{ => sysemu}/time_helper.h       |    0
>   target/riscv/{ => tcg}/XVentanaCondOps.decode |    0
>   target/riscv/{ => tcg}/insn16.decode          |    0
>   target/riscv/{ => tcg}/insn32.decode          |    0
>   target/riscv/{ => tcg}/xthead.decode          |    0
>   hw/riscv/virt.c                               |    2 +-
>   target/riscv/cpu.c                            |   35 +-
>   target/riscv/cpu_helper.c                     | 1692 +----------------
>   target/riscv/csr.c                            |    6 +-
>   target/riscv/{ => sysemu}/arch_dump.c         |    0
>   target/riscv/sysemu/cpu_helper.c              |  863 +++++++++
>   target/riscv/{ => sysemu}/debug.c             |  153 +-
>   target/riscv/{ => sysemu}/kvm-stub.c          |    0
>   target/riscv/{ => sysemu}/kvm.c               |    0
>   target/riscv/{ => sysemu}/machine.c           |    8 +-
>   target/riscv/{ => sysemu}/monitor.c           |    0
>   target/riscv/{ => sysemu}/pmp.c               |    0
>   target/riscv/{ => sysemu}/pmu.c               |    0
>   target/riscv/{ => sysemu}/riscv-qmp-cmds.c    |    0
>   target/riscv/{ => sysemu}/time_helper.c       |    0
>   target/riscv/{ => tcg}/bitmanip_helper.c      |    0
>   target/riscv/tcg/cpu.c                        |   97 +
>   target/riscv/{ => tcg}/crypto_helper.c        |    0
>   target/riscv/{ => tcg}/fpu_helper.c           |    0
>   target/riscv/{ => tcg}/m128_helper.c          |    0
>   target/riscv/{ => tcg}/op_helper.c            |    0
>   target/riscv/tcg/sysemu/cpu_helper.c          |  766 ++++++++
>   target/riscv/tcg/sysemu/debug.c               |  165 ++
>   target/riscv/tcg/tcg-stub.c                   |   31 +
>   target/riscv/{ => tcg}/translate.c            |    1 -
>   target/riscv/{ => tcg}/vector_helper.c        |    0
>   target/riscv/{ => tcg}/zce_helper.c           |    0
>   .gitlab-ci.d/crossbuilds.yml                  |    8 +
>   target/riscv/meson.build                      |   33 +-
>   target/riscv/sysemu/meson.build               |   14 +
>   target/riscv/tcg/meson.build                  |   22 +
>   target/riscv/tcg/sysemu/meson.build           |    4 +
>   44 files changed, 2046 insertions(+), 1893 deletions(-)
>   rename target/riscv/{ => sysemu}/debug.h (96%)
>   rename target/riscv/{ => sysemu}/instmap.h (100%)
>   rename target/riscv/{ => sysemu}/kvm_riscv.h (100%)
>   rename target/riscv/{ => sysemu}/pmp.h (100%)
>   rename target/riscv/{ => sysemu}/pmu.h (100%)
>   rename target/riscv/{ => sysemu}/time_helper.h (100%)
>   rename target/riscv/{ => tcg}/XVentanaCondOps.decode (100%)
>   rename target/riscv/{ => tcg}/insn16.decode (100%)
>   rename target/riscv/{ => tcg}/insn32.decode (100%)
>   rename target/riscv/{ => tcg}/xthead.decode (100%)
>   rename target/riscv/{ => sysemu}/arch_dump.c (100%)
>   create mode 100644 target/riscv/sysemu/cpu_helper.c
>   rename target/riscv/{ => sysemu}/debug.c (83%)
>   rename target/riscv/{ => sysemu}/kvm-stub.c (100%)
>   rename target/riscv/{ => sysemu}/kvm.c (100%)
>   rename target/riscv/{ => sysemu}/machine.c (98%)
>   rename target/riscv/{ => sysemu}/monitor.c (100%)
>   rename target/riscv/{ => sysemu}/pmp.c (100%)
>   rename target/riscv/{ => sysemu}/pmu.c (100%)
>   rename target/riscv/{ => sysemu}/riscv-qmp-cmds.c (100%)
>   rename target/riscv/{ => sysemu}/time_helper.c (100%)
>   rename target/riscv/{ => tcg}/bitmanip_helper.c (100%)
>   create mode 100644 target/riscv/tcg/cpu.c
>   rename target/riscv/{ => tcg}/crypto_helper.c (100%)
>   rename target/riscv/{ => tcg}/fpu_helper.c (100%)
>   rename target/riscv/{ => tcg}/m128_helper.c (100%)
>   rename target/riscv/{ => tcg}/op_helper.c (100%)
>   create mode 100644 target/riscv/tcg/sysemu/cpu_helper.c
>   create mode 100644 target/riscv/tcg/sysemu/debug.c
>   create mode 100644 target/riscv/tcg/tcg-stub.c
>   rename target/riscv/{ => tcg}/translate.c (99%)
>   rename target/riscv/{ => tcg}/vector_helper.c (100%)
>   rename target/riscv/{ => tcg}/zce_helper.c (100%)
>   create mode 100644 target/riscv/sysemu/meson.build
>   create mode 100644 target/riscv/tcg/meson.build
>   create mode 100644 target/riscv/tcg/sysemu/meson.build
> 


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

* Re: [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far)
  2023-06-27 18:54 ` [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Daniel Henrique Barboza
@ 2023-06-27 22:32   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 19+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-06-27 22:32 UTC (permalink / raw)
  To: Daniel Henrique Barboza, qemu-devel
  Cc: Bin Meng, Liu Zhiwei, Alex Bennée, Thomas Huth, Beraldo Leal,
	Alistair Francis, Palmer Dabbelt, Wainer dos Santos Moschetta,
	Weiwei Li, qemu-riscv

On 27/6/23 20:54, Daniel Henrique Barboza wrote:
> Phil,
> 
> Can you rebase this on top of Alistair's riscv-to-apply.next?
> 
> https://github.com/alistair23/qemu/tree/riscv-to-apply.next
> 
> There's a trivial conflict in patch 8 and a not so trivial conflict in 
> patch 14
> that I'd rather let you deal with it.

Sure, no problem.

I'd like patches 1-4,6 to go for the 8.1 release. I don't expect the
rest to be picked, and am ready to rebase and repost once the tree
re-opens after the release. So don't worry about 8/14.

> Also, can you take a look at these KVM patches to see if there's a 
> potential
> design conflict with what you're doing here?
> 
> "[PATCH v5 00/19] target/riscv, KVM: fixes and enhancements"
> 
> We're missing a few details in one of the patches and it seems good to 
> go. I am
> doing some stuff there that I'm unsure if it will compromise the work 
> you're
> doing here (e.g. creating kvm user properties by using TCG user 
> properties). In
> a quick glance at your series I think we'll be fine, but better safe 
> than sorry.

I had a quick look and I don't see any particular divergeance. Anyhow
your work is older and more important that what I'm cleaning here, so
don't worry :)

> I guess I'll wait for you to send a rebased version of this series and 
> apply
> mine on top of it to see what happens. That would be a good test.

Nah, at this point in the cycle, don't bother.

Thanks for having a look at this series!

Phil.


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

end of thread, other threads:[~2023-06-27 22:33 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-26 23:19 [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Philippe Mathieu-Daudé
2023-06-26 23:19 ` [PATCH 01/16] target/riscv: Remove unused 'instmap.h' header in translate.c Philippe Mathieu-Daudé
2023-06-26 23:19 ` [PATCH 02/16] target/riscv: Restrict KVM-specific fields from ArchCPU Philippe Mathieu-Daudé
2023-06-26 23:19 ` [PATCH 03/16] target/riscv: Restrict sysemu specific header to user emulation Philippe Mathieu-Daudé
2023-06-26 23:19 ` [PATCH 04/16] target/riscv: Restrict 'rv128' machine to TCG accelerator Philippe Mathieu-Daudé
2023-06-26 23:19 ` [PATCH 05/16] target/riscv: Move sysemu-specific files to target/riscv/sysemu/ Philippe Mathieu-Daudé
2023-06-26 23:19 ` [PATCH 06/16] target/riscv: Restrict riscv_cpu_do_interrupt() to sysemu Philippe Mathieu-Daudé
2023-06-26 23:19 ` [PATCH 07/16] target/riscv: Move TCG-specific files to target/riscv/tcg/ Philippe Mathieu-Daudé
2023-06-26 23:19 ` [PATCH 08/16] target/riscv: Move TCG-specific cpu_get_tb_cpu_state() to tcg/cpu.c Philippe Mathieu-Daudé
2023-06-26 23:20 ` [PATCH 09/16] target/riscv: Expose some 'trigger' prototypes from debug.c Philippe Mathieu-Daudé
2023-06-26 23:20 ` [PATCH 10/16] target/riscv: Extract TCG-specific code " Philippe Mathieu-Daudé
2023-06-26 23:20 ` [PATCH 11/16] target/riscv: Move sysemu-specific debug files to target/riscv/sysemu/ Philippe Mathieu-Daudé
2023-06-26 23:20 ` [PATCH 12/16] target/riscv: Expose riscv_cpu_pending_to_irq() from cpu_helper.c Philippe Mathieu-Daudé
2023-06-26 23:20 ` [RFC PATCH 13/16] target/riscv: Move TCG/sysemu-specific code to tcg/sysemu/cpu_helper.c Philippe Mathieu-Daudé
2023-06-26 23:20 ` [PATCH 14/16] target/riscv: Move sysemu-specific code to sysemu/cpu_helper.c Philippe Mathieu-Daudé
2023-06-26 23:20 ` [PATCH 15/16] target/riscv: Restrict TCG-specific prototype declarations Philippe Mathieu-Daudé
2023-06-26 23:20 ` [PATCH 16/16] gitlab-ci.d/crossbuilds: Add KVM riscv64 cross-build jobs Philippe Mathieu-Daudé
2023-06-27 18:54 ` [PATCH 00/16] target/riscv: Allow building without TCG (KVM-only so far) Daniel Henrique Barboza
2023-06-27 22:32   ` Philippe Mathieu-Daudé

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).