On 2026/10/9 上午11:05, SignKirigami wrote:
Add gcsrrd, gcsrwr and gcsrxchg. Make all csr helper be used by both vm level
0 and 1.

Signed-off-by: SignKirigami <[email protected]>
Signed-off-by: Hengyu Yu <[email protected]>
---
  target/loongarch/disas.c                      |   3 +
  target/loongarch/insns.decode                 |   6 +
  target/loongarch/tcg/csr_helper.c             |  78 +++++++-----
  target/loongarch/tcg/helper.h                 |  22 ++--
  .../tcg/insn_trans/trans_privileged.c.inc     | 111 ++++++++++++++----
  5 files changed, 161 insertions(+), 59 deletions(-)

diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 03d1e560dd..2436c9eec3 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -682,6 +682,9 @@ INSN(bgeu,         rr_offs)
  INSN(csrrd,        r_csr)
  INSN(csrwr,        r_csr)
  INSN(csrxchg,      rr_csr)
+INSN(gcsrrd,        r_csr)
+INSN(gcsrwr,        r_csr)
+INSN(gcsrxchg,      rr_csr)
  INSN(iocsrrd_b,    rr)
  INSN(iocsrrd_h,    rr)
  INSN(iocsrrd_w,    rr)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 3089d42044..4612af9433 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -493,6 +493,12 @@ bgeu            0110 11 ................ ..... .....     
@rr_offs16
    csrxchg           0000 0100 .............. ..... .....     @rr_csr
  }
+{
+  gcsrrd            0000 0101 .............. 00000 .....     @r_csr
+  gcsrwr            0000 0101 .............. 00001 .....     @r_csr
+  gcsrxchg          0000 0101 .............. ..... .....     @rr_csr
+}
+
  iocsrrd_b        0000 01100100 10000 00000 ..... .....    @rr
  iocsrrd_h        0000 01100100 10000 00001 ..... .....    @rr
  iocsrrd_w        0000 01100100 10000 00010 ..... .....    @rr
diff --git a/target/loongarch/tcg/csr_helper.c 
b/target/loongarch/tcg/csr_helper.c
index ecfba63228..7ef0032f5d 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -18,9 +18,10 @@
  #include "cpu-csr.h"
  #include "cpu-mmu.h"
-target_ulong helper_csrwr_stlbps(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_stlbps(CPULoongArchState *env,
+                                 target_ulong val, uint32_t vm_level)
  {
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
      int64_t old_v = sys->CSR_STLBPS;
/*
@@ -40,10 +41,10 @@ target_ulong helper_csrwr_stlbps(CPULoongArchState *env, 
target_ulong val)
      return old_v;
  }
-target_ulong helper_csrrd_pgd(CPULoongArchState *env)
+target_ulong helper_csrrd_pgd(CPULoongArchState *env, uint32_t vm_level)
  {
      int64_t v;
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
if (sys->CSR_TLBRERA & 0x1) {
          v = sys->CSR_TLBRBADV;
@@ -60,25 +61,30 @@ target_ulong helper_csrrd_pgd(CPULoongArchState *env)
      return v;
  }
-target_ulong helper_csrrd_cpuid(CPULoongArchState *env)
+target_ulong helper_csrrd_cpuid(CPULoongArchState *env, uint32_t vm_level)
  {
      LoongArchCPU *lac = env_archcpu(env);
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
+
+    if (vm_level) {
+        return sys->CSR_CPUID;
+    }
sys->CSR_CPUID = CPU(lac)->cpu_index; return sys->CSR_CPUID;
  }
-target_ulong helper_csrrd_tval(CPULoongArchState *env)
+target_ulong helper_csrrd_tval(CPULoongArchState *env, uint32_t vm_level)
  {
-    return cpu_loongarch_get_timer_ticks(env_timer(env));
+    CPUTimerState *timer = vm_level ? env_guest_timer(env) : env_timer(env);
+    return cpu_loongarch_get_timer_ticks(timer);
  }
-target_ulong helper_csrrd_msgir(CPULoongArchState *env)
+target_ulong helper_csrrd_msgir(CPULoongArchState *env, uint32_t vm_level)
  {
      int irq, new;
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
irq = find_first_bit((unsigned long *)sys->CSR_MSGIS, 256);
      if (irq < 256) {
@@ -97,13 +103,23 @@ target_ulong helper_csrrd_msgir(CPULoongArchState *env)
      return irq;
  }
-target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_estat(CPULoongArchState *env,
+                                target_ulong val, uint32_t vm_level)
  {
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
      int64_t old_v = sys->CSR_ESTAT;
- /* Only IS[1:0] can be written */
+    /* When guest = 0, only IS[1:0] can be written.
+     * When guest = 1, ecode and esubcode of
+     * VM_LEVEL1 can be written by VM_LEVEL0.
+     */
      sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, 0, 2, val);
+    if (vm_level) {
+        sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, 2, 11,
+                                   extract64(val, 2, 11));
+        sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, 16, 15,
+                                   extract64(val, 16, 15));
+    }
      /*
       * Software interrupts (SWI0/SWI1) are latched in CSR.ESTAT.IS[1:0].
       * Make sure the CPU interrupt request state tracks the pending bits,
@@ -111,16 +127,17 @@ target_ulong helper_csrwr_estat(CPULoongArchState *env, 
target_ulong val)
       */
      if (sys->CSR_ESTAT != old_v) {
          bql_lock();
-        loongarch_cpu_update_irq(env_archcpu(env), false);
+        loongarch_cpu_update_irq(env_archcpu(env), vm_level);
          bql_unlock();
      }
return old_v;
  }
-target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_asid(CPULoongArchState *env,
+                               target_ulong val, uint32_t vm_level)
  {
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
      int64_t old_v = sys->CSR_ASID;
/* Only ASID filed of CSR_ASID can be written */
@@ -131,9 +148,10 @@ target_ulong helper_csrwr_asid(CPULoongArchState *env, 
target_ulong val)
      return old_v;
  }
-target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_tcfg(CPULoongArchState *env,
+                               target_ulong val, uint32_t vm_level)
  {
-    CPUTimerState *timer = env_timer(env);
+    CPUTimerState *timer = vm_level ? env_guest_timer(env) : env_timer(env);
      CPUSysState *sys = container_of(timer, CPUSysState, timer_state);
      int64_t old_v = sys->CSR_TCFG;
@@ -142,9 +160,10 @@ target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val)
      return old_v;
  }
-target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_ticlr(CPULoongArchState *env,
+                                target_ulong val, uint32_t vm_level)
  {
-    CPUTimerState *timer = env_timer(env);
+    CPUTimerState *timer = vm_level ? env_guest_timer(env) : env_timer(env);
      int64_t old_v = 0;
if (val & 0x1) {
@@ -155,10 +174,11 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env, 
target_ulong val)
      return old_v;
  }
-target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_pwcl(CPULoongArchState *env,
+                               target_ulong val, uint32_t vm_level)
  {
      uint8_t shift, ptbase;
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
      int64_t old_v = sys->CSR_PWCL;
/*
@@ -180,18 +200,20 @@ target_ulong helper_csrwr_pwcl(CPULoongArchState *env, 
target_ulong val)
      return old_v;
  }
-target_ulong helper_csrwr_pwch(CPULoongArchState *env, target_ulong val)
+target_ulong helper_csrwr_pwch(CPULoongArchState *env,
+                               target_ulong val, uint32_t vm_level)
  {
-    uint8_t has_ptw;
-    CPUSysState *sys = env_sys(env);
+    uint8_t host_has_ptw;
+    CPUSysState *sys = get_sys(env, vm_level);
      int64_t old_v = sys->CSR_PWCH;
val = FIELD_DP64(val, CSR_PWCH, RESERVE, 0);
-    has_ptw = FIELD_EX32(env->cpucfg[2], CPUCFG2, HPTW);
-    if (!has_ptw) {
+    //TODO: host can't read guest cpucfg
+    host_has_ptw = FIELD_EX32(env->cpucfg[2], CPUCFG2, HPTW);
+    if (!host_has_ptw) {
          val = FIELD_DP64(val, CSR_PWCH, HPTW_EN, 0);
      }
sys->CSR_PWCH = val;
      return old_v;
- }
+}
diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h
index a27b80b087..bce5f46dc2 100644
--- a/target/loongarch/tcg/helper.h
+++ b/target/loongarch/tcg/helper.h
@@ -93,17 +93,17 @@ DEF_HELPER_1(rdtime_d, i64, env)
#ifndef CONFIG_USER_ONLY
  /* CSRs helper */
-DEF_HELPER_1(csrrd_pgd, i64, env)
-DEF_HELPER_1(csrrd_cpuid, i64, env)
-DEF_HELPER_1(csrrd_tval, i64, env)
-DEF_HELPER_1(csrrd_msgir, i64, env)
-DEF_HELPER_2(csrwr_stlbps, i64, env, tl)
-DEF_HELPER_2(csrwr_estat, i64, env, tl)
-DEF_HELPER_2(csrwr_asid, i64, env, tl)
-DEF_HELPER_2(csrwr_tcfg, i64, env, tl)
-DEF_HELPER_2(csrwr_ticlr, i64, env, tl)
-DEF_HELPER_2(csrwr_pwcl, i64, env, tl)
-DEF_HELPER_2(csrwr_pwch, i64, env, tl)
+DEF_HELPER_2(csrrd_pgd, i64, env, i32)
+DEF_HELPER_2(csrrd_cpuid, i64, env, i32)
+DEF_HELPER_2(csrrd_tval, i64, env, i32)
+DEF_HELPER_2(csrrd_msgir, i64, env, i32)
+DEF_HELPER_3(csrwr_stlbps, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_estat, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_asid, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_tcfg, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_ticlr, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_pwcl, i64, env, tl, i32)
+DEF_HELPER_3(csrwr_pwch, i64, env, tl, i32)
  DEF_HELPER_2(iocsrrd_b, i64, env, tl)
  DEF_HELPER_2(iocsrrd_h, i64, env, tl)
  DEF_HELPER_2(iocsrrd_w, i64, env, tl)
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc 
b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 00e8f61e42..139dbd6e2a 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -39,11 +39,14 @@ GEN_FALSE_TRANS(lddir)
  GEN_FALSE_TRANS(ertn)
  GEN_FALSE_TRANS(dbcl)
  GEN_FALSE_TRANS(idle)
+GEN_FALSE_TRANS(gcsrrd)
+GEN_FALSE_TRANS(gcsrwr)
+GEN_FALSE_TRANS(gcsrxchg)
#else -typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env);
-typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src);
+typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env, TCGv_i32 vm_level);
+typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src, TCGv_i32 
vm_level);
static bool check_plv(DisasContext *ctx)
  {
@@ -88,10 +91,14 @@ void loongarch_csr_translate_init(void)
  }
  #undef SET_CSR_FUNC
-static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write)
+static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr,
+                            bool write, int vm_level)
  {
      if ((csr->flags & CSRFL_READONLY) && write) {
-        return false;
+        /* host writes guest read-only CSRs is allowed */
+        if (is_guest_mmu_idx(ctx->mem_idx) || vm_level == VM_LEVEL0) {
+            return false;
+        }
      }
      if ((csr->flags & CSRFL_IO) && translator_io_start(&ctx->base)) {
          ctx->base.is_jmp = DISAS_EXIT_UPDATE;
@@ -101,7 +108,7 @@ static bool check_csr_flags(DisasContext *ctx, const 
CSRInfo *csr, bool write)
      return true;
  }
-static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
+static bool trans_csrrd_impl(DisasContext *ctx, arg_r_csr *a, int vm_level)
  {
      TCGv dest;
      const CSRInfo *csr;
@@ -116,21 +123,29 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
          /* CSR is undefined: read as 0. */
          dest = tcg_constant_tl(0);
      } else {
-        check_csr_flags(ctx, csr, false);
-        dest = gpr_dst(ctx, a->rd, EXT_NONE);
-        readfn = (GenCSRRead)csr->readfn;
-        if (readfn) {
-            readfn(dest, tcg_env);
+        check_csr_flags(ctx, csr, false, vm_level);
+        if (vm_level && (csr->flags & CSRFL_GSPR)) {
+            if (is_guest_mmu_idx(ctx->mem_idx)) {
+                generate_exception(ctx, EXCCODE_GSPR);
+                return true;
+            }
+            dest = tcg_constant_tl(0);
          } else {
-            offset = get_csr_offset(csr, 0);
-            tcg_gen_ld_tl(dest, tcg_env, offset);
+            dest = gpr_dst(ctx, a->rd, EXT_NONE);
+            readfn = (GenCSRRead)csr->readfn;
+            if (readfn) {
+                readfn(dest, tcg_env, tcg_constant_i32(vm_level));
+            } else {
+                offset = get_csr_offset(csr, vm_level);
+                tcg_gen_ld_tl(dest, tcg_env, offset);
+            }
Can this patch be split into three smaller verson? such as:
  1. lvz support with csrrd/csrwr/csrxchg instruction.
  2. lvz support with new gcsrrd/gcsrwr/gcsrxchg instruction.
  3. Common API for csrrd/gcsrrd.
or
  1. lvz support with csrrd/csrwr/csrxchg instruction.
  2. Common API extraction for csrrd/gcsrr.
  3. lvz support with new gcsrrd/gcsrwr/gcsrxchg instruction.

With the smaller versions, it is easier to review and find the potential issues.

Regards
Bibo Mao
          }
      }
      gen_set_gpr(a->rd, dest, EXT_NONE);
      return true;
  }
-static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
+static bool trans_csrwr_impl(DisasContext *ctx, arg_r_csr *a, int vm_level)
  {
      TCGv dest, src1;
      const CSRInfo *csr;
@@ -146,18 +161,26 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
          gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
          return true;
      }
-    if (!check_csr_flags(ctx, csr, true)) {
+    if (!check_csr_flags(ctx, csr, true, vm_level)) {
          /* CSR is readonly: trap. */
          return false;
      }
+    if (vm_level && (csr->flags & CSRFL_GSPR)) {
+        if (is_guest_mmu_idx(ctx->mem_idx)) {
+            generate_exception(ctx, EXCCODE_GSPR);
+            return true;
+        }
+        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+        return true;
+    }
      src1 = gpr_src(ctx, a->rd, EXT_NONE);
      writefn = (GenCSRWrite)csr->writefn;
      if (writefn) {
          dest = gpr_dst(ctx, a->rd, EXT_NONE);
-        writefn(dest, tcg_env, src1);
+        writefn(dest, tcg_env, src1, tcg_constant_i32(vm_level));
      } else {
          dest = tcg_temp_new();
-        offset = get_csr_offset(csr, 0);
+        offset = get_csr_offset(csr, vm_level);
          tcg_gen_ld_tl(dest, tcg_env, offset);
          tcg_gen_st_tl(src1, tcg_env, offset);
      }
@@ -165,7 +188,7 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
      return true;
  }
-static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
+static bool trans_csrxchg_impl(DisasContext *ctx, arg_rr_csr *a, int vm_level)
  {
      TCGv src1, mask, oldv, newv, temp;
      const CSRInfo *csr;
@@ -182,11 +205,20 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg 
*a)
          return true;
      }
- if (!check_csr_flags(ctx, csr, true)) {
+    if (!check_csr_flags(ctx, csr, true, vm_level)) {
          /* CSR is readonly: trap. */
          return false;
      }
+ if (vm_level && (csr->flags & CSRFL_GSPR)) {
+        if (is_guest_mmu_idx(ctx->mem_idx)) {
+            generate_exception(ctx, EXCCODE_GSPR);
+            return true;
+        }
+        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+        return true;
+    }
+
      /* So far only readonly csrs have readfn. */
      assert(csr->readfn == NULL);
@@ -196,7 +228,7 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
      newv = tcg_temp_new();
      temp = tcg_temp_new();
- offset = get_csr_offset(csr, 0);
+    offset = get_csr_offset(csr, vm_level);
      tcg_gen_ld_tl(oldv, tcg_env, offset);
      tcg_gen_and_tl(newv, src1, mask);
      tcg_gen_andc_tl(temp, oldv, mask);
@@ -204,7 +236,7 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
writefn = (GenCSRWrite)csr->writefn;
      if (writefn) {
-        writefn(oldv, tcg_env, newv);
+        writefn(oldv, tcg_env, newv, tcg_constant_i32(vm_level));
      } else {
          tcg_gen_st_tl(newv, tcg_env, offset);
      }
@@ -212,6 +244,45 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg 
*a)
      return true;
  }
+static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
+{
+    return trans_csrrd_impl(ctx, a, is_guest_mmu_idx(ctx->mem_idx));
+}
+
+static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
+{
+    return trans_csrwr_impl(ctx, a, is_guest_mmu_idx(ctx->mem_idx));
+}
+
+static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
+{
+    return trans_csrxchg_impl(ctx, a, is_guest_mmu_idx(ctx->mem_idx));
+}
+
+static bool trans_gcsrrd(DisasContext *ctx, arg_gcsrrd *a)
+{
+    if (!avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+        return false;
+    }
+    return trans_csrrd_impl(ctx, a, VM_LEVEL1);
+}
+
+static bool trans_gcsrwr(DisasContext *ctx, arg_gcsrwr *a)
+{
+    if (!avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+        return false;
+    }
+    return trans_csrwr_impl(ctx, a, VM_LEVEL1);
+}
+
+static bool trans_gcsrxchg(DisasContext *ctx, arg_gcsrxchg *a)
+{
+    if (!avail_LVZ(ctx) || is_guest_mmu_idx(ctx->mem_idx)) {
+        return false;
+    }
+    return trans_csrxchg_impl(ctx, a, VM_LEVEL1);
+}
+
  static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a,
                          void (*func)(TCGv, TCGv_ptr, TCGv))
  {



Reply via email to