qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4
@ 2019-08-23 23:37 Alistair Francis
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension Alistair Francis
                   ` (27 more replies)
  0 siblings, 28 replies; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:37 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra


This patch series adds the RISC-V Hypervisor extension v0.4. This is the
latest draft spec of the Hypervisor extension.

The Hypervisor extension is disabled by default, so this series should
result in no changes to anyone using QEMU unless they enable the
extension. The extention can be enabled with the -cpu property (see
below).

At the moment the spec does not include information about the mstatush
register. Although this information has since been merged into the
master spec. As it is only adding support for 32-bit I have added this
register to this series.

Testing of this implementation has been done by using the baremetal
Xvisor Hypervisor. We are able to run two Linux guests (that's all I
have tried) as guests in 64-bit. In 32-bit so far I can only run
baremetal guests, but I think this is a baremetal boot loader issue and
not an issue in QEMU.

The RISC-V KVM implementation was also written using these patches. The
KVM implementation is currently under review.

These patches result in a reproducable race when booting a SMP Linux
guest inside a SMP Linux KVM host. This will need to be fixed.

At the moment this spec is in a draft state and is subject to change. As
QEMU is extreamly useful in early bring up I think it makes sense for
QEMU to support non-frozen extensions.

Thanks to Anup for doing the initial port of Xvisor. The port is avaliable here:
https://github.com/avpatel/xvisor-next and will run on QEMU.

Also thanks to Atish for implementing the SBI call support in Xvisor and
for lots of help debugging.

To run this yourself:
 1. Apply this patch series to QEMU. The latest branch can be found here:
      https://github.com/alistair23/qemu/tree/mainline/alistair/riscv-hyp-ext-v0.4.next
 2. Get the version of OpenSBI that supports the H extension. This can
    be found here:
      https://github.com/riscv/opensbi/tree/hyp_ext_changes_v1
 3. Build the next release of Xvisor. It is available here:
      https://github.com/avpatel/xvisor-next
 4. Make sure you build the Xvisor tests, see here for details:
      https://github.com/avpatel/xvisor-next/tree/master/tests/riscv/virt64/linux
 5. Run QEMU:
     ./riscv64-softmmu/qemu-system-riscv64 -nographic \
       -machine virt -cpu rv64,x-h=true\
       -serial mon:stdio -serial null -m 4G \
       -device loader,file=vmm.bin,addr=0x80200000 \
       -kernel fw_jump.elf \
       -initrd vmm-disk-linux.img \
       -append "vmm.console=uart@10000000 vmm.bootcmd=\"vfs mount initrd /;vfs run /boot.xscript;vfs cat /system/banner.txt\""

   Once you get to the prompt you can start the geust by running:
     guest kick guest0
   You can then bind to the serial port using:
     vserial bind guest0/uart0
   Then you can start Linux using:
     autoexec

 This was all tested with the mainline 5.2/5.3 kernels.

There is very early work on a Xen port as well which is avaliable here:
https://github.com/alistair23/xen/tree/alistair/riscv-port

ToDo/Issues
 - Get 32-bit fully working
 - Fix KVM SMP race condition

Based-on: cover.1566573576.git.alistair.francis@wdc.com



Alistair Francis (28):
  target/riscv: Add the Hypervisor extension
  target/riscv: Add the virtulisation mode
  target/riscv: Add the force HS exception mode
  target/riscv: Fix CSR perm checking for HS mode
  target/riscv: Add the Hypervisor CSRs to CPUState
  target/riscv: Print priv and virt in disas log
  target/riscv: Dump Hypervisor registers if enabled
  target/riscv: Add Hypervisor CSR access functions
  target/riscv: Add Hypervisor virtual CSRs accesses
  target/riscv: Convert mie and mstatus to pointers
  target/riscv: Add background register swapping function
  target/riscv: Add support for virtual interrupt setting
  target/ricsv: Flush the TLB on virtulisation mode changes
  target/riscv: Generate illegal instruction on WFI when V=1
  riscv: plic: Always set sip.SEIP bit for HS
  target/riscv: Add hypvervisor trap support
  target/riscv: Add Hypervisor trap return support
  target/riscv: Add hfence instructions
  target/riscv: Disable guest FP support based on virtual status
  target/riscv: Mark both sstatus and vsstatus as dirty
  target/riscv: Respect MPRV and SPRV for floating point ops
  target/riscv: Allow specifying MMU stage
  target/riscv: Allow specifying number of MMU stages
  target/riscv: Implement second stage MMU
  target/riscv: Call the second stage MMU in virtualisation mode
  target/riscv: Add support for the 32-bit MSTATUSH CSR
  target/riscv: Add the MSTATUS_MPV_ISSET helper macro
  target/riscv: Allow enabling the Hypervisor extension

 hw/riscv/sifive_plic.c                        |  12 +-
 target/riscv/cpu.c                            |  61 ++-
 target/riscv/cpu.h                            |  68 ++-
 target/riscv/cpu_bits.h                       |  48 +-
 target/riscv/cpu_helper.c                     | 485 ++++++++++++++++--
 target/riscv/csr.c                            | 252 ++++++++-
 target/riscv/insn32.decode                    |  23 +-
 .../riscv/insn_trans/trans_privileged.inc.c   |  40 ++
 target/riscv/op_helper.c                      |  81 ++-
 target/riscv/translate.c                      |  34 ++
 10 files changed, 998 insertions(+), 106 deletions(-)

-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
@ 2019-08-23 23:37 ` Alistair Francis
  2019-08-27 15:26   ` Chih-Min Chao
  2019-09-10 13:43   ` Palmer Dabbelt
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 02/28] target/riscv: Add the virtulisation mode Alistair Francis
                   ` (26 subsequent siblings)
  27 siblings, 2 replies; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:37 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 124ed33ee4..7f54fb8c87 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -67,6 +67,7 @@
 #define RVC RV('C')
 #define RVS RV('S')
 #define RVU RV('U')
+#define RVH RV('H')
 
 /* S extension denotes that Supervisor mode exists, however it is possible
    to have a core that support S mode but does not have an MMU and there
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 02/28] target/riscv: Add the virtulisation mode
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension Alistair Francis
@ 2019-08-23 23:37 ` Alistair Francis
  2019-08-27 15:44   ` [Qemu-devel] [Qemu-riscv] " Chih-Min Chao
  2019-09-10 13:44   ` [Qemu-devel] " Palmer Dabbelt
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 03/28] target/riscv: Add the force HS exception mode Alistair Francis
                   ` (25 subsequent siblings)
  27 siblings, 2 replies; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:37 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        |  4 ++++
 target/riscv/cpu_bits.h   |  6 ++++++
 target/riscv/cpu_helper.c | 23 +++++++++++++++++++++++
 3 files changed, 33 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 7f54fb8c87..0ef1ecb0e0 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -117,6 +117,8 @@ struct CPURISCVState {
 
 #ifndef CONFIG_USER_ONLY
     target_ulong priv;
+    /* This contains QEMU specific information about the virt state. */
+    target_ulong virt;
     target_ulong resetvec;
 
     target_ulong mhartid;
@@ -257,6 +259,8 @@ int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
 int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
 bool riscv_cpu_fp_enabled(CPURISCVState *env);
+bool riscv_cpu_virt_enabled(CPURISCVState *env);
+void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
 int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
 hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index e99834856c..1fbde516be 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -422,6 +422,12 @@
 #define PRV_H 2 /* Reserved */
 #define PRV_M 3
 
+/* Virtulisation modes */
+#define VIRT_OFF            0
+#define VIRT_ON             1
+#define VIRT_MODE_SHIFT     0
+#define VIRT_MODE_MASK      (1 << VIRT_MODE_SHIFT)
+
 /* RV32 satp CSR field masks */
 #define SATP32_MODE         0x80000000
 #define SATP32_ASID         0x7fc00000
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 225e407cff..7b0bb14c01 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -81,6 +81,29 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
     return false;
 }
 
+bool riscv_cpu_virt_enabled(CPURISCVState *env)
+{
+    bool tmp;
+
+    if (!riscv_has_ext(env, RVH)) {
+        return false;
+    }
+
+    tmp = (env->virt & VIRT_MODE_MASK) >> VIRT_MODE_SHIFT;
+
+    return tmp == VIRT_ON;
+}
+
+void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
+{
+    if (!riscv_has_ext(env, RVH)) {
+        return;
+    }
+
+    env->virt &= ~VIRT_MODE_MASK;
+    env->virt |= enable << VIRT_MODE_SHIFT;
+}
+
 int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
 {
     CPURISCVState *env = &cpu->env;
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 03/28] target/riscv: Add the force HS exception mode
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension Alistair Francis
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 02/28] target/riscv: Add the virtulisation mode Alistair Francis
@ 2019-08-23 23:37 ` Alistair Francis
  2019-08-27 15:46   ` Chih-Min Chao
  2019-09-10 14:48   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 04/28] target/riscv: Fix CSR perm checking for HS mode Alistair Francis
                   ` (24 subsequent siblings)
  27 siblings, 2 replies; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:37 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        |  2 ++
 target/riscv/cpu_bits.h   |  6 ++++++
 target/riscv/cpu_helper.c | 23 +++++++++++++++++++++++
 3 files changed, 31 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0ef1ecb0e0..3a95c41428 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -261,6 +261,8 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
 bool riscv_cpu_fp_enabled(CPURISCVState *env);
 bool riscv_cpu_virt_enabled(CPURISCVState *env);
 void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
+bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env);
+void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable);
 int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
 hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 1fbde516be..204d9d9a79 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -428,6 +428,12 @@
 #define VIRT_MODE_SHIFT     0
 #define VIRT_MODE_MASK      (1 << VIRT_MODE_SHIFT)
 
+/* HS-level exception modes */
+#define CLEAR_HS_EXCEP        0
+#define FORCE_HS_EXCEP        1
+#define FORCE_HS_EXCEP_SHIFT  1
+#define FORCE_HS_EXCEP_MASK   (1 << FORCE_HS_EXCEP_SHIFT)
+
 /* RV32 satp CSR field masks */
 #define SATP32_MODE         0x80000000
 #define SATP32_ASID         0x7fc00000
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 7b0bb14c01..5bcfc2e090 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -104,6 +104,29 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
     env->virt |= enable << VIRT_MODE_SHIFT;
 }
 
+bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env)
+{
+    bool tmp;
+
+    if (!riscv_has_ext(env, RVH)) {
+        return false;
+    }
+
+    tmp = (env->virt & FORCE_HS_EXCEP_MASK) >> FORCE_HS_EXCEP_SHIFT;
+
+    return tmp == FORCE_HS_EXCEP;
+}
+
+void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable)
+{
+    if (!riscv_has_ext(env, RVH)) {
+        return;
+    }
+
+    env->virt &= ~FORCE_HS_EXCEP_MASK;
+    env->virt |= enable << FORCE_HS_EXCEP_SHIFT;
+}
+
 int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
 {
     CPURISCVState *env = &cpu->env;
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 04/28] target/riscv: Fix CSR perm checking for HS mode
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (2 preceding siblings ...)
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 03/28] target/riscv: Add the force HS exception mode Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-10 14:48   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 05/28] target/riscv: Add the Hypervisor CSRs to CPUState Alistair Francis
                   ` (23 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Update the CSR permission checking to work correctly when we are in
HS-mode.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index f767ad24be..471f23a1d0 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -799,9 +799,15 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
 
     /* check privileges and return -1 if check fails */
 #if !defined(CONFIG_USER_ONLY)
-    int csr_priv = get_field(csrno, 0x300);
+    int csr_priv = env->priv;
     int read_only = get_field(csrno, 0xC00) == 3;
-    if ((write_mask && read_only) || (env->priv < csr_priv)) {
+
+    if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
+        /* Plus 1 as we are in HS mode */
+        csr_priv++;
+    }
+
+    if ((write_mask && read_only) || (csr_priv < get_field(csrno, 0x300))) {
         return -1;
     }
 #endif
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 05/28] target/riscv: Add the Hypervisor CSRs to CPUState
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (3 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 04/28] target/riscv: Fix CSR perm checking for HS mode Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-08-27 15:50   ` [Qemu-devel] [Qemu-riscv] " Chih-Min Chao
  2019-09-10 14:48   ` [Qemu-devel] " Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 06/28] target/riscv: Print priv and virt in disas log Alistair Francis
                   ` (22 subsequent siblings)
  27 siblings, 2 replies; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

As the MIP CSR is 32-bits to allow atomic_read on 32-bit hosts the vsip
is 32-bit as well.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 3a95c41428..4c342e7a79 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -154,6 +154,23 @@ struct CPURISCVState {
     target_ulong mcause;
     target_ulong mtval;  /* since: priv-1.10.0 */
 
+    /* Hypervisor CSRs */
+    target_ulong hstatus;
+    target_ulong hedeleg;
+    target_ulong hideleg;
+    target_ulong hgatp;
+
+    /* Virtual CSRs */
+    target_ulong vsstatus;
+    uint32_t vsip;
+    target_ulong vsie;
+    target_ulong vstvec;
+    target_ulong vsscratch;
+    target_ulong vsepc;
+    target_ulong vscause;
+    target_ulong vstval;
+    target_ulong vsatp;
+
     target_ulong scounteren;
     target_ulong mcounteren;
 
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 06/28] target/riscv: Print priv and virt in disas log
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (4 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 05/28] target/riscv: Add the Hypervisor CSRs to CPUState Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-10 14:48   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 07/28] target/riscv: Dump Hypervisor registers if enabled Alistair Francis
                   ` (21 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/translate.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index adeddb85f6..8ac72c6470 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -810,7 +810,15 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
 
 static void riscv_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
 {
+#ifndef CONFIG_USER_ONLY
+    RISCVCPU *rvcpu = RISCV_CPU(cpu);
+    CPURISCVState *env = &rvcpu->env;
+#endif
+
     qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
+#ifndef CONFIG_USER_ONLY
+    qemu_log("Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", env->priv, env->virt);
+#endif
     log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
 }
 
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 07/28] target/riscv: Dump Hypervisor registers if enabled
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (5 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 06/28] target/riscv: Print priv and virt in disas log Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-10 14:48   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 08/28] target/riscv: Add Hypervisor CSR access functions Alistair Francis
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Dump the Hypervisor registers and the current Hypervisor state.

While we are editing this code let's also dump stvec and scause.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Atish Patra <atish.patra@wdc.com>
---
 target/riscv/cpu.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index f13e298a36..be8f643fc2 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -220,18 +220,52 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     CPURISCVState *env = &cpu->env;
     int i;
 
+#if !defined(CONFIG_USER_ONLY)
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s %d\n", "V      =  ", riscv_cpu_virt_enabled(env));
+    }
+#endif
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
 #ifndef CONFIG_USER_ONLY
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ", env->vsstatus);
+    }
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ",
                  (target_ulong)atomic_read(&env->mip));
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsip    ",
+                     (target_ulong)atomic_read(&env->vsip));
+    }
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsie    ", env->vsie);
+    }
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
+    }
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hedeleg ", env->hedeleg);
+    }
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec   ", env->mtvec);
+    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stvec   ", env->stvec);
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vstvec  ", env->vstvec);
+    }
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc    ", env->mepc);
+    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "sepc    ", env->sepc);
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsepc   ", env->vsepc);
+    }
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause  ", env->mcause);
+    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "scause  ", env->scause);
+    if (riscv_has_ext(env, RVH)) {
+        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vscause ", env->vscause);
+    }
 #endif
 
     for (i = 0; i < 32; i++) {
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 08/28] target/riscv: Add Hypervisor CSR access functions
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (6 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 07/28] target/riscv: Dump Hypervisor registers if enabled Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-10 14:48   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 09/28] target/riscv: Add Hypervisor virtual CSRs accesses Alistair Francis
                   ` (19 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/csr.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 471f23a1d0..388775d45a 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -98,6 +98,20 @@ static int smode(CPURISCVState *env, int csrno)
     return -!riscv_has_ext(env, RVS);
 }
 
+static int hmode(CPURISCVState *env, int csrno)
+{
+    if (riscv_has_ext(env, RVS) &&
+        riscv_has_ext(env, RVH)) {
+        /* Hypervisor extension is supported */
+        if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
+            env->priv == PRV_M) {
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
 static int pmp(CPURISCVState *env, int csrno)
 {
     return -!riscv_feature(env, RISCV_FEATURE_PMP);
@@ -754,6 +768,55 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
     return 0;
 }
 
+/* Hypervisor Extensions */
+static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->hstatus;
+    return 0;
+}
+
+static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->hstatus = val;
+    return 0;
+}
+
+static int read_hedeleg(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->hedeleg;
+    return 0;
+}
+
+static int write_hedeleg(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->hedeleg = val;
+    return 0;
+}
+
+static int read_hideleg(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->hideleg;
+    return 0;
+}
+
+static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->hideleg = val;
+    return 0;
+}
+
+static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->hgatp;
+    return 0;
+}
+
+static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->hgatp = val;
+    return 0;
+}
+
 /* Physical Memory Protection */
 static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val)
 {
@@ -950,6 +1013,11 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     /* Supervisor Protection and Translation */
     [CSR_SATP] =                { smode, read_satp,        write_satp        },
 
+    [CSR_HSTATUS] =             { hmode,   read_hstatus,     write_hstatus    },
+    [CSR_HEDELEG] =             { hmode,   read_hedeleg,     write_hedeleg    },
+    [CSR_HIDELEG] =             { hmode,   read_hideleg,     write_hideleg    },
+    [CSR_HGATP] =               { hmode,   read_hgatp,       write_hgatp      },
+
     /* Physical Memory Protection */
     [CSR_PMPCFG0  ... CSR_PMPADDR9] =  { pmp,   read_pmpcfg,  write_pmpcfg   },
     [CSR_PMPADDR0 ... CSR_PMPADDR15] = { pmp,   read_pmpaddr, write_pmpaddr  },
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 09/28] target/riscv: Add Hypervisor virtual CSRs accesses
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (7 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 08/28] target/riscv: Add Hypervisor CSR access functions Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-10 14:48   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers Alistair Francis
                   ` (18 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_bits.h |  11 ++++
 target/riscv/csr.c      | 119 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 130 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 204d9d9a79..78067901a2 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -191,6 +191,17 @@
 #define HGATP_PPN            SATP64_PPN
 #endif
 
+/* Virtual CSRs */
+#define CSR_VSSTATUS        0x200
+#define CSR_VSIE            0x204
+#define CSR_VSTVEC          0x205
+#define CSR_VSSCRATCH       0x240
+#define CSR_VSEPC           0x241
+#define CSR_VSCAUSE         0x242
+#define CSR_VSTVAL          0x243
+#define CSR_VSIP            0x244
+#define CSR_VSATP           0x280
+
 /* Physical Memory Protection */
 #define CSR_PMPCFG0         0x3a0
 #define CSR_PMPCFG1         0x3a1
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 388775d45a..e2e908fbc0 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -817,6 +817,115 @@ static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val)
     return 0;
 }
 
+/* Virtual CSR Registers */
+static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->vsstatus;
+    return 0;
+}
+
+static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->vsstatus = val;
+    return 0;
+}
+
+static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->vsie;
+    return 0;
+}
+
+static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->vsie = val;
+    return 0;
+}
+
+static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->vstvec;
+    return 0;
+}
+
+static int write_vstvec(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->vstvec = val;
+    return 0;
+}
+
+static int read_vsscratch(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->vsscratch;
+    return 0;
+}
+
+static int write_vsscratch(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->vsscratch = val;
+    return 0;
+}
+
+static int read_vsepc(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->vsepc;
+    return 0;
+}
+
+static int write_vsepc(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->vsepc = val;
+    return 0;
+}
+
+static int read_vscause(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->vscause;
+    return 0;
+}
+
+static int write_vscause(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->vscause = val;
+    return 0;
+}
+
+static int read_vstval(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->vstval;
+    return 0;
+}
+
+static int write_vstval(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->vstval = val;
+    return 0;
+}
+
+static int read_vsip(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = (target_ulong)atomic_read(&env->vsip);
+    return 0;
+}
+
+static int write_vsip(CPURISCVState *env, int csrno, target_ulong val)
+{
+    atomic_set(&env->vsip, val);
+    return 0;
+}
+
+static int read_vsatp(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = env->vsatp;
+    return 0;
+}
+
+static int write_vsatp(CPURISCVState *env, int csrno, target_ulong val)
+{
+    env->vsatp = val;
+    return 0;
+}
+
 /* Physical Memory Protection */
 static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val)
 {
@@ -1018,6 +1127,16 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     [CSR_HIDELEG] =             { hmode,   read_hideleg,     write_hideleg    },
     [CSR_HGATP] =               { hmode,   read_hgatp,       write_hgatp      },
 
+    [CSR_VSSTATUS] =            { hmode,   read_vsstatus,    write_vsstatus   },
+    [CSR_VSIE] =                { hmode,   read_vsie,        write_vsie       },
+    [CSR_VSTVEC] =              { hmode,   read_vstvec,      write_vstvec     },
+    [CSR_VSSCRATCH] =           { hmode,   read_vsscratch,   write_vsscratch  },
+    [CSR_VSEPC] =               { hmode,   read_vsepc,       write_vsepc      },
+    [CSR_VSCAUSE] =             { hmode,   read_vscause,     write_vscause    },
+    [CSR_VSTVAL] =              { hmode,   read_vstval,      write_vstval     },
+    [CSR_VSIP] =                { hmode,   read_vsip,        write_vsip       },
+    [CSR_VSATP] =               { hmode,   read_vsatp,       write_vsatp      },
+
     /* Physical Memory Protection */
     [CSR_PMPCFG0  ... CSR_PMPADDR9] =  { pmp,   read_pmpcfg,  write_pmpcfg   },
     [CSR_PMPADDR0 ... CSR_PMPADDR15] = { pmp,   read_pmpaddr, write_pmpaddr  },
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (8 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 09/28] target/riscv: Add Hypervisor virtual CSRs accesses Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-11  8:24   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 11/28] target/riscv: Add background register swapping function Alistair Francis
                   ` (17 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

To handle the new Hypervisor CSR register swapping let's use pointers.

We only need to convert the MIE and MSTATUS CSRs. With the exception of
MIP all of the other CSRs that swap with virtulsation changes are S-Mode
only, so we can just do a lazy switch. This because more challenging for
the M-Mode registers so it ends up being easier to use pointers.

As the MIP CSR is always accessed atomicly the pointer swap doesn't work
so we leave that as is.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c        | 16 ++++++++++++----
 target/riscv/cpu.h        | 12 ++++++++++--
 target/riscv/cpu_helper.c | 32 ++++++++++++++++----------------
 target/riscv/csr.c        | 28 ++++++++++++++--------------
 target/riscv/op_helper.c  | 14 +++++++-------
 5 files changed, 59 insertions(+), 43 deletions(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index be8f643fc2..371d5845af 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -228,7 +228,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
 #ifndef CONFIG_USER_ONLY
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
-    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
+    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", *env->mstatus);
     if (riscv_has_ext(env, RVH)) {
         qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
         qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ", env->vsstatus);
@@ -239,7 +239,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
         qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsip    ",
                      (target_ulong)atomic_read(&env->vsip));
     }
-    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
+    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", *env->mie);
     if (riscv_has_ext(env, RVH)) {
         qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsie    ", env->vsie);
     }
@@ -309,7 +309,7 @@ static bool riscv_cpu_has_work(CPUState *cs)
      * Definition of the WFI instruction requires it to ignore the privilege
      * mode and delegation registers, but respect individual enables
      */
-    return (atomic_read(&env->mip) & env->mie) != 0;
+    return (atomic_read(&env->mip) & *env->mie) != 0;
 #else
     return true;
 #endif
@@ -330,7 +330,7 @@ static void riscv_cpu_reset(CPUState *cs)
     mcc->parent_reset(cs);
 #ifndef CONFIG_USER_ONLY
     env->priv = PRV_M;
-    env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
+    *env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
     env->mcause = 0;
     env->pc = env->resetvec;
 #endif
@@ -459,8 +459,16 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
 static void riscv_cpu_init(Object *obj)
 {
     RISCVCPU *cpu = RISCV_CPU(obj);
+#ifndef CONFIG_USER_ONLY
+    CPURISCVState *env = &cpu->env;
+#endif
 
     cpu_set_cpustate_pointers(cpu);
+
+#ifndef CONFIG_USER_ONLY
+    env->mie = &env->mie_novirt;
+    env->mstatus = &env->mstatus_novirt;
+#endif
 }
 
 static const VMStateDescription vmstate_riscv_cpu = {
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 4c342e7a79..680592cb60 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -122,7 +122,7 @@ struct CPURISCVState {
     target_ulong resetvec;
 
     target_ulong mhartid;
-    target_ulong mstatus;
+    target_ulong *mstatus;
 
     /*
      * CAUTION! Unlike the rest of this struct, mip is accessed asynchonously
@@ -136,7 +136,7 @@ struct CPURISCVState {
     uint32_t mip;
     uint32_t miclaim;
 
-    target_ulong mie;
+    target_ulong *mie;
     target_ulong mideleg;
 
     target_ulong sptbr;  /* until: priv-1.9.1 */
@@ -154,6 +154,14 @@ struct CPURISCVState {
     target_ulong mcause;
     target_ulong mtval;  /* since: priv-1.10.0 */
 
+    /* The following registers are the "real" versions that the pointer
+     * versions point to. These should never be used unless you know what you
+     * are doing. To access these use the pointer versions instead. This is
+     * required to handle the Hypervisor register swapping.
+     */
+    target_ulong mie_novirt;
+    target_ulong mstatus_novirt;
+
     /* Hypervisor CSRs */
     target_ulong hstatus;
     target_ulong hedeleg;
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 5bcfc2e090..c597523d74 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -36,9 +36,9 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
 #ifndef CONFIG_USER_ONLY
 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
-    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
-    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
-    target_ulong pending = atomic_read(&env->mip) & env->mie;
+    target_ulong mstatus_mie = get_field(*env->mstatus, MSTATUS_MIE);
+    target_ulong mstatus_sie = get_field(*env->mstatus, MSTATUS_SIE);
+    target_ulong pending = atomic_read(env->mip) & *env->mie;
     target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie);
     target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie);
     target_ulong irqs = (pending & ~env->mideleg & -mie) |
@@ -74,7 +74,7 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 /* Return true is floating point support is currently enabled */
 bool riscv_cpu_fp_enabled(CPURISCVState *env)
 {
-    if (env->mstatus & MSTATUS_FS) {
+    if (*env->mstatus & MSTATUS_FS) {
         return true;
     }
 
@@ -219,8 +219,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
     int mode = mmu_idx;
 
     if (mode == PRV_M && access_type != MMU_INST_FETCH) {
-        if (get_field(env->mstatus, MSTATUS_MPRV)) {
-            mode = get_field(env->mstatus, MSTATUS_MPP);
+        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
+            mode = get_field(*env->mstatus, MSTATUS_MPP);
         }
     }
 
@@ -234,11 +234,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
 
     target_ulong base;
     int levels, ptidxbits, ptesize, vm, sum;
-    int mxr = get_field(env->mstatus, MSTATUS_MXR);
+    int mxr = get_field(*env->mstatus, MSTATUS_MXR);
 
     if (env->priv_ver >= PRIV_VERSION_1_10_0) {
         base = get_field(env->satp, SATP_PPN) << PGSHIFT;
-        sum = get_field(env->mstatus, MSTATUS_SUM);
+        sum = get_field(*env->mstatus, MSTATUS_SUM);
         vm = get_field(env->satp, SATP_MODE);
         switch (vm) {
         case VM_1_10_SV32:
@@ -258,8 +258,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
         }
     } else {
         base = env->sptbr << PGSHIFT;
-        sum = !get_field(env->mstatus, MSTATUS_PUM);
-        vm = get_field(env->mstatus, MSTATUS_VM);
+        sum = !get_field(*env->mstatus, MSTATUS_PUM);
+        vm = get_field(*env->mstatus, MSTATUS_VM);
         switch (vm) {
         case VM_1_09_SV32:
           levels = 2; ptidxbits = 10; ptesize = 4; break;
@@ -505,8 +505,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
 
     if (mode == PRV_M && access_type != MMU_INST_FETCH) {
-        if (get_field(env->mstatus, MSTATUS_MPRV)) {
-            mode = get_field(env->mstatus, MSTATUS_MPP);
+        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
+            mode = get_field(*env->mstatus, MSTATUS_MPP);
         }
     }
 
@@ -606,12 +606,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
     if (env->priv <= PRV_S &&
             cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
         /* handle the trap in S-mode */
-        target_ulong s = env->mstatus;
+        target_ulong s = *env->mstatus;
         s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
             get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
         s = set_field(s, MSTATUS_SPP, env->priv);
         s = set_field(s, MSTATUS_SIE, 0);
-        env->mstatus = s;
+        *env->mstatus = s;
         env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
         env->sepc = env->pc;
         env->sbadaddr = tval;
@@ -620,12 +620,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
         riscv_cpu_set_mode(env, PRV_S);
     } else {
         /* handle the trap in M-mode */
-        target_ulong s = env->mstatus;
+        target_ulong s = *env->mstatus;
         s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
             get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
         s = set_field(s, MSTATUS_MPP, env->priv);
         s = set_field(s, MSTATUS_MIE, 0);
-        env->mstatus = s;
+        *env->mstatus = s;
         env->mcause = cause | ~(((target_ulong)-1) >> async);
         env->mepc = env->pc;
         env->mbadaddr = tval;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index e2e908fbc0..30ec8c0a8e 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -136,7 +136,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
     if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
         return -1;
     }
-    env->mstatus |= MSTATUS_FS;
+    *env->mstatus |= MSTATUS_FS;
 #endif
     riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
     return 0;
@@ -159,7 +159,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
     if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
         return -1;
     }
-    env->mstatus |= MSTATUS_FS;
+    *env->mstatus |= MSTATUS_FS;
 #endif
     env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
     return 0;
@@ -183,7 +183,7 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
     if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
         return -1;
     }
-    env->mstatus |= MSTATUS_FS;
+    *env->mstatus |= MSTATUS_FS;
 #endif
     env->frm = (val & FSR_RD) >> FSR_RD_SHIFT;
     riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
@@ -307,7 +307,7 @@ static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val)
 /* Machine Trap Setup */
 static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val)
 {
-    *val = env->mstatus;
+    *val = *env->mstatus;
     return 0;
 }
 
@@ -319,7 +319,7 @@ static int validate_vm(CPURISCVState *env, target_ulong vm)
 
 static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
 {
-    target_ulong mstatus = env->mstatus;
+    target_ulong mstatus = *env->mstatus;
     target_ulong mask = 0;
     int dirty;
 
@@ -359,7 +359,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
              ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
             ((mstatus & MSTATUS_XS) == MSTATUS_XS);
     mstatus = set_field(mstatus, MSTATUS_SD, dirty);
-    env->mstatus = mstatus;
+    *env->mstatus = mstatus;
 
     return 0;
 }
@@ -448,13 +448,13 @@ static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
 
 static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
 {
-    *val = env->mie;
+    *val = *env->mie;
     return 0;
 }
 
 static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
 {
-    env->mie = (env->mie & ~all_ints) | (val & all_ints);
+    *env->mie = (*env->mie & ~all_ints) | (val & all_ints);
     return 0;
 }
 
@@ -608,7 +608,7 @@ static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
 {
     target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
                          sstatus_v1_10_mask : sstatus_v1_9_mask);
-    *val = env->mstatus & mask;
+    *val = *env->mstatus & mask;
     return 0;
 }
 
@@ -616,19 +616,19 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
 {
     target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
                          sstatus_v1_10_mask : sstatus_v1_9_mask);
-    target_ulong newval = (env->mstatus & ~mask) | (val & mask);
+    target_ulong newval = (*env->mstatus & ~mask) | (val & mask);
     return write_mstatus(env, CSR_MSTATUS, newval);
 }
 
 static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
 {
-    *val = env->mie & env->mideleg;
+    *val = *env->mie & env->mideleg;
     return 0;
 }
 
 static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
 {
-    target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg);
+    target_ulong newval = (*env->mie & ~env->mideleg) | (val & env->mideleg);
     return write_mie(env, CSR_MIE, newval);
 }
 
@@ -731,7 +731,7 @@ static int read_satp(CPURISCVState *env, int csrno, target_ulong *val)
     if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
         *val = 0;
     } else if (env->priv_ver >= PRIV_VERSION_1_10_0) {
-        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
+        if (env->priv == PRV_S && get_field(*env->mstatus, MSTATUS_TVM)) {
             return -1;
         } else {
             *val = env->satp;
@@ -756,7 +756,7 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
         validate_vm(env, get_field(val, SATP_MODE)) &&
         ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
     {
-        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
+        if (env->priv == PRV_S && get_field(*env->mstatus, MSTATUS_TVM)) {
             return -1;
         } else {
             if((val ^ env->satp) & SATP_ASID) {
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 331cc36232..d150551bc9 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -83,11 +83,11 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
     }
 
     if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
-        get_field(env->mstatus, MSTATUS_TSR)) {
+        get_field(*env->mstatus, MSTATUS_TSR)) {
         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     }
 
-    target_ulong mstatus = env->mstatus;
+    target_ulong mstatus = *env->mstatus;
     target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
     mstatus = set_field(mstatus,
         env->priv_ver >= PRIV_VERSION_1_10_0 ?
@@ -96,7 +96,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
     mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
     mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
     riscv_cpu_set_mode(env, prev_priv);
-    env->mstatus = mstatus;
+    *env->mstatus = mstatus;
 
     return retpc;
 }
@@ -112,7 +112,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
         riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
     }
 
-    target_ulong mstatus = env->mstatus;
+    target_ulong mstatus = *env->mstatus;
     target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
     mstatus = set_field(mstatus,
         env->priv_ver >= PRIV_VERSION_1_10_0 ?
@@ -121,7 +121,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
     mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
     mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
     riscv_cpu_set_mode(env, prev_priv);
-    env->mstatus = mstatus;
+    *env->mstatus = mstatus;
 
     return retpc;
 }
@@ -132,7 +132,7 @@ void helper_wfi(CPURISCVState *env)
 
     if (env->priv == PRV_S &&
         env->priv_ver >= PRIV_VERSION_1_10_0 &&
-        get_field(env->mstatus, MSTATUS_TW)) {
+        get_field(*env->mstatus, MSTATUS_TW)) {
         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     } else {
         cs->halted = 1;
@@ -147,7 +147,7 @@ void helper_tlb_flush(CPURISCVState *env)
     if (!(env->priv >= PRV_S) ||
         (env->priv == PRV_S &&
          env->priv_ver >= PRIV_VERSION_1_10_0 &&
-         get_field(env->mstatus, MSTATUS_TVM))) {
+         get_field(*env->mstatus, MSTATUS_TVM))) {
         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     } else {
         tlb_flush(cs);
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 11/28] target/riscv: Add background register swapping function
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (9 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-11 14:17   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 12/28] target/riscv: Add support for virtual interrupt setting Alistair Francis
                   ` (16 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.h        | 24 ++++++++---
 target/riscv/cpu_bits.h   |  7 ++++
 target/riscv/cpu_helper.c | 88 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+), 6 deletions(-)

diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 680592cb60..05957f32a8 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -125,15 +125,18 @@ struct CPURISCVState {
     target_ulong *mstatus;
 
     /*
-     * CAUTION! Unlike the rest of this struct, mip is accessed asynchonously
-     * by I/O threads. It should be read with atomic_read. It should be updated
-     * using riscv_cpu_update_mip with the iothread mutex held. The iothread
-     * mutex must be held because mip must be consistent with the CPU inturrept
-     * state. riscv_cpu_update_mip calls cpu_interrupt or cpu_reset_interrupt
-     * wuth the invariant that CPU_INTERRUPT_HARD is set iff mip is non-zero.
+     * CAUTION! Unlike the rest of this struct, mip and mip_novirt is accessed
+     * asynchonously by I/O threads. It should be read with atomic_read. It should
+     * be updated using riscv_cpu_update_mip with the iothread mutex held. The
+     * iothread mutex must be held because mip must be consistent with the CPU
+     * inturrept state. riscv_cpu_update_mip calls cpu_interrupt or
+     * cpu_reset_interrupt wuth the invariant that CPU_INTERRUPT_HARD is set if
+     * mip is non-zero.
      * mip is 32-bits to allow atomic_read on 32-bit hosts.
      */
     uint32_t mip;
+    uint32_t mip_novirt;
+
     uint32_t miclaim;
 
     target_ulong *mie;
@@ -179,6 +182,14 @@ struct CPURISCVState {
     target_ulong vstval;
     target_ulong vsatp;
 
+    /* HS Backup CSRs */
+    target_ulong stvec_hs;
+    target_ulong sscratch_hs;
+    target_ulong sepc_hs;
+    target_ulong scause_hs;
+    target_ulong stval_hs;
+    target_ulong satp_hs;
+
     target_ulong scounteren;
     target_ulong mcounteren;
 
@@ -306,6 +317,7 @@ void riscv_cpu_list(void);
 #define cpu_mmu_index riscv_cpu_mmu_index
 
 #ifndef CONFIG_USER_ONLY
+void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
 int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
 uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
 #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 78067901a2..5cee72b726 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -556,4 +556,11 @@
 #define SIP_STIP                           MIP_STIP
 #define SIP_SEIP                           MIP_SEIP
 
+/* MIE masks */
+#define MIE_SEIE                           (1 << IRQ_S_EXT)
+#define MIE_UEIE                           (1 << IRQ_U_EXT)
+#define MIE_STIE                           (1 << IRQ_S_TIMER)
+#define MIE_UTIE                           (1 << IRQ_U_TIMER)
+#define MIE_SSIE                           (1 << IRQ_S_SOFT)
+#define MIE_USIE                           (1 << IRQ_U_SOFT)
 #endif
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index c597523d74..41d4368128 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -81,6 +81,94 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
     return false;
 }
 
+void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
+{
+    RISCVCPU *cpu = RISCV_CPU(env_cpu(env));
+    uint32_t tmp;
+    target_ulong mstatus_mask = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_FS |
+                                MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE;
+    target_ulong sie_mask = MIE_SEIE | MIE_STIE | MIE_SSIE |
+                            MIE_UEIE | MIE_UTIE | MIE_USIE;
+    target_ulong mip_mask = MIP_SSIP | MIP_STIP | MIP_SEIP;
+    bool current_virt = riscv_cpu_virt_enabled(env);
+
+    g_assert(riscv_has_ext(env, RVH));
+
+#if defined(TARGET_RISCV64)
+    mstatus_mask |= MSTATUS64_UXL;
+#endif
+
+    if (current_virt) {
+        /* Current V=1 and we are about to change to V=0 */
+        env->mstatus = &env->mstatus_novirt;
+        *env->mstatus &= mstatus_mask;
+        *env->mstatus |= env->vsstatus & ~mstatus_mask;
+        /* Ensure that vsstatus only holds the correct bits */
+        env->vsstatus &= mstatus_mask;
+
+        env->mie = &env->mie_novirt;
+        *env->mie &= sie_mask;
+        *env->mie |= env->vsie & ~sie_mask;
+        /* Ensure that vsie only holds the correct bits */
+        env->vsie &= sie_mask;
+
+        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->sbadaddr;
+        env->sbadaddr = env->stval_hs;
+
+        env->vsatp = env->satp;
+        env->satp = env->satp_hs;
+
+        tmp = (uint32_t)atomic_read(&env->mip_novirt);
+        tmp = riscv_cpu_update_mip(cpu, mip_mask, tmp);
+        tmp &= mip_mask;
+        atomic_set(&env->vsip, tmp);
+    } else {
+        /* Current V=0 and we are about to change to V=1 */
+        env->mstatus = &env->vsstatus;
+        *env->mstatus &= mstatus_mask;
+        *env->mstatus |= env->mstatus_novirt & ~mstatus_mask;
+
+        env->mie = &env->vsie;
+        *env->mie &= sie_mask;
+        *env->mie |= env->mie_novirt & ~sie_mask;
+
+        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->sbadaddr;
+        env->sbadaddr = env->vstval;
+
+        env->satp_hs = env->satp;
+        env->satp = env->vsatp;
+
+        tmp = (uint32_t)atomic_read(&env->vsip);
+        tmp = riscv_cpu_update_mip(cpu, mip_mask, tmp);
+        tmp &= mip_mask;
+        atomic_set(&env->mip_novirt, tmp);
+    }
+}
+
 bool riscv_cpu_virt_enabled(CPURISCVState *env)
 {
     bool tmp;
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 12/28] target/riscv: Add support for virtual interrupt setting
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (10 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 11/28] target/riscv: Add background register swapping function Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-14 20:30   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 13/28] target/ricsv: Flush the TLB on virtulisation mode changes Alistair Francis
                   ` (15 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 41d4368128..afb3e8579e 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -38,12 +38,27 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
 {
     target_ulong mstatus_mie = get_field(*env->mstatus, MSTATUS_MIE);
     target_ulong mstatus_sie = get_field(*env->mstatus, MSTATUS_SIE);
-    target_ulong pending = atomic_read(env->mip) & *env->mie;
-    target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie);
-    target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie);
+    target_ulong vsstatus_sie = get_field(env->mstatus_novirt, MSTATUS_SIE);
+
+    target_ulong pending = atomic_read(&env->mip) & *env->mie;
+    target_ulong hspending = atomic_read(&env->mip_novirt) & env->mie_novirt;
+
+    target_ulong mie  = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie);
+    target_ulong sie  = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie);
+    target_ulong vsie = env->priv < PRV_S || (env->priv == PRV_S && vsstatus_sie);
+
     target_ulong irqs = (pending & ~env->mideleg & -mie) |
                         (pending &  env->mideleg & -sie);
 
+    if (riscv_cpu_virt_enabled(env)) {
+        target_ulong pending_hs_irq = hspending & -vsie;
+
+        if (pending_hs_irq) {
+            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
+            return ctz64(pending_hs_irq);
+        }
+    }
+
     if (irqs) {
         return ctz64(irqs); /* since non-zero */
     } else {
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 13/28] target/ricsv: Flush the TLB on virtulisation mode changes
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (11 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 12/28] target/riscv: Add support for virtual interrupt setting Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-14 20:30   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 14/28] target/riscv: Generate illegal instruction on WFI when V=1 Alistair Francis
                   ` (14 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

To ensure our TLB isn't out-of-date we flush it on all virt mode
changes. Unlike priv mode this isn't saved in the mmu_idx as all
guests share V=1. The easiest option is just to flush on all changes.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index afb3e8579e..8e8b156fc0 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -203,6 +203,11 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
         return;
     }
 
+    /* Flush the TLB on all virt mode changes. */
+    if (((env->virt & VIRT_MODE_MASK) >> VIRT_MODE_SHIFT) != enable) {
+        tlb_flush(env_cpu(env));
+    }
+
     env->virt &= ~VIRT_MODE_MASK;
     env->virt |= enable << VIRT_MODE_SHIFT;
 }
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 14/28] target/riscv: Generate illegal instruction on WFI when V=1
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (12 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 13/28] target/ricsv: Flush the TLB on virtulisation mode changes Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-14 20:30   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 15/28] riscv: plic: Always set sip.SEIP bit for HS Alistair Francis
                   ` (13 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/op_helper.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index d150551bc9..beb34e705b 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -130,9 +130,10 @@ void helper_wfi(CPURISCVState *env)
 {
     CPUState *cs = env_cpu(env);
 
-    if (env->priv == PRV_S &&
+    if ((env->priv == PRV_S &&
         env->priv_ver >= PRIV_VERSION_1_10_0 &&
-        get_field(*env->mstatus, MSTATUS_TW)) {
+        get_field(*env->mstatus, MSTATUS_TW)) ||
+        riscv_cpu_virt_enabled(env)) {
         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     } else {
         cs->halted = 1;
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 15/28] riscv: plic: Always set sip.SEIP bit for HS
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (13 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 14/28] target/riscv: Generate illegal instruction on WFI when V=1 Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-14 20:32   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 16/28] target/riscv: Add hypvervisor trap support Alistair Francis
                   ` (12 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

When the PLIC generates an interrupt ensure we always set it for the SIP
CSR that corresponds to the HS (V=0) register.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 hw/riscv/sifive_plic.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c
index 98e4304b66..8309e96f64 100644
--- a/hw/riscv/sifive_plic.c
+++ b/hw/riscv/sifive_plic.c
@@ -150,7 +150,17 @@ static void sifive_plic_update(SiFivePLICState *plic)
             riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level));
             break;
         case PLICMode_S:
-            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level));
+            if (riscv_cpu_virt_enabled(env)) {
+                if (level) {
+                    atomic_or(&env->mip_novirt, MIP_SEIP);
+                    g_assert(riscv_cpu_virt_enabled(env));
+                } else {
+                    atomic_and(&env->mip_novirt, ~MIP_SEIP);
+                    g_assert(riscv_cpu_virt_enabled(env));
+                }
+            } else {
+                riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level));
+            }
             break;
         default:
             break;
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 16/28] target/riscv: Add hypvervisor trap support
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (14 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 15/28] riscv: plic: Always set sip.SEIP bit for HS Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-09-20 14:01   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 17/28] target/riscv: Add Hypervisor trap return support Alistair Francis
                   ` (11 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_bits.h   |  4 +--
 target/riscv/cpu_helper.c | 71 +++++++++++++++++++++++++++++++++------
 target/riscv/csr.c        |  4 +--
 3 files changed, 65 insertions(+), 14 deletions(-)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 5cee72b726..353fc9a24a 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -513,8 +513,8 @@
 #define RISCV_EXCP_STORE_AMO_ADDR_MIS      0x6
 #define RISCV_EXCP_STORE_AMO_ACCESS_FAULT  0x7
 #define RISCV_EXCP_U_ECALL                 0x8
-#define RISCV_EXCP_S_ECALL                 0x9
-#define RISCV_EXCP_H_ECALL                 0xa
+#define RISCV_EXCP_HS_ECALL                0x9
+#define RISCV_EXCP_VS_ECALL                0xa
 #define RISCV_EXCP_M_ECALL                 0xb
 #define RISCV_EXCP_INST_PAGE_FAULT         0xc /* since: priv-1.10.0 */
 #define RISCV_EXCP_LOAD_PAGE_FAULT         0xd /* since: priv-1.10.0 */
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 8e8b156fc0..17eec6217b 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -668,6 +668,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
 
     RISCVCPU *cpu = RISCV_CPU(cs);
     CPURISCVState *env = &cpu->env;
+    target_ulong 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.
@@ -677,13 +678,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
     target_ulong deleg = async ? env->mideleg : env->medeleg;
     target_ulong tval = 0;
 
-    static const int ecall_cause_map[] = {
-        [PRV_U] = RISCV_EXCP_U_ECALL,
-        [PRV_S] = RISCV_EXCP_S_ECALL,
-        [PRV_H] = RISCV_EXCP_H_ECALL,
-        [PRV_M] = RISCV_EXCP_M_ECALL
-    };
-
     if (!async) {
         /* set tval to badaddr for traps with address information */
         switch (cause) {
@@ -704,7 +698,16 @@ void riscv_cpu_do_interrupt(CPUState *cs)
         /* ecall is dispatched as one cause so translate based on mode */
         if (cause == RISCV_EXCP_U_ECALL) {
             assert(env->priv <= 3);
-            cause = ecall_cause_map[env->priv];
+
+            if (env->priv == PRV_M) {
+                cause = RISCV_EXCP_M_ECALL;
+            } else if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) {
+                cause = RISCV_EXCP_VS_ECALL;
+            } else if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) {
+                cause = RISCV_EXCP_HS_ECALL;
+            } else if (env->priv == PRV_U) {
+                cause = RISCV_EXCP_U_ECALL;
+            }
         }
     }
 
@@ -714,7 +717,42 @@ void riscv_cpu_do_interrupt(CPUState *cs)
     if (env->priv <= PRV_S &&
             cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
         /* handle the trap in S-mode */
-        target_ulong s = *env->mstatus;
+        if (riscv_has_ext(env, RVH)) {
+            target_ulong hdeleg = async ? env->hideleg : env->hedeleg;
+
+            if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1) &&
+                !riscv_cpu_force_hs_excep_enabled(env)) {
+                /* Trap to VS mode */
+            } else if (riscv_cpu_virt_enabled(env)) {
+                /* Trap into HS mode, from virt */
+                riscv_cpu_swap_hypervisor_regs(env);
+                env->hstatus = set_field(env->hstatus, HSTATUS_SP2V,
+                                         get_field(env->hstatus, HSTATUS_SPV));
+                env->hstatus = set_field(env->hstatus, HSTATUS_SP2P,
+                                         get_field(*env->mstatus, SSTATUS_SPP));
+                env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
+                                         riscv_cpu_virt_enabled(env));
+
+                if (riscv_cpu_force_hs_excep_enabled(env)) {
+                    env->hstatus = set_field(env->hstatus, HSTATUS_STL, 1);
+                } else {
+                    env->hstatus = set_field(env->hstatus, HSTATUS_STL, 0);
+                }
+
+                riscv_cpu_set_virt_enabled(env, VIRT_OFF);
+                riscv_cpu_set_force_hs_excep(env, CLEAR_HS_EXCEP);
+            } else {
+                /* Trap into HS mode */
+                env->hstatus = set_field(env->hstatus, HSTATUS_SP2V,
+                                         get_field(env->hstatus, HSTATUS_SPV));
+                env->hstatus = set_field(env->hstatus, HSTATUS_SP2P,
+                                         get_field(*env->mstatus, SSTATUS_SPP));
+                env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
+                                         riscv_cpu_virt_enabled(env));
+            }
+        }
+
+        s = *env->mstatus;
         s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
             get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
         s = set_field(s, MSTATUS_SPP, env->priv);
@@ -728,7 +766,20 @@ void riscv_cpu_do_interrupt(CPUState *cs)
         riscv_cpu_set_mode(env, PRV_S);
     } else {
         /* handle the trap in M-mode */
-        target_ulong s = *env->mstatus;
+        if (riscv_has_ext(env, RVH)) {
+            if (riscv_cpu_virt_enabled(env)) {
+                riscv_cpu_swap_hypervisor_regs(env);
+            }
+            *env->mstatus = set_field(*env->mstatus, MSTATUS_MPV,
+                                      riscv_cpu_virt_enabled(env));
+            *env->mstatus = set_field(*env->mstatus, MSTATUS_MTL,
+                                      riscv_cpu_force_hs_excep_enabled(env));
+
+            /* Trapping to M mode, virt is disabled */
+            riscv_cpu_set_virt_enabled(env, VIRT_OFF);
+        }
+
+        s = *env->mstatus;
         s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
             get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
         s = set_field(s, MSTATUS_MPP, env->priv);
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 30ec8c0a8e..47be4b1d42 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -255,8 +255,8 @@ static const target_ulong delegable_excps =
     (1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS)) |
     (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) |
     (1ULL << (RISCV_EXCP_U_ECALL)) |
-    (1ULL << (RISCV_EXCP_S_ECALL)) |
-    (1ULL << (RISCV_EXCP_H_ECALL)) |
+    (1ULL << (RISCV_EXCP_VS_ECALL)) |
+    (1ULL << (RISCV_EXCP_HS_ECALL)) |
     (1ULL << (RISCV_EXCP_M_ECALL)) |
     (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) |
     (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) |
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 17/28] target/riscv: Add Hypervisor trap return support
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (15 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 16/28] target/riscv: Add hypvervisor trap support Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-01 18:33   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 18/28] target/riscv: Add hfence instructions Alistair Francis
                   ` (10 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/op_helper.c | 66 ++++++++++++++++++++++++++++++++--------
 1 file changed, 54 insertions(+), 12 deletions(-)

diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index beb34e705b..5bcf5d2ff7 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -73,6 +73,8 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
 
 target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
 {
+    target_ulong prev_priv, prev_virt, mstatus;
+
     if (!(env->priv >= PRV_S)) {
         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     }
@@ -87,16 +89,46 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
         riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
     }
 
-    target_ulong mstatus = *env->mstatus;
-    target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
-    mstatus = set_field(mstatus,
-        env->priv_ver >= PRIV_VERSION_1_10_0 ?
-        MSTATUS_SIE : MSTATUS_UIE << prev_priv,
-        get_field(mstatus, MSTATUS_SPIE));
-    mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
-    mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
+    mstatus = *env->mstatus;
+
+    if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
+        /* We support Hypervisor extensions and virtulisation is disabled */
+        target_ulong hstatus = env->hstatus;
+
+        prev_priv = get_field(mstatus, MSTATUS_SPP);
+        prev_virt = get_field(hstatus, HSTATUS_SPV);
+
+        hstatus = set_field(hstatus, HSTATUS_SPV,
+                                 get_field(hstatus, HSTATUS_SP2V));
+        mstatus = set_field(mstatus, MSTATUS_SPP,
+                            get_field(hstatus, HSTATUS_SP2P));
+        hstatus = set_field(hstatus, HSTATUS_SP2V, 0);
+        hstatus = set_field(hstatus, HSTATUS_SP2P, 0);
+        mstatus = set_field(mstatus, SSTATUS_SIE,
+                            get_field(mstatus, SSTATUS_SPIE));
+        mstatus = set_field(mstatus, SSTATUS_SPIE, 1);
+
+        *env->mstatus = mstatus;
+        env->hstatus = hstatus;
+
+        if (prev_virt == VIRT_ON) {
+            riscv_cpu_swap_hypervisor_regs(env);
+        }
+
+        riscv_cpu_set_virt_enabled(env, prev_virt);
+    } else {
+        prev_priv = get_field(mstatus, MSTATUS_SPP);
+
+        mstatus = set_field(mstatus,
+            env->priv_ver >= PRIV_VERSION_1_10_0 ?
+            MSTATUS_SIE : MSTATUS_UIE << prev_priv,
+            get_field(mstatus, MSTATUS_SPIE));
+        mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
+        mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
+        *env->mstatus = mstatus;
+    }
+
     riscv_cpu_set_mode(env, prev_priv);
-    *env->mstatus = mstatus;
 
     return retpc;
 }
@@ -114,14 +146,24 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
 
     target_ulong mstatus = *env->mstatus;
     target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
+    target_ulong prev_virt = get_field(mstatus, MSTATUS_MPV);
     mstatus = set_field(mstatus,
         env->priv_ver >= PRIV_VERSION_1_10_0 ?
         MSTATUS_MIE : MSTATUS_UIE << prev_priv,
         get_field(mstatus, MSTATUS_MPIE));
-    mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
-    mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
-    riscv_cpu_set_mode(env, prev_priv);
+    mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
+    mstatus = set_field(mstatus, MSTATUS_MPP, 0);
+    mstatus = set_field(mstatus, MSTATUS_MPV, 0);
     *env->mstatus = mstatus;
+    riscv_cpu_set_mode(env, prev_priv);
+
+    if (riscv_has_ext(env, RVH)) {
+        if (prev_virt == VIRT_ON) {
+            riscv_cpu_swap_hypervisor_regs(env);
+        }
+
+        riscv_cpu_set_virt_enabled(env, prev_virt);
+    }
 
     return retpc;
 }
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 18/28] target/riscv: Add hfence instructions
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (16 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 17/28] target/riscv: Add Hypervisor trap return support Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-01 18:34   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 19/28] target/riscv: Disable guest FP support based on virtual status Alistair Francis
                   ` (9 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/insn32.decode                    | 23 ++++++-----
 .../riscv/insn_trans/trans_privileged.inc.c   | 40 +++++++++++++++++++
 2 files changed, 54 insertions(+), 9 deletions(-)

diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 77f794ed70..cfd9ca6d2b 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -63,20 +63,25 @@
 @r2_rm   .......   ..... ..... ... ..... ....... %rs1 %rm %rd
 @r2      .......   ..... ..... ... ..... ....... %rs1 %rd
 
+@hfence_gvma ....... ..... .....   ... ..... ....... %rs2 %rs1
+@hfence_bvma ....... ..... .....   ... ..... ....... %rs2 %rs1
+
 @sfence_vma ....... ..... .....   ... ..... ....... %rs2 %rs1
 @sfence_vm  ....... ..... .....   ... ..... ....... %rs1
 
 
 # *** Privileged Instructions ***
-ecall      000000000000     00000 000 00000 1110011
-ebreak     000000000001     00000 000 00000 1110011
-uret       0000000    00010 00000 000 00000 1110011
-sret       0001000    00010 00000 000 00000 1110011
-hret       0010000    00010 00000 000 00000 1110011
-mret       0011000    00010 00000 000 00000 1110011
-wfi        0001000    00101 00000 000 00000 1110011
-sfence_vma 0001001    ..... ..... 000 00000 1110011 @sfence_vma
-sfence_vm  0001000    00100 ..... 000 00000 1110011 @sfence_vm
+ecall       000000000000     00000 000 00000 1110011
+ebreak      000000000001     00000 000 00000 1110011
+uret        0000000    00010 00000 000 00000 1110011
+sret        0001000    00010 00000 000 00000 1110011
+hret        0010000    00010 00000 000 00000 1110011
+mret        0011000    00010 00000 000 00000 1110011
+wfi         0001000    00101 00000 000 00000 1110011
+hfence_gvma 0110001    ..... ..... 000 00000 1110011 @hfence_gvma
+hfence_bvma 0010001    ..... ..... 000 00000 1110011 @hfence_bvma
+sfence_vma  0001001    ..... ..... 000 00000 1110011 @sfence_vma
+sfence_vm   0001000    00100 ..... 000 00000 1110011 @sfence_vm
 
 # *** RV32I Base Instruction Set ***
 lui      ....................       ..... 0110111 @u
diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c
index c5e4b3e49a..b9b5a89b52 100644
--- a/target/riscv/insn_trans/trans_privileged.inc.c
+++ b/target/riscv/insn_trans/trans_privileged.inc.c
@@ -108,3 +108,43 @@ static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
 #endif
     return false;
 }
+
+static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
+{
+#ifndef CONFIG_USER_ONLY
+    if (ctx->priv_ver >= PRIV_VERSION_1_10_0 &&
+        has_ext(ctx, RVH)) {
+        /* Hpervisor extensions exist */
+        /*
+         * if (env->priv == PRV_M ||
+         *   (env->priv == PRV_S &&
+         *    !riscv_cpu_virt_enabled(env) &&
+         *    get_field(ctx->mstatus_fs, MSTATUS_TVM))) {
+         */
+            gen_helper_tlb_flush(cpu_env);
+            return true;
+        /* } */
+    }
+#endif
+    return false;
+}
+
+static bool trans_hfence_bvma(DisasContext *ctx, arg_sfence_vma *a)
+{
+#ifndef CONFIG_USER_ONLY
+    if (ctx->priv_ver >= PRIV_VERSION_1_10_0 &&
+        has_ext(ctx, RVH)) {
+        /* Hpervisor extensions exist */
+        /*
+         * if (env->priv == PRV_M ||
+         *   (env->priv == PRV_S &&
+         *    !riscv_cpu_virt_enabled(env) &&
+         *    get_field(ctx->mstatus_fs, MSTATUS_TVM))) {
+         */
+            gen_helper_tlb_flush(cpu_env);
+            return true;
+        /* } */
+    }
+#endif
+    return false;
+}
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 19/28] target/riscv: Disable guest FP support based on virtual status
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (17 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 18/28] target/riscv: Add hfence instructions Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-01 18:34   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 20/28] target/riscv: Mark both sstatus and vsstatus as dirty Alistair Francis
                   ` (8 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

When the Hypervisor extension is in use we only enable floating point
support when both status and vsstatus have enabled floating point
support.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 17eec6217b..098873c83e 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -90,6 +90,9 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 bool riscv_cpu_fp_enabled(CPURISCVState *env)
 {
     if (*env->mstatus & MSTATUS_FS) {
+        if (riscv_cpu_virt_enabled(env) && !(env->vsstatus & MSTATUS_FS)) {
+            return false;
+        }
         return true;
     }
 
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 20/28] target/riscv: Mark both sstatus and vsstatus as dirty
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (18 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 19/28] target/riscv: Disable guest FP support based on virtual status Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-01 18:34   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 21/28] target/riscv: Respect MPRV and SPRV for floating point ops Alistair Francis
                   ` (7 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Mark both sstatus and vsstatus as dirty (3).

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/translate.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 8ac72c6470..19771904f4 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -44,6 +44,7 @@ typedef struct DisasContext {
     /* pc_succ_insn points to the instruction following base.pc_next */
     target_ulong pc_succ_insn;
     target_ulong priv_ver;
+    bool virt_enabled;
     uint32_t opcode;
     uint32_t mstatus_fs;
     uint32_t misa;
@@ -398,6 +399,12 @@ static void mark_fs_dirty(DisasContext *ctx)
     tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
     tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
     tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
+
+    if (ctx->virt_enabled) {
+        tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, vsstatus));
+        tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
+        tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, vsstatus));
+    }
     tcg_temp_free(tmp);
 }
 #else
@@ -742,6 +749,11 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->mem_idx = ctx->base.tb->flags & TB_FLAGS_MMU_MASK;
     ctx->mstatus_fs = ctx->base.tb->flags & TB_FLAGS_MSTATUS_FS;
     ctx->priv_ver = env->priv_ver;
+#if !defined(CONFIG_USER_ONLY)
+    ctx->virt_enabled = riscv_cpu_virt_enabled(env);
+#else
+    ctx->virt_enabled = false;
+#endif
     ctx->misa = env->misa;
     ctx->frm = -1;  /* unknown rounding mode */
     ctx->ext_ifencei = cpu->cfg.ext_ifencei;
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 21/28] target/riscv: Respect MPRV and SPRV for floating point ops
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (19 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 20/28] target/riscv: Mark both sstatus and vsstatus as dirty Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-02 23:52   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 22/28] target/riscv: Allow specifying MMU stage Alistair Francis
                   ` (6 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Respect the contents of MSTATUS.MPRV and HSTATUS.SPRV when performing
floating point operations when V=0.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/translate.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 19771904f4..ea19ba9c5d 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -750,7 +750,21 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
     ctx->mstatus_fs = ctx->base.tb->flags & TB_FLAGS_MSTATUS_FS;
     ctx->priv_ver = env->priv_ver;
 #if !defined(CONFIG_USER_ONLY)
-    ctx->virt_enabled = riscv_cpu_virt_enabled(env);
+    if (riscv_has_ext(env, RVH)) {
+        ctx->virt_enabled = riscv_cpu_virt_enabled(env);
+        if (env->priv_ver == PRV_M &&
+            get_field(*env->mstatus, MSTATUS_MPRV) &&
+            get_field(*env->mstatus, MSTATUS_MPV)) {
+            ctx->virt_enabled = true;
+        } else if (env->priv == PRV_S &&
+                   !riscv_cpu_virt_enabled(env) &&
+                   get_field(env->hstatus, HSTATUS_SPRV) &&
+                   get_field(env->hstatus, HSTATUS_SPV)) {
+            ctx->virt_enabled = true;
+        }
+    } else {
+        ctx->virt_enabled = false;
+    }
 #else
     ctx->virt_enabled = false;
 #endif
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 22/28] target/riscv: Allow specifying MMU stage
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (20 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 21/28] target/riscv: Respect MPRV and SPRV for floating point ops Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-03 15:53   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 23/28] target/riscv: Allow specifying number of MMU stages Alistair Francis
                   ` (5 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 39 ++++++++++++++++++++++++++++++---------
 1 file changed, 30 insertions(+), 9 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 098873c83e..9aa6906acd 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -318,10 +318,19 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
  *
  * 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 to be translated
+ * @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
  */
 static int get_physical_address(CPURISCVState *env, hwaddr *physical,
                                 int *prot, target_ulong addr,
-                                int access_type, int mmu_idx)
+                                int access_type, int mmu_idx,
+                                bool first_stage)
 {
     /* NOTE: the env->pc value visible here will not be
      * correct, but the value visible to the exception handler
@@ -518,13 +527,23 @@ restart:
 }
 
 static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
-                                MMUAccessType access_type, bool pmp_violation)
+                                MMUAccessType access_type, bool pmp_violation,
+                                bool first_stage)
 {
     CPUState *cs = env_cpu(env);
-    int page_fault_exceptions =
-        (env->priv_ver >= PRIV_VERSION_1_10_0) &&
-        get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
-        !pmp_violation;
+    int page_fault_exceptions;
+    if (first_stage) {
+        page_fault_exceptions =
+            (env->priv_ver >= PRIV_VERSION_1_10_0) &&
+            get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
+            !pmp_violation;
+            riscv_cpu_set_force_hs_excep(env, CLEAR_HS_EXCEP);
+    } else {
+        page_fault_exceptions =
+            get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE &&
+            !pmp_violation;
+            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
+    }
     switch (access_type) {
     case MMU_INST_FETCH:
         cs->exception_index = page_fault_exceptions ?
@@ -551,7 +570,8 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
     int prot;
     int mmu_idx = cpu_mmu_index(&cpu->env, false);
 
-    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) {
+    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
+                             true)) {
         return -1;
     }
     return phys_addr;
@@ -613,7 +633,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
                   __func__, address, access_type, mmu_idx);
 
-    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
+    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
+                               true);
 
     if (mode == PRV_M && access_type != MMU_INST_FETCH) {
         if (get_field(*env->mstatus, MSTATUS_MPRV)) {
@@ -640,7 +661,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     } else if (probe) {
         return false;
     } else {
-        raise_mmu_exception(env, address, access_type, pmp_violation);
+        raise_mmu_exception(env, address, access_type, pmp_violation, true);
         riscv_raise_exception(env, cs->exception_index, retaddr);
     }
 #else
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 23/28] target/riscv: Allow specifying number of MMU stages
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (21 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 22/28] target/riscv: Allow specifying MMU stage Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 24/28] target/riscv: Implement second stage MMU Alistair Francis
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 9aa6906acd..8b9871f9ea 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -330,7 +330,7 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
 static int get_physical_address(CPURISCVState *env, hwaddr *physical,
                                 int *prot, target_ulong addr,
                                 int access_type, int mmu_idx,
-                                bool first_stage)
+                                bool first_stage, bool two_stage)
 {
     /* NOTE: the env->pc value visible here will not be
      * correct, but the value visible to the exception handler
@@ -571,9 +571,10 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
     int mmu_idx = cpu_mmu_index(&cpu->env, false);
 
     if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
-                             true)) {
+                             true, false)) {
         return -1;
     }
+
     return phys_addr;
 }
 
@@ -634,7 +635,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                   __func__, address, access_type, mmu_idx);
 
     ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
-                               true);
+                               true, false);
 
     if (mode == PRV_M && access_type != MMU_INST_FETCH) {
         if (get_field(*env->mstatus, MSTATUS_MPRV)) {
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 24/28] target/riscv: Implement second stage MMU
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (22 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 23/28] target/riscv: Allow specifying number of MMU stages Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-07 16:15   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 25/28] target/riscv: Call the second stage MMU in virtualisation mode Alistair Francis
                   ` (3 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 96 +++++++++++++++++++++++++++++++++++----
 1 file changed, 86 insertions(+), 10 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 8b9871f9ea..188d5cb39f 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -337,13 +337,40 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
      * (riscv_cpu_do_interrupt) is correct */
 
     int mode = mmu_idx;
+    bool use_background = false;
 
+    /*
+     * 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 (mode == PRV_M && access_type != MMU_INST_FETCH) {
         if (get_field(*env->mstatus, MSTATUS_MPRV)) {
             mode = get_field(*env->mstatus, MSTATUS_MPP);
+
+            if (riscv_has_ext(env, RVH) &&
+                get_field(*env->mstatus, MSTATUS_MPV)) {
+                use_background = true;
+            }
         }
     }
 
+    if (mode == PRV_S && access_type != MMU_INST_FETCH &&
+        riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
+        if (get_field(env->hstatus, HSTATUS_SPRV)) {
+            mode = get_field(*env->mstatus, SSTATUS_SPP);
+            use_background = true;
+        }
+    }
+
+    if (first_stage == false) {
+        /* We are in stage 2 translation, this is similar to stage 1. */
+        /* Stage 2 is always taken as U-mode */
+        mode = PRV_U;
+    }
+
     if (mode == PRV_M || !riscv_feature(env, RISCV_FEATURE_MMU)) {
         *physical = addr;
         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
@@ -353,13 +380,30 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
     *prot = 0;
 
     target_ulong base;
-    int levels, ptidxbits, ptesize, vm, sum;
-    int mxr = get_field(*env->mstatus, MSTATUS_MXR);
+    int levels, ptidxbits, ptesize, vm, sum, mxr, widened;
+
+    if (first_stage == true) {
+        mxr = get_field(*env->mstatus, MSTATUS_MXR);
+    } else {
+        mxr = get_field(env->vsstatus, MSTATUS_MXR);
+    }
 
     if (env->priv_ver >= PRIV_VERSION_1_10_0) {
-        base = get_field(env->satp, SATP_PPN) << PGSHIFT;
+        if (first_stage == true) {
+            if (use_background) {
+                base = get_field(env->vsatp, SATP_PPN) << PGSHIFT;
+                vm = get_field(env->vsatp, SATP_MODE);
+            } else {
+                base = get_field(env->satp, SATP_PPN) << PGSHIFT;
+                vm = get_field(env->satp, SATP_MODE);
+            }
+            widened = 0;
+        } else {
+            base = get_field(env->hgatp, HGATP_PPN) << PGSHIFT;
+            vm = get_field(env->hgatp, HGATP_MODE);
+            widened = 2;
+        }
         sum = get_field(*env->mstatus, MSTATUS_SUM);
-        vm = get_field(env->satp, SATP_MODE);
         switch (vm) {
         case VM_1_10_SV32:
           levels = 2; ptidxbits = 10; ptesize = 4; break;
@@ -377,6 +421,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
           g_assert_not_reached();
         }
     } else {
+        widened = 0;
         base = env->sptbr << PGSHIFT;
         sum = !get_field(*env->mstatus, MSTATUS_PUM);
         vm = get_field(*env->mstatus, MSTATUS_VM);
@@ -397,9 +442,16 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
     }
 
     CPUState *cs = env_cpu(env);
-    int va_bits = PGSHIFT + levels * ptidxbits;
-    target_ulong mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
-    target_ulong masked_msbs = (addr >> (va_bits - 1)) & mask;
+    int va_bits = PGSHIFT + levels * ptidxbits + widened;
+    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;
     }
@@ -411,17 +463,36 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
 restart:
 #endif
     for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
-        target_ulong idx = (addr >> (PGSHIFT + ptshift)) &
+        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 */
-        target_ulong pte_addr = base + idx * ptesize;
+        target_ulong pte_addr;
+
+        if (two_stage && first_stage) {
+            hwaddr vbase;
+
+            /* Do the second stage translation on the base PTE address. */
+            get_physical_address(env, &vbase, prot, base, access_type,
+                                 mmu_idx, false, true);
+
+            pte_addr = vbase + idx * ptesize;
+        } else {
+            pte_addr = base + idx * ptesize;
+        }
 
         if (riscv_feature(env, RISCV_FEATURE_PMP) &&
             !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong),
             1 << MMU_DATA_LOAD, PRV_S)) {
             return TRANSLATE_PMP_FAIL;
         }
+
 #if defined(TARGET_RISCV32)
         target_ulong pte = ldl_phys(cs->as, pte_addr);
 #elif defined(TARGET_RISCV64)
@@ -507,7 +578,12 @@ restart:
             /* for superpage mappings, make a fake leaf PTE for the TLB's
                benefit. */
             target_ulong vpn = addr >> PGSHIFT;
-            *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT;
+            if (i == 0) {
+                *physical = (ppn | (vpn & ((1L << (ptshift + widened)) - 1))) <<
+                             PGSHIFT;
+            } else {
+                *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT;
+            }
 
             /* set permissions on the TLB entry */
             if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) {
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 25/28] target/riscv: Call the second stage MMU in virtualisation mode
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (23 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 24/28] target/riscv: Implement second stage MMU Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-08 17:54   ` Palmer Dabbelt
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 26/28] target/riscv: Add support for the 32-bit MSTATUSH CSR Alistair Francis
                   ` (2 subsequent siblings)
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

The qemu_log_mask(CPU_LOG_MMU,... calls trigger false positive
checkpatch errors which are being ignored.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_helper.c | 94 +++++++++++++++++++++++++++++++++++----
 1 file changed, 86 insertions(+), 8 deletions(-)

diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 188d5cb39f..0761191f11 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -642,15 +642,23 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
 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(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
-                             true, false)) {
+    if (get_physical_address(env, &phys_addr, &prot, addr, 0, mmu_idx,
+                             true, riscv_cpu_virt_enabled(env))) {
         return -1;
     }
 
+    if (riscv_cpu_virt_enabled(env)) {
+        if (get_physical_address(env, &phys_addr, &prot, phys_addr,
+                                 0, mmu_idx, false, true)) {
+            return -1;
+        }
+    }
+
     return phys_addr;
 }
 
@@ -701,17 +709,35 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
 #ifndef CONFIG_USER_ONLY
     RISCVCPU *cpu = RISCV_CPU(cs);
     CPURISCVState *env = &cpu->env;
+    vaddr im_address;
     hwaddr pa = 0;
     int prot;
     bool pmp_violation = false;
+    bool m_mode_two_stage = false;
+    bool hs_mode_two_stage = false;
+    bool first_stage_error = true;
     int ret = TRANSLATE_FAIL;
     int mode = mmu_idx;
 
     qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
                   __func__, address, access_type, mmu_idx);
 
-    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
-                               true, false);
+    /*
+     * Determine if we are in M mode and MPRV is set or in HS mode and SPRV is
+     * set and we want to access a virtulisation address.
+     */
+    if (riscv_has_ext(env, RVH)) {
+        m_mode_two_stage = env->priv == PRV_M &&
+                           access_type != MMU_INST_FETCH &&
+                           get_field(*env->mstatus, MSTATUS_MPRV) &&
+                           get_field(*env->mstatus, MSTATUS_MPV);
+
+        hs_mode_two_stage = env->priv == PRV_S &&
+                            !riscv_cpu_virt_enabled(env) &&
+                            access_type != MMU_INST_FETCH &&
+                            get_field(env->hstatus, HSTATUS_SPRV) &&
+                            get_field(env->hstatus, HSTATUS_SPV);
+    }
 
     if (mode == PRV_M && access_type != MMU_INST_FETCH) {
         if (get_field(*env->mstatus, MSTATUS_MPRV)) {
@@ -719,10 +745,58 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
         }
     }
 
-    qemu_log_mask(CPU_LOG_MMU,
-                  "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
-                  " prot %d\n", __func__, address, ret, pa, prot);
+    if (riscv_cpu_virt_enabled(env) || m_mode_two_stage || hs_mode_two_stage) {
+        /* Two stage lookup */
+        ret = get_physical_address(env, &pa, &prot, address, access_type,
+                                   mmu_idx, true, true);
+
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s 1st-stage address=%" VADDR_PRIx " ret %d physical "
+                      TARGET_FMT_plx " prot %d\n",
+                      __func__, address, ret, pa, prot);
+
+        if (ret == TRANSLATE_FAIL) {
+            goto tlb_lookup_done;
+        }
+
+        /* Second stage lookup */
+        im_address = pa;
 
+        ret = get_physical_address(env, &pa, &prot, im_address, access_type, mmu_idx,
+                                   false, true);
+
+        qemu_log_mask(CPU_LOG_MMU,
+                "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical "
+                TARGET_FMT_plx " prot %d\n",
+                __func__, im_address, ret, pa, prot);
+
+        if (riscv_feature(env, RISCV_FEATURE_PMP) &&
+            (ret == TRANSLATE_SUCCESS) &&
+            !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
+            ret = TRANSLATE_PMP_FAIL;
+        }
+
+        if (ret != TRANSLATE_SUCCESS) {
+            /*
+             * Guest physical address translation failed, this is a HS
+             * level exception
+             */
+            first_stage_error = false;
+            address = im_address | (address & (TARGET_PAGE_SIZE - 1));
+            goto tlb_lookup_done;
+        }
+    } else {
+        /* Single stage lookup */
+        ret = get_physical_address(env, &pa, &prot, address, access_type,
+                                   mmu_idx, true, false);
+
+        qemu_log_mask(CPU_LOG_MMU,
+                      "%s address=%" VADDR_PRIx " ret %d physical "
+                      TARGET_FMT_plx " prot %d\n",
+                      __func__, address, ret, pa, prot);
+    }
+
+tlb_lookup_done:
     if (riscv_feature(env, RISCV_FEATURE_PMP) &&
         (ret == TRANSLATE_SUCCESS) &&
         !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
@@ -731,6 +805,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     if (ret == TRANSLATE_PMP_FAIL) {
         pmp_violation = true;
     }
+
     if (ret == TRANSLATE_SUCCESS) {
         tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK,
                      prot, mmu_idx, TARGET_PAGE_SIZE);
@@ -738,9 +813,12 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     } else if (probe) {
         return false;
     } else {
-        raise_mmu_exception(env, address, access_type, pmp_violation, true);
+        raise_mmu_exception(env, address, access_type, pmp_violation, first_stage_error);
         riscv_raise_exception(env, cs->exception_index, retaddr);
     }
+
+    return true;
+
 #else
     switch (access_type) {
     case MMU_INST_FETCH:
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 26/28] target/riscv: Add support for the 32-bit MSTATUSH CSR
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (24 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 25/28] target/riscv: Call the second stage MMU in virtualisation mode Alistair Francis
@ 2019-08-23 23:38 ` Alistair Francis
  2019-10-08 18:36   ` Palmer Dabbelt
  2019-08-23 23:39 ` [Qemu-devel] [PATCH v1 27/28] target/riscv: Add the MSTATUS_MPV_ISSET helper macro Alistair Francis
  2019-08-23 23:39 ` [Qemu-devel] [PATCH v1 28/28] target/riscv: Allow enabling the Hypervisor extension Alistair Francis
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:38 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c        |  6 ++++++
 target/riscv/cpu.h        |  7 +++++++
 target/riscv/cpu_bits.h   |  3 +++
 target/riscv/cpu_helper.c |  7 +++++++
 target/riscv/csr.c        | 23 +++++++++++++++++++++++
 target/riscv/op_helper.c  |  4 ++++
 6 files changed, 50 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 371d5845af..06ee551ebe 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -229,6 +229,9 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 #ifndef CONFIG_USER_ONLY
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
     qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", *env->mstatus);
+#ifdef TARGET_RISCV32
+    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatush ", *env->mstatush);
+#endif
     if (riscv_has_ext(env, RVH)) {
         qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
         qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ", env->vsstatus);
@@ -468,6 +471,9 @@ static void riscv_cpu_init(Object *obj)
 #ifndef CONFIG_USER_ONLY
     env->mie = &env->mie_novirt;
     env->mstatus = &env->mstatus_novirt;
+# ifdef TARGET_RISCV32
+    env->mstatush = &env->mstatush_novirt;
+# endif
 #endif
 }
 
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 05957f32a8..b63f1f3cdc 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -124,6 +124,10 @@ struct CPURISCVState {
     target_ulong mhartid;
     target_ulong *mstatus;
 
+#ifdef TARGET_RISCV32
+    target_ulong *mstatush;
+#endif
+
     /*
      * CAUTION! Unlike the rest of this struct, mip and mip_novirt is accessed
      * asynchonously by I/O threads. It should be read with atomic_read. It should
@@ -164,6 +168,9 @@ struct CPURISCVState {
      */
     target_ulong mie_novirt;
     target_ulong mstatus_novirt;
+#ifdef TARGET_RISCV32
+    target_ulong mstatush_novirt;
+#endif
 
     /* Hypervisor CSRs */
     target_ulong hstatus;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 353fc9a24a..55e20af6d9 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -135,6 +135,9 @@
 #define CSR_MTVEC           0x305
 #define CSR_MCOUNTEREN      0x306
 
+/* 32-bit only */
+#define CSR_MSTATUSH        0x310
+
 /* Legacy Counter Setup (priv v1.9.1) */
 /* Update to #define CSR_MCOUNTINHIBIT 0x320 for 1.11.0 */
 #define CSR_MUCOUNTEREN     0x320
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 0761191f11..8c80486dd0 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -949,10 +949,17 @@ void riscv_cpu_do_interrupt(CPUState *cs)
             if (riscv_cpu_virt_enabled(env)) {
                 riscv_cpu_swap_hypervisor_regs(env);
             }
+#ifdef TARGET_RISCV32
+            *env->mstatush = set_field(*env->mstatush, MSTATUS_MPV,
+                                       riscv_cpu_virt_enabled(env));
+            *env->mstatush = set_field(*env->mstatush, MSTATUS_MTL,
+                                       riscv_cpu_force_hs_excep_enabled(env));
+#else
             *env->mstatus = set_field(*env->mstatus, MSTATUS_MPV,
                                       riscv_cpu_virt_enabled(env));
             *env->mstatus = set_field(*env->mstatus, MSTATUS_MTL,
                                       riscv_cpu_force_hs_excep_enabled(env));
+#endif
 
             /* Trapping to M mode, virt is disabled */
             riscv_cpu_set_virt_enabled(env, VIRT_OFF);
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 47be4b1d42..b7d6d009dc 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -364,6 +364,25 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
     return 0;
 }
 
+#ifdef TARGET_RISCV32
+static int read_mstatush(CPURISCVState *env, int csrno, target_ulong *val)
+{
+    *val = *env->mstatush;
+    return 0;
+}
+
+static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val)
+{
+    if ((val ^ *env->mstatush) & (MSTATUS_MPV)) {
+        tlb_flush(env_cpu(env));
+    }
+
+    *env->mstatush = val;
+
+    return 0;
+}
+#endif
+
 static int read_misa(CPURISCVState *env, int csrno, target_ulong *val)
 {
     *val = env->misa;
@@ -1095,6 +1114,10 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
     [CSR_MTVEC] =               { any,  read_mtvec,       write_mtvec       },
     [CSR_MCOUNTEREN] =          { any,  read_mcounteren,  write_mcounteren  },
 
+#if defined(TARGET_RISCV32)
+    [CSR_MSTATUSH] =            { any,  read_mstatush,    write_mstatush    },
+#endif
+
     /* Legacy Counter Setup (priv v1.9.1) */
     [CSR_MUCOUNTEREN] =         { any,  read_mucounteren, write_mucounteren },
     [CSR_MSCOUNTEREN] =         { any,  read_mscounteren, write_mscounteren },
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 5bcf5d2ff7..8dec1aee99 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -153,7 +153,11 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
         get_field(mstatus, MSTATUS_MPIE));
     mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
     mstatus = set_field(mstatus, MSTATUS_MPP, 0);
+#ifdef TARGET_RISCV32
+    *env->mstatush = set_field(*env->mstatush, MSTATUS_MPV, 0);
+#else
     mstatus = set_field(mstatus, MSTATUS_MPV, 0);
+#endif
     *env->mstatus = mstatus;
     riscv_cpu_set_mode(env, prev_priv);
 
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 27/28] target/riscv: Add the MSTATUS_MPV_ISSET helper macro
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (25 preceding siblings ...)
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 26/28] target/riscv: Add support for the 32-bit MSTATUSH CSR Alistair Francis
@ 2019-08-23 23:39 ` Alistair Francis
  2019-10-08 18:36   ` Palmer Dabbelt
  2019-08-23 23:39 ` [Qemu-devel] [PATCH v1 28/28] target/riscv: Allow enabling the Hypervisor extension Alistair Francis
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:39 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Add a helper macro MSTATUS_MPV_ISSET() which will determine if the
MSTATUS_MPV bit is set for both 32-bit and 64-bit RISC-V.

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu_bits.h   | 11 +++++++++++
 target/riscv/cpu_helper.c |  4 ++--
 target/riscv/op_helper.c  |  2 +-
 target/riscv/translate.c  |  2 +-
 4 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index 55e20af6d9..7056d9218b 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -365,8 +365,19 @@
 #define MSTATUS_TVM         0x00100000 /* since: priv-1.10 */
 #define MSTATUS_TW          0x20000000 /* since: priv-1.10 */
 #define MSTATUS_TSR         0x40000000 /* since: priv-1.10 */
+#if defined(TARGET_RISCV64)
 #define MSTATUS_MTL         0x4000000000ULL
 #define MSTATUS_MPV         0x8000000000ULL
+#elif defined(TARGET_RISCV32)
+#define MSTATUS_MTL         0x00000040
+#define MSTATUS_MPV         0x00000080
+#endif
+
+#ifdef TARGET_RISCV32
+# define MSTATUS_MPV_ISSET(env)  get_field(*env->mstatush, MSTATUS_MPV)
+#else
+# define MSTATUS_MPV_ISSET(env)  get_field(*env->mstatus, MSTATUS_MPV)
+#endif
 
 #define MSTATUS64_UXL       0x0000000300000000ULL
 #define MSTATUS64_SXL       0x0000000C00000000ULL
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 8c80486dd0..2b88f756bb 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -351,7 +351,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
             mode = get_field(*env->mstatus, MSTATUS_MPP);
 
             if (riscv_has_ext(env, RVH) &&
-                get_field(*env->mstatus, MSTATUS_MPV)) {
+                MSTATUS_MPV_ISSET(env)) {
                 use_background = true;
             }
         }
@@ -730,7 +730,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
         m_mode_two_stage = env->priv == PRV_M &&
                            access_type != MMU_INST_FETCH &&
                            get_field(*env->mstatus, MSTATUS_MPRV) &&
-                           get_field(*env->mstatus, MSTATUS_MPV);
+                           MSTATUS_MPV_ISSET(env);
 
         hs_mode_two_stage = env->priv == PRV_S &&
                             !riscv_cpu_virt_enabled(env) &&
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 8dec1aee99..6149cd9c15 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -146,7 +146,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
 
     target_ulong mstatus = *env->mstatus;
     target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
-    target_ulong prev_virt = get_field(mstatus, MSTATUS_MPV);
+    target_ulong prev_virt = MSTATUS_MPV_ISSET(env);
     mstatus = set_field(mstatus,
         env->priv_ver >= PRIV_VERSION_1_10_0 ?
         MSTATUS_MIE : MSTATUS_UIE << prev_priv,
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index ea19ba9c5d..f0d9860429 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -754,7 +754,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
         ctx->virt_enabled = riscv_cpu_virt_enabled(env);
         if (env->priv_ver == PRV_M &&
             get_field(*env->mstatus, MSTATUS_MPRV) &&
-            get_field(*env->mstatus, MSTATUS_MPV)) {
+            MSTATUS_MPV_ISSET(env)) {
             ctx->virt_enabled = true;
         } else if (env->priv == PRV_S &&
                    !riscv_cpu_virt_enabled(env) &&
-- 
2.22.0



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

* [Qemu-devel] [PATCH v1 28/28] target/riscv: Allow enabling the Hypervisor extension
  2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
                   ` (26 preceding siblings ...)
  2019-08-23 23:39 ` [Qemu-devel] [PATCH v1 27/28] target/riscv: Add the MSTATUS_MPV_ISSET helper macro Alistair Francis
@ 2019-08-23 23:39 ` Alistair Francis
  2019-10-08 18:53   ` Palmer Dabbelt
  27 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-08-23 23:39 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair23, Anup.Patel, palmer, alistair.francis, Atish.Patra

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 target/riscv/cpu.c | 5 +++++
 target/riscv/cpu.h | 1 +
 2 files changed, 6 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 06ee551ebe..39e1c130df 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -447,6 +447,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
         if (cpu->cfg.ext_u) {
             target_misa |= RVU;
         }
+        if (cpu->cfg.ext_h) {
+            target_misa |= RVH;
+        }
 
         set_misa(env, RVXLEN | target_misa);
     }
@@ -493,6 +496,8 @@ static Property riscv_cpu_properties[] = {
     DEFINE_PROP_BOOL("c", RISCVCPU, cfg.ext_c, true),
     DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true),
     DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
+    /* This is experimental so mark with 'x-' */
+    DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false),
     DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true),
     DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
     DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index b63f1f3cdc..500496a3be 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -268,6 +268,7 @@ typedef struct RISCVCPU {
         bool ext_c;
         bool ext_s;
         bool ext_u;
+        bool ext_h;
         bool ext_counters;
         bool ext_ifencei;
         bool ext_icsr;
-- 
2.22.0



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

* Re: [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension Alistair Francis
@ 2019-08-27 15:26   ` Chih-Min Chao
  2019-09-10 13:43   ` Palmer Dabbelt
  1 sibling, 0 replies; 75+ messages in thread
From: Chih-Min Chao @ 2019-08-27 15:26 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Palmer Dabbelt, open list:RISC-V, Anup.Patel,
	qemu-devel@nongnu.org Developers, Atish.Patra, Alistair Francis

On Sat, Aug 24, 2019 at 7:42 AM Alistair Francis <alistair.francis@wdc.com>
wrote:

> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 124ed33ee4..7f54fb8c87 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -67,6 +67,7 @@
>  #define RVC RV('C')
>  #define RVS RV('S')
>  #define RVU RV('U')
> +#define RVH RV('H')
>
>  /* S extension denotes that Supervisor mode exists, however it is possible
>     to have a core that support S mode but does not have an MMU and there
> --
> 2.22.0
>
>
> Reviewed-by: Chih-Min Chao <chihmin.chao@sifive.com>

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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 02/28] target/riscv: Add the virtulisation mode
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 02/28] target/riscv: Add the virtulisation mode Alistair Francis
@ 2019-08-27 15:44   ` Chih-Min Chao
  2019-08-28  0:08     ` Alistair Francis
  2019-09-10 13:44   ` [Qemu-devel] " Palmer Dabbelt
  1 sibling, 1 reply; 75+ messages in thread
From: Chih-Min Chao @ 2019-08-27 15:44 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Palmer Dabbelt, open list:RISC-V, Anup.Patel,
	qemu-devel@nongnu.org Developers, Atish.Patra, Alistair Francis

On Sat, Aug 24, 2019 at 7:41 AM Alistair Francis <alistair.francis@wdc.com>
wrote:

> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h        |  4 ++++
>  target/riscv/cpu_bits.h   |  6 ++++++
>  target/riscv/cpu_helper.c | 23 +++++++++++++++++++++++
>  3 files changed, 33 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 7f54fb8c87..0ef1ecb0e0 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -117,6 +117,8 @@ struct CPURISCVState {
>
>  #ifndef CONFIG_USER_ONLY
>      target_ulong priv;
> +    /* This contains QEMU specific information about the virt state. */
> +    target_ulong virt;
>      target_ulong resetvec;
>
>      target_ulong mhartid;
> @@ -257,6 +259,8 @@ int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t
> *buf, int reg);
>  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
>  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> +bool riscv_cpu_virt_enabled(CPURISCVState *env);
> +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
>  int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
>  hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
>  void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index e99834856c..1fbde516be 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -422,6 +422,12 @@
>  #define PRV_H 2 /* Reserved */
>  #define PRV_M 3
>
> +/* Virtulisation modes */
> +#define VIRT_OFF            0
> +#define VIRT_ON             1
> +#define VIRT_MODE_SHIFT     0
> +#define VIRT_MODE_MASK      (1 << VIRT_MODE_SHIFT)
> +
>
 /* RV32 satp CSR field masks */
>  #define SATP32_MODE         0x80000000
>  #define SATP32_ASID         0x7fc00000
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 225e407cff..7b0bb14c01 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -81,6 +81,29 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
>      return false;
>  }
>
> +bool riscv_cpu_virt_enabled(CPURISCVState *env)
> +{
> +    bool tmp;
> +
> +    if (!riscv_has_ext(env, RVH)) {
> +        return false;
> +    }
> +
> +    tmp = (env->virt & VIRT_MODE_MASK) >> VIRT_MODE_SHIFT;
> +
> +    return tmp == VIRT_ON;
> +}
> +
> +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
> +{
> +    if (!riscv_has_ext(env, RVH)) {
> +        return;
> +    }
> +
> +    env->virt &= ~VIRT_MODE_MASK;
> +    env->virt |= enable << VIRT_MODE_SHIFT;
> +}
> +
>  int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
>  {
>      CPURISCVState *env = &cpu->env;
> --
> 2.22.0
>
> Why not to use get_field and set_field though it is not a real register
but an internal state

#define VIRT_ONOFF            0x01
#define VIRT_OFF             0
#define VIRT_ON             1

access
       get_field(env->virt, VIRT_ONOFF);
       set_field(env->virt, VIRT_ONOFF, enable);


chihmin

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

* Re: [Qemu-devel] [PATCH v1 03/28] target/riscv: Add the force HS exception mode
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 03/28] target/riscv: Add the force HS exception mode Alistair Francis
@ 2019-08-27 15:46   ` Chih-Min Chao
  2019-09-10 14:48   ` Palmer Dabbelt
  1 sibling, 0 replies; 75+ messages in thread
From: Chih-Min Chao @ 2019-08-27 15:46 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Palmer Dabbelt, open list:RISC-V, Anup.Patel,
	qemu-devel@nongnu.org Developers, Atish.Patra, Alistair Francis

On Sat, Aug 24, 2019 at 7:50 AM Alistair Francis <alistair.francis@wdc.com>
wrote:

> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h        |  2 ++
>  target/riscv/cpu_bits.h   |  6 ++++++
>  target/riscv/cpu_helper.c | 23 +++++++++++++++++++++++
>  3 files changed, 31 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 0ef1ecb0e0..3a95c41428 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -261,6 +261,8 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int
> interrupt_request);
>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
>  bool riscv_cpu_virt_enabled(CPURISCVState *env);
>  void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
> +bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env);
> +void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable);
>  int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
>  hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
>  void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 1fbde516be..204d9d9a79 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -428,6 +428,12 @@
>  #define VIRT_MODE_SHIFT     0
>  #define VIRT_MODE_MASK      (1 << VIRT_MODE_SHIFT)
>
> +/* HS-level exception modes */
> +#define CLEAR_HS_EXCEP        0
> +#define FORCE_HS_EXCEP        1
> +#define FORCE_HS_EXCEP_SHIFT  1
> +#define FORCE_HS_EXCEP_MASK   (1 << FORCE_HS_EXCEP_SHIFT)
> +
>  /* RV32 satp CSR field masks */
>  #define SATP32_MODE         0x80000000
>  #define SATP32_ASID         0x7fc00000
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 7b0bb14c01..5bcfc2e090 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -104,6 +104,29 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env,
> bool enable)
>      env->virt |= enable << VIRT_MODE_SHIFT;
>  }
>
> +bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env)
> +{
> +    bool tmp;
> +
> +    if (!riscv_has_ext(env, RVH)) {
> +        return false;
> +    }
> +
> +    tmp = (env->virt & FORCE_HS_EXCEP_MASK) >> FORCE_HS_EXCEP_SHIFT;
> +
> +    return tmp == FORCE_HS_EXCEP;
> +}
> +
> +void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable)
> +{
> +    if (!riscv_has_ext(env, RVH)) {
> +        return;
> +    }
> +
> +    env->virt &= ~FORCE_HS_EXCEP_MASK;
> +    env->virt |= enable << FORCE_HS_EXCEP_SHIFT;
> +}
> +
>  int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
>  {
>      CPURISCVState *env = &cpu->env;
> --
> 2.22.0
>
>
> I have the same option as [PATCH 2/28].  Why not to use get_field and
set_field ?

chihmin

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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 05/28] target/riscv: Add the Hypervisor CSRs to CPUState
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 05/28] target/riscv: Add the Hypervisor CSRs to CPUState Alistair Francis
@ 2019-08-27 15:50   ` Chih-Min Chao
  2019-09-10 14:48   ` [Qemu-devel] " Palmer Dabbelt
  1 sibling, 0 replies; 75+ messages in thread
From: Chih-Min Chao @ 2019-08-27 15:50 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Palmer Dabbelt, open list:RISC-V, Anup.Patel,
	qemu-devel@nongnu.org Developers, Atish.Patra, Alistair Francis

On Sat, Aug 24, 2019 at 7:45 AM Alistair Francis <alistair.francis@wdc.com>
wrote:

> As the MIP CSR is 32-bits to allow atomic_read on 32-bit hosts the vsip
> is 32-bit as well.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 3a95c41428..4c342e7a79 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -154,6 +154,23 @@ struct CPURISCVState {
>      target_ulong mcause;
>      target_ulong mtval;  /* since: priv-1.10.0 */
>
> +    /* Hypervisor CSRs */
> +    target_ulong hstatus;
> +    target_ulong hedeleg;
> +    target_ulong hideleg;
> +    target_ulong hgatp;
> +
> +    /* Virtual CSRs */
> +    target_ulong vsstatus;
> +    uint32_t vsip;
> +    target_ulong vsie;
> +    target_ulong vstvec;
> +    target_ulong vsscratch;
> +    target_ulong vsepc;
> +    target_ulong vscause;
> +    target_ulong vstval;
> +    target_ulong vsatp;
> +
>      target_ulong scounteren;
>      target_ulong mcounteren;
>
> --
> 2.22.0
>
>
Reviewed-by: Chih-Min Chao <chihmin.chao@sifive.com>

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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 02/28] target/riscv: Add the virtulisation mode
  2019-08-27 15:44   ` [Qemu-devel] [Qemu-riscv] " Chih-Min Chao
@ 2019-08-28  0:08     ` Alistair Francis
  0 siblings, 0 replies; 75+ messages in thread
From: Alistair Francis @ 2019-08-28  0:08 UTC (permalink / raw)
  To: Chih-Min Chao
  Cc: Palmer Dabbelt, open list:RISC-V, Anup.Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis

On Tue, Aug 27, 2019 at 8:44 AM Chih-Min Chao <chihmin.chao@sifive.com> wrote:
>
>
>
> On Sat, Aug 24, 2019 at 7:41 AM Alistair Francis <alistair.francis@wdc.com> wrote:
>>
>> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
>> ---
>>  target/riscv/cpu.h        |  4 ++++
>>  target/riscv/cpu_bits.h   |  6 ++++++
>>  target/riscv/cpu_helper.c | 23 +++++++++++++++++++++++
>>  3 files changed, 33 insertions(+)
>>
>> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>> index 7f54fb8c87..0ef1ecb0e0 100644
>> --- a/target/riscv/cpu.h
>> +++ b/target/riscv/cpu.h
>> @@ -117,6 +117,8 @@ struct CPURISCVState {
>>
>>  #ifndef CONFIG_USER_ONLY
>>      target_ulong priv;
>> +    /* This contains QEMU specific information about the virt state. */
>> +    target_ulong virt;
>>      target_ulong resetvec;
>>
>>      target_ulong mhartid;
>> @@ -257,6 +259,8 @@ int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
>>  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
>>  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
>>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
>> +bool riscv_cpu_virt_enabled(CPURISCVState *env);
>> +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
>>  int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
>>  hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
>>  void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
>> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
>> index e99834856c..1fbde516be 100644
>> --- a/target/riscv/cpu_bits.h
>> +++ b/target/riscv/cpu_bits.h
>> @@ -422,6 +422,12 @@
>>  #define PRV_H 2 /* Reserved */
>>  #define PRV_M 3
>>
>> +/* Virtulisation modes */
>> +#define VIRT_OFF            0
>> +#define VIRT_ON             1
>> +#define VIRT_MODE_SHIFT     0
>> +#define VIRT_MODE_MASK      (1 << VIRT_MODE_SHIFT)
>> +
>>
>>  /* RV32 satp CSR field masks */
>>  #define SATP32_MODE         0x80000000
>>  #define SATP32_ASID         0x7fc00000
>> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
>> index 225e407cff..7b0bb14c01 100644
>> --- a/target/riscv/cpu_helper.c
>> +++ b/target/riscv/cpu_helper.c
>> @@ -81,6 +81,29 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
>>      return false;
>>  }
>>
>> +bool riscv_cpu_virt_enabled(CPURISCVState *env)
>> +{
>> +    bool tmp;
>> +
>> +    if (!riscv_has_ext(env, RVH)) {
>> +        return false;
>> +    }
>> +
>> +    tmp = (env->virt & VIRT_MODE_MASK) >> VIRT_MODE_SHIFT;
>> +
>> +    return tmp == VIRT_ON;
>> +}
>> +
>> +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
>> +{
>> +    if (!riscv_has_ext(env, RVH)) {
>> +        return;
>> +    }
>> +
>> +    env->virt &= ~VIRT_MODE_MASK;
>> +    env->virt |= enable << VIRT_MODE_SHIFT;
>> +}
>> +
>>  int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
>>  {
>>      CPURISCVState *env = &cpu->env;
>> --
>> 2.22.0
>>
> Why not to use get_field and set_field though it is not a real register but an internal state
>
> #define VIRT_ONOFF            0x01
> #define VIRT_OFF             0
> #define VIRT_ON             1
>
> access
>        get_field(env->virt, VIRT_ONOFF);
>        set_field(env->virt, VIRT_ONOFF, enable);

Good idea, I have updated this.

Alistair

>
>
> chihmin


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

* Re: [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension Alistair Francis
  2019-08-27 15:26   ` Chih-Min Chao
@ 2019-09-10 13:43   ` Palmer Dabbelt
  1 sibling, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 13:43 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:37:52 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 124ed33ee4..7f54fb8c87 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -67,6 +67,7 @@
>  #define RVC RV('C')
>  #define RVS RV('S')
>  #define RVU RV('U')
> +#define RVH RV('H')
>
>  /* S extension denotes that Supervisor mode exists, however it is possible
>     to have a core that support S mode but does not have an MMU and there

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 02/28] target/riscv: Add the virtulisation mode
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 02/28] target/riscv: Add the virtulisation mode Alistair Francis
  2019-08-27 15:44   ` [Qemu-devel] [Qemu-riscv] " Chih-Min Chao
@ 2019-09-10 13:44   ` Palmer Dabbelt
  2019-09-16 15:57     ` Alistair Francis
  1 sibling, 1 reply; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 13:44 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:37:54 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h        |  4 ++++
>  target/riscv/cpu_bits.h   |  6 ++++++
>  target/riscv/cpu_helper.c | 23 +++++++++++++++++++++++
>  3 files changed, 33 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 7f54fb8c87..0ef1ecb0e0 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -117,6 +117,8 @@ struct CPURISCVState {
>
>  #ifndef CONFIG_USER_ONLY
>      target_ulong priv;
> +    /* This contains QEMU specific information about the virt state. */
> +    target_ulong virt;
>      target_ulong resetvec;
>
>      target_ulong mhartid;
> @@ -257,6 +259,8 @@ int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
>  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
>  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> +bool riscv_cpu_virt_enabled(CPURISCVState *env);
> +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
>  int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
>  hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
>  void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index e99834856c..1fbde516be 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -422,6 +422,12 @@
>  #define PRV_H 2 /* Reserved */
>  #define PRV_M 3
>
> +/* Virtulisation modes */
> +#define VIRT_OFF            0
> +#define VIRT_ON             1
> +#define VIRT_MODE_SHIFT     0
> +#define VIRT_MODE_MASK      (1 << VIRT_MODE_SHIFT)
> +
>  /* RV32 satp CSR field masks */
>  #define SATP32_MODE         0x80000000
>  #define SATP32_ASID         0x7fc00000
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 225e407cff..7b0bb14c01 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -81,6 +81,29 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
>      return false;
>  }
>
> +bool riscv_cpu_virt_enabled(CPURISCVState *env)
> +{
> +    bool tmp;
> +
> +    if (!riscv_has_ext(env, RVH)) {
> +        return false;
> +    }
> +
> +    tmp = (env->virt & VIRT_MODE_MASK) >> VIRT_MODE_SHIFT;
> +
> +    return tmp == VIRT_ON;
> +}

extract64() is a bit cleaner.

> +
> +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
> +{
> +    if (!riscv_has_ext(env, RVH)) {
> +        return;
> +    }
> +
> +    env->virt &= ~VIRT_MODE_MASK;
> +    env->virt |= enable << VIRT_MODE_SHIFT;
> +}
> +
>  int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
>  {
>      CPURISCVState *env = &cpu->env;

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 03/28] target/riscv: Add the force HS exception mode
  2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 03/28] target/riscv: Add the force HS exception mode Alistair Francis
  2019-08-27 15:46   ` Chih-Min Chao
@ 2019-09-10 14:48   ` Palmer Dabbelt
  1 sibling, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 14:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:37:57 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

There's really no description of what this does, either in the commit message
or as a comment.

> ---
>  target/riscv/cpu.h        |  2 ++
>  target/riscv/cpu_bits.h   |  6 ++++++
>  target/riscv/cpu_helper.c | 23 +++++++++++++++++++++++
>  3 files changed, 31 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 0ef1ecb0e0..3a95c41428 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -261,6 +261,8 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
>  bool riscv_cpu_virt_enabled(CPURISCVState *env);
>  void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
> +bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env);
> +void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable);
>  int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
>  hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
>  void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 1fbde516be..204d9d9a79 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -428,6 +428,12 @@
>  #define VIRT_MODE_SHIFT     0
>  #define VIRT_MODE_MASK      (1 << VIRT_MODE_SHIFT)
>
> +/* HS-level exception modes */
> +#define CLEAR_HS_EXCEP        0
> +#define FORCE_HS_EXCEP        1
> +#define FORCE_HS_EXCEP_SHIFT  1
> +#define FORCE_HS_EXCEP_MASK   (1 << FORCE_HS_EXCEP_SHIFT)
> +
>  /* RV32 satp CSR field masks */
>  #define SATP32_MODE         0x80000000
>  #define SATP32_ASID         0x7fc00000
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 7b0bb14c01..5bcfc2e090 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -104,6 +104,29 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
>      env->virt |= enable << VIRT_MODE_SHIFT;
>  }
>
> +bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env)
> +{
> +    bool tmp;
> +
> +    if (!riscv_has_ext(env, RVH)) {
> +        return false;
> +    }
> +
> +    tmp = (env->virt & FORCE_HS_EXCEP_MASK) >> FORCE_HS_EXCEP_SHIFT;
> +
> +    return tmp == FORCE_HS_EXCEP;
> +}
> +
> +void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable)
> +{
> +    if (!riscv_has_ext(env, RVH)) {
> +        return;
> +    }
> +
> +    env->virt &= ~FORCE_HS_EXCEP_MASK;
> +    env->virt |= enable << FORCE_HS_EXCEP_SHIFT;
> +}
> +
>  int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
>  {
>      CPURISCVState *env = &cpu->env;


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

* Re: [Qemu-devel] [PATCH v1 04/28] target/riscv: Fix CSR perm checking for HS mode
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 04/28] target/riscv: Fix CSR perm checking for HS mode Alistair Francis
@ 2019-09-10 14:48   ` Palmer Dabbelt
  2019-10-16 20:56     ` Alistair Francis
  0 siblings, 1 reply; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 14:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:00 PDT (-0700), Alistair Francis wrote:
> Update the CSR permission checking to work correctly when we are in
> HS-mode.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/csr.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index f767ad24be..471f23a1d0 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -799,9 +799,15 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
>
>      /* check privileges and return -1 if check fails */
>  #if !defined(CONFIG_USER_ONLY)
> -    int csr_priv = get_field(csrno, 0x300);
> +    int csr_priv = env->priv;

This isn't really "csr_priv" (ie, the priv needed to access the CSR) any more, 
it's really the effective priv of the machine.  Leaving the variable with the 
same name makes this hard to read, but I think it is correct.

>      int read_only = get_field(csrno, 0xC00) == 3;
> -    if ((write_mask && read_only) || (env->priv < csr_priv)) {
> +
> +    if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
> +        /* Plus 1 as we are in HS mode */

The comment is useless, it doesn't say why we increment it.  Also, I don't 
think this is correct: doesn't it allow U mode to access S CSRs when H is 
present and V is disabled?

Something like

    riscv_effective_priv(CPURISCVState *env)
    {
        if (riscv_has_ext(env, RVH) && env->priv == PRIV_S && !riscv_cpu_virt_enabled(env)) {
            return PRIV_HS;
        }
    
        return env->priv;
    }

would probably be used in a handful of places, and would be a drop in for
env->priv here.

> +        csr_priv++;
> +    }
> +
> +    if ((write_mask && read_only) || (csr_priv < get_field(csrno, 0x300))) {
>          return -1;
>      }
>  #endif


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

* Re: [Qemu-devel] [PATCH v1 05/28] target/riscv: Add the Hypervisor CSRs to CPUState
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 05/28] target/riscv: Add the Hypervisor CSRs to CPUState Alistair Francis
  2019-08-27 15:50   ` [Qemu-devel] [Qemu-riscv] " Chih-Min Chao
@ 2019-09-10 14:48   ` Palmer Dabbelt
  1 sibling, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 14:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:02 PDT (-0700), Alistair Francis wrote:
> As the MIP CSR is 32-bits to allow atomic_read on 32-bit hosts the vsip
> is 32-bit as well.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 3a95c41428..4c342e7a79 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -154,6 +154,23 @@ struct CPURISCVState {
>      target_ulong mcause;
>      target_ulong mtval;  /* since: priv-1.10.0 */
>
> +    /* Hypervisor CSRs */
> +    target_ulong hstatus;
> +    target_ulong hedeleg;
> +    target_ulong hideleg;
> +    target_ulong hgatp;
> +
> +    /* Virtual CSRs */
> +    target_ulong vsstatus;
> +    uint32_t vsip;
> +    target_ulong vsie;
> +    target_ulong vstvec;
> +    target_ulong vsscratch;
> +    target_ulong vsepc;
> +    target_ulong vscause;
> +    target_ulong vstval;
> +    target_ulong vsatp;
> +
>      target_ulong scounteren;
>      target_ulong mcounteren;

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 06/28] target/riscv: Print priv and virt in disas log
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 06/28] target/riscv: Print priv and virt in disas log Alistair Francis
@ 2019-09-10 14:48   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 14:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:05 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/translate.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> index adeddb85f6..8ac72c6470 100644
> --- a/target/riscv/translate.c
> +++ b/target/riscv/translate.c
> @@ -810,7 +810,15 @@ static void riscv_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
>
>  static void riscv_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
>  {
> +#ifndef CONFIG_USER_ONLY
> +    RISCVCPU *rvcpu = RISCV_CPU(cpu);
> +    CPURISCVState *env = &rvcpu->env;
> +#endif
> +
>      qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
> +#ifndef CONFIG_USER_ONLY
> +    qemu_log("Priv: "TARGET_FMT_ld"; Virt: "TARGET_FMT_ld"\n", env->priv, env->virt);
> +#endif
>      log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
>  }

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 07/28] target/riscv: Dump Hypervisor registers if enabled
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 07/28] target/riscv: Dump Hypervisor registers if enabled Alistair Francis
@ 2019-09-10 14:48   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 14:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:07 PDT (-0700), Alistair Francis wrote:
> Dump the Hypervisor registers and the current Hypervisor state.
>
> While we are editing this code let's also dump stvec and scause.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> Signed-off-by: Atish Patra <atish.patra@wdc.com>
> ---
>  target/riscv/cpu.c | 34 ++++++++++++++++++++++++++++++++++
>  1 file changed, 34 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index f13e298a36..be8f643fc2 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -220,18 +220,52 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>      CPURISCVState *env = &cpu->env;
>      int i;
>
> +#if !defined(CONFIG_USER_ONLY)
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s %d\n", "V      =  ", riscv_cpu_virt_enabled(env));
> +    }
> +#endif
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
>  #ifndef CONFIG_USER_ONLY
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ", env->vsstatus);
> +    }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ",
>                   (target_ulong)atomic_read(&env->mip));
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsip    ",
> +                     (target_ulong)atomic_read(&env->vsip));
> +    }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsie    ", env->vsie);
> +    }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> +    }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hedeleg ", env->hedeleg);
> +    }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mtvec   ", env->mtvec);
> +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "stvec   ", env->stvec);
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vstvec  ", env->vstvec);
> +    }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mepc    ", env->mepc);
> +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "sepc    ", env->sepc);
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsepc   ", env->vsepc);
> +    }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mcause  ", env->mcause);
> +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "scause  ", env->scause);
> +    if (riscv_has_ext(env, RVH)) {
> +        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vscause ", env->vscause);
> +    }
>  #endif
>
>      for (i = 0; i < 32; i++) {

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 08/28] target/riscv: Add Hypervisor CSR access functions
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 08/28] target/riscv: Add Hypervisor CSR access functions Alistair Francis
@ 2019-09-10 14:48   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 14:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:10 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/csr.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 68 insertions(+)
>
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 471f23a1d0..388775d45a 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -98,6 +98,20 @@ static int smode(CPURISCVState *env, int csrno)
>      return -!riscv_has_ext(env, RVS);
>  }
>
> +static int hmode(CPURISCVState *env, int csrno)
> +{
> +    if (riscv_has_ext(env, RVS) &&
> +        riscv_has_ext(env, RVH)) {
> +        /* Hypervisor extension is supported */
> +        if ((env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) ||
> +            env->priv == PRV_M) {
> +            return 0;
> +        }
> +    }
> +
> +    return -1;
> +}
> +
>  static int pmp(CPURISCVState *env, int csrno)
>  {
>      return -!riscv_feature(env, RISCV_FEATURE_PMP);
> @@ -754,6 +768,55 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +/* Hypervisor Extensions */
> +static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->hstatus;
> +    return 0;
> +}
> +
> +static int write_hstatus(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->hstatus = val;
> +    return 0;
> +}
> +
> +static int read_hedeleg(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->hedeleg;
> +    return 0;
> +}
> +
> +static int write_hedeleg(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->hedeleg = val;
> +    return 0;
> +}
> +
> +static int read_hideleg(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->hideleg;
> +    return 0;
> +}
> +
> +static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->hideleg = val;
> +    return 0;
> +}
> +
> +static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->hgatp;
> +    return 0;
> +}
> +
> +static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->hgatp = val;
> +    return 0;
> +}
> +
>  /* Physical Memory Protection */
>  static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> @@ -950,6 +1013,11 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      /* Supervisor Protection and Translation */
>      [CSR_SATP] =                { smode, read_satp,        write_satp        },
>
> +    [CSR_HSTATUS] =             { hmode,   read_hstatus,     write_hstatus    },
> +    [CSR_HEDELEG] =             { hmode,   read_hedeleg,     write_hedeleg    },
> +    [CSR_HIDELEG] =             { hmode,   read_hideleg,     write_hideleg    },
> +    [CSR_HGATP] =               { hmode,   read_hgatp,       write_hgatp      },
> +
>      /* Physical Memory Protection */
>      [CSR_PMPCFG0  ... CSR_PMPADDR9] =  { pmp,   read_pmpcfg,  write_pmpcfg   },
>      [CSR_PMPADDR0 ... CSR_PMPADDR15] = { pmp,   read_pmpaddr, write_pmpaddr  },

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 09/28] target/riscv: Add Hypervisor virtual CSRs accesses
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 09/28] target/riscv: Add Hypervisor virtual CSRs accesses Alistair Francis
@ 2019-09-10 14:48   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-10 14:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:13 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_bits.h |  11 ++++
>  target/riscv/csr.c      | 119 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 130 insertions(+)
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 204d9d9a79..78067901a2 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -191,6 +191,17 @@
>  #define HGATP_PPN            SATP64_PPN
>  #endif
>
> +/* Virtual CSRs */
> +#define CSR_VSSTATUS        0x200
> +#define CSR_VSIE            0x204
> +#define CSR_VSTVEC          0x205
> +#define CSR_VSSCRATCH       0x240
> +#define CSR_VSEPC           0x241
> +#define CSR_VSCAUSE         0x242
> +#define CSR_VSTVAL          0x243
> +#define CSR_VSIP            0x244
> +#define CSR_VSATP           0x280
> +
>  /* Physical Memory Protection */
>  #define CSR_PMPCFG0         0x3a0
>  #define CSR_PMPCFG1         0x3a1
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 388775d45a..e2e908fbc0 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -817,6 +817,115 @@ static int write_hgatp(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +/* Virtual CSR Registers */
> +static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->vsstatus;
> +    return 0;
> +}
> +
> +static int write_vsstatus(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->vsstatus = val;
> +    return 0;
> +}
> +
> +static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->vsie;
> +    return 0;
> +}
> +
> +static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->vsie = val;
> +    return 0;
> +}
> +
> +static int read_vstvec(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->vstvec;
> +    return 0;
> +}
> +
> +static int write_vstvec(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->vstvec = val;
> +    return 0;
> +}
> +
> +static int read_vsscratch(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->vsscratch;
> +    return 0;
> +}
> +
> +static int write_vsscratch(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->vsscratch = val;
> +    return 0;
> +}
> +
> +static int read_vsepc(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->vsepc;
> +    return 0;
> +}
> +
> +static int write_vsepc(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->vsepc = val;
> +    return 0;
> +}
> +
> +static int read_vscause(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->vscause;
> +    return 0;
> +}
> +
> +static int write_vscause(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->vscause = val;
> +    return 0;
> +}
> +
> +static int read_vstval(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->vstval;
> +    return 0;
> +}
> +
> +static int write_vstval(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->vstval = val;
> +    return 0;
> +}
> +
> +static int read_vsip(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = (target_ulong)atomic_read(&env->vsip);
> +    return 0;
> +}
> +
> +static int write_vsip(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    atomic_set(&env->vsip, val);
> +    return 0;
> +}
> +
> +static int read_vsatp(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->vsatp;
> +    return 0;
> +}
> +
> +static int write_vsatp(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->vsatp = val;
> +    return 0;
> +}
> +
>  /* Physical Memory Protection */
>  static int read_pmpcfg(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> @@ -1018,6 +1127,16 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_HIDELEG] =             { hmode,   read_hideleg,     write_hideleg    },
>      [CSR_HGATP] =               { hmode,   read_hgatp,       write_hgatp      },
>
> +    [CSR_VSSTATUS] =            { hmode,   read_vsstatus,    write_vsstatus   },
> +    [CSR_VSIE] =                { hmode,   read_vsie,        write_vsie       },
> +    [CSR_VSTVEC] =              { hmode,   read_vstvec,      write_vstvec     },
> +    [CSR_VSSCRATCH] =           { hmode,   read_vsscratch,   write_vsscratch  },
> +    [CSR_VSEPC] =               { hmode,   read_vsepc,       write_vsepc      },
> +    [CSR_VSCAUSE] =             { hmode,   read_vscause,     write_vscause    },
> +    [CSR_VSTVAL] =              { hmode,   read_vstval,      write_vstval     },
> +    [CSR_VSIP] =                { hmode,   read_vsip,        write_vsip       },
> +    [CSR_VSATP] =               { hmode,   read_vsatp,       write_vsatp      },
> +
>      /* Physical Memory Protection */
>      [CSR_PMPCFG0  ... CSR_PMPADDR9] =  { pmp,   read_pmpcfg,  write_pmpcfg   },
>      [CSR_PMPADDR0 ... CSR_PMPADDR15] = { pmp,   read_pmpaddr, write_pmpaddr  },

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers Alistair Francis
@ 2019-09-11  8:24   ` Palmer Dabbelt
  2019-09-11 14:54     ` [Qemu-devel] [Qemu-riscv] " Jonathan Behrens
  0 siblings, 1 reply; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-11  8:24 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:15 PDT (-0700), Alistair Francis wrote:
> To handle the new Hypervisor CSR register swapping let's use pointers.
>
> We only need to convert the MIE and MSTATUS CSRs. With the exception of
> MIP all of the other CSRs that swap with virtulsation changes are S-Mode
> only, so we can just do a lazy switch. This because more challenging for
> the M-Mode registers so it ends up being easier to use pointers.
>
> As the MIP CSR is always accessed atomicly the pointer swap doesn't work
> so we leave that as is.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.c        | 16 ++++++++++++----
>  target/riscv/cpu.h        | 12 ++++++++++--
>  target/riscv/cpu_helper.c | 32 ++++++++++++++++----------------
>  target/riscv/csr.c        | 28 ++++++++++++++--------------
>  target/riscv/op_helper.c  | 14 +++++++-------
>  5 files changed, 59 insertions(+), 43 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index be8f643fc2..371d5845af 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -228,7 +228,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
>  #ifndef CONFIG_USER_ONLY
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
> -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
> +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", *env->mstatus);
>      if (riscv_has_ext(env, RVH)) {
>          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
>          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ", env->vsstatus);
> @@ -239,7 +239,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsip    ",
>                       (target_ulong)atomic_read(&env->vsip));
>      }
> -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", *env->mie);
>      if (riscv_has_ext(env, RVH)) {
>          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsie    ", env->vsie);
>      }
> @@ -309,7 +309,7 @@ static bool riscv_cpu_has_work(CPUState *cs)
>       * Definition of the WFI instruction requires it to ignore the privilege
>       * mode and delegation registers, but respect individual enables
>       */
> -    return (atomic_read(&env->mip) & env->mie) != 0;
> +    return (atomic_read(&env->mip) & *env->mie) != 0;
>  #else
>      return true;
>  #endif
> @@ -330,7 +330,7 @@ static void riscv_cpu_reset(CPUState *cs)
>      mcc->parent_reset(cs);
>  #ifndef CONFIG_USER_ONLY
>      env->priv = PRV_M;
> -    env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
> +    *env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
>      env->mcause = 0;
>      env->pc = env->resetvec;
>  #endif
> @@ -459,8 +459,16 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
>  static void riscv_cpu_init(Object *obj)
>  {
>      RISCVCPU *cpu = RISCV_CPU(obj);
> +#ifndef CONFIG_USER_ONLY
> +    CPURISCVState *env = &cpu->env;
> +#endif
>
>      cpu_set_cpustate_pointers(cpu);
> +
> +#ifndef CONFIG_USER_ONLY
> +    env->mie = &env->mie_novirt;
> +    env->mstatus = &env->mstatus_novirt;
> +#endif
>  }
>
>  static const VMStateDescription vmstate_riscv_cpu = {
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 4c342e7a79..680592cb60 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -122,7 +122,7 @@ struct CPURISCVState {
>      target_ulong resetvec;
>
>      target_ulong mhartid;
> -    target_ulong mstatus;
> +    target_ulong *mstatus;
>
>      /*
>       * CAUTION! Unlike the rest of this struct, mip is accessed asynchonously
> @@ -136,7 +136,7 @@ struct CPURISCVState {
>      uint32_t mip;
>      uint32_t miclaim;
>
> -    target_ulong mie;
> +    target_ulong *mie;
>      target_ulong mideleg;
>
>      target_ulong sptbr;  /* until: priv-1.9.1 */
> @@ -154,6 +154,14 @@ struct CPURISCVState {
>      target_ulong mcause;
>      target_ulong mtval;  /* since: priv-1.10.0 */
>
> +    /* The following registers are the "real" versions that the pointer
> +     * versions point to. These should never be used unless you know what you
> +     * are doing. To access these use the pointer versions instead. This is
> +     * required to handle the Hypervisor register swapping.
> +     */
> +    target_ulong mie_novirt;
> +    target_ulong mstatus_novirt;
> +
>      /* Hypervisor CSRs */
>      target_ulong hstatus;
>      target_ulong hedeleg;
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 5bcfc2e090..c597523d74 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -36,9 +36,9 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
>  #ifndef CONFIG_USER_ONLY
>  static int riscv_cpu_local_irq_pending(CPURISCVState *env)
>  {
> -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> -    target_ulong pending = atomic_read(&env->mip) & env->mie;
> +    target_ulong mstatus_mie = get_field(*env->mstatus, MSTATUS_MIE);
> +    target_ulong mstatus_sie = get_field(*env->mstatus, MSTATUS_SIE);
> +    target_ulong pending = atomic_read(env->mip) & *env->mie;
>      target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie);
>      target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie);
>      target_ulong irqs = (pending & ~env->mideleg & -mie) |
> @@ -74,7 +74,7 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
>  /* Return true is floating point support is currently enabled */
>  bool riscv_cpu_fp_enabled(CPURISCVState *env)
>  {
> -    if (env->mstatus & MSTATUS_FS) {
> +    if (*env->mstatus & MSTATUS_FS) {
>          return true;
>      }
>
> @@ -219,8 +219,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>      int mode = mmu_idx;
>
>      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
> -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
> -            mode = get_field(env->mstatus, MSTATUS_MPP);
> +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> +            mode = get_field(*env->mstatus, MSTATUS_MPP);
>          }
>      }
>
> @@ -234,11 +234,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>
>      target_ulong base;
>      int levels, ptidxbits, ptesize, vm, sum;
> -    int mxr = get_field(env->mstatus, MSTATUS_MXR);
> +    int mxr = get_field(*env->mstatus, MSTATUS_MXR);
>
>      if (env->priv_ver >= PRIV_VERSION_1_10_0) {
>          base = get_field(env->satp, SATP_PPN) << PGSHIFT;
> -        sum = get_field(env->mstatus, MSTATUS_SUM);
> +        sum = get_field(*env->mstatus, MSTATUS_SUM);
>          vm = get_field(env->satp, SATP_MODE);
>          switch (vm) {
>          case VM_1_10_SV32:
> @@ -258,8 +258,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>          }
>      } else {
>          base = env->sptbr << PGSHIFT;
> -        sum = !get_field(env->mstatus, MSTATUS_PUM);
> -        vm = get_field(env->mstatus, MSTATUS_VM);
> +        sum = !get_field(*env->mstatus, MSTATUS_PUM);
> +        vm = get_field(*env->mstatus, MSTATUS_VM);
>          switch (vm) {
>          case VM_1_09_SV32:
>            levels = 2; ptidxbits = 10; ptesize = 4; break;
> @@ -505,8 +505,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>      ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
>
>      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
> -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
> -            mode = get_field(env->mstatus, MSTATUS_MPP);
> +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> +            mode = get_field(*env->mstatus, MSTATUS_MPP);
>          }
>      }
>
> @@ -606,12 +606,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>      if (env->priv <= PRV_S &&
>              cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
>          /* handle the trap in S-mode */
> -        target_ulong s = env->mstatus;
> +        target_ulong s = *env->mstatus;
>          s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
>              get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
>          s = set_field(s, MSTATUS_SPP, env->priv);
>          s = set_field(s, MSTATUS_SIE, 0);
> -        env->mstatus = s;
> +        *env->mstatus = s;
>          env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
>          env->sepc = env->pc;
>          env->sbadaddr = tval;
> @@ -620,12 +620,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>          riscv_cpu_set_mode(env, PRV_S);
>      } else {
>          /* handle the trap in M-mode */
> -        target_ulong s = env->mstatus;
> +        target_ulong s = *env->mstatus;
>          s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
>              get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
>          s = set_field(s, MSTATUS_MPP, env->priv);
>          s = set_field(s, MSTATUS_MIE, 0);
> -        env->mstatus = s;
> +        *env->mstatus = s;
>          env->mcause = cause | ~(((target_ulong)-1) >> async);
>          env->mepc = env->pc;
>          env->mbadaddr = tval;
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index e2e908fbc0..30ec8c0a8e 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -136,7 +136,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
>      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>          return -1;
>      }
> -    env->mstatus |= MSTATUS_FS;
> +    *env->mstatus |= MSTATUS_FS;
>  #endif
>      riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
>      return 0;
> @@ -159,7 +159,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
>      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>          return -1;
>      }
> -    env->mstatus |= MSTATUS_FS;
> +    *env->mstatus |= MSTATUS_FS;
>  #endif
>      env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
>      return 0;
> @@ -183,7 +183,7 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
>      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>          return -1;
>      }
> -    env->mstatus |= MSTATUS_FS;
> +    *env->mstatus |= MSTATUS_FS;
>  #endif
>      env->frm = (val & FSR_RD) >> FSR_RD_SHIFT;
>      riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
> @@ -307,7 +307,7 @@ static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val)
>  /* Machine Trap Setup */
>  static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> -    *val = env->mstatus;
> +    *val = *env->mstatus;
>      return 0;
>  }
>
> @@ -319,7 +319,7 @@ static int validate_vm(CPURISCVState *env, target_ulong vm)
>
>  static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    target_ulong mstatus = env->mstatus;
> +    target_ulong mstatus = *env->mstatus;
>      target_ulong mask = 0;
>      int dirty;
>
> @@ -359,7 +359,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
>               ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
>              ((mstatus & MSTATUS_XS) == MSTATUS_XS);
>      mstatus = set_field(mstatus, MSTATUS_SD, dirty);
> -    env->mstatus = mstatus;
> +    *env->mstatus = mstatus;
>
>      return 0;
>  }
> @@ -448,13 +448,13 @@ static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
>
>  static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> -    *val = env->mie;
> +    *val = *env->mie;
>      return 0;
>  }
>
>  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> +    *env->mie = (*env->mie & ~all_ints) | (val & all_ints);
>      return 0;
>  }
>
> @@ -608,7 +608,7 @@ static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
>  {
>      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
>                           sstatus_v1_10_mask : sstatus_v1_9_mask);
> -    *val = env->mstatus & mask;
> +    *val = *env->mstatus & mask;
>      return 0;
>  }
>
> @@ -616,19 +616,19 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
>  {
>      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
>                           sstatus_v1_10_mask : sstatus_v1_9_mask);
> -    target_ulong newval = (env->mstatus & ~mask) | (val & mask);
> +    target_ulong newval = (*env->mstatus & ~mask) | (val & mask);
>      return write_mstatus(env, CSR_MSTATUS, newval);
>  }
>
>  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> -    *val = env->mie & env->mideleg;
> +    *val = *env->mie & env->mideleg;
>      return 0;
>  }
>
>  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg);
> +    target_ulong newval = (*env->mie & ~env->mideleg) | (val & env->mideleg);
>      return write_mie(env, CSR_MIE, newval);
>  }
>
> @@ -731,7 +731,7 @@ static int read_satp(CPURISCVState *env, int csrno, target_ulong *val)
>      if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
>          *val = 0;
>      } else if (env->priv_ver >= PRIV_VERSION_1_10_0) {
> -        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
> +        if (env->priv == PRV_S && get_field(*env->mstatus, MSTATUS_TVM)) {
>              return -1;
>          } else {
>              *val = env->satp;
> @@ -756,7 +756,7 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
>          validate_vm(env, get_field(val, SATP_MODE)) &&
>          ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
>      {
> -        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
> +        if (env->priv == PRV_S && get_field(*env->mstatus, MSTATUS_TVM)) {
>              return -1;
>          } else {
>              if((val ^ env->satp) & SATP_ASID) {
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index 331cc36232..d150551bc9 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -83,11 +83,11 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>      }
>
>      if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
> -        get_field(env->mstatus, MSTATUS_TSR)) {
> +        get_field(*env->mstatus, MSTATUS_TSR)) {
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      }
>
> -    target_ulong mstatus = env->mstatus;
> +    target_ulong mstatus = *env->mstatus;
>      target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
>      mstatus = set_field(mstatus,
>          env->priv_ver >= PRIV_VERSION_1_10_0 ?
> @@ -96,7 +96,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>      mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
>      mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
>      riscv_cpu_set_mode(env, prev_priv);
> -    env->mstatus = mstatus;
> +    *env->mstatus = mstatus;
>
>      return retpc;
>  }
> @@ -112,7 +112,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>          riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
>      }
>
> -    target_ulong mstatus = env->mstatus;
> +    target_ulong mstatus = *env->mstatus;
>      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
>      mstatus = set_field(mstatus,
>          env->priv_ver >= PRIV_VERSION_1_10_0 ?
> @@ -121,7 +121,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>      mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
>      mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
>      riscv_cpu_set_mode(env, prev_priv);
> -    env->mstatus = mstatus;
> +    *env->mstatus = mstatus;
>
>      return retpc;
>  }
> @@ -132,7 +132,7 @@ void helper_wfi(CPURISCVState *env)
>
>      if (env->priv == PRV_S &&
>          env->priv_ver >= PRIV_VERSION_1_10_0 &&
> -        get_field(env->mstatus, MSTATUS_TW)) {
> +        get_field(*env->mstatus, MSTATUS_TW)) {
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      } else {
>          cs->halted = 1;
> @@ -147,7 +147,7 @@ void helper_tlb_flush(CPURISCVState *env)
>      if (!(env->priv >= PRV_S) ||
>          (env->priv == PRV_S &&
>           env->priv_ver >= PRIV_VERSION_1_10_0 &&
> -         get_field(env->mstatus, MSTATUS_TVM))) {
> +         get_field(*env->mstatus, MSTATUS_TVM))) {
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      } else {
>          tlb_flush(cs);

I don't think this is that bad.

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 11/28] target/riscv: Add background register swapping function
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 11/28] target/riscv: Add background register swapping function Alistair Francis
@ 2019-09-11 14:17   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-11 14:17 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:18 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.h        | 24 ++++++++---
>  target/riscv/cpu_bits.h   |  7 ++++
>  target/riscv/cpu_helper.c | 88 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 113 insertions(+), 6 deletions(-)
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 680592cb60..05957f32a8 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -125,15 +125,18 @@ struct CPURISCVState {
>      target_ulong *mstatus;
>
>      /*
> -     * CAUTION! Unlike the rest of this struct, mip is accessed asynchonously
> -     * by I/O threads. It should be read with atomic_read. It should be updated
> -     * using riscv_cpu_update_mip with the iothread mutex held. The iothread
> -     * mutex must be held because mip must be consistent with the CPU inturrept
> -     * state. riscv_cpu_update_mip calls cpu_interrupt or cpu_reset_interrupt
> -     * wuth the invariant that CPU_INTERRUPT_HARD is set iff mip is non-zero.
> +     * CAUTION! Unlike the rest of this struct, mip and mip_novirt is accessed
> +     * asynchonously by I/O threads. It should be read with atomic_read. It should
> +     * be updated using riscv_cpu_update_mip with the iothread mutex held. The
> +     * iothread mutex must be held because mip must be consistent with the CPU
> +     * inturrept state. riscv_cpu_update_mip calls cpu_interrupt or
> +     * cpu_reset_interrupt wuth the invariant that CPU_INTERRUPT_HARD is set if
> +     * mip is non-zero.
>       * mip is 32-bits to allow atomic_read on 32-bit hosts.
>       */
>      uint32_t mip;
> +    uint32_t mip_novirt;
> +
>      uint32_t miclaim;
>
>      target_ulong *mie;
> @@ -179,6 +182,14 @@ struct CPURISCVState {
>      target_ulong vstval;
>      target_ulong vsatp;
>
> +    /* HS Backup CSRs */
> +    target_ulong stvec_hs;
> +    target_ulong sscratch_hs;
> +    target_ulong sepc_hs;
> +    target_ulong scause_hs;
> +    target_ulong stval_hs;
> +    target_ulong satp_hs;
> +
>      target_ulong scounteren;
>      target_ulong mcounteren;
>
> @@ -306,6 +317,7 @@ void riscv_cpu_list(void);
>  #define cpu_mmu_index riscv_cpu_mmu_index
>
>  #ifndef CONFIG_USER_ONLY
> +void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
>  int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
>  uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
>  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 78067901a2..5cee72b726 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -556,4 +556,11 @@
>  #define SIP_STIP                           MIP_STIP
>  #define SIP_SEIP                           MIP_SEIP
>
> +/* MIE masks */
> +#define MIE_SEIE                           (1 << IRQ_S_EXT)
> +#define MIE_UEIE                           (1 << IRQ_U_EXT)
> +#define MIE_STIE                           (1 << IRQ_S_TIMER)
> +#define MIE_UTIE                           (1 << IRQ_U_TIMER)
> +#define MIE_SSIE                           (1 << IRQ_S_SOFT)
> +#define MIE_USIE                           (1 << IRQ_U_SOFT)
>  #endif
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index c597523d74..41d4368128 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -81,6 +81,94 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
>      return false;
>  }
>
> +void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env)
> +{
> +    RISCVCPU *cpu = RISCV_CPU(env_cpu(env));
> +    uint32_t tmp;
> +    target_ulong mstatus_mask = MSTATUS_MXR | MSTATUS_SUM | MSTATUS_FS |
> +                                MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE;
> +    target_ulong sie_mask = MIE_SEIE | MIE_STIE | MIE_SSIE |
> +                            MIE_UEIE | MIE_UTIE | MIE_USIE;
> +    target_ulong mip_mask = MIP_SSIP | MIP_STIP | MIP_SEIP;
> +    bool current_virt = riscv_cpu_virt_enabled(env);
> +
> +    g_assert(riscv_has_ext(env, RVH));
> +
> +#if defined(TARGET_RISCV64)
> +    mstatus_mask |= MSTATUS64_UXL;
> +#endif
> +
> +    if (current_virt) {

This worries me more than the pointer stuff: specifically, my worry is keeping 
V in sync with the register set in use.

> +        /* Current V=1 and we are about to change to V=0 */
> +        env->mstatus = &env->mstatus_novirt;
> +        *env->mstatus &= mstatus_mask;
> +        *env->mstatus |= env->vsstatus & ~mstatus_mask;
> +        /* Ensure that vsstatus only holds the correct bits */
> +        env->vsstatus &= mstatus_mask;
> +
> +        env->mie = &env->mie_novirt;
> +        *env->mie &= sie_mask;
> +        *env->mie |= env->vsie & ~sie_mask;
> +        /* Ensure that vsie only holds the correct bits */
> +        env->vsie &= sie_mask;
> +
> +        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->sbadaddr;
> +        env->sbadaddr = env->stval_hs;
> +
> +        env->vsatp = env->satp;
> +        env->satp = env->satp_hs;
> +
> +        tmp = (uint32_t)atomic_read(&env->mip_novirt);
> +        tmp = riscv_cpu_update_mip(cpu, mip_mask, tmp);
> +        tmp &= mip_mask;
> +        atomic_set(&env->vsip, tmp);

We talked about this in person, and Alistair is going to do the fake interrupt 
thing to avoid the atomicity requirements entirely.

> +    } else {
> +        /* Current V=0 and we are about to change to V=1 */
> +        env->mstatus = &env->vsstatus;
> +        *env->mstatus &= mstatus_mask;
> +        *env->mstatus |= env->mstatus_novirt & ~mstatus_mask;
> +
> +        env->mie = &env->vsie;
> +        *env->mie &= sie_mask;
> +        *env->mie |= env->mie_novirt & ~sie_mask;
> +
> +        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->sbadaddr;
> +        env->sbadaddr = env->vstval;
> +
> +        env->satp_hs = env->satp;
> +        env->satp = env->vsatp;
> +
> +        tmp = (uint32_t)atomic_read(&env->vsip);
> +        tmp = riscv_cpu_update_mip(cpu, mip_mask, tmp);
> +        tmp &= mip_mask;
> +        atomic_set(&env->mip_novirt, tmp);
> +    }
> +}
> +
>  bool riscv_cpu_virt_enabled(CPURISCVState *env)
>  {
>      bool tmp;


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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-09-11  8:24   ` Palmer Dabbelt
@ 2019-09-11 14:54     ` Jonathan Behrens
  2019-09-17 23:33       ` Alistair Francis
  0 siblings, 1 reply; 75+ messages in thread
From: Jonathan Behrens @ 2019-09-11 14:54 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: open list:RISC-V, Anup Patel, qemu-devel@nongnu.org Developers,
	Atish Patra, Alistair Francis, Alistair Francis

Version 0.4 of the hypervisor spec no longer talks about swapping
registers. Instead when running in VS-mode some of the supervisor registers
are "aliased" and actually refer to alternate versions. Implementations are
of course still allowed to do swapping internally if desired, but it adds
complexity compared to a more straightforward implementation and isn't
obvious to me whether QEMU would get any benefit from it. At least, it is
probably worth fleshing out the rest of the v0.4 implementation before
deciding on this patch.

Jonathan

On Wed, Sep 11, 2019 at 4:24 AM Palmer Dabbelt <palmer@sifive.com> wrote:

> On Fri, 23 Aug 2019 16:38:15 PDT (-0700), Alistair Francis wrote:
> > To handle the new Hypervisor CSR register swapping let's use pointers.
> >
> > We only need to convert the MIE and MSTATUS CSRs. With the exception of
> > MIP all of the other CSRs that swap with virtulsation changes are S-Mode
> > only, so we can just do a lazy switch. This because more challenging for
> > the M-Mode registers so it ends up being easier to use pointers.
> >
> > As the MIP CSR is always accessed atomicly the pointer swap doesn't work
> > so we leave that as is.
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  target/riscv/cpu.c        | 16 ++++++++++++----
> >  target/riscv/cpu.h        | 12 ++++++++++--
> >  target/riscv/cpu_helper.c | 32 ++++++++++++++++----------------
> >  target/riscv/csr.c        | 28 ++++++++++++++--------------
> >  target/riscv/op_helper.c  | 14 +++++++-------
> >  5 files changed, 59 insertions(+), 43 deletions(-)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index be8f643fc2..371d5845af 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -228,7 +228,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE
> *f, int flags)
> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
> >  #ifndef CONFIG_USER_ONLY
> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ",
> env->mhartid);
> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ",
> env->mstatus);
> > +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ",
> *env->mstatus);
> >      if (riscv_has_ext(env, RVH)) {
> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ",
> env->hstatus);
> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ",
> env->vsstatus);
> > @@ -239,7 +239,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE
> *f, int flags)
> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsip    ",
> >                       (target_ulong)atomic_read(&env->vsip));
> >      }
> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", *env->mie);
> >      if (riscv_has_ext(env, RVH)) {
> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsie    ",
> env->vsie);
> >      }
> > @@ -309,7 +309,7 @@ static bool riscv_cpu_has_work(CPUState *cs)
> >       * Definition of the WFI instruction requires it to ignore the
> privilege
> >       * mode and delegation registers, but respect individual enables
> >       */
> > -    return (atomic_read(&env->mip) & env->mie) != 0;
> > +    return (atomic_read(&env->mip) & *env->mie) != 0;
> >  #else
> >      return true;
> >  #endif
> > @@ -330,7 +330,7 @@ static void riscv_cpu_reset(CPUState *cs)
> >      mcc->parent_reset(cs);
> >  #ifndef CONFIG_USER_ONLY
> >      env->priv = PRV_M;
> > -    env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
> > +    *env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
> >      env->mcause = 0;
> >      env->pc = env->resetvec;
> >  #endif
> > @@ -459,8 +459,16 @@ static void riscv_cpu_realize(DeviceState *dev,
> Error **errp)
> >  static void riscv_cpu_init(Object *obj)
> >  {
> >      RISCVCPU *cpu = RISCV_CPU(obj);
> > +#ifndef CONFIG_USER_ONLY
> > +    CPURISCVState *env = &cpu->env;
> > +#endif
> >
> >      cpu_set_cpustate_pointers(cpu);
> > +
> > +#ifndef CONFIG_USER_ONLY
> > +    env->mie = &env->mie_novirt;
> > +    env->mstatus = &env->mstatus_novirt;
> > +#endif
> >  }
> >
> >  static const VMStateDescription vmstate_riscv_cpu = {
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index 4c342e7a79..680592cb60 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -122,7 +122,7 @@ struct CPURISCVState {
> >      target_ulong resetvec;
> >
> >      target_ulong mhartid;
> > -    target_ulong mstatus;
> > +    target_ulong *mstatus;
> >
> >      /*
> >       * CAUTION! Unlike the rest of this struct, mip is accessed
> asynchonously
> > @@ -136,7 +136,7 @@ struct CPURISCVState {
> >      uint32_t mip;
> >      uint32_t miclaim;
> >
> > -    target_ulong mie;
> > +    target_ulong *mie;
> >      target_ulong mideleg;
> >
> >      target_ulong sptbr;  /* until: priv-1.9.1 */
> > @@ -154,6 +154,14 @@ struct CPURISCVState {
> >      target_ulong mcause;
> >      target_ulong mtval;  /* since: priv-1.10.0 */
> >
> > +    /* The following registers are the "real" versions that the pointer
> > +     * versions point to. These should never be used unless you know
> what you
> > +     * are doing. To access these use the pointer versions instead.
> This is
> > +     * required to handle the Hypervisor register swapping.
> > +     */
> > +    target_ulong mie_novirt;
> > +    target_ulong mstatus_novirt;
> > +
> >      /* Hypervisor CSRs */
> >      target_ulong hstatus;
> >      target_ulong hedeleg;
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index 5bcfc2e090..c597523d74 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -36,9 +36,9 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool
> ifetch)
> >  #ifndef CONFIG_USER_ONLY
> >  static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> >  {
> > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> > -    target_ulong pending = atomic_read(&env->mip) & env->mie;
> > +    target_ulong mstatus_mie = get_field(*env->mstatus, MSTATUS_MIE);
> > +    target_ulong mstatus_sie = get_field(*env->mstatus, MSTATUS_SIE);
> > +    target_ulong pending = atomic_read(env->mip) & *env->mie;
> >      target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M &&
> mstatus_mie);
> >      target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S &&
> mstatus_sie);
> >      target_ulong irqs = (pending & ~env->mideleg & -mie) |
> > @@ -74,7 +74,7 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int
> interrupt_request)
> >  /* Return true is floating point support is currently enabled */
> >  bool riscv_cpu_fp_enabled(CPURISCVState *env)
> >  {
> > -    if (env->mstatus & MSTATUS_FS) {
> > +    if (*env->mstatus & MSTATUS_FS) {
> >          return true;
> >      }
> >
> > @@ -219,8 +219,8 @@ static int get_physical_address(CPURISCVState *env,
> hwaddr *physical,
> >      int mode = mmu_idx;
> >
> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
> > -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
> > -            mode = get_field(env->mstatus, MSTATUS_MPP);
> > +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> > +            mode = get_field(*env->mstatus, MSTATUS_MPP);
> >          }
> >      }
> >
> > @@ -234,11 +234,11 @@ static int get_physical_address(CPURISCVState
> *env, hwaddr *physical,
> >
> >      target_ulong base;
> >      int levels, ptidxbits, ptesize, vm, sum;
> > -    int mxr = get_field(env->mstatus, MSTATUS_MXR);
> > +    int mxr = get_field(*env->mstatus, MSTATUS_MXR);
> >
> >      if (env->priv_ver >= PRIV_VERSION_1_10_0) {
> >          base = get_field(env->satp, SATP_PPN) << PGSHIFT;
> > -        sum = get_field(env->mstatus, MSTATUS_SUM);
> > +        sum = get_field(*env->mstatus, MSTATUS_SUM);
> >          vm = get_field(env->satp, SATP_MODE);
> >          switch (vm) {
> >          case VM_1_10_SV32:
> > @@ -258,8 +258,8 @@ static int get_physical_address(CPURISCVState *env,
> hwaddr *physical,
> >          }
> >      } else {
> >          base = env->sptbr << PGSHIFT;
> > -        sum = !get_field(env->mstatus, MSTATUS_PUM);
> > -        vm = get_field(env->mstatus, MSTATUS_VM);
> > +        sum = !get_field(*env->mstatus, MSTATUS_PUM);
> > +        vm = get_field(*env->mstatus, MSTATUS_VM);
> >          switch (vm) {
> >          case VM_1_09_SV32:
> >            levels = 2; ptidxbits = 10; ptesize = 4; break;
> > @@ -505,8 +505,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address,
> int size,
> >      ret = get_physical_address(env, &pa, &prot, address, access_type,
> mmu_idx);
> >
> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
> > -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
> > -            mode = get_field(env->mstatus, MSTATUS_MPP);
> > +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> > +            mode = get_field(*env->mstatus, MSTATUS_MPP);
> >          }
> >      }
> >
> > @@ -606,12 +606,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> >      if (env->priv <= PRV_S &&
> >              cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
> >          /* handle the trap in S-mode */
> > -        target_ulong s = env->mstatus;
> > +        target_ulong s = *env->mstatus;
> >          s = set_field(s, MSTATUS_SPIE, env->priv_ver >=
> PRIV_VERSION_1_10_0 ?
> >              get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE <<
> env->priv));
> >          s = set_field(s, MSTATUS_SPP, env->priv);
> >          s = set_field(s, MSTATUS_SIE, 0);
> > -        env->mstatus = s;
> > +        *env->mstatus = s;
> >          env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS
> - 1));
> >          env->sepc = env->pc;
> >          env->sbadaddr = tval;
> > @@ -620,12 +620,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> >          riscv_cpu_set_mode(env, PRV_S);
> >      } else {
> >          /* handle the trap in M-mode */
> > -        target_ulong s = env->mstatus;
> > +        target_ulong s = *env->mstatus;
> >          s = set_field(s, MSTATUS_MPIE, env->priv_ver >=
> PRIV_VERSION_1_10_0 ?
> >              get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE <<
> env->priv));
> >          s = set_field(s, MSTATUS_MPP, env->priv);
> >          s = set_field(s, MSTATUS_MIE, 0);
> > -        env->mstatus = s;
> > +        *env->mstatus = s;
> >          env->mcause = cause | ~(((target_ulong)-1) >> async);
> >          env->mepc = env->pc;
> >          env->mbadaddr = tval;
> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > index e2e908fbc0..30ec8c0a8e 100644
> > --- a/target/riscv/csr.c
> > +++ b/target/riscv/csr.c
> > @@ -136,7 +136,7 @@ static int write_fflags(CPURISCVState *env, int
> csrno, target_ulong val)
> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
> >          return -1;
> >      }
> > -    env->mstatus |= MSTATUS_FS;
> > +    *env->mstatus |= MSTATUS_FS;
> >  #endif
> >      riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
> >      return 0;
> > @@ -159,7 +159,7 @@ static int write_frm(CPURISCVState *env, int csrno,
> target_ulong val)
> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
> >          return -1;
> >      }
> > -    env->mstatus |= MSTATUS_FS;
> > +    *env->mstatus |= MSTATUS_FS;
> >  #endif
> >      env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
> >      return 0;
> > @@ -183,7 +183,7 @@ static int write_fcsr(CPURISCVState *env, int csrno,
> target_ulong val)
> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
> >          return -1;
> >      }
> > -    env->mstatus |= MSTATUS_FS;
> > +    *env->mstatus |= MSTATUS_FS;
> >  #endif
> >      env->frm = (val & FSR_RD) >> FSR_RD_SHIFT;
> >      riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
> > @@ -307,7 +307,7 @@ static int read_mhartid(CPURISCVState *env, int
> csrno, target_ulong *val)
> >  /* Machine Trap Setup */
> >  static int read_mstatus(CPURISCVState *env, int csrno, target_ulong
> *val)
> >  {
> > -    *val = env->mstatus;
> > +    *val = *env->mstatus;
> >      return 0;
> >  }
> >
> > @@ -319,7 +319,7 @@ static int validate_vm(CPURISCVState *env,
> target_ulong vm)
> >
> >  static int write_mstatus(CPURISCVState *env, int csrno, target_ulong
> val)
> >  {
> > -    target_ulong mstatus = env->mstatus;
> > +    target_ulong mstatus = *env->mstatus;
> >      target_ulong mask = 0;
> >      int dirty;
> >
> > @@ -359,7 +359,7 @@ static int write_mstatus(CPURISCVState *env, int
> csrno, target_ulong val)
> >               ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
> >              ((mstatus & MSTATUS_XS) == MSTATUS_XS);
> >      mstatus = set_field(mstatus, MSTATUS_SD, dirty);
> > -    env->mstatus = mstatus;
> > +    *env->mstatus = mstatus;
> >
> >      return 0;
> >  }
> > @@ -448,13 +448,13 @@ static int write_mideleg(CPURISCVState *env, int
> csrno, target_ulong val)
> >
> >  static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > -    *val = env->mie;
> > +    *val = *env->mie;
> >      return 0;
> >  }
> >
> >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> > +    *env->mie = (*env->mie & ~all_ints) | (val & all_ints);
> >      return 0;
> >  }
> >
> > @@ -608,7 +608,7 @@ static int read_sstatus(CPURISCVState *env, int
> csrno, target_ulong *val)
> >  {
> >      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
> >                           sstatus_v1_10_mask : sstatus_v1_9_mask);
> > -    *val = env->mstatus & mask;
> > +    *val = *env->mstatus & mask;
> >      return 0;
> >  }
> >
> > @@ -616,19 +616,19 @@ static int write_sstatus(CPURISCVState *env, int
> csrno, target_ulong val)
> >  {
> >      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
> >                           sstatus_v1_10_mask : sstatus_v1_9_mask);
> > -    target_ulong newval = (env->mstatus & ~mask) | (val & mask);
> > +    target_ulong newval = (*env->mstatus & ~mask) | (val & mask);
> >      return write_mstatus(env, CSR_MSTATUS, newval);
> >  }
> >
> >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > -    *val = env->mie & env->mideleg;
> > +    *val = *env->mie & env->mideleg;
> >      return 0;
> >  }
> >
> >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > -    target_ulong newval = (env->mie & ~env->mideleg) | (val &
> env->mideleg);
> > +    target_ulong newval = (*env->mie & ~env->mideleg) | (val &
> env->mideleg);
> >      return write_mie(env, CSR_MIE, newval);
> >  }
> >
> > @@ -731,7 +731,7 @@ static int read_satp(CPURISCVState *env, int csrno,
> target_ulong *val)
> >      if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
> >          *val = 0;
> >      } else if (env->priv_ver >= PRIV_VERSION_1_10_0) {
> > -        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM))
> {
> > +        if (env->priv == PRV_S && get_field(*env->mstatus,
> MSTATUS_TVM)) {
> >              return -1;
> >          } else {
> >              *val = env->satp;
> > @@ -756,7 +756,7 @@ static int write_satp(CPURISCVState *env, int csrno,
> target_ulong val)
> >          validate_vm(env, get_field(val, SATP_MODE)) &&
> >          ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
> >      {
> > -        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM))
> {
> > +        if (env->priv == PRV_S && get_field(*env->mstatus,
> MSTATUS_TVM)) {
> >              return -1;
> >          } else {
> >              if((val ^ env->satp) & SATP_ASID) {
> > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> > index 331cc36232..d150551bc9 100644
> > --- a/target/riscv/op_helper.c
> > +++ b/target/riscv/op_helper.c
> > @@ -83,11 +83,11 @@ target_ulong helper_sret(CPURISCVState *env,
> target_ulong cpu_pc_deb)
> >      }
> >
> >      if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
> > -        get_field(env->mstatus, MSTATUS_TSR)) {
> > +        get_field(*env->mstatus, MSTATUS_TSR)) {
> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
> >      }
> >
> > -    target_ulong mstatus = env->mstatus;
> > +    target_ulong mstatus = *env->mstatus;
> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
> >      mstatus = set_field(mstatus,
> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
> > @@ -96,7 +96,7 @@ target_ulong helper_sret(CPURISCVState *env,
> target_ulong cpu_pc_deb)
> >      mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
> >      mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
> >      riscv_cpu_set_mode(env, prev_priv);
> > -    env->mstatus = mstatus;
> > +    *env->mstatus = mstatus;
> >
> >      return retpc;
> >  }
> > @@ -112,7 +112,7 @@ target_ulong helper_mret(CPURISCVState *env,
> target_ulong cpu_pc_deb)
> >          riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
> >      }
> >
> > -    target_ulong mstatus = env->mstatus;
> > +    target_ulong mstatus = *env->mstatus;
> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
> >      mstatus = set_field(mstatus,
> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
> > @@ -121,7 +121,7 @@ target_ulong helper_mret(CPURISCVState *env,
> target_ulong cpu_pc_deb)
> >      mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
> >      mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
> >      riscv_cpu_set_mode(env, prev_priv);
> > -    env->mstatus = mstatus;
> > +    *env->mstatus = mstatus;
> >
> >      return retpc;
> >  }
> > @@ -132,7 +132,7 @@ void helper_wfi(CPURISCVState *env)
> >
> >      if (env->priv == PRV_S &&
> >          env->priv_ver >= PRIV_VERSION_1_10_0 &&
> > -        get_field(env->mstatus, MSTATUS_TW)) {
> > +        get_field(*env->mstatus, MSTATUS_TW)) {
> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
> >      } else {
> >          cs->halted = 1;
> > @@ -147,7 +147,7 @@ void helper_tlb_flush(CPURISCVState *env)
> >      if (!(env->priv >= PRV_S) ||
> >          (env->priv == PRV_S &&
> >           env->priv_ver >= PRIV_VERSION_1_10_0 &&
> > -         get_field(env->mstatus, MSTATUS_TVM))) {
> > +         get_field(*env->mstatus, MSTATUS_TVM))) {
> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
> >      } else {
> >          tlb_flush(cs);
>
> I don't think this is that bad.
>
> Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
>
>

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

* Re: [Qemu-devel] [PATCH v1 12/28] target/riscv: Add support for virtual interrupt setting
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 12/28] target/riscv: Add support for virtual interrupt setting Alistair Francis
@ 2019-09-14 20:30   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-14 20:30 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:21 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_helper.c | 21 ++++++++++++++++++---
>  1 file changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 41d4368128..afb3e8579e 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -38,12 +38,27 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
>  {
>      target_ulong mstatus_mie = get_field(*env->mstatus, MSTATUS_MIE);
>      target_ulong mstatus_sie = get_field(*env->mstatus, MSTATUS_SIE);
> -    target_ulong pending = atomic_read(env->mip) & *env->mie;
> -    target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie);
> -    target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie);
> +    target_ulong vsstatus_sie = get_field(env->mstatus_novirt, MSTATUS_SIE);
> +
> +    target_ulong pending = atomic_read(&env->mip) & *env->mie;
> +    target_ulong hspending = atomic_read(&env->mip_novirt) & env->mie_novirt;
> +
> +    target_ulong mie  = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie);
> +    target_ulong sie  = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie);
> +    target_ulong vsie = env->priv < PRV_S || (env->priv == PRV_S && vsstatus_sie);
> +
>      target_ulong irqs = (pending & ~env->mideleg & -mie) |
>                          (pending &  env->mideleg & -sie);
>
> +    if (riscv_cpu_virt_enabled(env)) {
> +        target_ulong pending_hs_irq = hspending & -vsie;
> +
> +        if (pending_hs_irq) {
> +            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> +            return ctz64(pending_hs_irq);
> +        }
> +    }
> +
>      if (irqs) {
>          return ctz64(irqs); /* since non-zero */
>      } else {

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 13/28] target/ricsv: Flush the TLB on virtulisation mode changes
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 13/28] target/ricsv: Flush the TLB on virtulisation mode changes Alistair Francis
@ 2019-09-14 20:30   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-14 20:30 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:23 PDT (-0700), Alistair Francis wrote:
> To ensure our TLB isn't out-of-date we flush it on all virt mode
> changes. Unlike priv mode this isn't saved in the mmu_idx as all
> guests share V=1. The easiest option is just to flush on all changes.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_helper.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index afb3e8579e..8e8b156fc0 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -203,6 +203,11 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
>          return;
>      }
>
> +    /* Flush the TLB on all virt mode changes. */
> +    if (((env->virt & VIRT_MODE_MASK) >> VIRT_MODE_SHIFT) != enable) {
> +        tlb_flush(env_cpu(env));
> +    }
> +
>      env->virt &= ~VIRT_MODE_MASK;
>      env->virt |= enable << VIRT_MODE_SHIFT;
>  }

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 14/28] target/riscv: Generate illegal instruction on WFI when V=1
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 14/28] target/riscv: Generate illegal instruction on WFI when V=1 Alistair Francis
@ 2019-09-14 20:30   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-14 20:30 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:26 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/op_helper.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index d150551bc9..beb34e705b 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -130,9 +130,10 @@ void helper_wfi(CPURISCVState *env)
>  {
>      CPUState *cs = env_cpu(env);
>
> -    if (env->priv == PRV_S &&
> +    if ((env->priv == PRV_S &&
>          env->priv_ver >= PRIV_VERSION_1_10_0 &&
> -        get_field(*env->mstatus, MSTATUS_TW)) {
> +        get_field(*env->mstatus, MSTATUS_TW)) ||
> +        riscv_cpu_virt_enabled(env)) {
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      } else {
>          cs->halted = 1;

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [Qemu-devel] [PATCH v1 15/28] riscv: plic: Always set sip.SEIP bit for HS
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 15/28] riscv: plic: Always set sip.SEIP bit for HS Alistair Francis
@ 2019-09-14 20:32   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-14 20:32 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:29 PDT (-0700), Alistair Francis wrote:
> When the PLIC generates an interrupt ensure we always set it for the SIP
> CSR that corresponds to the HS (V=0) register.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  hw/riscv/sifive_plic.c | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c
> index 98e4304b66..8309e96f64 100644
> --- a/hw/riscv/sifive_plic.c
> +++ b/hw/riscv/sifive_plic.c
> @@ -150,7 +150,17 @@ static void sifive_plic_update(SiFivePLICState *plic)
>              riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_MEIP, BOOL_TO_MASK(level));
>              break;
>          case PLICMode_S:
> -            riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level));
> +            if (riscv_cpu_virt_enabled(env)) {
> +                if (level) {
> +                    atomic_or(&env->mip_novirt, MIP_SEIP);
> +                    g_assert(riscv_cpu_virt_enabled(env));
> +                } else {
> +                    atomic_and(&env->mip_novirt, ~MIP_SEIP);
> +                    g_assert(riscv_cpu_virt_enabled(env));
> +                }
> +            } else {
> +                riscv_cpu_update_mip(RISCV_CPU(cpu), MIP_SEIP, BOOL_TO_MASK(level));
> +            }
>              break;
>          default:
>              break;

This is going to go when we change the interrupt delivery mechanism.


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

* Re: [Qemu-devel] [PATCH v1 02/28] target/riscv: Add the virtulisation mode
  2019-09-10 13:44   ` [Qemu-devel] " Palmer Dabbelt
@ 2019-09-16 15:57     ` Alistair Francis
  0 siblings, 0 replies; 75+ messages in thread
From: Alistair Francis @ 2019-09-16 15:57 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: open list:RISC-V, Anup Patel, Alistair Francis,
	qemu-devel@nongnu.org Developers, Atish Patra

On Tue, Sep 10, 2019 at 6:44 AM Palmer Dabbelt <palmer@sifive.com> wrote:
>
> On Fri, 23 Aug 2019 16:37:54 PDT (-0700), Alistair Francis wrote:
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  target/riscv/cpu.h        |  4 ++++
> >  target/riscv/cpu_bits.h   |  6 ++++++
> >  target/riscv/cpu_helper.c | 23 +++++++++++++++++++++++
> >  3 files changed, 33 insertions(+)
> >
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index 7f54fb8c87..0ef1ecb0e0 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -117,6 +117,8 @@ struct CPURISCVState {
> >
> >  #ifndef CONFIG_USER_ONLY
> >      target_ulong priv;
> > +    /* This contains QEMU specific information about the virt state. */
> > +    target_ulong virt;
> >      target_ulong resetvec;
> >
> >      target_ulong mhartid;
> > @@ -257,6 +259,8 @@ int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
> >  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> >  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
> >  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> > +bool riscv_cpu_virt_enabled(CPURISCVState *env);
> > +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
> >  int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
> >  hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
> >  void  riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
> > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> > index e99834856c..1fbde516be 100644
> > --- a/target/riscv/cpu_bits.h
> > +++ b/target/riscv/cpu_bits.h
> > @@ -422,6 +422,12 @@
> >  #define PRV_H 2 /* Reserved */
> >  #define PRV_M 3
> >
> > +/* Virtulisation modes */
> > +#define VIRT_OFF            0
> > +#define VIRT_ON             1
> > +#define VIRT_MODE_SHIFT     0
> > +#define VIRT_MODE_MASK      (1 << VIRT_MODE_SHIFT)
> > +
> >  /* RV32 satp CSR field masks */
> >  #define SATP32_MODE         0x80000000
> >  #define SATP32_ASID         0x7fc00000
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index 225e407cff..7b0bb14c01 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -81,6 +81,29 @@ bool riscv_cpu_fp_enabled(CPURISCVState *env)
> >      return false;
> >  }
> >
> > +bool riscv_cpu_virt_enabled(CPURISCVState *env)
> > +{
> > +    bool tmp;
> > +
> > +    if (!riscv_has_ext(env, RVH)) {
> > +        return false;
> > +    }
> > +
> > +    tmp = (env->virt & VIRT_MODE_MASK) >> VIRT_MODE_SHIFT;
> > +
> > +    return tmp == VIRT_ON;
> > +}
>
> extract64() is a bit cleaner.

I have already changed it to get_field() and set_field().

>
> > +
> > +void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
> > +{
> > +    if (!riscv_has_ext(env, RVH)) {
> > +        return;
> > +    }
> > +
> > +    env->virt &= ~VIRT_MODE_MASK;
> > +    env->virt |= enable << VIRT_MODE_SHIFT;
> > +}
> > +
> >  int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> >  {
> >      CPURISCVState *env = &cpu->env;
>
> Reviewed-by: Palmer Dabbelt <palmer@sifive.com>

This patch is a little out of date, so I'll not include your RB line in the v2.

Alistair


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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-09-11 14:54     ` [Qemu-devel] [Qemu-riscv] " Jonathan Behrens
@ 2019-09-17 23:33       ` Alistair Francis
  2019-09-18  1:59         ` Jonathan Behrens
  0 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-09-17 23:33 UTC (permalink / raw)
  To: Jonathan Behrens
  Cc: Palmer Dabbelt, open list:RISC-V, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis

On Wed, Sep 11, 2019 at 7:55 AM Jonathan Behrens <fintelia@gmail.com> wrote:
>
> Version 0.4 of the hypervisor spec no longer talks about swapping registers. Instead when running in VS-mode some of the supervisor registers are "aliased" and actually refer to alternate versions. Implementations are of course still allowed to do swapping internally if desired, but it adds complexity compared to a more straightforward implementation and isn't obvious to me whether QEMU would get any benefit from it. At least, it is probably worth fleshing out the rest of the v0.4 implementation before deciding on this patch.

This patch is to handle the aliasing. The commit message isn't clear
(I'll fix that up) but this patch is required to handle the new alias
method instead of the previous swapping.

Alistair

> Jonathan
>
> On Wed, Sep 11, 2019 at 4:24 AM Palmer Dabbelt <palmer@sifive.com> wrote:
>>
>> On Fri, 23 Aug 2019 16:38:15 PDT (-0700), Alistair Francis wrote:
>> > To handle the new Hypervisor CSR register swapping let's use pointers.
>> >
>> > We only need to convert the MIE and MSTATUS CSRs. With the exception of
>> > MIP all of the other CSRs that swap with virtulsation changes are S-Mode
>> > only, so we can just do a lazy switch. This because more challenging for
>> > the M-Mode registers so it ends up being easier to use pointers.
>> >
>> > As the MIP CSR is always accessed atomicly the pointer swap doesn't work
>> > so we leave that as is.
>> >
>> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
>> > ---
>> >  target/riscv/cpu.c        | 16 ++++++++++++----
>> >  target/riscv/cpu.h        | 12 ++++++++++--
>> >  target/riscv/cpu_helper.c | 32 ++++++++++++++++----------------
>> >  target/riscv/csr.c        | 28 ++++++++++++++--------------
>> >  target/riscv/op_helper.c  | 14 +++++++-------
>> >  5 files changed, 59 insertions(+), 43 deletions(-)
>> >
>> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
>> > index be8f643fc2..371d5845af 100644
>> > --- a/target/riscv/cpu.c
>> > +++ b/target/riscv/cpu.c
>> > @@ -228,7 +228,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
>> >  #ifndef CONFIG_USER_ONLY
>> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
>> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
>> > +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", *env->mstatus);
>> >      if (riscv_has_ext(env, RVH)) {
>> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
>> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ", env->vsstatus);
>> > @@ -239,7 +239,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsip    ",
>> >                       (target_ulong)atomic_read(&env->vsip));
>> >      }
>> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
>> > +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", *env->mie);
>> >      if (riscv_has_ext(env, RVH)) {
>> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsie    ", env->vsie);
>> >      }
>> > @@ -309,7 +309,7 @@ static bool riscv_cpu_has_work(CPUState *cs)
>> >       * Definition of the WFI instruction requires it to ignore the privilege
>> >       * mode and delegation registers, but respect individual enables
>> >       */
>> > -    return (atomic_read(&env->mip) & env->mie) != 0;
>> > +    return (atomic_read(&env->mip) & *env->mie) != 0;
>> >  #else
>> >      return true;
>> >  #endif
>> > @@ -330,7 +330,7 @@ static void riscv_cpu_reset(CPUState *cs)
>> >      mcc->parent_reset(cs);
>> >  #ifndef CONFIG_USER_ONLY
>> >      env->priv = PRV_M;
>> > -    env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
>> > +    *env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
>> >      env->mcause = 0;
>> >      env->pc = env->resetvec;
>> >  #endif
>> > @@ -459,8 +459,16 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
>> >  static void riscv_cpu_init(Object *obj)
>> >  {
>> >      RISCVCPU *cpu = RISCV_CPU(obj);
>> > +#ifndef CONFIG_USER_ONLY
>> > +    CPURISCVState *env = &cpu->env;
>> > +#endif
>> >
>> >      cpu_set_cpustate_pointers(cpu);
>> > +
>> > +#ifndef CONFIG_USER_ONLY
>> > +    env->mie = &env->mie_novirt;
>> > +    env->mstatus = &env->mstatus_novirt;
>> > +#endif
>> >  }
>> >
>> >  static const VMStateDescription vmstate_riscv_cpu = {
>> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>> > index 4c342e7a79..680592cb60 100644
>> > --- a/target/riscv/cpu.h
>> > +++ b/target/riscv/cpu.h
>> > @@ -122,7 +122,7 @@ struct CPURISCVState {
>> >      target_ulong resetvec;
>> >
>> >      target_ulong mhartid;
>> > -    target_ulong mstatus;
>> > +    target_ulong *mstatus;
>> >
>> >      /*
>> >       * CAUTION! Unlike the rest of this struct, mip is accessed asynchonously
>> > @@ -136,7 +136,7 @@ struct CPURISCVState {
>> >      uint32_t mip;
>> >      uint32_t miclaim;
>> >
>> > -    target_ulong mie;
>> > +    target_ulong *mie;
>> >      target_ulong mideleg;
>> >
>> >      target_ulong sptbr;  /* until: priv-1.9.1 */
>> > @@ -154,6 +154,14 @@ struct CPURISCVState {
>> >      target_ulong mcause;
>> >      target_ulong mtval;  /* since: priv-1.10.0 */
>> >
>> > +    /* The following registers are the "real" versions that the pointer
>> > +     * versions point to. These should never be used unless you know what you
>> > +     * are doing. To access these use the pointer versions instead. This is
>> > +     * required to handle the Hypervisor register swapping.
>> > +     */
>> > +    target_ulong mie_novirt;
>> > +    target_ulong mstatus_novirt;
>> > +
>> >      /* Hypervisor CSRs */
>> >      target_ulong hstatus;
>> >      target_ulong hedeleg;
>> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
>> > index 5bcfc2e090..c597523d74 100644
>> > --- a/target/riscv/cpu_helper.c
>> > +++ b/target/riscv/cpu_helper.c
>> > @@ -36,9 +36,9 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
>> >  #ifndef CONFIG_USER_ONLY
>> >  static int riscv_cpu_local_irq_pending(CPURISCVState *env)
>> >  {
>> > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
>> > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
>> > -    target_ulong pending = atomic_read(&env->mip) & env->mie;
>> > +    target_ulong mstatus_mie = get_field(*env->mstatus, MSTATUS_MIE);
>> > +    target_ulong mstatus_sie = get_field(*env->mstatus, MSTATUS_SIE);
>> > +    target_ulong pending = atomic_read(env->mip) & *env->mie;
>> >      target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie);
>> >      target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie);
>> >      target_ulong irqs = (pending & ~env->mideleg & -mie) |
>> > @@ -74,7 +74,7 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
>> >  /* Return true is floating point support is currently enabled */
>> >  bool riscv_cpu_fp_enabled(CPURISCVState *env)
>> >  {
>> > -    if (env->mstatus & MSTATUS_FS) {
>> > +    if (*env->mstatus & MSTATUS_FS) {
>> >          return true;
>> >      }
>> >
>> > @@ -219,8 +219,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>> >      int mode = mmu_idx;
>> >
>> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
>> > -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
>> > -            mode = get_field(env->mstatus, MSTATUS_MPP);
>> > +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
>> > +            mode = get_field(*env->mstatus, MSTATUS_MPP);
>> >          }
>> >      }
>> >
>> > @@ -234,11 +234,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>> >
>> >      target_ulong base;
>> >      int levels, ptidxbits, ptesize, vm, sum;
>> > -    int mxr = get_field(env->mstatus, MSTATUS_MXR);
>> > +    int mxr = get_field(*env->mstatus, MSTATUS_MXR);
>> >
>> >      if (env->priv_ver >= PRIV_VERSION_1_10_0) {
>> >          base = get_field(env->satp, SATP_PPN) << PGSHIFT;
>> > -        sum = get_field(env->mstatus, MSTATUS_SUM);
>> > +        sum = get_field(*env->mstatus, MSTATUS_SUM);
>> >          vm = get_field(env->satp, SATP_MODE);
>> >          switch (vm) {
>> >          case VM_1_10_SV32:
>> > @@ -258,8 +258,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>> >          }
>> >      } else {
>> >          base = env->sptbr << PGSHIFT;
>> > -        sum = !get_field(env->mstatus, MSTATUS_PUM);
>> > -        vm = get_field(env->mstatus, MSTATUS_VM);
>> > +        sum = !get_field(*env->mstatus, MSTATUS_PUM);
>> > +        vm = get_field(*env->mstatus, MSTATUS_VM);
>> >          switch (vm) {
>> >          case VM_1_09_SV32:
>> >            levels = 2; ptidxbits = 10; ptesize = 4; break;
>> > @@ -505,8 +505,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>> >      ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
>> >
>> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
>> > -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
>> > -            mode = get_field(env->mstatus, MSTATUS_MPP);
>> > +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
>> > +            mode = get_field(*env->mstatus, MSTATUS_MPP);
>> >          }
>> >      }
>> >
>> > @@ -606,12 +606,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>> >      if (env->priv <= PRV_S &&
>> >              cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
>> >          /* handle the trap in S-mode */
>> > -        target_ulong s = env->mstatus;
>> > +        target_ulong s = *env->mstatus;
>> >          s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
>> >              get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
>> >          s = set_field(s, MSTATUS_SPP, env->priv);
>> >          s = set_field(s, MSTATUS_SIE, 0);
>> > -        env->mstatus = s;
>> > +        *env->mstatus = s;
>> >          env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
>> >          env->sepc = env->pc;
>> >          env->sbadaddr = tval;
>> > @@ -620,12 +620,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>> >          riscv_cpu_set_mode(env, PRV_S);
>> >      } else {
>> >          /* handle the trap in M-mode */
>> > -        target_ulong s = env->mstatus;
>> > +        target_ulong s = *env->mstatus;
>> >          s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
>> >              get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
>> >          s = set_field(s, MSTATUS_MPP, env->priv);
>> >          s = set_field(s, MSTATUS_MIE, 0);
>> > -        env->mstatus = s;
>> > +        *env->mstatus = s;
>> >          env->mcause = cause | ~(((target_ulong)-1) >> async);
>> >          env->mepc = env->pc;
>> >          env->mbadaddr = tval;
>> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>> > index e2e908fbc0..30ec8c0a8e 100644
>> > --- a/target/riscv/csr.c
>> > +++ b/target/riscv/csr.c
>> > @@ -136,7 +136,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
>> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>> >          return -1;
>> >      }
>> > -    env->mstatus |= MSTATUS_FS;
>> > +    *env->mstatus |= MSTATUS_FS;
>> >  #endif
>> >      riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
>> >      return 0;
>> > @@ -159,7 +159,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
>> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>> >          return -1;
>> >      }
>> > -    env->mstatus |= MSTATUS_FS;
>> > +    *env->mstatus |= MSTATUS_FS;
>> >  #endif
>> >      env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
>> >      return 0;
>> > @@ -183,7 +183,7 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
>> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>> >          return -1;
>> >      }
>> > -    env->mstatus |= MSTATUS_FS;
>> > +    *env->mstatus |= MSTATUS_FS;
>> >  #endif
>> >      env->frm = (val & FSR_RD) >> FSR_RD_SHIFT;
>> >      riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
>> > @@ -307,7 +307,7 @@ static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val)
>> >  /* Machine Trap Setup */
>> >  static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val)
>> >  {
>> > -    *val = env->mstatus;
>> > +    *val = *env->mstatus;
>> >      return 0;
>> >  }
>> >
>> > @@ -319,7 +319,7 @@ static int validate_vm(CPURISCVState *env, target_ulong vm)
>> >
>> >  static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
>> >  {
>> > -    target_ulong mstatus = env->mstatus;
>> > +    target_ulong mstatus = *env->mstatus;
>> >      target_ulong mask = 0;
>> >      int dirty;
>> >
>> > @@ -359,7 +359,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
>> >               ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
>> >              ((mstatus & MSTATUS_XS) == MSTATUS_XS);
>> >      mstatus = set_field(mstatus, MSTATUS_SD, dirty);
>> > -    env->mstatus = mstatus;
>> > +    *env->mstatus = mstatus;
>> >
>> >      return 0;
>> >  }
>> > @@ -448,13 +448,13 @@ static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
>> >
>> >  static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
>> >  {
>> > -    *val = env->mie;
>> > +    *val = *env->mie;
>> >      return 0;
>> >  }
>> >
>> >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
>> >  {
>> > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
>> > +    *env->mie = (*env->mie & ~all_ints) | (val & all_ints);
>> >      return 0;
>> >  }
>> >
>> > @@ -608,7 +608,7 @@ static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
>> >  {
>> >      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
>> >                           sstatus_v1_10_mask : sstatus_v1_9_mask);
>> > -    *val = env->mstatus & mask;
>> > +    *val = *env->mstatus & mask;
>> >      return 0;
>> >  }
>> >
>> > @@ -616,19 +616,19 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
>> >  {
>> >      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
>> >                           sstatus_v1_10_mask : sstatus_v1_9_mask);
>> > -    target_ulong newval = (env->mstatus & ~mask) | (val & mask);
>> > +    target_ulong newval = (*env->mstatus & ~mask) | (val & mask);
>> >      return write_mstatus(env, CSR_MSTATUS, newval);
>> >  }
>> >
>> >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
>> >  {
>> > -    *val = env->mie & env->mideleg;
>> > +    *val = *env->mie & env->mideleg;
>> >      return 0;
>> >  }
>> >
>> >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
>> >  {
>> > -    target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg);
>> > +    target_ulong newval = (*env->mie & ~env->mideleg) | (val & env->mideleg);
>> >      return write_mie(env, CSR_MIE, newval);
>> >  }
>> >
>> > @@ -731,7 +731,7 @@ static int read_satp(CPURISCVState *env, int csrno, target_ulong *val)
>> >      if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
>> >          *val = 0;
>> >      } else if (env->priv_ver >= PRIV_VERSION_1_10_0) {
>> > -        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
>> > +        if (env->priv == PRV_S && get_field(*env->mstatus, MSTATUS_TVM)) {
>> >              return -1;
>> >          } else {
>> >              *val = env->satp;
>> > @@ -756,7 +756,7 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
>> >          validate_vm(env, get_field(val, SATP_MODE)) &&
>> >          ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
>> >      {
>> > -        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
>> > +        if (env->priv == PRV_S && get_field(*env->mstatus, MSTATUS_TVM)) {
>> >              return -1;
>> >          } else {
>> >              if((val ^ env->satp) & SATP_ASID) {
>> > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
>> > index 331cc36232..d150551bc9 100644
>> > --- a/target/riscv/op_helper.c
>> > +++ b/target/riscv/op_helper.c
>> > @@ -83,11 +83,11 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>> >      }
>> >
>> >      if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
>> > -        get_field(env->mstatus, MSTATUS_TSR)) {
>> > +        get_field(*env->mstatus, MSTATUS_TSR)) {
>> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>> >      }
>> >
>> > -    target_ulong mstatus = env->mstatus;
>> > +    target_ulong mstatus = *env->mstatus;
>> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
>> >      mstatus = set_field(mstatus,
>> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
>> > @@ -96,7 +96,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>> >      mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
>> >      mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
>> >      riscv_cpu_set_mode(env, prev_priv);
>> > -    env->mstatus = mstatus;
>> > +    *env->mstatus = mstatus;
>> >
>> >      return retpc;
>> >  }
>> > @@ -112,7 +112,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>> >          riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
>> >      }
>> >
>> > -    target_ulong mstatus = env->mstatus;
>> > +    target_ulong mstatus = *env->mstatus;
>> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
>> >      mstatus = set_field(mstatus,
>> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
>> > @@ -121,7 +121,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>> >      mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
>> >      mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
>> >      riscv_cpu_set_mode(env, prev_priv);
>> > -    env->mstatus = mstatus;
>> > +    *env->mstatus = mstatus;
>> >
>> >      return retpc;
>> >  }
>> > @@ -132,7 +132,7 @@ void helper_wfi(CPURISCVState *env)
>> >
>> >      if (env->priv == PRV_S &&
>> >          env->priv_ver >= PRIV_VERSION_1_10_0 &&
>> > -        get_field(env->mstatus, MSTATUS_TW)) {
>> > +        get_field(*env->mstatus, MSTATUS_TW)) {
>> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>> >      } else {
>> >          cs->halted = 1;
>> > @@ -147,7 +147,7 @@ void helper_tlb_flush(CPURISCVState *env)
>> >      if (!(env->priv >= PRV_S) ||
>> >          (env->priv == PRV_S &&
>> >           env->priv_ver >= PRIV_VERSION_1_10_0 &&
>> > -         get_field(env->mstatus, MSTATUS_TVM))) {
>> > +         get_field(*env->mstatus, MSTATUS_TVM))) {
>> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>> >      } else {
>> >          tlb_flush(cs);
>>
>> I don't think this is that bad.
>>
>> Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
>>


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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-09-17 23:33       ` Alistair Francis
@ 2019-09-18  1:59         ` Jonathan Behrens
  2019-09-18 23:47           ` Alistair Francis
  0 siblings, 1 reply; 75+ messages in thread
From: Jonathan Behrens @ 2019-09-18  1:59 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Palmer Dabbelt, open list:RISC-V, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis

I went through the uses of mie in the entire hypervisor patch series and it
seems like it would be much simpler to just have two non-pointer fields in
the CPU struct: mie and vsie. To if an interrupt is pending, you are either
running with V=0 in which case the contents of vsie can be ignored, or you
are running with V=1 and have to check both anyway. And the
read_sie/write_sie would just need a single extra branch return proper
results. The read_mie and write_mie function wouldn't need to be changed at
all: if M-mode is running to access them, then V=0. (When queried from a
debugger while V=1, I think the result would actually be more correct this
way: the bits of mie are supposed to always reflect sie rather than vsie).

Jonathan

On Tue, Sep 17, 2019 at 7:37 PM Alistair Francis <alistair23@gmail.com>
wrote:

> On Wed, Sep 11, 2019 at 7:55 AM Jonathan Behrens <fintelia@gmail.com>
> wrote:
> >
> > Version 0.4 of the hypervisor spec no longer talks about swapping
> registers. Instead when running in VS-mode some of the supervisor registers
> are "aliased" and actually refer to alternate versions. Implementations are
> of course still allowed to do swapping internally if desired, but it adds
> complexity compared to a more straightforward implementation and isn't
> obvious to me whether QEMU would get any benefit from it. At least, it is
> probably worth fleshing out the rest of the v0.4 implementation before
> deciding on this patch.
>
> This patch is to handle the aliasing. The commit message isn't clear
> (I'll fix that up) but this patch is required to handle the new alias
> method instead of the previous swapping.
>
> Alistair
>
> > Jonathan
> >
> > On Wed, Sep 11, 2019 at 4:24 AM Palmer Dabbelt <palmer@sifive.com>
> wrote:
> >>
> >> On Fri, 23 Aug 2019 16:38:15 PDT (-0700), Alistair Francis wrote:
> >> > To handle the new Hypervisor CSR register swapping let's use pointers.
> >> >
> >> > We only need to convert the MIE and MSTATUS CSRs. With the exception
> of
> >> > MIP all of the other CSRs that swap with virtulsation changes are
> S-Mode
> >> > only, so we can just do a lazy switch. This because more challenging
> for
> >> > the M-Mode registers so it ends up being easier to use pointers.
> >> >
> >> > As the MIP CSR is always accessed atomicly the pointer swap doesn't
> work
> >> > so we leave that as is.
> >> >
> >> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> >> > ---
> >> >  target/riscv/cpu.c        | 16 ++++++++++++----
> >> >  target/riscv/cpu.h        | 12 ++++++++++--
> >> >  target/riscv/cpu_helper.c | 32 ++++++++++++++++----------------
> >> >  target/riscv/csr.c        | 28 ++++++++++++++--------------
> >> >  target/riscv/op_helper.c  | 14 +++++++-------
> >> >  5 files changed, 59 insertions(+), 43 deletions(-)
> >> >
> >> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> >> > index be8f643fc2..371d5845af 100644
> >> > --- a/target/riscv/cpu.c
> >> > +++ b/target/riscv/cpu.c
> >> > @@ -228,7 +228,7 @@ static void riscv_cpu_dump_state(CPUState *cs,
> FILE *f, int flags)
> >> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
> >> >  #ifndef CONFIG_USER_ONLY
> >> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ",
> env->mhartid);
> >> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ",
> env->mstatus);
> >> > +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ",
> *env->mstatus);
> >> >      if (riscv_has_ext(env, RVH)) {
> >> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ",
> env->hstatus);
> >> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ",
> env->vsstatus);
> >> > @@ -239,7 +239,7 @@ static void riscv_cpu_dump_state(CPUState *cs,
> FILE *f, int flags)
> >> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsip    ",
> >> >                       (target_ulong)atomic_read(&env->vsip));
> >> >      }
> >> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> >> > +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ",
> *env->mie);
> >> >      if (riscv_has_ext(env, RVH)) {
> >> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsie    ",
> env->vsie);
> >> >      }
> >> > @@ -309,7 +309,7 @@ static bool riscv_cpu_has_work(CPUState *cs)
> >> >       * Definition of the WFI instruction requires it to ignore the
> privilege
> >> >       * mode and delegation registers, but respect individual enables
> >> >       */
> >> > -    return (atomic_read(&env->mip) & env->mie) != 0;
> >> > +    return (atomic_read(&env->mip) & *env->mie) != 0;
> >> >  #else
> >> >      return true;
> >> >  #endif
> >> > @@ -330,7 +330,7 @@ static void riscv_cpu_reset(CPUState *cs)
> >> >      mcc->parent_reset(cs);
> >> >  #ifndef CONFIG_USER_ONLY
> >> >      env->priv = PRV_M;
> >> > -    env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
> >> > +    *env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
> >> >      env->mcause = 0;
> >> >      env->pc = env->resetvec;
> >> >  #endif
> >> > @@ -459,8 +459,16 @@ static void riscv_cpu_realize(DeviceState *dev,
> Error **errp)
> >> >  static void riscv_cpu_init(Object *obj)
> >> >  {
> >> >      RISCVCPU *cpu = RISCV_CPU(obj);
> >> > +#ifndef CONFIG_USER_ONLY
> >> > +    CPURISCVState *env = &cpu->env;
> >> > +#endif
> >> >
> >> >      cpu_set_cpustate_pointers(cpu);
> >> > +
> >> > +#ifndef CONFIG_USER_ONLY
> >> > +    env->mie = &env->mie_novirt;
> >> > +    env->mstatus = &env->mstatus_novirt;
> >> > +#endif
> >> >  }
> >> >
> >> >  static const VMStateDescription vmstate_riscv_cpu = {
> >> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> >> > index 4c342e7a79..680592cb60 100644
> >> > --- a/target/riscv/cpu.h
> >> > +++ b/target/riscv/cpu.h
> >> > @@ -122,7 +122,7 @@ struct CPURISCVState {
> >> >      target_ulong resetvec;
> >> >
> >> >      target_ulong mhartid;
> >> > -    target_ulong mstatus;
> >> > +    target_ulong *mstatus;
> >> >
> >> >      /*
> >> >       * CAUTION! Unlike the rest of this struct, mip is accessed
> asynchonously
> >> > @@ -136,7 +136,7 @@ struct CPURISCVState {
> >> >      uint32_t mip;
> >> >      uint32_t miclaim;
> >> >
> >> > -    target_ulong mie;
> >> > +    target_ulong *mie;
> >> >      target_ulong mideleg;
> >> >
> >> >      target_ulong sptbr;  /* until: priv-1.9.1 */
> >> > @@ -154,6 +154,14 @@ struct CPURISCVState {
> >> >      target_ulong mcause;
> >> >      target_ulong mtval;  /* since: priv-1.10.0 */
> >> >
> >> > +    /* The following registers are the "real" versions that the
> pointer
> >> > +     * versions point to. These should never be used unless you know
> what you
> >> > +     * are doing. To access these use the pointer versions instead.
> This is
> >> > +     * required to handle the Hypervisor register swapping.
> >> > +     */
> >> > +    target_ulong mie_novirt;
> >> > +    target_ulong mstatus_novirt;
> >> > +
> >> >      /* Hypervisor CSRs */
> >> >      target_ulong hstatus;
> >> >      target_ulong hedeleg;
> >> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> >> > index 5bcfc2e090..c597523d74 100644
> >> > --- a/target/riscv/cpu_helper.c
> >> > +++ b/target/riscv/cpu_helper.c
> >> > @@ -36,9 +36,9 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool
> ifetch)
> >> >  #ifndef CONFIG_USER_ONLY
> >> >  static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> >> >  {
> >> > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> >> > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> >> > -    target_ulong pending = atomic_read(&env->mip) & env->mie;
> >> > +    target_ulong mstatus_mie = get_field(*env->mstatus, MSTATUS_MIE);
> >> > +    target_ulong mstatus_sie = get_field(*env->mstatus, MSTATUS_SIE);
> >> > +    target_ulong pending = atomic_read(env->mip) & *env->mie;
> >> >      target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M &&
> mstatus_mie);
> >> >      target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S &&
> mstatus_sie);
> >> >      target_ulong irqs = (pending & ~env->mideleg & -mie) |
> >> > @@ -74,7 +74,7 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int
> interrupt_request)
> >> >  /* Return true is floating point support is currently enabled */
> >> >  bool riscv_cpu_fp_enabled(CPURISCVState *env)
> >> >  {
> >> > -    if (env->mstatus & MSTATUS_FS) {
> >> > +    if (*env->mstatus & MSTATUS_FS) {
> >> >          return true;
> >> >      }
> >> >
> >> > @@ -219,8 +219,8 @@ static int get_physical_address(CPURISCVState
> *env, hwaddr *physical,
> >> >      int mode = mmu_idx;
> >> >
> >> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
> >> > -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
> >> > -            mode = get_field(env->mstatus, MSTATUS_MPP);
> >> > +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> >> > +            mode = get_field(*env->mstatus, MSTATUS_MPP);
> >> >          }
> >> >      }
> >> >
> >> > @@ -234,11 +234,11 @@ static int get_physical_address(CPURISCVState
> *env, hwaddr *physical,
> >> >
> >> >      target_ulong base;
> >> >      int levels, ptidxbits, ptesize, vm, sum;
> >> > -    int mxr = get_field(env->mstatus, MSTATUS_MXR);
> >> > +    int mxr = get_field(*env->mstatus, MSTATUS_MXR);
> >> >
> >> >      if (env->priv_ver >= PRIV_VERSION_1_10_0) {
> >> >          base = get_field(env->satp, SATP_PPN) << PGSHIFT;
> >> > -        sum = get_field(env->mstatus, MSTATUS_SUM);
> >> > +        sum = get_field(*env->mstatus, MSTATUS_SUM);
> >> >          vm = get_field(env->satp, SATP_MODE);
> >> >          switch (vm) {
> >> >          case VM_1_10_SV32:
> >> > @@ -258,8 +258,8 @@ static int get_physical_address(CPURISCVState
> *env, hwaddr *physical,
> >> >          }
> >> >      } else {
> >> >          base = env->sptbr << PGSHIFT;
> >> > -        sum = !get_field(env->mstatus, MSTATUS_PUM);
> >> > -        vm = get_field(env->mstatus, MSTATUS_VM);
> >> > +        sum = !get_field(*env->mstatus, MSTATUS_PUM);
> >> > +        vm = get_field(*env->mstatus, MSTATUS_VM);
> >> >          switch (vm) {
> >> >          case VM_1_09_SV32:
> >> >            levels = 2; ptidxbits = 10; ptesize = 4; break;
> >> > @@ -505,8 +505,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr
> address, int size,
> >> >      ret = get_physical_address(env, &pa, &prot, address,
> access_type, mmu_idx);
> >> >
> >> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
> >> > -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
> >> > -            mode = get_field(env->mstatus, MSTATUS_MPP);
> >> > +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> >> > +            mode = get_field(*env->mstatus, MSTATUS_MPP);
> >> >          }
> >> >      }
> >> >
> >> > @@ -606,12 +606,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> >> >      if (env->priv <= PRV_S &&
> >> >              cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
> >> >          /* handle the trap in S-mode */
> >> > -        target_ulong s = env->mstatus;
> >> > +        target_ulong s = *env->mstatus;
> >> >          s = set_field(s, MSTATUS_SPIE, env->priv_ver >=
> PRIV_VERSION_1_10_0 ?
> >> >              get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE <<
> env->priv));
> >> >          s = set_field(s, MSTATUS_SPP, env->priv);
> >> >          s = set_field(s, MSTATUS_SIE, 0);
> >> > -        env->mstatus = s;
> >> > +        *env->mstatus = s;
> >> >          env->scause = cause | ((target_ulong)async <<
> (TARGET_LONG_BITS - 1));
> >> >          env->sepc = env->pc;
> >> >          env->sbadaddr = tval;
> >> > @@ -620,12 +620,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> >> >          riscv_cpu_set_mode(env, PRV_S);
> >> >      } else {
> >> >          /* handle the trap in M-mode */
> >> > -        target_ulong s = env->mstatus;
> >> > +        target_ulong s = *env->mstatus;
> >> >          s = set_field(s, MSTATUS_MPIE, env->priv_ver >=
> PRIV_VERSION_1_10_0 ?
> >> >              get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE <<
> env->priv));
> >> >          s = set_field(s, MSTATUS_MPP, env->priv);
> >> >          s = set_field(s, MSTATUS_MIE, 0);
> >> > -        env->mstatus = s;
> >> > +        *env->mstatus = s;
> >> >          env->mcause = cause | ~(((target_ulong)-1) >> async);
> >> >          env->mepc = env->pc;
> >> >          env->mbadaddr = tval;
> >> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> >> > index e2e908fbc0..30ec8c0a8e 100644
> >> > --- a/target/riscv/csr.c
> >> > +++ b/target/riscv/csr.c
> >> > @@ -136,7 +136,7 @@ static int write_fflags(CPURISCVState *env, int
> csrno, target_ulong val)
> >> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
> >> >          return -1;
> >> >      }
> >> > -    env->mstatus |= MSTATUS_FS;
> >> > +    *env->mstatus |= MSTATUS_FS;
> >> >  #endif
> >> >      riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
> >> >      return 0;
> >> > @@ -159,7 +159,7 @@ static int write_frm(CPURISCVState *env, int
> csrno, target_ulong val)
> >> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
> >> >          return -1;
> >> >      }
> >> > -    env->mstatus |= MSTATUS_FS;
> >> > +    *env->mstatus |= MSTATUS_FS;
> >> >  #endif
> >> >      env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
> >> >      return 0;
> >> > @@ -183,7 +183,7 @@ static int write_fcsr(CPURISCVState *env, int
> csrno, target_ulong val)
> >> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
> >> >          return -1;
> >> >      }
> >> > -    env->mstatus |= MSTATUS_FS;
> >> > +    *env->mstatus |= MSTATUS_FS;
> >> >  #endif
> >> >      env->frm = (val & FSR_RD) >> FSR_RD_SHIFT;
> >> >      riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
> >> > @@ -307,7 +307,7 @@ static int read_mhartid(CPURISCVState *env, int
> csrno, target_ulong *val)
> >> >  /* Machine Trap Setup */
> >> >  static int read_mstatus(CPURISCVState *env, int csrno, target_ulong
> *val)
> >> >  {
> >> > -    *val = env->mstatus;
> >> > +    *val = *env->mstatus;
> >> >      return 0;
> >> >  }
> >> >
> >> > @@ -319,7 +319,7 @@ static int validate_vm(CPURISCVState *env,
> target_ulong vm)
> >> >
> >> >  static int write_mstatus(CPURISCVState *env, int csrno, target_ulong
> val)
> >> >  {
> >> > -    target_ulong mstatus = env->mstatus;
> >> > +    target_ulong mstatus = *env->mstatus;
> >> >      target_ulong mask = 0;
> >> >      int dirty;
> >> >
> >> > @@ -359,7 +359,7 @@ static int write_mstatus(CPURISCVState *env, int
> csrno, target_ulong val)
> >> >               ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
> >> >              ((mstatus & MSTATUS_XS) == MSTATUS_XS);
> >> >      mstatus = set_field(mstatus, MSTATUS_SD, dirty);
> >> > -    env->mstatus = mstatus;
> >> > +    *env->mstatus = mstatus;
> >> >
> >> >      return 0;
> >> >  }
> >> > @@ -448,13 +448,13 @@ static int write_mideleg(CPURISCVState *env,
> int csrno, target_ulong val)
> >> >
> >> >  static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
> >> >  {
> >> > -    *val = env->mie;
> >> > +    *val = *env->mie;
> >> >      return 0;
> >> >  }
> >> >
> >> >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
> >> >  {
> >> > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> >> > +    *env->mie = (*env->mie & ~all_ints) | (val & all_ints);
> >> >      return 0;
> >> >  }
> >> >
> >> > @@ -608,7 +608,7 @@ static int read_sstatus(CPURISCVState *env, int
> csrno, target_ulong *val)
> >> >  {
> >> >      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
> >> >                           sstatus_v1_10_mask : sstatus_v1_9_mask);
> >> > -    *val = env->mstatus & mask;
> >> > +    *val = *env->mstatus & mask;
> >> >      return 0;
> >> >  }
> >> >
> >> > @@ -616,19 +616,19 @@ static int write_sstatus(CPURISCVState *env,
> int csrno, target_ulong val)
> >> >  {
> >> >      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
> >> >                           sstatus_v1_10_mask : sstatus_v1_9_mask);
> >> > -    target_ulong newval = (env->mstatus & ~mask) | (val & mask);
> >> > +    target_ulong newval = (*env->mstatus & ~mask) | (val & mask);
> >> >      return write_mstatus(env, CSR_MSTATUS, newval);
> >> >  }
> >> >
> >> >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
> >> >  {
> >> > -    *val = env->mie & env->mideleg;
> >> > +    *val = *env->mie & env->mideleg;
> >> >      return 0;
> >> >  }
> >> >
> >> >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
> >> >  {
> >> > -    target_ulong newval = (env->mie & ~env->mideleg) | (val &
> env->mideleg);
> >> > +    target_ulong newval = (*env->mie & ~env->mideleg) | (val &
> env->mideleg);
> >> >      return write_mie(env, CSR_MIE, newval);
> >> >  }
> >> >
> >> > @@ -731,7 +731,7 @@ static int read_satp(CPURISCVState *env, int
> csrno, target_ulong *val)
> >> >      if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
> >> >          *val = 0;
> >> >      } else if (env->priv_ver >= PRIV_VERSION_1_10_0) {
> >> > -        if (env->priv == PRV_S && get_field(env->mstatus,
> MSTATUS_TVM)) {
> >> > +        if (env->priv == PRV_S && get_field(*env->mstatus,
> MSTATUS_TVM)) {
> >> >              return -1;
> >> >          } else {
> >> >              *val = env->satp;
> >> > @@ -756,7 +756,7 @@ static int write_satp(CPURISCVState *env, int
> csrno, target_ulong val)
> >> >          validate_vm(env, get_field(val, SATP_MODE)) &&
> >> >          ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
> >> >      {
> >> > -        if (env->priv == PRV_S && get_field(env->mstatus,
> MSTATUS_TVM)) {
> >> > +        if (env->priv == PRV_S && get_field(*env->mstatus,
> MSTATUS_TVM)) {
> >> >              return -1;
> >> >          } else {
> >> >              if((val ^ env->satp) & SATP_ASID) {
> >> > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> >> > index 331cc36232..d150551bc9 100644
> >> > --- a/target/riscv/op_helper.c
> >> > +++ b/target/riscv/op_helper.c
> >> > @@ -83,11 +83,11 @@ target_ulong helper_sret(CPURISCVState *env,
> target_ulong cpu_pc_deb)
> >> >      }
> >> >
> >> >      if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
> >> > -        get_field(env->mstatus, MSTATUS_TSR)) {
> >> > +        get_field(*env->mstatus, MSTATUS_TSR)) {
> >> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
> >> >      }
> >> >
> >> > -    target_ulong mstatus = env->mstatus;
> >> > +    target_ulong mstatus = *env->mstatus;
> >> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
> >> >      mstatus = set_field(mstatus,
> >> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
> >> > @@ -96,7 +96,7 @@ target_ulong helper_sret(CPURISCVState *env,
> target_ulong cpu_pc_deb)
> >> >      mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
> >> >      mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
> >> >      riscv_cpu_set_mode(env, prev_priv);
> >> > -    env->mstatus = mstatus;
> >> > +    *env->mstatus = mstatus;
> >> >
> >> >      return retpc;
> >> >  }
> >> > @@ -112,7 +112,7 @@ target_ulong helper_mret(CPURISCVState *env,
> target_ulong cpu_pc_deb)
> >> >          riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS,
> GETPC());
> >> >      }
> >> >
> >> > -    target_ulong mstatus = env->mstatus;
> >> > +    target_ulong mstatus = *env->mstatus;
> >> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
> >> >      mstatus = set_field(mstatus,
> >> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
> >> > @@ -121,7 +121,7 @@ target_ulong helper_mret(CPURISCVState *env,
> target_ulong cpu_pc_deb)
> >> >      mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
> >> >      mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
> >> >      riscv_cpu_set_mode(env, prev_priv);
> >> > -    env->mstatus = mstatus;
> >> > +    *env->mstatus = mstatus;
> >> >
> >> >      return retpc;
> >> >  }
> >> > @@ -132,7 +132,7 @@ void helper_wfi(CPURISCVState *env)
> >> >
> >> >      if (env->priv == PRV_S &&
> >> >          env->priv_ver >= PRIV_VERSION_1_10_0 &&
> >> > -        get_field(env->mstatus, MSTATUS_TW)) {
> >> > +        get_field(*env->mstatus, MSTATUS_TW)) {
> >> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
> >> >      } else {
> >> >          cs->halted = 1;
> >> > @@ -147,7 +147,7 @@ void helper_tlb_flush(CPURISCVState *env)
> >> >      if (!(env->priv >= PRV_S) ||
> >> >          (env->priv == PRV_S &&
> >> >           env->priv_ver >= PRIV_VERSION_1_10_0 &&
> >> > -         get_field(env->mstatus, MSTATUS_TVM))) {
> >> > +         get_field(*env->mstatus, MSTATUS_TVM))) {
> >> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
> >> >      } else {
> >> >          tlb_flush(cs);
> >>
> >> I don't think this is that bad.
> >>
> >> Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
> >>
>

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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-09-18  1:59         ` Jonathan Behrens
@ 2019-09-18 23:47           ` Alistair Francis
  2019-09-19 14:50             ` Richard Henderson
  0 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-09-18 23:47 UTC (permalink / raw)
  To: Jonathan Behrens
  Cc: Palmer Dabbelt, open list:RISC-V, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis

On Tue, Sep 17, 2019 at 7:00 PM Jonathan Behrens <fintelia@gmail.com> wrote:
>
> I went through the uses of mie in the entire hypervisor patch series and it seems like it would be much simpler to just have two non-pointer fields in the CPU struct: mie and vsie. To if an interrupt is pending, you are either running with V=0 in which case the contents of vsie can be ignored, or you are running with V=1 and have to check both anyway. And the read_sie/write_sie would just need a single extra branch return proper results. The read_mie and write_mie function wouldn't need to be changed at all: if M-mode is running to access them, then V=0. (When queried from a debugger while V=1, I think the result would actually be more correct this way: the bits of mie are supposed to always reflect sie rather than vsie).

Hello Jonathan,

Pleas make sure you reply inline, otherwise it is difficult to track
the order of messages. Can you also please wrap your lines at 80
characters.

What about in the future when some other extension does something with
mie? I would rather not have conditionals around accessing core CSRs
(hence the pointer way).

The other problem is mstatus, which is more confusing. I am trying to
keep mie and mstatus (and eventually mip) all the same. Having
different styles for different CSRs also seems confusing. Granted it
is now different between the m/s and s only CSRs, but that seems
unavoidable.

I'm not a fan of the pointer method that I'm using, but to me it seems
the least worst in terms of handling future code, keeping everythign
consistnent and avoiding complex access rules.

Alistair

>
> Jonathan
>
> On Tue, Sep 17, 2019 at 7:37 PM Alistair Francis <alistair23@gmail.com> wrote:
>>
>> On Wed, Sep 11, 2019 at 7:55 AM Jonathan Behrens <fintelia@gmail.com> wrote:
>> >
>> > Version 0.4 of the hypervisor spec no longer talks about swapping registers. Instead when running in VS-mode some of the supervisor registers are "aliased" and actually refer to alternate versions. Implementations are of course still allowed to do swapping internally if desired, but it adds complexity compared to a more straightforward implementation and isn't obvious to me whether QEMU would get any benefit from it. At least, it is probably worth fleshing out the rest of the v0.4 implementation before deciding on this patch.
>>
>> This patch is to handle the aliasing. The commit message isn't clear
>> (I'll fix that up) but this patch is required to handle the new alias
>> method instead of the previous swapping.
>>
>> Alistair
>>
>> > Jonathan
>> >
>> > On Wed, Sep 11, 2019 at 4:24 AM Palmer Dabbelt <palmer@sifive.com> wrote:
>> >>
>> >> On Fri, 23 Aug 2019 16:38:15 PDT (-0700), Alistair Francis wrote:
>> >> > To handle the new Hypervisor CSR register swapping let's use pointers.
>> >> >
>> >> > We only need to convert the MIE and MSTATUS CSRs. With the exception of
>> >> > MIP all of the other CSRs that swap with virtulsation changes are S-Mode
>> >> > only, so we can just do a lazy switch. This because more challenging for
>> >> > the M-Mode registers so it ends up being easier to use pointers.
>> >> >
>> >> > As the MIP CSR is always accessed atomicly the pointer swap doesn't work
>> >> > so we leave that as is.
>> >> >
>> >> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
>> >> > ---
>> >> >  target/riscv/cpu.c        | 16 ++++++++++++----
>> >> >  target/riscv/cpu.h        | 12 ++++++++++--
>> >> >  target/riscv/cpu_helper.c | 32 ++++++++++++++++----------------
>> >> >  target/riscv/csr.c        | 28 ++++++++++++++--------------
>> >> >  target/riscv/op_helper.c  | 14 +++++++-------
>> >> >  5 files changed, 59 insertions(+), 43 deletions(-)
>> >> >
>> >> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
>> >> > index be8f643fc2..371d5845af 100644
>> >> > --- a/target/riscv/cpu.c
>> >> > +++ b/target/riscv/cpu.c
>> >> > @@ -228,7 +228,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>> >> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "pc      ", env->pc);
>> >> >  #ifndef CONFIG_USER_ONLY
>> >> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
>> >> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", env->mstatus);
>> >> > +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", *env->mstatus);
>> >> >      if (riscv_has_ext(env, RVH)) {
>> >> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
>> >> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ", env->vsstatus);
>> >> > @@ -239,7 +239,7 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>> >> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsip    ",
>> >> >                       (target_ulong)atomic_read(&env->vsip));
>> >> >      }
>> >> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
>> >> > +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", *env->mie);
>> >> >      if (riscv_has_ext(env, RVH)) {
>> >> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsie    ", env->vsie);
>> >> >      }
>> >> > @@ -309,7 +309,7 @@ static bool riscv_cpu_has_work(CPUState *cs)
>> >> >       * Definition of the WFI instruction requires it to ignore the privilege
>> >> >       * mode and delegation registers, but respect individual enables
>> >> >       */
>> >> > -    return (atomic_read(&env->mip) & env->mie) != 0;
>> >> > +    return (atomic_read(&env->mip) & *env->mie) != 0;
>> >> >  #else
>> >> >      return true;
>> >> >  #endif
>> >> > @@ -330,7 +330,7 @@ static void riscv_cpu_reset(CPUState *cs)
>> >> >      mcc->parent_reset(cs);
>> >> >  #ifndef CONFIG_USER_ONLY
>> >> >      env->priv = PRV_M;
>> >> > -    env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
>> >> > +    *env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV);
>> >> >      env->mcause = 0;
>> >> >      env->pc = env->resetvec;
>> >> >  #endif
>> >> > @@ -459,8 +459,16 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
>> >> >  static void riscv_cpu_init(Object *obj)
>> >> >  {
>> >> >      RISCVCPU *cpu = RISCV_CPU(obj);
>> >> > +#ifndef CONFIG_USER_ONLY
>> >> > +    CPURISCVState *env = &cpu->env;
>> >> > +#endif
>> >> >
>> >> >      cpu_set_cpustate_pointers(cpu);
>> >> > +
>> >> > +#ifndef CONFIG_USER_ONLY
>> >> > +    env->mie = &env->mie_novirt;
>> >> > +    env->mstatus = &env->mstatus_novirt;
>> >> > +#endif
>> >> >  }
>> >> >
>> >> >  static const VMStateDescription vmstate_riscv_cpu = {
>> >> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
>> >> > index 4c342e7a79..680592cb60 100644
>> >> > --- a/target/riscv/cpu.h
>> >> > +++ b/target/riscv/cpu.h
>> >> > @@ -122,7 +122,7 @@ struct CPURISCVState {
>> >> >      target_ulong resetvec;
>> >> >
>> >> >      target_ulong mhartid;
>> >> > -    target_ulong mstatus;
>> >> > +    target_ulong *mstatus;
>> >> >
>> >> >      /*
>> >> >       * CAUTION! Unlike the rest of this struct, mip is accessed asynchonously
>> >> > @@ -136,7 +136,7 @@ struct CPURISCVState {
>> >> >      uint32_t mip;
>> >> >      uint32_t miclaim;
>> >> >
>> >> > -    target_ulong mie;
>> >> > +    target_ulong *mie;
>> >> >      target_ulong mideleg;
>> >> >
>> >> >      target_ulong sptbr;  /* until: priv-1.9.1 */
>> >> > @@ -154,6 +154,14 @@ struct CPURISCVState {
>> >> >      target_ulong mcause;
>> >> >      target_ulong mtval;  /* since: priv-1.10.0 */
>> >> >
>> >> > +    /* The following registers are the "real" versions that the pointer
>> >> > +     * versions point to. These should never be used unless you know what you
>> >> > +     * are doing. To access these use the pointer versions instead. This is
>> >> > +     * required to handle the Hypervisor register swapping.
>> >> > +     */
>> >> > +    target_ulong mie_novirt;
>> >> > +    target_ulong mstatus_novirt;
>> >> > +
>> >> >      /* Hypervisor CSRs */
>> >> >      target_ulong hstatus;
>> >> >      target_ulong hedeleg;
>> >> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
>> >> > index 5bcfc2e090..c597523d74 100644
>> >> > --- a/target/riscv/cpu_helper.c
>> >> > +++ b/target/riscv/cpu_helper.c
>> >> > @@ -36,9 +36,9 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
>> >> >  #ifndef CONFIG_USER_ONLY
>> >> >  static int riscv_cpu_local_irq_pending(CPURISCVState *env)
>> >> >  {
>> >> > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
>> >> > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
>> >> > -    target_ulong pending = atomic_read(&env->mip) & env->mie;
>> >> > +    target_ulong mstatus_mie = get_field(*env->mstatus, MSTATUS_MIE);
>> >> > +    target_ulong mstatus_sie = get_field(*env->mstatus, MSTATUS_SIE);
>> >> > +    target_ulong pending = atomic_read(env->mip) & *env->mie;
>> >> >      target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie);
>> >> >      target_ulong sie = env->priv < PRV_S || (env->priv == PRV_S && mstatus_sie);
>> >> >      target_ulong irqs = (pending & ~env->mideleg & -mie) |
>> >> > @@ -74,7 +74,7 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
>> >> >  /* Return true is floating point support is currently enabled */
>> >> >  bool riscv_cpu_fp_enabled(CPURISCVState *env)
>> >> >  {
>> >> > -    if (env->mstatus & MSTATUS_FS) {
>> >> > +    if (*env->mstatus & MSTATUS_FS) {
>> >> >          return true;
>> >> >      }
>> >> >
>> >> > @@ -219,8 +219,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>> >> >      int mode = mmu_idx;
>> >> >
>> >> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
>> >> > -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
>> >> > -            mode = get_field(env->mstatus, MSTATUS_MPP);
>> >> > +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
>> >> > +            mode = get_field(*env->mstatus, MSTATUS_MPP);
>> >> >          }
>> >> >      }
>> >> >
>> >> > @@ -234,11 +234,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>> >> >
>> >> >      target_ulong base;
>> >> >      int levels, ptidxbits, ptesize, vm, sum;
>> >> > -    int mxr = get_field(env->mstatus, MSTATUS_MXR);
>> >> > +    int mxr = get_field(*env->mstatus, MSTATUS_MXR);
>> >> >
>> >> >      if (env->priv_ver >= PRIV_VERSION_1_10_0) {
>> >> >          base = get_field(env->satp, SATP_PPN) << PGSHIFT;
>> >> > -        sum = get_field(env->mstatus, MSTATUS_SUM);
>> >> > +        sum = get_field(*env->mstatus, MSTATUS_SUM);
>> >> >          vm = get_field(env->satp, SATP_MODE);
>> >> >          switch (vm) {
>> >> >          case VM_1_10_SV32:
>> >> > @@ -258,8 +258,8 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>> >> >          }
>> >> >      } else {
>> >> >          base = env->sptbr << PGSHIFT;
>> >> > -        sum = !get_field(env->mstatus, MSTATUS_PUM);
>> >> > -        vm = get_field(env->mstatus, MSTATUS_VM);
>> >> > +        sum = !get_field(*env->mstatus, MSTATUS_PUM);
>> >> > +        vm = get_field(*env->mstatus, MSTATUS_VM);
>> >> >          switch (vm) {
>> >> >          case VM_1_09_SV32:
>> >> >            levels = 2; ptidxbits = 10; ptesize = 4; break;
>> >> > @@ -505,8 +505,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>> >> >      ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
>> >> >
>> >> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
>> >> > -        if (get_field(env->mstatus, MSTATUS_MPRV)) {
>> >> > -            mode = get_field(env->mstatus, MSTATUS_MPP);
>> >> > +        if (get_field(*env->mstatus, MSTATUS_MPRV)) {
>> >> > +            mode = get_field(*env->mstatus, MSTATUS_MPP);
>> >> >          }
>> >> >      }
>> >> >
>> >> > @@ -606,12 +606,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>> >> >      if (env->priv <= PRV_S &&
>> >> >              cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
>> >> >          /* handle the trap in S-mode */
>> >> > -        target_ulong s = env->mstatus;
>> >> > +        target_ulong s = *env->mstatus;
>> >> >          s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
>> >> >              get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
>> >> >          s = set_field(s, MSTATUS_SPP, env->priv);
>> >> >          s = set_field(s, MSTATUS_SIE, 0);
>> >> > -        env->mstatus = s;
>> >> > +        *env->mstatus = s;
>> >> >          env->scause = cause | ((target_ulong)async << (TARGET_LONG_BITS - 1));
>> >> >          env->sepc = env->pc;
>> >> >          env->sbadaddr = tval;
>> >> > @@ -620,12 +620,12 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>> >> >          riscv_cpu_set_mode(env, PRV_S);
>> >> >      } else {
>> >> >          /* handle the trap in M-mode */
>> >> > -        target_ulong s = env->mstatus;
>> >> > +        target_ulong s = *env->mstatus;
>> >> >          s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
>> >> >              get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
>> >> >          s = set_field(s, MSTATUS_MPP, env->priv);
>> >> >          s = set_field(s, MSTATUS_MIE, 0);
>> >> > -        env->mstatus = s;
>> >> > +        *env->mstatus = s;
>> >> >          env->mcause = cause | ~(((target_ulong)-1) >> async);
>> >> >          env->mepc = env->pc;
>> >> >          env->mbadaddr = tval;
>> >> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
>> >> > index e2e908fbc0..30ec8c0a8e 100644
>> >> > --- a/target/riscv/csr.c
>> >> > +++ b/target/riscv/csr.c
>> >> > @@ -136,7 +136,7 @@ static int write_fflags(CPURISCVState *env, int csrno, target_ulong val)
>> >> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>> >> >          return -1;
>> >> >      }
>> >> > -    env->mstatus |= MSTATUS_FS;
>> >> > +    *env->mstatus |= MSTATUS_FS;
>> >> >  #endif
>> >> >      riscv_cpu_set_fflags(env, val & (FSR_AEXC >> FSR_AEXC_SHIFT));
>> >> >      return 0;
>> >> > @@ -159,7 +159,7 @@ static int write_frm(CPURISCVState *env, int csrno, target_ulong val)
>> >> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>> >> >          return -1;
>> >> >      }
>> >> > -    env->mstatus |= MSTATUS_FS;
>> >> > +    *env->mstatus |= MSTATUS_FS;
>> >> >  #endif
>> >> >      env->frm = val & (FSR_RD >> FSR_RD_SHIFT);
>> >> >      return 0;
>> >> > @@ -183,7 +183,7 @@ static int write_fcsr(CPURISCVState *env, int csrno, target_ulong val)
>> >> >      if (!env->debugger && !riscv_cpu_fp_enabled(env)) {
>> >> >          return -1;
>> >> >      }
>> >> > -    env->mstatus |= MSTATUS_FS;
>> >> > +    *env->mstatus |= MSTATUS_FS;
>> >> >  #endif
>> >> >      env->frm = (val & FSR_RD) >> FSR_RD_SHIFT;
>> >> >      riscv_cpu_set_fflags(env, (val & FSR_AEXC) >> FSR_AEXC_SHIFT);
>> >> > @@ -307,7 +307,7 @@ static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val)
>> >> >  /* Machine Trap Setup */
>> >> >  static int read_mstatus(CPURISCVState *env, int csrno, target_ulong *val)
>> >> >  {
>> >> > -    *val = env->mstatus;
>> >> > +    *val = *env->mstatus;
>> >> >      return 0;
>> >> >  }
>> >> >
>> >> > @@ -319,7 +319,7 @@ static int validate_vm(CPURISCVState *env, target_ulong vm)
>> >> >
>> >> >  static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
>> >> >  {
>> >> > -    target_ulong mstatus = env->mstatus;
>> >> > +    target_ulong mstatus = *env->mstatus;
>> >> >      target_ulong mask = 0;
>> >> >      int dirty;
>> >> >
>> >> > @@ -359,7 +359,7 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
>> >> >               ((mstatus & MSTATUS_FS) == MSTATUS_FS)) |
>> >> >              ((mstatus & MSTATUS_XS) == MSTATUS_XS);
>> >> >      mstatus = set_field(mstatus, MSTATUS_SD, dirty);
>> >> > -    env->mstatus = mstatus;
>> >> > +    *env->mstatus = mstatus;
>> >> >
>> >> >      return 0;
>> >> >  }
>> >> > @@ -448,13 +448,13 @@ static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
>> >> >
>> >> >  static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
>> >> >  {
>> >> > -    *val = env->mie;
>> >> > +    *val = *env->mie;
>> >> >      return 0;
>> >> >  }
>> >> >
>> >> >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
>> >> >  {
>> >> > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
>> >> > +    *env->mie = (*env->mie & ~all_ints) | (val & all_ints);
>> >> >      return 0;
>> >> >  }
>> >> >
>> >> > @@ -608,7 +608,7 @@ static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
>> >> >  {
>> >> >      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
>> >> >                           sstatus_v1_10_mask : sstatus_v1_9_mask);
>> >> > -    *val = env->mstatus & mask;
>> >> > +    *val = *env->mstatus & mask;
>> >> >      return 0;
>> >> >  }
>> >> >
>> >> > @@ -616,19 +616,19 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
>> >> >  {
>> >> >      target_ulong mask = ((env->priv_ver >= PRIV_VERSION_1_10_0) ?
>> >> >                           sstatus_v1_10_mask : sstatus_v1_9_mask);
>> >> > -    target_ulong newval = (env->mstatus & ~mask) | (val & mask);
>> >> > +    target_ulong newval = (*env->mstatus & ~mask) | (val & mask);
>> >> >      return write_mstatus(env, CSR_MSTATUS, newval);
>> >> >  }
>> >> >
>> >> >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
>> >> >  {
>> >> > -    *val = env->mie & env->mideleg;
>> >> > +    *val = *env->mie & env->mideleg;
>> >> >      return 0;
>> >> >  }
>> >> >
>> >> >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
>> >> >  {
>> >> > -    target_ulong newval = (env->mie & ~env->mideleg) | (val & env->mideleg);
>> >> > +    target_ulong newval = (*env->mie & ~env->mideleg) | (val & env->mideleg);
>> >> >      return write_mie(env, CSR_MIE, newval);
>> >> >  }
>> >> >
>> >> > @@ -731,7 +731,7 @@ static int read_satp(CPURISCVState *env, int csrno, target_ulong *val)
>> >> >      if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
>> >> >          *val = 0;
>> >> >      } else if (env->priv_ver >= PRIV_VERSION_1_10_0) {
>> >> > -        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
>> >> > +        if (env->priv == PRV_S && get_field(*env->mstatus, MSTATUS_TVM)) {
>> >> >              return -1;
>> >> >          } else {
>> >> >              *val = env->satp;
>> >> > @@ -756,7 +756,7 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
>> >> >          validate_vm(env, get_field(val, SATP_MODE)) &&
>> >> >          ((val ^ env->satp) & (SATP_MODE | SATP_ASID | SATP_PPN)))
>> >> >      {
>> >> > -        if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
>> >> > +        if (env->priv == PRV_S && get_field(*env->mstatus, MSTATUS_TVM)) {
>> >> >              return -1;
>> >> >          } else {
>> >> >              if((val ^ env->satp) & SATP_ASID) {
>> >> > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
>> >> > index 331cc36232..d150551bc9 100644
>> >> > --- a/target/riscv/op_helper.c
>> >> > +++ b/target/riscv/op_helper.c
>> >> > @@ -83,11 +83,11 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>> >> >      }
>> >> >
>> >> >      if (env->priv_ver >= PRIV_VERSION_1_10_0 &&
>> >> > -        get_field(env->mstatus, MSTATUS_TSR)) {
>> >> > +        get_field(*env->mstatus, MSTATUS_TSR)) {
>> >> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>> >> >      }
>> >> >
>> >> > -    target_ulong mstatus = env->mstatus;
>> >> > +    target_ulong mstatus = *env->mstatus;
>> >> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
>> >> >      mstatus = set_field(mstatus,
>> >> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
>> >> > @@ -96,7 +96,7 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>> >> >      mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
>> >> >      mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
>> >> >      riscv_cpu_set_mode(env, prev_priv);
>> >> > -    env->mstatus = mstatus;
>> >> > +    *env->mstatus = mstatus;
>> >> >
>> >> >      return retpc;
>> >> >  }
>> >> > @@ -112,7 +112,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>> >> >          riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC());
>> >> >      }
>> >> >
>> >> > -    target_ulong mstatus = env->mstatus;
>> >> > +    target_ulong mstatus = *env->mstatus;
>> >> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
>> >> >      mstatus = set_field(mstatus,
>> >> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
>> >> > @@ -121,7 +121,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>> >> >      mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
>> >> >      mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
>> >> >      riscv_cpu_set_mode(env, prev_priv);
>> >> > -    env->mstatus = mstatus;
>> >> > +    *env->mstatus = mstatus;
>> >> >
>> >> >      return retpc;
>> >> >  }
>> >> > @@ -132,7 +132,7 @@ void helper_wfi(CPURISCVState *env)
>> >> >
>> >> >      if (env->priv == PRV_S &&
>> >> >          env->priv_ver >= PRIV_VERSION_1_10_0 &&
>> >> > -        get_field(env->mstatus, MSTATUS_TW)) {
>> >> > +        get_field(*env->mstatus, MSTATUS_TW)) {
>> >> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>> >> >      } else {
>> >> >          cs->halted = 1;
>> >> > @@ -147,7 +147,7 @@ void helper_tlb_flush(CPURISCVState *env)
>> >> >      if (!(env->priv >= PRV_S) ||
>> >> >          (env->priv == PRV_S &&
>> >> >           env->priv_ver >= PRIV_VERSION_1_10_0 &&
>> >> > -         get_field(env->mstatus, MSTATUS_TVM))) {
>> >> > +         get_field(*env->mstatus, MSTATUS_TVM))) {
>> >> >          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>> >> >      } else {
>> >> >          tlb_flush(cs);
>> >>
>> >> I don't think this is that bad.
>> >>
>> >> Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
>> >>


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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-09-18 23:47           ` Alistair Francis
@ 2019-09-19 14:50             ` Richard Henderson
  2019-09-19 16:58               ` Jonathan Behrens
  0 siblings, 1 reply; 75+ messages in thread
From: Richard Henderson @ 2019-09-19 14:50 UTC (permalink / raw)
  To: Alistair Francis, Jonathan Behrens
  Cc: Palmer Dabbelt, open list:RISC-V, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis

On 9/18/19 4:47 PM, Alistair Francis wrote:
> I'm not a fan of the pointer method that I'm using, but to me it seems
> the least worst in terms of handling future code, keeping everythign
> consistnent and avoiding complex access rules.

FWIW, I prefer the "banked" register method used by ARM.

enum {
    M_REG_NS = 0,    /* non-secure mode */
    M_REG_S = 1,     /* secure mode */
    M_REG_NUM_BANKS = 2,
};

...

        uint32_t vecbase[M_REG_NUM_BANKS];
        uint32_t basepri[M_REG_NUM_BANKS];
        uint32_t control[M_REG_NUM_BANKS];

The major difference that I see is that a pointer can only represent a single
state at a single time.  With an index, different parts of the code can ask
different questions that may have different states.  E.g. "are we currently in
secure mode" vs "will the exception return to secure mode".


r~


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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-09-19 14:50             ` Richard Henderson
@ 2019-09-19 16:58               ` Jonathan Behrens
  2019-10-25 20:28                 ` Alistair Francis
  0 siblings, 1 reply; 75+ messages in thread
From: Jonathan Behrens @ 2019-09-19 16:58 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Palmer Dabbelt, open list:RISC-V, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Alistair Francis

On Thu, Sep 19, 2019 at 10:50 AM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 9/18/19 4:47 PM, Alistair Francis wrote:
> > I'm not a fan of the pointer method that I'm using, but to me it seems
> > the least worst in terms of handling future code, keeping everythign
> > consistnent and avoiding complex access rules.
>
> FWIW, I prefer the "banked" register method used by ARM.
>
> enum {
>     M_REG_NS = 0,    /* non-secure mode */
>     M_REG_S = 1,     /* secure mode */
>     M_REG_NUM_BANKS = 2,
> };
>
> ...
>
>         uint32_t vecbase[M_REG_NUM_BANKS];
>         uint32_t basepri[M_REG_NUM_BANKS];
>         uint32_t control[M_REG_NUM_BANKS];
>
> The major difference that I see is that a pointer can only represent a single
> state at a single time.  With an index, different parts of the code can ask
> different questions that may have different states.  E.g. "are we currently in
> secure mode" vs "will the exception return to secure mode".

This makes a lot of sense to me. It means that any individual control register
has an unambiguous name that doesn't change based on context. They aren't quite
the same names as used in the architecture specification (mie & vsie
vs. mie[NOVIRT] & mie[VIRT]), but they are reasonably close. It also means other
parts of the code can't ignore that there are two different versions of the
registers in play. Perhaps the biggest benefit though is that you can sidestep
swapping on mode changes *and* avoid needing any super fancy logic in the access
functions:

int read_mstatus(...) {
    target_ulong novirt_mask = ...;
    *val = env->mstatus[NOVIRT] & novirt_mask | env->mstatus[virt_mode()];
}

int read_vsstatus(...) {
    *val = env->mstatus[VIRT];
}

int write_mstatus(...) {
    ...
    target_ulong novirt_mask = ...;
    env->mstatus[NOVIRT] = (env->mstatus[NOVIRT] & ~novirt_mask) |
                           (newval & novirt_mask);
    env->mstatus[virt_mode()] = (env->mstatus[virt_mode()] & novirt_mask) |
                                (newval & ~novirt_mask);
}


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

* Re: [PATCH v1 16/28] target/riscv: Add hypvervisor trap support
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 16/28] target/riscv: Add hypvervisor trap support Alistair Francis
@ 2019-09-20 14:01   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-09-20 14:01 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:31 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_bits.h   |  4 +--
>  target/riscv/cpu_helper.c | 71 +++++++++++++++++++++++++++++++++------
>  target/riscv/csr.c        |  4 +--
>  3 files changed, 65 insertions(+), 14 deletions(-)
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 5cee72b726..353fc9a24a 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -513,8 +513,8 @@
>  #define RISCV_EXCP_STORE_AMO_ADDR_MIS      0x6
>  #define RISCV_EXCP_STORE_AMO_ACCESS_FAULT  0x7
>  #define RISCV_EXCP_U_ECALL                 0x8
> -#define RISCV_EXCP_S_ECALL                 0x9
> -#define RISCV_EXCP_H_ECALL                 0xa
> +#define RISCV_EXCP_HS_ECALL                0x9
> +#define RISCV_EXCP_VS_ECALL                0xa
>  #define RISCV_EXCP_M_ECALL                 0xb
>  #define RISCV_EXCP_INST_PAGE_FAULT         0xc /* since: priv-1.10.0 */
>  #define RISCV_EXCP_LOAD_PAGE_FAULT         0xd /* since: priv-1.10.0 */
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 8e8b156fc0..17eec6217b 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -668,6 +668,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>
>      RISCVCPU *cpu = RISCV_CPU(cs);
>      CPURISCVState *env = &cpu->env;
> +    target_ulong 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.
> @@ -677,13 +678,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>      target_ulong deleg = async ? env->mideleg : env->medeleg;
>      target_ulong tval = 0;
>
> -    static const int ecall_cause_map[] = {
> -        [PRV_U] = RISCV_EXCP_U_ECALL,
> -        [PRV_S] = RISCV_EXCP_S_ECALL,
> -        [PRV_H] = RISCV_EXCP_H_ECALL,
> -        [PRV_M] = RISCV_EXCP_M_ECALL
> -    };
> -
>      if (!async) {
>          /* set tval to badaddr for traps with address information */
>          switch (cause) {
> @@ -704,7 +698,16 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>          /* ecall is dispatched as one cause so translate based on mode */
>          if (cause == RISCV_EXCP_U_ECALL) {
>              assert(env->priv <= 3);
> -            cause = ecall_cause_map[env->priv];
> +
> +            if (env->priv == PRV_M) {
> +                cause = RISCV_EXCP_M_ECALL;
> +            } else if (env->priv == PRV_S && riscv_cpu_virt_enabled(env)) {
> +                cause = RISCV_EXCP_VS_ECALL;
> +            } else if (env->priv == PRV_S && !riscv_cpu_virt_enabled(env)) {
> +                cause = RISCV_EXCP_HS_ECALL;
> +            } else if (env->priv == PRV_U) {
> +                cause = RISCV_EXCP_U_ECALL;
> +            }
>          }
>      }
>
> @@ -714,7 +717,42 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>      if (env->priv <= PRV_S &&
>              cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
>          /* handle the trap in S-mode */
> -        target_ulong s = *env->mstatus;
> +        if (riscv_has_ext(env, RVH)) {
> +            target_ulong hdeleg = async ? env->hideleg : env->hedeleg;
> +
> +            if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1) &&
> +                !riscv_cpu_force_hs_excep_enabled(env)) {
> +                /* Trap to VS mode */
> +            } else if (riscv_cpu_virt_enabled(env)) {
> +                /* Trap into HS mode, from virt */
> +                riscv_cpu_swap_hypervisor_regs(env);
> +                env->hstatus = set_field(env->hstatus, HSTATUS_SP2V,
> +                                         get_field(env->hstatus, HSTATUS_SPV));
> +                env->hstatus = set_field(env->hstatus, HSTATUS_SP2P,
> +                                         get_field(*env->mstatus, SSTATUS_SPP));
> +                env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
> +                                         riscv_cpu_virt_enabled(env));
> +
> +                if (riscv_cpu_force_hs_excep_enabled(env)) {
> +                    env->hstatus = set_field(env->hstatus, HSTATUS_STL, 1);
> +                } else {
> +                    env->hstatus = set_field(env->hstatus, HSTATUS_STL, 0);
> +                }
> +
> +                riscv_cpu_set_virt_enabled(env, VIRT_OFF);
> +                riscv_cpu_set_force_hs_excep(env, CLEAR_HS_EXCEP);
> +            } else {
> +                /* Trap into HS mode */
> +                env->hstatus = set_field(env->hstatus, HSTATUS_SP2V,
> +                                         get_field(env->hstatus, HSTATUS_SPV));
> +                env->hstatus = set_field(env->hstatus, HSTATUS_SP2P,
> +                                         get_field(*env->mstatus, SSTATUS_SPP));
> +                env->hstatus = set_field(env->hstatus, HSTATUS_SPV,
> +                                         riscv_cpu_virt_enabled(env));
> +            }
> +        }
> +
> +        s = *env->mstatus;
>          s = set_field(s, MSTATUS_SPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
>              get_field(s, MSTATUS_SIE) : get_field(s, MSTATUS_UIE << env->priv));
>          s = set_field(s, MSTATUS_SPP, env->priv);
> @@ -728,7 +766,20 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>          riscv_cpu_set_mode(env, PRV_S);
>      } else {
>          /* handle the trap in M-mode */
> -        target_ulong s = *env->mstatus;
> +        if (riscv_has_ext(env, RVH)) {
> +            if (riscv_cpu_virt_enabled(env)) {
> +                riscv_cpu_swap_hypervisor_regs(env);
> +            }
> +            *env->mstatus = set_field(*env->mstatus, MSTATUS_MPV,
> +                                      riscv_cpu_virt_enabled(env));
> +            *env->mstatus = set_field(*env->mstatus, MSTATUS_MTL,
> +                                      riscv_cpu_force_hs_excep_enabled(env));
> +
> +            /* Trapping to M mode, virt is disabled */
> +            riscv_cpu_set_virt_enabled(env, VIRT_OFF);
> +        }
> +
> +        s = *env->mstatus;
>          s = set_field(s, MSTATUS_MPIE, env->priv_ver >= PRIV_VERSION_1_10_0 ?
>              get_field(s, MSTATUS_MIE) : get_field(s, MSTATUS_UIE << env->priv));
>          s = set_field(s, MSTATUS_MPP, env->priv);
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 30ec8c0a8e..47be4b1d42 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -255,8 +255,8 @@ static const target_ulong delegable_excps =
>      (1ULL << (RISCV_EXCP_STORE_AMO_ADDR_MIS)) |
>      (1ULL << (RISCV_EXCP_STORE_AMO_ACCESS_FAULT)) |
>      (1ULL << (RISCV_EXCP_U_ECALL)) |
> -    (1ULL << (RISCV_EXCP_S_ECALL)) |
> -    (1ULL << (RISCV_EXCP_H_ECALL)) |
> +    (1ULL << (RISCV_EXCP_VS_ECALL)) |
> +    (1ULL << (RISCV_EXCP_HS_ECALL)) |
>      (1ULL << (RISCV_EXCP_M_ECALL)) |
>      (1ULL << (RISCV_EXCP_INST_PAGE_FAULT)) |
>      (1ULL << (RISCV_EXCP_LOAD_PAGE_FAULT)) |

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [PATCH v1 17/28] target/riscv: Add Hypervisor trap return support
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 17/28] target/riscv: Add Hypervisor trap return support Alistair Francis
@ 2019-10-01 18:33   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-01 18:33 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:34 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/op_helper.c | 66 ++++++++++++++++++++++++++++++++--------
>  1 file changed, 54 insertions(+), 12 deletions(-)
>
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index beb34e705b..5bcf5d2ff7 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -73,6 +73,8 @@ target_ulong helper_csrrc(CPURISCVState *env, target_ulong src,
>
>  target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>  {
> +    target_ulong prev_priv, prev_virt, mstatus;
> +
>      if (!(env->priv >= PRV_S)) {
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      }
> @@ -87,16 +89,46 @@ target_ulong helper_sret(CPURISCVState *env, target_ulong cpu_pc_deb)
>          riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
>      }
>
> -    target_ulong mstatus = *env->mstatus;
> -    target_ulong prev_priv = get_field(mstatus, MSTATUS_SPP);
> -    mstatus = set_field(mstatus,
> -        env->priv_ver >= PRIV_VERSION_1_10_0 ?
> -        MSTATUS_SIE : MSTATUS_UIE << prev_priv,
> -        get_field(mstatus, MSTATUS_SPIE));
> -    mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
> -    mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
> +    mstatus = *env->mstatus;
> +
> +    if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
> +        /* We support Hypervisor extensions and virtulisation is disabled */
> +        target_ulong hstatus = env->hstatus;
> +
> +        prev_priv = get_field(mstatus, MSTATUS_SPP);
> +        prev_virt = get_field(hstatus, HSTATUS_SPV);
> +
> +        hstatus = set_field(hstatus, HSTATUS_SPV,
> +                                 get_field(hstatus, HSTATUS_SP2V));
> +        mstatus = set_field(mstatus, MSTATUS_SPP,
> +                            get_field(hstatus, HSTATUS_SP2P));
> +        hstatus = set_field(hstatus, HSTATUS_SP2V, 0);
> +        hstatus = set_field(hstatus, HSTATUS_SP2P, 0);
> +        mstatus = set_field(mstatus, SSTATUS_SIE,
> +                            get_field(mstatus, SSTATUS_SPIE));
> +        mstatus = set_field(mstatus, SSTATUS_SPIE, 1);
> +
> +        *env->mstatus = mstatus;
> +        env->hstatus = hstatus;
> +
> +        if (prev_virt == VIRT_ON) {
> +            riscv_cpu_swap_hypervisor_regs(env);
> +        }
> +
> +        riscv_cpu_set_virt_enabled(env, prev_virt);
> +    } else {
> +        prev_priv = get_field(mstatus, MSTATUS_SPP);
> +
> +        mstatus = set_field(mstatus,
> +            env->priv_ver >= PRIV_VERSION_1_10_0 ?
> +            MSTATUS_SIE : MSTATUS_UIE << prev_priv,
> +            get_field(mstatus, MSTATUS_SPIE));
> +        mstatus = set_field(mstatus, MSTATUS_SPIE, 0);
> +        mstatus = set_field(mstatus, MSTATUS_SPP, PRV_U);
> +        *env->mstatus = mstatus;
> +    }
> +
>      riscv_cpu_set_mode(env, prev_priv);
> -    *env->mstatus = mstatus;
>
>      return retpc;
>  }
> @@ -114,14 +146,24 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>
>      target_ulong mstatus = *env->mstatus;
>      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
> +    target_ulong prev_virt = get_field(mstatus, MSTATUS_MPV);
>      mstatus = set_field(mstatus,
>          env->priv_ver >= PRIV_VERSION_1_10_0 ?
>          MSTATUS_MIE : MSTATUS_UIE << prev_priv,
>          get_field(mstatus, MSTATUS_MPIE));
> -    mstatus = set_field(mstatus, MSTATUS_MPIE, 0);
> -    mstatus = set_field(mstatus, MSTATUS_MPP, PRV_U);
> -    riscv_cpu_set_mode(env, prev_priv);
> +    mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
> +    mstatus = set_field(mstatus, MSTATUS_MPP, 0);
> +    mstatus = set_field(mstatus, MSTATUS_MPV, 0);
>      *env->mstatus = mstatus;
> +    riscv_cpu_set_mode(env, prev_priv);
> +
> +    if (riscv_has_ext(env, RVH)) {
> +        if (prev_virt == VIRT_ON) {
> +            riscv_cpu_swap_hypervisor_regs(env);
> +        }
> +
> +        riscv_cpu_set_virt_enabled(env, prev_virt);
> +    }
>
>      return retpc;
>  }

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [PATCH v1 18/28] target/riscv: Add hfence instructions
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 18/28] target/riscv: Add hfence instructions Alistair Francis
@ 2019-10-01 18:34   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-01 18:34 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:36 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/insn32.decode                    | 23 ++++++-----
>  .../riscv/insn_trans/trans_privileged.inc.c   | 40 +++++++++++++++++++
>  2 files changed, 54 insertions(+), 9 deletions(-)
>
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
> index 77f794ed70..cfd9ca6d2b 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -63,20 +63,25 @@
>  @r2_rm   .......   ..... ..... ... ..... ....... %rs1 %rm %rd
>  @r2      .......   ..... ..... ... ..... ....... %rs1 %rd
>
> +@hfence_gvma ....... ..... .....   ... ..... ....... %rs2 %rs1
> +@hfence_bvma ....... ..... .....   ... ..... ....... %rs2 %rs1
> +
>  @sfence_vma ....... ..... .....   ... ..... ....... %rs2 %rs1
>  @sfence_vm  ....... ..... .....   ... ..... ....... %rs1
>
>
>  # *** Privileged Instructions ***
> -ecall      000000000000     00000 000 00000 1110011
> -ebreak     000000000001     00000 000 00000 1110011
> -uret       0000000    00010 00000 000 00000 1110011
> -sret       0001000    00010 00000 000 00000 1110011
> -hret       0010000    00010 00000 000 00000 1110011
> -mret       0011000    00010 00000 000 00000 1110011
> -wfi        0001000    00101 00000 000 00000 1110011
> -sfence_vma 0001001    ..... ..... 000 00000 1110011 @sfence_vma
> -sfence_vm  0001000    00100 ..... 000 00000 1110011 @sfence_vm
> +ecall       000000000000     00000 000 00000 1110011
> +ebreak      000000000001     00000 000 00000 1110011
> +uret        0000000    00010 00000 000 00000 1110011
> +sret        0001000    00010 00000 000 00000 1110011
> +hret        0010000    00010 00000 000 00000 1110011
> +mret        0011000    00010 00000 000 00000 1110011
> +wfi         0001000    00101 00000 000 00000 1110011
> +hfence_gvma 0110001    ..... ..... 000 00000 1110011 @hfence_gvma
> +hfence_bvma 0010001    ..... ..... 000 00000 1110011 @hfence_bvma
> +sfence_vma  0001001    ..... ..... 000 00000 1110011 @sfence_vma
> +sfence_vm   0001000    00100 ..... 000 00000 1110011 @sfence_vm
>
>  # *** RV32I Base Instruction Set ***
>  lui      ....................       ..... 0110111 @u
> diff --git a/target/riscv/insn_trans/trans_privileged.inc.c b/target/riscv/insn_trans/trans_privileged.inc.c
> index c5e4b3e49a..b9b5a89b52 100644
> --- a/target/riscv/insn_trans/trans_privileged.inc.c
> +++ b/target/riscv/insn_trans/trans_privileged.inc.c
> @@ -108,3 +108,43 @@ static bool trans_sfence_vm(DisasContext *ctx, arg_sfence_vm *a)
>  #endif
>      return false;
>  }
> +
> +static bool trans_hfence_gvma(DisasContext *ctx, arg_sfence_vma *a)
> +{
> +#ifndef CONFIG_USER_ONLY
> +    if (ctx->priv_ver >= PRIV_VERSION_1_10_0 &&
> +        has_ext(ctx, RVH)) {
> +        /* Hpervisor extensions exist */
> +        /*
> +         * if (env->priv == PRV_M ||
> +         *   (env->priv == PRV_S &&
> +         *    !riscv_cpu_virt_enabled(env) &&
> +         *    get_field(ctx->mstatus_fs, MSTATUS_TVM))) {
> +         */
> +            gen_helper_tlb_flush(cpu_env);
> +            return true;
> +        /* } */
> +    }
> +#endif
> +    return false;
> +}
> +
> +static bool trans_hfence_bvma(DisasContext *ctx, arg_sfence_vma *a)
> +{
> +#ifndef CONFIG_USER_ONLY
> +    if (ctx->priv_ver >= PRIV_VERSION_1_10_0 &&
> +        has_ext(ctx, RVH)) {
> +        /* Hpervisor extensions exist */
> +        /*
> +         * if (env->priv == PRV_M ||
> +         *   (env->priv == PRV_S &&
> +         *    !riscv_cpu_virt_enabled(env) &&
> +         *    get_field(ctx->mstatus_fs, MSTATUS_TVM))) {
> +         */
> +            gen_helper_tlb_flush(cpu_env);
> +            return true;
> +        /* } */
> +    }
> +#endif
> +    return false;
> +}

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [PATCH v1 19/28] target/riscv: Disable guest FP support based on virtual status
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 19/28] target/riscv: Disable guest FP support based on virtual status Alistair Francis
@ 2019-10-01 18:34   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-01 18:34 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:39 PDT (-0700), Alistair Francis wrote:
> When the Hypervisor extension is in use we only enable floating point
> support when both status and vsstatus have enabled floating point
> support.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_helper.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 17eec6217b..098873c83e 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -90,6 +90,9 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
>  bool riscv_cpu_fp_enabled(CPURISCVState *env)
>  {
>      if (*env->mstatus & MSTATUS_FS) {
> +        if (riscv_cpu_virt_enabled(env) && !(env->vsstatus & MSTATUS_FS)) {
> +            return false;
> +        }
>          return true;
>      }

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [PATCH v1 20/28] target/riscv: Mark both sstatus and vsstatus as dirty
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 20/28] target/riscv: Mark both sstatus and vsstatus as dirty Alistair Francis
@ 2019-10-01 18:34   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-01 18:34 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:42 PDT (-0700), Alistair Francis wrote:
> Mark both sstatus and vsstatus as dirty (3).
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/translate.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> index 8ac72c6470..19771904f4 100644
> --- a/target/riscv/translate.c
> +++ b/target/riscv/translate.c
> @@ -44,6 +44,7 @@ typedef struct DisasContext {
>      /* pc_succ_insn points to the instruction following base.pc_next */
>      target_ulong pc_succ_insn;
>      target_ulong priv_ver;
> +    bool virt_enabled;
>      uint32_t opcode;
>      uint32_t mstatus_fs;
>      uint32_t misa;
> @@ -398,6 +399,12 @@ static void mark_fs_dirty(DisasContext *ctx)
>      tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
>      tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
>      tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, mstatus));
> +
> +    if (ctx->virt_enabled) {
> +        tcg_gen_ld_tl(tmp, cpu_env, offsetof(CPURISCVState, vsstatus));
> +        tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
> +        tcg_gen_st_tl(tmp, cpu_env, offsetof(CPURISCVState, vsstatus));
> +    }
>      tcg_temp_free(tmp);
>  }
>  #else
> @@ -742,6 +749,11 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
>      ctx->mem_idx = ctx->base.tb->flags & TB_FLAGS_MMU_MASK;
>      ctx->mstatus_fs = ctx->base.tb->flags & TB_FLAGS_MSTATUS_FS;
>      ctx->priv_ver = env->priv_ver;
> +#if !defined(CONFIG_USER_ONLY)
> +    ctx->virt_enabled = riscv_cpu_virt_enabled(env);
> +#else
> +    ctx->virt_enabled = false;
> +#endif
>      ctx->misa = env->misa;
>      ctx->frm = -1;  /* unknown rounding mode */
>      ctx->ext_ifencei = cpu->cfg.ext_ifencei;

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [PATCH v1 21/28] target/riscv: Respect MPRV and SPRV for floating point ops
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 21/28] target/riscv: Respect MPRV and SPRV for floating point ops Alistair Francis
@ 2019-10-02 23:52   ` Palmer Dabbelt
  2019-10-16 21:01     ` Alistair Francis
  0 siblings, 1 reply; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-02 23:52 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:44 PDT (-0700), Alistair Francis wrote:
> Respect the contents of MSTATUS.MPRV and HSTATUS.SPRV when performing
> floating point operations when V=0.

I'm confused as to what this has to do with floating point.

>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/translate.c | 16 +++++++++++++++-
>  1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> index 19771904f4..ea19ba9c5d 100644
> --- a/target/riscv/translate.c
> +++ b/target/riscv/translate.c
> @@ -750,7 +750,21 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
>      ctx->mstatus_fs = ctx->base.tb->flags & TB_FLAGS_MSTATUS_FS;
>      ctx->priv_ver = env->priv_ver;
>  #if !defined(CONFIG_USER_ONLY)
> -    ctx->virt_enabled = riscv_cpu_virt_enabled(env);
> +    if (riscv_has_ext(env, RVH)) {
> +        ctx->virt_enabled = riscv_cpu_virt_enabled(env);
> +        if (env->priv_ver == PRV_M &&
> +            get_field(*env->mstatus, MSTATUS_MPRV) &&
> +            get_field(*env->mstatus, MSTATUS_MPV)) {
> +            ctx->virt_enabled = true;
> +        } else if (env->priv == PRV_S &&
> +                   !riscv_cpu_virt_enabled(env) &&
> +                   get_field(env->hstatus, HSTATUS_SPRV) &&
> +                   get_field(env->hstatus, HSTATUS_SPV)) {
> +            ctx->virt_enabled = true;
> +        }
> +    } else {
> +        ctx->virt_enabled = false;
> +    }
>  #else
>      ctx->virt_enabled = false;
>  #endif


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

* Re: [PATCH v1 22/28] target/riscv: Allow specifying MMU stage
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 22/28] target/riscv: Allow specifying MMU stage Alistair Francis
@ 2019-10-03 15:53   ` Palmer Dabbelt
  2019-10-07 18:05     ` Alistair Francis
  0 siblings, 1 reply; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-03 15:53 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:47 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_helper.c | 39 ++++++++++++++++++++++++++++++---------
>  1 file changed, 30 insertions(+), 9 deletions(-)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 098873c83e..9aa6906acd 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -318,10 +318,19 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
>   *
>   * 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 to be translated
> + * @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
>   */
>  static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>                                  int *prot, target_ulong addr,
> -                                int access_type, int mmu_idx)
> +                                int access_type, int mmu_idx,
> +                                bool first_stage)
>  {
>      /* NOTE: the env->pc value visible here will not be
>       * correct, but the value visible to the exception handler
> @@ -518,13 +527,23 @@ restart:
>  }
>
>  static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
> -                                MMUAccessType access_type, bool pmp_violation)
> +                                MMUAccessType access_type, bool pmp_violation,
> +                                bool first_stage)
>  {
>      CPUState *cs = env_cpu(env);
> -    int page_fault_exceptions =
> -        (env->priv_ver >= PRIV_VERSION_1_10_0) &&
> -        get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
> -        !pmp_violation;
> +    int page_fault_exceptions;
> +    if (first_stage) {
> +        page_fault_exceptions =
> +            (env->priv_ver >= PRIV_VERSION_1_10_0) &&
> +            get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
> +            !pmp_violation;
> +            riscv_cpu_set_force_hs_excep(env, CLEAR_HS_EXCEP);

It might just be email, but the indentation looks wrong here.

> +    } else {
> +        page_fault_exceptions =
> +            get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE &&
> +            !pmp_violation;
> +            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> +    }
>      switch (access_type) {
>      case MMU_INST_FETCH:
>          cs->exception_index = page_fault_exceptions ?
> @@ -551,7 +570,8 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
>      int prot;
>      int mmu_idx = cpu_mmu_index(&cpu->env, false);
>
> -    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) {
> +    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
> +                             true)) {
>          return -1;
>      }
>      return phys_addr;
> @@ -613,7 +633,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>      qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
>                    __func__, address, access_type, mmu_idx);
>
> -    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
> +    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
> +                               true);
>
>      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
>          if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> @@ -640,7 +661,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>      } else if (probe) {
>          return false;
>      } else {
> -        raise_mmu_exception(env, address, access_type, pmp_violation);
> +        raise_mmu_exception(env, address, access_type, pmp_violation, true);
>          riscv_raise_exception(env, cs->exception_index, retaddr);
>      }
>  #else

I don't think it makes sense to split off these two (23 and 24, that add the 
argument) out from the implementation.


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

* Re: [PATCH v1 24/28] target/riscv: Implement second stage MMU
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 24/28] target/riscv: Implement second stage MMU Alistair Francis
@ 2019-10-07 16:15   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-07 16:15 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:52 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_helper.c | 96 +++++++++++++++++++++++++++++++++++----
>  1 file changed, 86 insertions(+), 10 deletions(-)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 8b9871f9ea..188d5cb39f 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -337,13 +337,40 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>       * (riscv_cpu_do_interrupt) is correct */
>
>      int mode = mmu_idx;
> +    bool use_background = false;
>
> +    /*
> +     * 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 (mode == PRV_M && access_type != MMU_INST_FETCH) {
>          if (get_field(*env->mstatus, MSTATUS_MPRV)) {
>              mode = get_field(*env->mstatus, MSTATUS_MPP);
> +
> +            if (riscv_has_ext(env, RVH) &&
> +                get_field(*env->mstatus, MSTATUS_MPV)) {
> +                use_background = true;
> +            }
>          }
>      }
>
> +    if (mode == PRV_S && access_type != MMU_INST_FETCH &&
> +        riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
> +        if (get_field(env->hstatus, HSTATUS_SPRV)) {
> +            mode = get_field(*env->mstatus, SSTATUS_SPP);
> +            use_background = true;
> +        }
> +    }
> +
> +    if (first_stage == false) {
> +        /* We are in stage 2 translation, this is similar to stage 1. */
> +        /* Stage 2 is always taken as U-mode */
> +        mode = PRV_U;
> +    }
> +
>      if (mode == PRV_M || !riscv_feature(env, RISCV_FEATURE_MMU)) {
>          *physical = addr;
>          *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> @@ -353,13 +380,30 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>      *prot = 0;
>
>      target_ulong base;
> -    int levels, ptidxbits, ptesize, vm, sum;
> -    int mxr = get_field(*env->mstatus, MSTATUS_MXR);
> +    int levels, ptidxbits, ptesize, vm, sum, mxr, widened;
> +
> +    if (first_stage == true) {
> +        mxr = get_field(*env->mstatus, MSTATUS_MXR);
> +    } else {
> +        mxr = get_field(env->vsstatus, MSTATUS_MXR);
> +    }
>
>      if (env->priv_ver >= PRIV_VERSION_1_10_0) {
> -        base = get_field(env->satp, SATP_PPN) << PGSHIFT;
> +        if (first_stage == true) {
> +            if (use_background) {
> +                base = get_field(env->vsatp, SATP_PPN) << PGSHIFT;
> +                vm = get_field(env->vsatp, SATP_MODE);
> +            } else {
> +                base = get_field(env->satp, SATP_PPN) << PGSHIFT;
> +                vm = get_field(env->satp, SATP_MODE);
> +            }
> +            widened = 0;
> +        } else {
> +            base = get_field(env->hgatp, HGATP_PPN) << PGSHIFT;
> +            vm = get_field(env->hgatp, HGATP_MODE);
> +            widened = 2;
> +        }
>          sum = get_field(*env->mstatus, MSTATUS_SUM);
> -        vm = get_field(env->satp, SATP_MODE);
>          switch (vm) {
>          case VM_1_10_SV32:
>            levels = 2; ptidxbits = 10; ptesize = 4; break;
> @@ -377,6 +421,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>            g_assert_not_reached();
>          }
>      } else {
> +        widened = 0;
>          base = env->sptbr << PGSHIFT;
>          sum = !get_field(*env->mstatus, MSTATUS_PUM);
>          vm = get_field(*env->mstatus, MSTATUS_VM);
> @@ -397,9 +442,16 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>      }
>
>      CPUState *cs = env_cpu(env);
> -    int va_bits = PGSHIFT + levels * ptidxbits;
> -    target_ulong mask = (1L << (TARGET_LONG_BITS - (va_bits - 1))) - 1;
> -    target_ulong masked_msbs = (addr >> (va_bits - 1)) & mask;
> +    int va_bits = PGSHIFT + levels * ptidxbits + widened;
> +    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;
>      }
> @@ -411,17 +463,36 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>  restart:
>  #endif
>      for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
> -        target_ulong idx = (addr >> (PGSHIFT + ptshift)) &
> +        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 */
> -        target_ulong pte_addr = base + idx * ptesize;
> +        target_ulong pte_addr;
> +
> +        if (two_stage && first_stage) {
> +            hwaddr vbase;
> +
> +            /* Do the second stage translation on the base PTE address. */
> +            get_physical_address(env, &vbase, prot, base, access_type,
> +                                 mmu_idx, false, true);
> +
> +            pte_addr = vbase + idx * ptesize;
> +        } else {
> +            pte_addr = base + idx * ptesize;
> +        }
>
>          if (riscv_feature(env, RISCV_FEATURE_PMP) &&
>              !pmp_hart_has_privs(env, pte_addr, sizeof(target_ulong),
>              1 << MMU_DATA_LOAD, PRV_S)) {
>              return TRANSLATE_PMP_FAIL;
>          }
> +
>  #if defined(TARGET_RISCV32)
>          target_ulong pte = ldl_phys(cs->as, pte_addr);
>  #elif defined(TARGET_RISCV64)
> @@ -507,7 +578,12 @@ restart:
>              /* for superpage mappings, make a fake leaf PTE for the TLB's
>                 benefit. */
>              target_ulong vpn = addr >> PGSHIFT;
> -            *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT;
> +            if (i == 0) {
> +                *physical = (ppn | (vpn & ((1L << (ptshift + widened)) - 1))) <<
> +                             PGSHIFT;
> +            } else {
> +                *physical = (ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT;
> +            }
>
>              /* set permissions on the TLB entry */
>              if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) {

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [PATCH v1 22/28] target/riscv: Allow specifying MMU stage
  2019-10-03 15:53   ` Palmer Dabbelt
@ 2019-10-07 18:05     ` Alistair Francis
  2019-10-16 19:02       ` Palmer Dabbelt
  0 siblings, 1 reply; 75+ messages in thread
From: Alistair Francis @ 2019-10-07 18:05 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: open list:RISC-V, Anup Patel, Alistair Francis,
	qemu-devel@nongnu.org Developers, Atish Patra

On Thu, Oct 3, 2019 at 8:53 AM Palmer Dabbelt <palmer@sifive.com> wrote:
>
> On Fri, 23 Aug 2019 16:38:47 PDT (-0700), Alistair Francis wrote:
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  target/riscv/cpu_helper.c | 39 ++++++++++++++++++++++++++++++---------
> >  1 file changed, 30 insertions(+), 9 deletions(-)
> >
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index 098873c83e..9aa6906acd 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -318,10 +318,19 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
> >   *
> >   * 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 to be translated
> > + * @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
> >   */
> >  static int get_physical_address(CPURISCVState *env, hwaddr *physical,
> >                                  int *prot, target_ulong addr,
> > -                                int access_type, int mmu_idx)
> > +                                int access_type, int mmu_idx,
> > +                                bool first_stage)
> >  {
> >      /* NOTE: the env->pc value visible here will not be
> >       * correct, but the value visible to the exception handler
> > @@ -518,13 +527,23 @@ restart:
> >  }
> >
> >  static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
> > -                                MMUAccessType access_type, bool pmp_violation)
> > +                                MMUAccessType access_type, bool pmp_violation,
> > +                                bool first_stage)
> >  {
> >      CPUState *cs = env_cpu(env);
> > -    int page_fault_exceptions =
> > -        (env->priv_ver >= PRIV_VERSION_1_10_0) &&
> > -        get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
> > -        !pmp_violation;
> > +    int page_fault_exceptions;
> > +    if (first_stage) {
> > +        page_fault_exceptions =
> > +            (env->priv_ver >= PRIV_VERSION_1_10_0) &&
> > +            get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
> > +            !pmp_violation;
> > +            riscv_cpu_set_force_hs_excep(env, CLEAR_HS_EXCEP);
>
> It might just be email, but the indentation looks wrong here.

Yep, fixed.

>
> > +    } else {
> > +        page_fault_exceptions =
> > +            get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE &&
> > +            !pmp_violation;
> > +            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> > +    }
> >      switch (access_type) {
> >      case MMU_INST_FETCH:
> >          cs->exception_index = page_fault_exceptions ?
> > @@ -551,7 +570,8 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
> >      int prot;
> >      int mmu_idx = cpu_mmu_index(&cpu->env, false);
> >
> > -    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) {
> > +    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
> > +                             true)) {
> >          return -1;
> >      }
> >      return phys_addr;
> > @@ -613,7 +633,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> >      qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
> >                    __func__, address, access_type, mmu_idx);
> >
> > -    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
> > +    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
> > +                               true);
> >
> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
> >          if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> > @@ -640,7 +661,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> >      } else if (probe) {
> >          return false;
> >      } else {
> > -        raise_mmu_exception(env, address, access_type, pmp_violation);
> > +        raise_mmu_exception(env, address, access_type, pmp_violation, true);
> >          riscv_raise_exception(env, cs->exception_index, retaddr);
> >      }
> >  #else
>
> I don't think it makes sense to split off these two (23 and 24, that add the
> argument) out from the implementation.

The goal was just to make it easier to review. If you want them
combined I can easily combine them.

Alistair


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

* Re: [PATCH v1 25/28] target/riscv: Call the second stage MMU in virtualisation mode
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 25/28] target/riscv: Call the second stage MMU in virtualisation mode Alistair Francis
@ 2019-10-08 17:54   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-08 17:54 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:55 PDT (-0700), Alistair Francis wrote:
> The qemu_log_mask(CPU_LOG_MMU,... calls trigger false positive
> checkpatch errors which are being ignored.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_helper.c | 94 +++++++++++++++++++++++++++++++++++----
>  1 file changed, 86 insertions(+), 8 deletions(-)
>
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 188d5cb39f..0761191f11 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -642,15 +642,23 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
>  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(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
> -                             true, false)) {
> +    if (get_physical_address(env, &phys_addr, &prot, addr, 0, mmu_idx,
> +                             true, riscv_cpu_virt_enabled(env))) {
>          return -1;
>      }
>
> +    if (riscv_cpu_virt_enabled(env)) {
> +        if (get_physical_address(env, &phys_addr, &prot, phys_addr,
> +                                 0, mmu_idx, false, true)) {
> +            return -1;
> +        }
> +    }
> +
>      return phys_addr;
>  }
>
> @@ -701,17 +709,35 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>  #ifndef CONFIG_USER_ONLY
>      RISCVCPU *cpu = RISCV_CPU(cs);
>      CPURISCVState *env = &cpu->env;
> +    vaddr im_address;
>      hwaddr pa = 0;
>      int prot;
>      bool pmp_violation = false;
> +    bool m_mode_two_stage = false;
> +    bool hs_mode_two_stage = false;
> +    bool first_stage_error = true;
>      int ret = TRANSLATE_FAIL;
>      int mode = mmu_idx;
>
>      qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
>                    __func__, address, access_type, mmu_idx);
>
> -    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
> -                               true, false);
> +    /*
> +     * Determine if we are in M mode and MPRV is set or in HS mode and SPRV is
> +     * set and we want to access a virtulisation address.
> +     */
> +    if (riscv_has_ext(env, RVH)) {
> +        m_mode_two_stage = env->priv == PRV_M &&
> +                           access_type != MMU_INST_FETCH &&
> +                           get_field(*env->mstatus, MSTATUS_MPRV) &&
> +                           get_field(*env->mstatus, MSTATUS_MPV);
> +
> +        hs_mode_two_stage = env->priv == PRV_S &&
> +                            !riscv_cpu_virt_enabled(env) &&
> +                            access_type != MMU_INST_FETCH &&
> +                            get_field(env->hstatus, HSTATUS_SPRV) &&
> +                            get_field(env->hstatus, HSTATUS_SPV);
> +    }
>
>      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
>          if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> @@ -719,10 +745,58 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>          }
>      }
>
> -    qemu_log_mask(CPU_LOG_MMU,
> -                  "%s address=%" VADDR_PRIx " ret %d physical " TARGET_FMT_plx
> -                  " prot %d\n", __func__, address, ret, pa, prot);
> +    if (riscv_cpu_virt_enabled(env) || m_mode_two_stage || hs_mode_two_stage) {
> +        /* Two stage lookup */
> +        ret = get_physical_address(env, &pa, &prot, address, access_type,
> +                                   mmu_idx, true, true);
> +
> +        qemu_log_mask(CPU_LOG_MMU,
> +                      "%s 1st-stage address=%" VADDR_PRIx " ret %d physical "
> +                      TARGET_FMT_plx " prot %d\n",
> +                      __func__, address, ret, pa, prot);
> +
> +        if (ret == TRANSLATE_FAIL) {
> +            goto tlb_lookup_done;
> +        }
> +
> +        /* Second stage lookup */
> +        im_address = pa;
>
> +        ret = get_physical_address(env, &pa, &prot, im_address, access_type, mmu_idx,
> +                                   false, true);
> +
> +        qemu_log_mask(CPU_LOG_MMU,
> +                "%s 2nd-stage address=%" VADDR_PRIx " ret %d physical "
> +                TARGET_FMT_plx " prot %d\n",
> +                __func__, im_address, ret, pa, prot);
> +
> +        if (riscv_feature(env, RISCV_FEATURE_PMP) &&
> +            (ret == TRANSLATE_SUCCESS) &&
> +            !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
> +            ret = TRANSLATE_PMP_FAIL;
> +        }
> +
> +        if (ret != TRANSLATE_SUCCESS) {
> +            /*
> +             * Guest physical address translation failed, this is a HS
> +             * level exception
> +             */
> +            first_stage_error = false;
> +            address = im_address | (address & (TARGET_PAGE_SIZE - 1));
> +            goto tlb_lookup_done;
> +        }
> +    } else {
> +        /* Single stage lookup */
> +        ret = get_physical_address(env, &pa, &prot, address, access_type,
> +                                   mmu_idx, true, false);
> +
> +        qemu_log_mask(CPU_LOG_MMU,
> +                      "%s address=%" VADDR_PRIx " ret %d physical "
> +                      TARGET_FMT_plx " prot %d\n",
> +                      __func__, address, ret, pa, prot);
> +    }
> +
> +tlb_lookup_done:
>      if (riscv_feature(env, RISCV_FEATURE_PMP) &&
>          (ret == TRANSLATE_SUCCESS) &&
>          !pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
> @@ -731,6 +805,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>      if (ret == TRANSLATE_PMP_FAIL) {
>          pmp_violation = true;
>      }
> +
>      if (ret == TRANSLATE_SUCCESS) {
>          tlb_set_page(cs, address & TARGET_PAGE_MASK, pa & TARGET_PAGE_MASK,
>                       prot, mmu_idx, TARGET_PAGE_SIZE);
> @@ -738,9 +813,12 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>      } else if (probe) {
>          return false;
>      } else {
> -        raise_mmu_exception(env, address, access_type, pmp_violation, true);
> +        raise_mmu_exception(env, address, access_type, pmp_violation, first_stage_error);
>          riscv_raise_exception(env, cs->exception_index, retaddr);
>      }
> +
> +    return true;
> +
>  #else
>      switch (access_type) {
>      case MMU_INST_FETCH:

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [PATCH v1 26/28] target/riscv: Add support for the 32-bit MSTATUSH CSR
  2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 26/28] target/riscv: Add support for the 32-bit MSTATUSH CSR Alistair Francis
@ 2019-10-08 18:36   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-08 18:36 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:38:58 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.c        |  6 ++++++
>  target/riscv/cpu.h        |  7 +++++++
>  target/riscv/cpu_bits.h   |  3 +++
>  target/riscv/cpu_helper.c |  7 +++++++
>  target/riscv/csr.c        | 23 +++++++++++++++++++++++
>  target/riscv/op_helper.c  |  4 ++++
>  6 files changed, 50 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 371d5845af..06ee551ebe 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -229,6 +229,9 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>  #ifndef CONFIG_USER_ONLY
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mhartid ", env->mhartid);
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatus ", *env->mstatus);
> +#ifdef TARGET_RISCV32
> +    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mstatush ", *env->mstatush);
> +#endif
>      if (riscv_has_ext(env, RVH)) {
>          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hstatus ", env->hstatus);
>          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "bstatus ", env->vsstatus);
> @@ -468,6 +471,9 @@ static void riscv_cpu_init(Object *obj)
>  #ifndef CONFIG_USER_ONLY
>      env->mie = &env->mie_novirt;
>      env->mstatus = &env->mstatus_novirt;
> +# ifdef TARGET_RISCV32
> +    env->mstatush = &env->mstatush_novirt;
> +# endif
>  #endif
>  }
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 05957f32a8..b63f1f3cdc 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -124,6 +124,10 @@ struct CPURISCVState {
>      target_ulong mhartid;
>      target_ulong *mstatus;
>
> +#ifdef TARGET_RISCV32
> +    target_ulong *mstatush;
> +#endif
> +
>      /*
>       * CAUTION! Unlike the rest of this struct, mip and mip_novirt is accessed
>       * asynchonously by I/O threads. It should be read with atomic_read. It should
> @@ -164,6 +168,9 @@ struct CPURISCVState {
>       */
>      target_ulong mie_novirt;
>      target_ulong mstatus_novirt;
> +#ifdef TARGET_RISCV32
> +    target_ulong mstatush_novirt;
> +#endif
>
>      /* Hypervisor CSRs */
>      target_ulong hstatus;
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 353fc9a24a..55e20af6d9 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -135,6 +135,9 @@
>  #define CSR_MTVEC           0x305
>  #define CSR_MCOUNTEREN      0x306
>
> +/* 32-bit only */
> +#define CSR_MSTATUSH        0x310
> +
>  /* Legacy Counter Setup (priv v1.9.1) */
>  /* Update to #define CSR_MCOUNTINHIBIT 0x320 for 1.11.0 */
>  #define CSR_MUCOUNTEREN     0x320
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 0761191f11..8c80486dd0 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -949,10 +949,17 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>              if (riscv_cpu_virt_enabled(env)) {
>                  riscv_cpu_swap_hypervisor_regs(env);
>              }
> +#ifdef TARGET_RISCV32
> +            *env->mstatush = set_field(*env->mstatush, MSTATUS_MPV,
> +                                       riscv_cpu_virt_enabled(env));
> +            *env->mstatush = set_field(*env->mstatush, MSTATUS_MTL,
> +                                       riscv_cpu_force_hs_excep_enabled(env));
> +#else
>              *env->mstatus = set_field(*env->mstatus, MSTATUS_MPV,
>                                        riscv_cpu_virt_enabled(env));
>              *env->mstatus = set_field(*env->mstatus, MSTATUS_MTL,
>                                        riscv_cpu_force_hs_excep_enabled(env));
> +#endif
>
>              /* Trapping to M mode, virt is disabled */
>              riscv_cpu_set_virt_enabled(env, VIRT_OFF);
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 47be4b1d42..b7d6d009dc 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -364,6 +364,25 @@ static int write_mstatus(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +#ifdef TARGET_RISCV32
> +static int read_mstatush(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = *env->mstatush;
> +    return 0;
> +}
> +
> +static int write_mstatush(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    if ((val ^ *env->mstatush) & (MSTATUS_MPV)) {
> +        tlb_flush(env_cpu(env));
> +    }
> +
> +    *env->mstatush = val;

The unsupported bits need to be masked off before writing them in.

> +
> +    return 0;
> +}
> +#endif
> +
>  static int read_misa(CPURISCVState *env, int csrno, target_ulong *val)
>  {
>      *val = env->misa;
> @@ -1095,6 +1114,10 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_MTVEC] =               { any,  read_mtvec,       write_mtvec       },
>      [CSR_MCOUNTEREN] =          { any,  read_mcounteren,  write_mcounteren  },
>
> +#if defined(TARGET_RISCV32)
> +    [CSR_MSTATUSH] =            { any,  read_mstatush,    write_mstatush    },
> +#endif
> +
>      /* Legacy Counter Setup (priv v1.9.1) */
>      [CSR_MUCOUNTEREN] =         { any,  read_mucounteren, write_mucounteren },
>      [CSR_MSCOUNTEREN] =         { any,  read_mscounteren, write_mscounteren },
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index 5bcf5d2ff7..8dec1aee99 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -153,7 +153,11 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>          get_field(mstatus, MSTATUS_MPIE));
>      mstatus = set_field(mstatus, MSTATUS_MPIE, 1);
>      mstatus = set_field(mstatus, MSTATUS_MPP, 0);
> +#ifdef TARGET_RISCV32
> +    *env->mstatush = set_field(*env->mstatush, MSTATUS_MPV, 0);
> +#else
>      mstatus = set_field(mstatus, MSTATUS_MPV, 0);
> +#endif
>      *env->mstatus = mstatus;
>      riscv_cpu_set_mode(env, prev_priv);




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

* Re: [PATCH v1 27/28] target/riscv: Add the MSTATUS_MPV_ISSET helper macro
  2019-08-23 23:39 ` [Qemu-devel] [PATCH v1 27/28] target/riscv: Add the MSTATUS_MPV_ISSET helper macro Alistair Francis
@ 2019-10-08 18:36   ` Palmer Dabbelt
  2019-10-16 21:14     ` Alistair Francis
  0 siblings, 1 reply; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-08 18:36 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:39:00 PDT (-0700), Alistair Francis wrote:
> Add a helper macro MSTATUS_MPV_ISSET() which will determine if the
> MSTATUS_MPV bit is set for both 32-bit and 64-bit RISC-V.
>
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu_bits.h   | 11 +++++++++++
>  target/riscv/cpu_helper.c |  4 ++--
>  target/riscv/op_helper.c  |  2 +-
>  target/riscv/translate.c  |  2 +-
>  4 files changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index 55e20af6d9..7056d9218b 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -365,8 +365,19 @@
>  #define MSTATUS_TVM         0x00100000 /* since: priv-1.10 */
>  #define MSTATUS_TW          0x20000000 /* since: priv-1.10 */
>  #define MSTATUS_TSR         0x40000000 /* since: priv-1.10 */
> +#if defined(TARGET_RISCV64)
>  #define MSTATUS_MTL         0x4000000000ULL
>  #define MSTATUS_MPV         0x8000000000ULL
> +#elif defined(TARGET_RISCV32)
> +#define MSTATUS_MTL         0x00000040
> +#define MSTATUS_MPV         0x00000080
> +#endif
> +
> +#ifdef TARGET_RISCV32
> +# define MSTATUS_MPV_ISSET(env)  get_field(*env->mstatush, MSTATUS_MPV)
> +#else
> +# define MSTATUS_MPV_ISSET(env)  get_field(*env->mstatus, MSTATUS_MPV)
> +#endif
>
>  #define MSTATUS64_UXL       0x0000000300000000ULL
>  #define MSTATUS64_SXL       0x0000000C00000000ULL
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 8c80486dd0..2b88f756bb 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -351,7 +351,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>              mode = get_field(*env->mstatus, MSTATUS_MPP);
>
>              if (riscv_has_ext(env, RVH) &&
> -                get_field(*env->mstatus, MSTATUS_MPV)) {
> +                MSTATUS_MPV_ISSET(env)) {
>                  use_background = true;
>              }
>          }
> @@ -730,7 +730,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>          m_mode_two_stage = env->priv == PRV_M &&
>                             access_type != MMU_INST_FETCH &&
>                             get_field(*env->mstatus, MSTATUS_MPRV) &&
> -                           get_field(*env->mstatus, MSTATUS_MPV);
> +                           MSTATUS_MPV_ISSET(env);
>
>          hs_mode_two_stage = env->priv == PRV_S &&
>                              !riscv_cpu_virt_enabled(env) &&
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index 8dec1aee99..6149cd9c15 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -146,7 +146,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
>
>      target_ulong mstatus = *env->mstatus;
>      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
> -    target_ulong prev_virt = get_field(mstatus, MSTATUS_MPV);
> +    target_ulong prev_virt = MSTATUS_MPV_ISSET(env);
>      mstatus = set_field(mstatus,
>          env->priv_ver >= PRIV_VERSION_1_10_0 ?
>          MSTATUS_MIE : MSTATUS_UIE << prev_priv,
> diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> index ea19ba9c5d..f0d9860429 100644
> --- a/target/riscv/translate.c
> +++ b/target/riscv/translate.c
> @@ -754,7 +754,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
>          ctx->virt_enabled = riscv_cpu_virt_enabled(env);
>          if (env->priv_ver == PRV_M &&
>              get_field(*env->mstatus, MSTATUS_MPRV) &&
> -            get_field(*env->mstatus, MSTATUS_MPV)) {
> +            MSTATUS_MPV_ISSET(env)) {
>              ctx->virt_enabled = true;
>          } else if (env->priv == PRV_S &&
>                     !riscv_cpu_virt_enabled(env) &&

This should be either ordered before or atomic with the patch that allows 
mstatush.mpv to be set, as otherwise there's point at which QEMU doesn't match 
the ISA.


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

* Re: [PATCH v1 28/28] target/riscv: Allow enabling the Hypervisor extension
  2019-08-23 23:39 ` [Qemu-devel] [PATCH v1 28/28] target/riscv: Allow enabling the Hypervisor extension Alistair Francis
@ 2019-10-08 18:53   ` Palmer Dabbelt
  0 siblings, 0 replies; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-08 18:53 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-riscv, Anup Patel, qemu-devel, Atish Patra,
	Alistair Francis, alistair23

On Fri, 23 Aug 2019 16:39:03 PDT (-0700), Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  target/riscv/cpu.c | 5 +++++
>  target/riscv/cpu.h | 1 +
>  2 files changed, 6 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 06ee551ebe..39e1c130df 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -447,6 +447,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
>          if (cpu->cfg.ext_u) {
>              target_misa |= RVU;
>          }
> +        if (cpu->cfg.ext_h) {
> +            target_misa |= RVH;
> +        }
>
>          set_misa(env, RVXLEN | target_misa);
>      }
> @@ -493,6 +496,8 @@ static Property riscv_cpu_properties[] = {
>      DEFINE_PROP_BOOL("c", RISCVCPU, cfg.ext_c, true),
>      DEFINE_PROP_BOOL("s", RISCVCPU, cfg.ext_s, true),
>      DEFINE_PROP_BOOL("u", RISCVCPU, cfg.ext_u, true),
> +    /* This is experimental so mark with 'x-' */
> +    DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false),
>      DEFINE_PROP_BOOL("Counters", RISCVCPU, cfg.ext_counters, true),
>      DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
>      DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index b63f1f3cdc..500496a3be 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -268,6 +268,7 @@ typedef struct RISCVCPU {
>          bool ext_c;
>          bool ext_s;
>          bool ext_u;
> +        bool ext_h;
>          bool ext_counters;
>          bool ext_ifencei;
>          bool ext_icsr;

Reviewed-by: Palmer Dabbelt <palmer@sifive.com>


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

* Re: [PATCH v1 22/28] target/riscv: Allow specifying MMU stage
  2019-10-07 18:05     ` Alistair Francis
@ 2019-10-16 19:02       ` Palmer Dabbelt
  2019-10-16 21:25         ` Alistair Francis
  0 siblings, 1 reply; 75+ messages in thread
From: Palmer Dabbelt @ 2019-10-16 19:02 UTC (permalink / raw)
  To: alistair23
  Cc: qemu-riscv, Anup Patel, Alistair Francis, qemu-devel, Atish Patra

On Mon, 07 Oct 2019 11:05:33 PDT (-0700), alistair23@gmail.com wrote:
> On Thu, Oct 3, 2019 at 8:53 AM Palmer Dabbelt <palmer@sifive.com> wrote:
>>
>> On Fri, 23 Aug 2019 16:38:47 PDT (-0700), Alistair Francis wrote:
>> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
>> > ---
>> >  target/riscv/cpu_helper.c | 39 ++++++++++++++++++++++++++++++---------
>> >  1 file changed, 30 insertions(+), 9 deletions(-)
>> >
>> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
>> > index 098873c83e..9aa6906acd 100644
>> > --- a/target/riscv/cpu_helper.c
>> > +++ b/target/riscv/cpu_helper.c
>> > @@ -318,10 +318,19 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
>> >   *
>> >   * 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 to be translated
>> > + * @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
>> >   */
>> >  static int get_physical_address(CPURISCVState *env, hwaddr *physical,
>> >                                  int *prot, target_ulong addr,
>> > -                                int access_type, int mmu_idx)
>> > +                                int access_type, int mmu_idx,
>> > +                                bool first_stage)
>> >  {
>> >      /* NOTE: the env->pc value visible here will not be
>> >       * correct, but the value visible to the exception handler
>> > @@ -518,13 +527,23 @@ restart:
>> >  }
>> >
>> >  static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
>> > -                                MMUAccessType access_type, bool pmp_violation)
>> > +                                MMUAccessType access_type, bool pmp_violation,
>> > +                                bool first_stage)
>> >  {
>> >      CPUState *cs = env_cpu(env);
>> > -    int page_fault_exceptions =
>> > -        (env->priv_ver >= PRIV_VERSION_1_10_0) &&
>> > -        get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
>> > -        !pmp_violation;
>> > +    int page_fault_exceptions;
>> > +    if (first_stage) {
>> > +        page_fault_exceptions =
>> > +            (env->priv_ver >= PRIV_VERSION_1_10_0) &&
>> > +            get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
>> > +            !pmp_violation;
>> > +            riscv_cpu_set_force_hs_excep(env, CLEAR_HS_EXCEP);
>>
>> It might just be email, but the indentation looks wrong here.
>
> Yep, fixed.
>
>>
>> > +    } else {
>> > +        page_fault_exceptions =
>> > +            get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE &&
>> > +            !pmp_violation;
>> > +            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
>> > +    }
>> >      switch (access_type) {
>> >      case MMU_INST_FETCH:
>> >          cs->exception_index = page_fault_exceptions ?
>> > @@ -551,7 +570,8 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
>> >      int prot;
>> >      int mmu_idx = cpu_mmu_index(&cpu->env, false);
>> >
>> > -    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) {
>> > +    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
>> > +                             true)) {
>> >          return -1;
>> >      }
>> >      return phys_addr;
>> > @@ -613,7 +633,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>> >      qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
>> >                    __func__, address, access_type, mmu_idx);
>> >
>> > -    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
>> > +    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
>> > +                               true);
>> >
>> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
>> >          if (get_field(*env->mstatus, MSTATUS_MPRV)) {
>> > @@ -640,7 +661,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>> >      } else if (probe) {
>> >          return false;
>> >      } else {
>> > -        raise_mmu_exception(env, address, access_type, pmp_violation);
>> > +        raise_mmu_exception(env, address, access_type, pmp_violation, true);
>> >          riscv_raise_exception(env, cs->exception_index, retaddr);
>> >      }
>> >  #else
>>
>> I don't think it makes sense to split off these two (23 and 24, that add the
>> argument) out from the implementation.
>
> The goal was just to make it easier to review. If you want them
> combined I can easily combine them.

It's making it harder to read on my end :)


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

* Re: [PATCH v1 04/28] target/riscv: Fix CSR perm checking for HS mode
  2019-09-10 14:48   ` Palmer Dabbelt
@ 2019-10-16 20:56     ` Alistair Francis
  0 siblings, 0 replies; 75+ messages in thread
From: Alistair Francis @ 2019-10-16 20:56 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: open list:RISC-V, Anup Patel, Alistair Francis,
	qemu-devel@nongnu.org Developers, Atish Patra

On Tue, Sep 10, 2019 at 7:48 AM Palmer Dabbelt <palmer@sifive.com> wrote:
>
> On Fri, 23 Aug 2019 16:38:00 PDT (-0700), Alistair Francis wrote:
> > Update the CSR permission checking to work correctly when we are in
> > HS-mode.
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  target/riscv/csr.c | 10 ++++++++--
> >  1 file changed, 8 insertions(+), 2 deletions(-)
> >
> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > index f767ad24be..471f23a1d0 100644
> > --- a/target/riscv/csr.c
> > +++ b/target/riscv/csr.c
> > @@ -799,9 +799,15 @@ int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >
> >      /* check privileges and return -1 if check fails */
> >  #if !defined(CONFIG_USER_ONLY)
> > -    int csr_priv = get_field(csrno, 0x300);
> > +    int csr_priv = env->priv;
>
> This isn't really "csr_priv" (ie, the priv needed to access the CSR) any more,
> it's really the effective priv of the machine.  Leaving the variable with the
> same name makes this hard to read, but I think it is correct.

I changed the name to effective_priv.

>
> >      int read_only = get_field(csrno, 0xC00) == 3;
> > -    if ((write_mask && read_only) || (env->priv < csr_priv)) {
> > +
> > +    if (riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
> > +        /* Plus 1 as we are in HS mode */
>
> The comment is useless, it doesn't say why we increment it.  Also, I don't
> think this is correct: doesn't it allow U mode to access S CSRs when H is
> present and V is disabled?

Yes, you are correct. I have changed it to check that we are in S mode.

>
> Something like
>
>     riscv_effective_priv(CPURISCVState *env)
>     {
>         if (riscv_has_ext(env, RVH) && env->priv == PRIV_S && !riscv_cpu_virt_enabled(env)) {
>             return PRIV_HS;

I don't like this as there is no PRIV_HS. It seems like a bad idea to
start using a reserved privilege level, if it is ever used we will
then be stuck updating this. I also don't think this is used anywhere
else. I have just fixed up the if statement and comment.

Alistair

>         }
>
>         return env->priv;
>     }
>
> would probably be used in a handful of places, and would be a drop in for
> env->priv here.
>
> > +        csr_priv++;
> > +    }
> > +
> > +    if ((write_mask && read_only) || (csr_priv < get_field(csrno, 0x300))) {
> >          return -1;
> >      }
> >  #endif


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

* Re: [PATCH v1 21/28] target/riscv: Respect MPRV and SPRV for floating point ops
  2019-10-02 23:52   ` Palmer Dabbelt
@ 2019-10-16 21:01     ` Alistair Francis
  0 siblings, 0 replies; 75+ messages in thread
From: Alistair Francis @ 2019-10-16 21:01 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: open list:RISC-V, Anup Patel, Alistair Francis,
	qemu-devel@nongnu.org Developers, Atish Patra

On Wed, Oct 2, 2019 at 4:52 PM Palmer Dabbelt <palmer@sifive.com> wrote:
>
> On Fri, 23 Aug 2019 16:38:44 PDT (-0700), Alistair Francis wrote:
> > Respect the contents of MSTATUS.MPRV and HSTATUS.SPRV when performing
> > floating point operations when V=0.
>
> I'm confused as to what this has to do with floating point.

virt_enabled is only checked in mark_fs_dirty() for floating point support.

Alistair

>
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  target/riscv/translate.c | 16 +++++++++++++++-
> >  1 file changed, 15 insertions(+), 1 deletion(-)
> >
> > diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> > index 19771904f4..ea19ba9c5d 100644
> > --- a/target/riscv/translate.c
> > +++ b/target/riscv/translate.c
> > @@ -750,7 +750,21 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> >      ctx->mstatus_fs = ctx->base.tb->flags & TB_FLAGS_MSTATUS_FS;
> >      ctx->priv_ver = env->priv_ver;
> >  #if !defined(CONFIG_USER_ONLY)
> > -    ctx->virt_enabled = riscv_cpu_virt_enabled(env);
> > +    if (riscv_has_ext(env, RVH)) {
> > +        ctx->virt_enabled = riscv_cpu_virt_enabled(env);
> > +        if (env->priv_ver == PRV_M &&
> > +            get_field(*env->mstatus, MSTATUS_MPRV) &&
> > +            get_field(*env->mstatus, MSTATUS_MPV)) {
> > +            ctx->virt_enabled = true;
> > +        } else if (env->priv == PRV_S &&
> > +                   !riscv_cpu_virt_enabled(env) &&
> > +                   get_field(env->hstatus, HSTATUS_SPRV) &&
> > +                   get_field(env->hstatus, HSTATUS_SPV)) {
> > +            ctx->virt_enabled = true;
> > +        }
> > +    } else {
> > +        ctx->virt_enabled = false;
> > +    }
> >  #else
> >      ctx->virt_enabled = false;
> >  #endif


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

* Re: [PATCH v1 27/28] target/riscv: Add the MSTATUS_MPV_ISSET helper macro
  2019-10-08 18:36   ` Palmer Dabbelt
@ 2019-10-16 21:14     ` Alistair Francis
  0 siblings, 0 replies; 75+ messages in thread
From: Alistair Francis @ 2019-10-16 21:14 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: open list:RISC-V, Anup Patel, Alistair Francis,
	qemu-devel@nongnu.org Developers, Atish Patra

On Tue, Oct 8, 2019 at 11:36 AM Palmer Dabbelt <palmer@sifive.com> wrote:
>
> On Fri, 23 Aug 2019 16:39:00 PDT (-0700), Alistair Francis wrote:
> > Add a helper macro MSTATUS_MPV_ISSET() which will determine if the
> > MSTATUS_MPV bit is set for both 32-bit and 64-bit RISC-V.
> >
> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> > ---
> >  target/riscv/cpu_bits.h   | 11 +++++++++++
> >  target/riscv/cpu_helper.c |  4 ++--
> >  target/riscv/op_helper.c  |  2 +-
> >  target/riscv/translate.c  |  2 +-
> >  4 files changed, 15 insertions(+), 4 deletions(-)
> >
> > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> > index 55e20af6d9..7056d9218b 100644
> > --- a/target/riscv/cpu_bits.h
> > +++ b/target/riscv/cpu_bits.h
> > @@ -365,8 +365,19 @@
> >  #define MSTATUS_TVM         0x00100000 /* since: priv-1.10 */
> >  #define MSTATUS_TW          0x20000000 /* since: priv-1.10 */
> >  #define MSTATUS_TSR         0x40000000 /* since: priv-1.10 */
> > +#if defined(TARGET_RISCV64)
> >  #define MSTATUS_MTL         0x4000000000ULL
> >  #define MSTATUS_MPV         0x8000000000ULL
> > +#elif defined(TARGET_RISCV32)
> > +#define MSTATUS_MTL         0x00000040
> > +#define MSTATUS_MPV         0x00000080
> > +#endif
> > +
> > +#ifdef TARGET_RISCV32
> > +# define MSTATUS_MPV_ISSET(env)  get_field(*env->mstatush, MSTATUS_MPV)
> > +#else
> > +# define MSTATUS_MPV_ISSET(env)  get_field(*env->mstatus, MSTATUS_MPV)
> > +#endif
> >
> >  #define MSTATUS64_UXL       0x0000000300000000ULL
> >  #define MSTATUS64_SXL       0x0000000C00000000ULL
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index 8c80486dd0..2b88f756bb 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -351,7 +351,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
> >              mode = get_field(*env->mstatus, MSTATUS_MPP);
> >
> >              if (riscv_has_ext(env, RVH) &&
> > -                get_field(*env->mstatus, MSTATUS_MPV)) {
> > +                MSTATUS_MPV_ISSET(env)) {
> >                  use_background = true;
> >              }
> >          }
> > @@ -730,7 +730,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> >          m_mode_two_stage = env->priv == PRV_M &&
> >                             access_type != MMU_INST_FETCH &&
> >                             get_field(*env->mstatus, MSTATUS_MPRV) &&
> > -                           get_field(*env->mstatus, MSTATUS_MPV);
> > +                           MSTATUS_MPV_ISSET(env);
> >
> >          hs_mode_two_stage = env->priv == PRV_S &&
> >                              !riscv_cpu_virt_enabled(env) &&
> > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> > index 8dec1aee99..6149cd9c15 100644
> > --- a/target/riscv/op_helper.c
> > +++ b/target/riscv/op_helper.c
> > @@ -146,7 +146,7 @@ target_ulong helper_mret(CPURISCVState *env, target_ulong cpu_pc_deb)
> >
> >      target_ulong mstatus = *env->mstatus;
> >      target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
> > -    target_ulong prev_virt = get_field(mstatus, MSTATUS_MPV);
> > +    target_ulong prev_virt = MSTATUS_MPV_ISSET(env);
> >      mstatus = set_field(mstatus,
> >          env->priv_ver >= PRIV_VERSION_1_10_0 ?
> >          MSTATUS_MIE : MSTATUS_UIE << prev_priv,
> > diff --git a/target/riscv/translate.c b/target/riscv/translate.c
> > index ea19ba9c5d..f0d9860429 100644
> > --- a/target/riscv/translate.c
> > +++ b/target/riscv/translate.c
> > @@ -754,7 +754,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
> >          ctx->virt_enabled = riscv_cpu_virt_enabled(env);
> >          if (env->priv_ver == PRV_M &&
> >              get_field(*env->mstatus, MSTATUS_MPRV) &&
> > -            get_field(*env->mstatus, MSTATUS_MPV)) {
> > +            MSTATUS_MPV_ISSET(env)) {
> >              ctx->virt_enabled = true;
> >          } else if (env->priv == PRV_S &&
> >                     !riscv_cpu_virt_enabled(env) &&
>
> This should be either ordered before or atomic with the patch that allows
> mstatush.mpv to be set, as otherwise there's point at which QEMU doesn't match
> the ISA.

I can't change the order due to dependencies, I can squash them but as
the Hypervisor extension can't be turned on there isn't really a
conflict with the ISA.

Do you still want me to squash them?

Alistair


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

* Re: [PATCH v1 22/28] target/riscv: Allow specifying MMU stage
  2019-10-16 19:02       ` Palmer Dabbelt
@ 2019-10-16 21:25         ` Alistair Francis
  0 siblings, 0 replies; 75+ messages in thread
From: Alistair Francis @ 2019-10-16 21:25 UTC (permalink / raw)
  To: Palmer Dabbelt
  Cc: open list:RISC-V, Anup Patel, Alistair Francis,
	qemu-devel@nongnu.org Developers, Atish Patra

On Wed, Oct 16, 2019 at 12:02 PM Palmer Dabbelt <palmer@sifive.com> wrote:
>
> On Mon, 07 Oct 2019 11:05:33 PDT (-0700), alistair23@gmail.com wrote:
> > On Thu, Oct 3, 2019 at 8:53 AM Palmer Dabbelt <palmer@sifive.com> wrote:
> >>
> >> On Fri, 23 Aug 2019 16:38:47 PDT (-0700), Alistair Francis wrote:
> >> > Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> >> > ---
> >> >  target/riscv/cpu_helper.c | 39 ++++++++++++++++++++++++++++++---------
> >> >  1 file changed, 30 insertions(+), 9 deletions(-)
> >> >
> >> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> >> > index 098873c83e..9aa6906acd 100644
> >> > --- a/target/riscv/cpu_helper.c
> >> > +++ b/target/riscv/cpu_helper.c
> >> > @@ -318,10 +318,19 @@ void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
> >> >   *
> >> >   * 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 to be translated
> >> > + * @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
> >> >   */
> >> >  static int get_physical_address(CPURISCVState *env, hwaddr *physical,
> >> >                                  int *prot, target_ulong addr,
> >> > -                                int access_type, int mmu_idx)
> >> > +                                int access_type, int mmu_idx,
> >> > +                                bool first_stage)
> >> >  {
> >> >      /* NOTE: the env->pc value visible here will not be
> >> >       * correct, but the value visible to the exception handler
> >> > @@ -518,13 +527,23 @@ restart:
> >> >  }
> >> >
> >> >  static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
> >> > -                                MMUAccessType access_type, bool pmp_violation)
> >> > +                                MMUAccessType access_type, bool pmp_violation,
> >> > +                                bool first_stage)
> >> >  {
> >> >      CPUState *cs = env_cpu(env);
> >> > -    int page_fault_exceptions =
> >> > -        (env->priv_ver >= PRIV_VERSION_1_10_0) &&
> >> > -        get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
> >> > -        !pmp_violation;
> >> > +    int page_fault_exceptions;
> >> > +    if (first_stage) {
> >> > +        page_fault_exceptions =
> >> > +            (env->priv_ver >= PRIV_VERSION_1_10_0) &&
> >> > +            get_field(env->satp, SATP_MODE) != VM_1_10_MBARE &&
> >> > +            !pmp_violation;
> >> > +            riscv_cpu_set_force_hs_excep(env, CLEAR_HS_EXCEP);
> >>
> >> It might just be email, but the indentation looks wrong here.
> >
> > Yep, fixed.
> >
> >>
> >> > +    } else {
> >> > +        page_fault_exceptions =
> >> > +            get_field(env->hgatp, HGATP_MODE) != VM_1_10_MBARE &&
> >> > +            !pmp_violation;
> >> > +            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> >> > +    }
> >> >      switch (access_type) {
> >> >      case MMU_INST_FETCH:
> >> >          cs->exception_index = page_fault_exceptions ?
> >> > @@ -551,7 +570,8 @@ hwaddr riscv_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
> >> >      int prot;
> >> >      int mmu_idx = cpu_mmu_index(&cpu->env, false);
> >> >
> >> > -    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx)) {
> >> > +    if (get_physical_address(&cpu->env, &phys_addr, &prot, addr, 0, mmu_idx,
> >> > +                             true)) {
> >> >          return -1;
> >> >      }
> >> >      return phys_addr;
> >> > @@ -613,7 +633,8 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> >> >      qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
> >> >                    __func__, address, access_type, mmu_idx);
> >> >
> >> > -    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx);
> >> > +    ret = get_physical_address(env, &pa, &prot, address, access_type, mmu_idx,
> >> > +                               true);
> >> >
> >> >      if (mode == PRV_M && access_type != MMU_INST_FETCH) {
> >> >          if (get_field(*env->mstatus, MSTATUS_MPRV)) {
> >> > @@ -640,7 +661,7 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> >> >      } else if (probe) {
> >> >          return false;
> >> >      } else {
> >> > -        raise_mmu_exception(env, address, access_type, pmp_violation);
> >> > +        raise_mmu_exception(env, address, access_type, pmp_violation, true);
> >> >          riscv_raise_exception(env, cs->exception_index, retaddr);
> >> >      }
> >> >  #else
> >>
> >> I don't think it makes sense to split off these two (23 and 24, that add the
> >> argument) out from the implementation.
> >
> > The goal was just to make it easier to review. If you want them
> > combined I can easily combine them.
>
> It's making it harder to read on my end :)

Ha ok. I have squashed all three.

Alistair


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

* Re: [Qemu-devel] [Qemu-riscv] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers
  2019-09-19 16:58               ` Jonathan Behrens
@ 2019-10-25 20:28                 ` Alistair Francis
  0 siblings, 0 replies; 75+ messages in thread
From: Alistair Francis @ 2019-10-25 20:28 UTC (permalink / raw)
  To: Jonathan Behrens
  Cc: Palmer Dabbelt, open list:RISC-V, Anup Patel, Richard Henderson,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis

On Thu, Sep 19, 2019 at 9:59 AM Jonathan Behrens <fintelia@gmail.com> wrote:
>
> On Thu, Sep 19, 2019 at 10:50 AM Richard Henderson
> <richard.henderson@linaro.org> wrote:
> >
> > On 9/18/19 4:47 PM, Alistair Francis wrote:
> > > I'm not a fan of the pointer method that I'm using, but to me it seems
> > > the least worst in terms of handling future code, keeping everythign
> > > consistnent and avoiding complex access rules.
> >
> > FWIW, I prefer the "banked" register method used by ARM.
> >
> > enum {
> >     M_REG_NS = 0,    /* non-secure mode */
> >     M_REG_S = 1,     /* secure mode */
> >     M_REG_NUM_BANKS = 2,
> > };
> >
> > ...
> >
> >         uint32_t vecbase[M_REG_NUM_BANKS];
> >         uint32_t basepri[M_REG_NUM_BANKS];
> >         uint32_t control[M_REG_NUM_BANKS];
> >
> > The major difference that I see is that a pointer can only represent a single
> > state at a single time.  With an index, different parts of the code can ask
> > different questions that may have different states.  E.g. "are we currently in
> > secure mode" vs "will the exception return to secure mode".
>
> This makes a lot of sense to me. It means that any individual control register
> has an unambiguous name that doesn't change based on context. They aren't quite
> the same names as used in the architecture specification (mie & vsie
> vs. mie[NOVIRT] & mie[VIRT]), but they are reasonably close. It also means other
> parts of the code can't ignore that there are two different versions of the
> registers in play. Perhaps the biggest benefit though is that you can sidestep
> swapping on mode changes *and* avoid needing any super fancy logic in the access
> functions:
>
> int read_mstatus(...) {
>     target_ulong novirt_mask = ...;
>     *val = env->mstatus[NOVIRT] & novirt_mask | env->mstatus[virt_mode()];
> }
>
> int read_vsstatus(...) {
>     *val = env->mstatus[VIRT];
> }
>
> int write_mstatus(...) {
>     ...
>     target_ulong novirt_mask = ...;
>     env->mstatus[NOVIRT] = (env->mstatus[NOVIRT] & ~novirt_mask) |
>                            (newval & novirt_mask);
>     env->mstatus[virt_mode()] = (env->mstatus[virt_mode()] & novirt_mask) |
>                                 (newval & ~novirt_mask);

The part I don't like about this is that it then requires all of the
RISC-V implementation to be affected by the Hypervisor extension. The
current way means that if you aren't interested in the extension you
can just ignore it and not worry about breaking anything. For ARM this
isn't as big of an issue, but RISC-V is much more modular (there will
be lots of platforms without the H extension) so I don't want people
to have to worry about it.

PS: Sorry for the delay here, I have been looking into some other ways
of doing this, but I still think the current way is the least bad.

Alistair

> }


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

end of thread, other threads:[~2019-10-25 20:40 UTC | newest]

Thread overview: 75+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-23 23:37 [Qemu-devel] [PATCH v1 00/28] Add RISC-V Hypervisor Extension v0.4 Alistair Francis
2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 01/28] target/riscv: Add the Hypervisor extension Alistair Francis
2019-08-27 15:26   ` Chih-Min Chao
2019-09-10 13:43   ` Palmer Dabbelt
2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 02/28] target/riscv: Add the virtulisation mode Alistair Francis
2019-08-27 15:44   ` [Qemu-devel] [Qemu-riscv] " Chih-Min Chao
2019-08-28  0:08     ` Alistair Francis
2019-09-10 13:44   ` [Qemu-devel] " Palmer Dabbelt
2019-09-16 15:57     ` Alistair Francis
2019-08-23 23:37 ` [Qemu-devel] [PATCH v1 03/28] target/riscv: Add the force HS exception mode Alistair Francis
2019-08-27 15:46   ` Chih-Min Chao
2019-09-10 14:48   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 04/28] target/riscv: Fix CSR perm checking for HS mode Alistair Francis
2019-09-10 14:48   ` Palmer Dabbelt
2019-10-16 20:56     ` Alistair Francis
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 05/28] target/riscv: Add the Hypervisor CSRs to CPUState Alistair Francis
2019-08-27 15:50   ` [Qemu-devel] [Qemu-riscv] " Chih-Min Chao
2019-09-10 14:48   ` [Qemu-devel] " Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 06/28] target/riscv: Print priv and virt in disas log Alistair Francis
2019-09-10 14:48   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 07/28] target/riscv: Dump Hypervisor registers if enabled Alistair Francis
2019-09-10 14:48   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 08/28] target/riscv: Add Hypervisor CSR access functions Alistair Francis
2019-09-10 14:48   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 09/28] target/riscv: Add Hypervisor virtual CSRs accesses Alistair Francis
2019-09-10 14:48   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 10/28] target/riscv: Convert mie and mstatus to pointers Alistair Francis
2019-09-11  8:24   ` Palmer Dabbelt
2019-09-11 14:54     ` [Qemu-devel] [Qemu-riscv] " Jonathan Behrens
2019-09-17 23:33       ` Alistair Francis
2019-09-18  1:59         ` Jonathan Behrens
2019-09-18 23:47           ` Alistair Francis
2019-09-19 14:50             ` Richard Henderson
2019-09-19 16:58               ` Jonathan Behrens
2019-10-25 20:28                 ` Alistair Francis
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 11/28] target/riscv: Add background register swapping function Alistair Francis
2019-09-11 14:17   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 12/28] target/riscv: Add support for virtual interrupt setting Alistair Francis
2019-09-14 20:30   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 13/28] target/ricsv: Flush the TLB on virtulisation mode changes Alistair Francis
2019-09-14 20:30   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 14/28] target/riscv: Generate illegal instruction on WFI when V=1 Alistair Francis
2019-09-14 20:30   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 15/28] riscv: plic: Always set sip.SEIP bit for HS Alistair Francis
2019-09-14 20:32   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 16/28] target/riscv: Add hypvervisor trap support Alistair Francis
2019-09-20 14:01   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 17/28] target/riscv: Add Hypervisor trap return support Alistair Francis
2019-10-01 18:33   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 18/28] target/riscv: Add hfence instructions Alistair Francis
2019-10-01 18:34   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 19/28] target/riscv: Disable guest FP support based on virtual status Alistair Francis
2019-10-01 18:34   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 20/28] target/riscv: Mark both sstatus and vsstatus as dirty Alistair Francis
2019-10-01 18:34   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 21/28] target/riscv: Respect MPRV and SPRV for floating point ops Alistair Francis
2019-10-02 23:52   ` Palmer Dabbelt
2019-10-16 21:01     ` Alistair Francis
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 22/28] target/riscv: Allow specifying MMU stage Alistair Francis
2019-10-03 15:53   ` Palmer Dabbelt
2019-10-07 18:05     ` Alistair Francis
2019-10-16 19:02       ` Palmer Dabbelt
2019-10-16 21:25         ` Alistair Francis
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 23/28] target/riscv: Allow specifying number of MMU stages Alistair Francis
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 24/28] target/riscv: Implement second stage MMU Alistair Francis
2019-10-07 16:15   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 25/28] target/riscv: Call the second stage MMU in virtualisation mode Alistair Francis
2019-10-08 17:54   ` Palmer Dabbelt
2019-08-23 23:38 ` [Qemu-devel] [PATCH v1 26/28] target/riscv: Add support for the 32-bit MSTATUSH CSR Alistair Francis
2019-10-08 18:36   ` Palmer Dabbelt
2019-08-23 23:39 ` [Qemu-devel] [PATCH v1 27/28] target/riscv: Add the MSTATUS_MPV_ISSET helper macro Alistair Francis
2019-10-08 18:36   ` Palmer Dabbelt
2019-10-16 21:14     ` Alistair Francis
2019-08-23 23:39 ` [Qemu-devel] [PATCH v1 28/28] target/riscv: Allow enabling the Hypervisor extension Alistair Francis
2019-10-08 18:53   ` Palmer Dabbelt

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).