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);
+            }
         }
     }
     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))
 {
-- 
2.55.0


Reply via email to