On 2026/5/19 下午2:30, SignKirigami wrote:
Signed-off-by: SignKirigami <[email protected]>
Signed-off-by: Hengyu Yu <[email protected]>
---
  target/loongarch/disas.c                      |   4 +
  target/loongarch/insns.decode                 |  11 +
  .../tcg/insn_trans/trans_privileged.c.inc     | 225 +++++++++++++++++-
  target/loongarch/tcg/translate.c              |   6 +-
  target/loongarch/translate.h                  |   2 +
  5 files changed, 240 insertions(+), 8 deletions(-)

diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 3249ab7ac6..cae416266b 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -698,6 +698,10 @@ INSN(tlbfill,      empty)
  INSN(tlbclr,       empty)
  INSN(tlbflush,     empty)
  INSN(invtlb,       i_rr)
+INSN(gcsrrd,       r_csr)
+INSN(gcsrwr,       r_csr)
+INSN(gcsrxchg,     rr_csr)
+INSN(hvcl,         i)
  INSN(cacop,        cop_r_i)
  INSN(lddir,        rr_i)
  INSN(ldpte,        j_i)
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 3089d42044..2ade384081 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -493,6 +493,17 @@ bgeu            0110 11 ................ ..... .....     
@rr_offs16
    csrxchg           0000 0100 .............. ..... .....     @rr_csr
  }
+#
+# LVZ (LoongArch Virtualization) instructions
+#
+{
+  gcsrrd            0000 0101 .............. 00000 .....     @r_csr
+  gcsrwr            0000 0101 .............. 00001 .....     @r_csr
+  gcsrxchg          0000 0101 .............. ..... .....     @rr_csr
+}
+
+hvcl             0000 0000 0010 1011 1 ...............    @i15
+
  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/insn_trans/trans_privileged.c.inc 
b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 2094d182ac..0cb629e5d7 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -39,6 +39,10 @@ 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)
+GEN_FALSE_TRANS(hvcl)
#else @@ -69,8 +73,25 @@ static bool set_csr_trans_func(unsigned int csr_num, GenCSRRead readfn,
      return true;
  }
+static bool set_gcsr_trans_func(unsigned int csr_num, GenCSRRead readfn,
+                                GenCSRWrite writefn)
+{
+    CSRInfo *csr;
+
+    csr = get_gcsr(csr_num);
+    if (!csr) {
+        return false;
+    }
+
+    csr->readfn = (GenCSRFunc)readfn;
+    csr->writefn = (GenCSRFunc)writefn;
+    return true;
+}
+
  #define SET_CSR_FUNC(NAME, read, write)                 \
          set_csr_trans_func(LOONGARCH_CSR_##NAME, read, write)
+#define SET_GCSR_FUNC(NAME, read, write)                \
+        set_gcsr_trans_func(LOONGARCH_CSR_##NAME, read, write)
void loongarch_csr_translate_init(void)
  {
@@ -85,14 +106,28 @@ void loongarch_csr_translate_init(void)
      SET_CSR_FUNC(TVAL,  gen_helper_csrrd_tval, NULL);
      SET_CSR_FUNC(TICLR, NULL, gen_helper_csrwr_ticlr);
      SET_CSR_FUNC(MSGIR, gen_helper_csrrd_msgir, NULL);
+    SET_CSR_FUNC(GSTAT, NULL, gen_helper_csrwr_gstat);
+    SET_CSR_FUNC(GTLBC, NULL, gen_helper_csrwr_gtlbc);
+    SET_CSR_FUNC(GINTC, NULL, gen_helper_csrwr_gintc);
+
+    SET_GCSR_FUNC(ESTAT, NULL, gen_helper_gcsrwr_estat);
+    SET_GCSR_FUNC(ASID, NULL, gen_helper_gcsrwr_asid);
+    SET_GCSR_FUNC(PGD, gen_helper_gcsrrd_pgd, NULL);
+    SET_GCSR_FUNC(TCFG, NULL, gen_helper_gcsrwr_tcfg);
+    SET_GCSR_FUNC(TVAL, gen_helper_gcsrrd_tval, NULL);
+    SET_GCSR_FUNC(TICLR, NULL, gen_helper_gcsrwr_ticlr);
  }
  #undef SET_CSR_FUNC
+#undef SET_GCSR_FUNC
static bool check_csr_flags(DisasContext *ctx, const CSRInfo *csr, bool write)
  {
      if ((csr->flags & CSRFL_READONLY) && write) {
          return false;
      }
+    if ((csr->flags & CSRFL_GUEST_READONLY) && ctx->guest_mode && write) {
+        return false;
+    }
      if ((csr->flags & CSRFL_IO) && translator_io_start(&ctx->base)) {
          ctx->base.is_jmp = DISAS_EXIT_UPDATE;
      } else if ((csr->flags & CSRFL_EXITTB) && write) {
@@ -110,12 +145,17 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
      if (check_plv(ctx)) {
          return false;
      }
-    csr = get_csr(a->csr);
+    csr = ctx->guest_mode ? get_gcsr(a->csr) : get_csr(a->csr);
      if (csr == NULL) {
          /* CSR is undefined: read as 0. */
          dest = tcg_constant_tl(0);
      } else {
          check_csr_flags(ctx, csr, false);
+        if (ctx->guest_mode && (csr->flags & CSRFL_GSPR)) {
+            gen_helper_gspr(tcg_env);
+            gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+            return true;
+        }
          dest = gpr_dst(ctx, a->rd, EXT_NONE);
          readfn = (GenCSRRead)csr->readfn;
          if (readfn) {
@@ -137,12 +177,17 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
      if (check_plv(ctx)) {
          return false;
      }
-    csr = get_csr(a->csr);
+    csr = ctx->guest_mode ? get_gcsr(a->csr) : get_csr(a->csr);
      if (csr == NULL) {
          /* CSR is undefined: write ignored, read old_value as 0. */
          gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
          return true;
      }
+    if (ctx->guest_mode && (csr->flags & CSRFL_GSPR)) {
+        gen_helper_gspr(tcg_env);
+        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+        return true;
+    }
      if (!check_csr_flags(ctx, csr, true)) {
          /* CSR is readonly: trap. */
          return false;
@@ -170,28 +215,35 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg 
*a)
      if (check_plv(ctx)) {
          return false;
      }
-    csr = get_csr(a->csr);
+    csr = ctx->guest_mode ? get_gcsr(a->csr) : get_csr(a->csr);
      if (csr == NULL) {
          /* CSR is undefined: write ignored, read old_value as 0. */
          gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
          return true;
      }
+    if (ctx->guest_mode && (csr->flags & CSRFL_GSPR)) {
+        gen_helper_gspr(tcg_env);
+        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+        return true;
+    }
if (!check_csr_flags(ctx, csr, true)) {
          /* CSR is readonly: trap. */
          return false;
      }
- /* So far only readonly csrs have readfn. */
-    assert(csr->readfn == NULL);
-
      src1 = gpr_src(ctx, a->rd, EXT_NONE);
      mask = gpr_src(ctx, a->rj, EXT_NONE);
      oldv = tcg_temp_new();
      newv = tcg_temp_new();
      temp = tcg_temp_new();
- tcg_gen_ld_tl(oldv, tcg_env, csr->offset);
+    if (csr->readfn) {
+        GenCSRRead readfn = (GenCSRRead)csr->readfn;
+        readfn(oldv, tcg_env);
+    } else {
+        tcg_gen_ld_tl(oldv, tcg_env, csr->offset);
+    }
      tcg_gen_and_tl(newv, src1, mask);
      tcg_gen_andc_tl(temp, oldv, mask);
      tcg_gen_or_tl(newv, newv, temp);
@@ -212,6 +264,11 @@ static bool gen_iocsrrd(DisasContext *ctx, arg_rr *a,
      TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
      TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+ if (ctx->guest_mode) {
+        gen_helper_gspr(tcg_env);
+        return true;
+    }
+
      if (check_plv(ctx)) {
          return false;
      }
@@ -225,6 +282,11 @@ static bool gen_iocsrwr(DisasContext *ctx, arg_rr *a,
      TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
      TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+ if (ctx->guest_mode) {
+        gen_helper_gspr(tcg_env);
+        return true;
+    }
+
      if (check_plv(ctx)) {
          return false;
      }
@@ -400,6 +462,10 @@ static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a)
      if (check_plv(ctx)) {
          return false;
      }
+    if (ctx->guest_mode) {
+        gen_helper_gspr(tcg_env);
+        return true;
+    }
      generate_exception(ctx, EXCCODE_DBP);
      return true;
  }
@@ -410,9 +476,154 @@ static bool trans_idle(DisasContext *ctx, arg_idle *a)
          return false;
      }
+ if (ctx->guest_mode) {
+        gen_helper_gspr(tcg_env);
+        return true;
+    }
+
      tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
      gen_helper_idle(tcg_env);
      ctx->base.is_jmp = DISAS_NORETURN;
      return true;
  }
+
+static bool trans_gcsrrd(DisasContext *ctx, arg_gcsrrd *a)
+{
+    TCGv dest;
+    const CSRInfo *csr;
+    GenCSRRead readfn;
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    if (!avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+
+    csr = get_gcsr(a->csr);
+    if (csr == NULL) {
+        dest = tcg_constant_tl(0);
+    } else {
+        dest = gpr_dst(ctx, a->rd, EXT_NONE);
+        if (csr->flags & CSRFL_GSPR) {
+            tcg_gen_movi_tl(dest, 0);
+        } else {
+            readfn = (GenCSRRead)csr->readfn;
+            if (readfn) {
+                readfn(dest, tcg_env);
+            } else {
+                tcg_gen_ld_tl(dest, tcg_env, csr->offset);
+            }
+        }
+    }
+    gen_set_gpr(a->rd, dest, EXT_NONE);
+    return true;
+}
+
+static bool trans_gcsrwr(DisasContext *ctx, arg_gcsrwr *a)
+{
+    TCGv dest, src1;
+    const CSRInfo *csr;
+    GenCSRWrite writefn;
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    if (!avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+
+    csr = get_gcsr(a->csr);
+    if (csr == NULL) {
+        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+        return true;
+    }
+    if (!check_csr_flags(ctx, csr, true)) {
+        return false;
+    }
+    if (csr->flags & CSRFL_GSPR) {
+        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);
+    } else {
+        dest = tcg_temp_new();
+        tcg_gen_ld_tl(dest, tcg_env, csr->offset);
+        tcg_gen_st_tl(src1, tcg_env, csr->offset);
+    }
+    gen_set_gpr(a->rd, dest, EXT_NONE);
+    return true;
+}
+
+static bool trans_gcsrxchg(DisasContext *ctx, arg_gcsrxchg *a)
+{
+    TCGv src1, mask, oldv, newv, temp;
+    const CSRInfo *csr;
+    GenCSRRead readfn;
+    GenCSRWrite writefn;
+
+    if (check_plv(ctx)) {
+        return false;
+    }
+    if (!avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+
+    csr = get_gcsr(a->csr);
+    if (csr == NULL) {
+        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+        return true;
+    }
+    if (!check_csr_flags(ctx, csr, true)) {
+        return false;
+    }
+    if (csr->flags & CSRFL_GSPR) {
+        gen_set_gpr(a->rd, tcg_constant_tl(0), EXT_NONE);
+        return true;
+    }
+
+    src1 = gpr_src(ctx, a->rd, EXT_NONE);
+    mask = gpr_src(ctx, a->rj, EXT_NONE);
+    oldv = tcg_temp_new();
+    newv = tcg_temp_new();
+    temp = tcg_temp_new();
+
+    readfn = (GenCSRRead)csr->readfn;
+    if (readfn) {
+        readfn(oldv, tcg_env);
+    } else {
+        tcg_gen_ld_tl(oldv, tcg_env, csr->offset);
+    }
+    tcg_gen_and_tl(newv, src1, mask);
+    tcg_gen_andc_tl(temp, oldv, mask);
+    tcg_gen_or_tl(newv, newv, temp);
+
+    writefn = (GenCSRWrite)csr->writefn;
+    if (writefn) {
+        writefn(oldv, tcg_env, newv);
+    } else {
+        tcg_gen_st_tl(newv, tcg_env, csr->offset);
+    }
+    gen_set_gpr(a->rd, oldv, EXT_NONE);
+    return true;
+}
+
+static bool trans_hvcl(DisasContext *ctx, arg_hvcl *a)
+{
+    if (!avail_LVZ(ctx)) {
+        return false;
+    }
+    if (!ctx->guest_mode) {
+        return false;
+    }
+    tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
+    gen_helper_hvcl(tcg_env, tcg_constant_i32(a->imm));
+    ctx->base.is_jmp = DISAS_NORETURN;
+    return true;
+}
  #endif
diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/translate.c
index 124dce6269..15c83ef72d 100644
--- a/target/loongarch/tcg/translate.c
+++ b/target/loongarch/tcg/translate.c
@@ -122,12 +122,16 @@ static void 
loongarch_tr_init_disas_context(DisasContextBase *dcbase,
      CPULoongArchState *env = cpu_env(cs);
      DisasContext *ctx = container_of(dcbase, DisasContext, base);
+ ctx->guest_mode = (ctx->base.tb->flags & HW_FLAGS_GUEST_MODE) != 0;
      ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
      ctx->plv = ctx->base.tb->flags & HW_FLAGS_PLV_MASK;
      if (ctx->base.tb->flags & HW_FLAGS_CRMD_PG) {
          ctx->mem_idx = ctx->plv;
+        if (ctx->guest_mode) {
+            ctx->mem_idx += MMU_GUEST_IDX;
+        }
      } else {
-        ctx->mem_idx = MMU_DA_IDX;
+        ctx->mem_idx = ctx->guest_mode ? MMU_GUEST_DA_IDX : MMU_DA_IDX;
      }
/* Bound the number of insns to execute to those left on the page. */
diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h
index 8aa8325dc6..db0650e713 100644
--- a/target/loongarch/translate.h
+++ b/target/loongarch/translate.h
@@ -26,6 +26,7 @@
  #define avail_FP_DP(C)  (FIELD_EX32((C)->cpucfg2, CPUCFG2, FP_DP))
  #define avail_LSPW(C)   (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSPW))
  #define avail_LAM(C)    (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM))
+#define avail_LVZ(C)    (FIELD_EX32((C)->cpucfg2, CPUCFG2, LVZ))
  #define avail_LAM_BH(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAM_BH))
  #define avail_LAMCAS(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LAMCAS))
  #define avail_LSX(C)    (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSX))

static void loongarch_tr_init_disas_context(DisasContextBase *dcbase,
                                            CPUState *cs)
{

    if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LSX)) {
        ctx->vl = LSX_LEN;
    }
    if (FIELD_EX64(env->cpucfg[2], CPUCFG2, LASX)) {
        ctx->vl = LASX_LEN;
    ctx->cpucfg1 = env->cpucfg[1];
    ctx->cpucfg2 = env->cpucfg[2];
    ctx->cpucfg3 = env->cpucfg[3];
}

There may be some problem with cpucfg configuration, for example host has LASX/LSX feature, however vCPU is configured with LASX/LSX feature disabled. With the upper piece of code, ctx->cpucfg1 comes from host feature setting instead.

Regards
Bibo Mao

@@ -66,6 +67,7 @@ typedef struct DisasContext {
      TCGv zero;
      bool la64; /* LoongArch64 mode */
      bool va32; /* 32-bit virtual address */
+    bool guest_mode;
      uint32_t cpucfg1;
      uint32_t cpucfg2;
      uint32_t cpucfg3;



Reply via email to