Add decode patterns for LVZ virtualization instructions:
gcsrrd, gcsrwr, gcsrxchg for guest CSR access, gtlbclr,
gtlbflush, gtlbsrch, gtlbrd, gtlbwr, gtlbfill for guest
TLB management, and hvcl for hypervisor call. Add TCG
translation with guest-mode CSR access, GSPR trapping,
GUEST_READONLY flag checking, and guest TLB operations.
Finalize CSR offset mechanism with per-VM-level offsets.
Add disassembly support for new CSR names.

Signed-off-by: SignKirigami <[email protected]>
Signed-off-by: Hengyu Yu <[email protected]>
---
 target/loongarch/csr.c                        |   8 +-
 target/loongarch/csr.h                        |   9 +-
 target/loongarch/disas.c                      |  16 +
 target/loongarch/insns.decode                 |  14 +
 .../tcg/insn_trans/trans_extra.c.inc          |   2 +-
 .../tcg/insn_trans/trans_privileged.c.inc     | 289 ++++++++++++++++--
 target/loongarch/tcg/translate.c              |   6 +-
 7 files changed, 314 insertions(+), 30 deletions(-)

diff --git a/target/loongarch/csr.c b/target/loongarch/csr.c
index 2157f55fb5..ed9d25edf2 100644
--- a/target/loongarch/csr.c
+++ b/target/loongarch/csr.c
@@ -9,14 +9,14 @@
 #define CSR_OFF_FUNCS(NAME, FL, RD, WR)                    \
     [LOONGARCH_CSR_##NAME] = {                             \
         .name   = (stringify(NAME)),                       \
-        .offset = CSR_OFFSET(CSR_##NAME),                  \
+        .offset = CSR_OFFSET(CSR_##NAME, 0),               \
         .flags = FL, .readfn = RD, .writefn = WR           \
     }
 
 #define CSR_OFF_ARRAY(NAME, N)                                \
     [LOONGARCH_CSR_##NAME(N)] = {                             \
         .name   = (stringify(NAME##N)),                       \
-        .offset = CSR_OFFSET(CSR_##NAME[N]),                  \
+        .offset = CSR_OFFSET(CSR_##NAME[N], 0),               \
         .flags = CSRFL_BASIC, .readfn = NULL, .writefn = NULL \
     }
 
@@ -25,13 +25,13 @@
 #define GCSR_OFF_FUNCS(NAME, FL, RD, WR)                  \
     [LOONGARCH_CSR_##NAME] = {                            \
         .name   = (stringify(GCSR_##NAME)),               \
-        .offset = CPU_CSR_OFFSET(CSR_##NAME, 1),          \
+        .offset = CSR_OFFSET(CSR_##NAME, 1),              \
         .flags = FL, .readfn = RD, .writefn = WR          \
     }
 #define GCSR_OFF_ARRAY(NAME, N)                               \
     [LOONGARCH_CSR_##NAME(N)] = {                             \
         .name   = (stringify(GCSR_##NAME##N)),                \
-        .offset = CPU_CSR_OFFSET(CSR_##NAME[N], 1),           \
+        .offset = CSR_OFFSET(CSR_##NAME[N], 1),               \
         .flags = CSRFL_BASIC, .readfn = NULL, .writefn = NULL \
     }
 #define GCSR_OFF_FLAGS(NAME, FL) GCSR_OFF_FUNCS(NAME, FL, NULL, NULL)
diff --git a/target/loongarch/csr.h b/target/loongarch/csr.h
index e233338dd3..c39230f30c 100644
--- a/target/loongarch/csr.h
+++ b/target/loongarch/csr.h
@@ -8,10 +8,9 @@
 
 #include "cpu-csr.h"
 
-#define CSR_OFFSET(id)                  offsetof(CPUSysState, id)
-#define CPU_CSR_OFFSET(id, vm_level)                                     \
+#define CSR_OFFSET(id, vm_level)                                     \
                     (offsetof(CPULoongArchState, sys_states[vm_level])   \
-                             + CSR_OFFSET(id))
+                    + offsetof(CPUSysState, id))
 
 typedef void (*GenCSRFunc)(void);
 enum {
@@ -35,8 +34,4 @@ typedef struct {
 CSRInfo *get_csr(unsigned int csr_num);
 CSRInfo *get_gcsr(unsigned int csr_num);
 bool set_csr_flag(unsigned int csr_num, int flag);
-static inline unsigned int get_csr_offset(const CSRInfo *csr, int vm_level)
-{
-    return csr->offset + offsetof(CPULoongArchState, sys_states[vm_level]);
-}
 #endif /* TARGET_LOONGARCH_CSR_H */
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 3249ab7ac6..db0e556adb 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -51,6 +51,8 @@ static const char * const csr_names[] = {
     CSR_NAME(BADI),
     CSR_NAME(EENTRY),
     CSR_NAME(TLBIDX),
+    CSR_NAME(GTLBC),
+    CSR_NAME(TRGP),
     CSR_NAME(TLBEHI),
     CSR_NAME(TLBELO0),
     CSR_NAME(TLBELO1),
@@ -87,6 +89,10 @@ static const char * const csr_names[] = {
     CSR_NAME(TVAL),
     CSR_NAME(CNTC),
     CSR_NAME(TICLR),
+    CSR_NAME(GSTAT),
+    CSR_NAME(GCFG),
+    CSR_NAME(GINTC),
+    CSR_NAME(GCNTC),
     CSR_NAME(LLBCTL),
     CSR_NAME(IMPCTL1),
     CSR_NAME(IMPCTL2),
@@ -698,6 +704,16 @@ 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(gtlbclr,      empty)
+INSN(gtlbflush,    empty)
+INSN(gtlbsrch,     empty)
+INSN(gtlbrd,       empty)
+INSN(gtlbwr,       empty)
+INSN(gtlbfill,     empty)
+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..b40fabe9d7 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -493,6 +493,20 @@ 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
+}
+
+gtlbclr          0000 01100100 10000 01000 00000 00001    @empty
+gtlbflush        0000 01100100 10000 01001 00000 00001    @empty
+gtlbsrch         0000 01100100 10000 01010 00000 00001    @empty
+gtlbrd           0000 01100100 10000 01011 00000 00001    @empty
+gtlbwr           0000 01100100 10000 01100 00000 00001    @empty
+gtlbfill         0000 01100100 10000 01101 00000 00001    @empty
+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_extra.c.inc 
b/target/loongarch/tcg/insn_trans/trans_extra.c.inc
index 655dce329e..5a404632f5 100644
--- a/target/loongarch/tcg/insn_trans/trans_extra.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_extra.c.inc
@@ -55,7 +55,7 @@ static bool gen_rdtime(DisasContext *ctx, arg_rr *a,
         tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32);
     }
 
-    offset = CPU_CSR_OFFSET(CSR_TID, 0);
+    offset = CSR_OFFSET(CSR_TID, 0);
     tcg_gen_ld_i64(dst2, tcg_env, offset);
 
     return true;
diff --git a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc 
b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
index 3cdf061e3d..adf088627e 100644
--- a/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/tcg/insn_trans/trans_privileged.c.inc
@@ -39,6 +39,16 @@ 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(gtlbclr)
+GEN_FALSE_TRANS(gtlbflush)
+GEN_FALSE_TRANS(gtlbsrch)
+GEN_FALSE_TRANS(gtlbrd)
+GEN_FALSE_TRANS(gtlbwr)
+GEN_FALSE_TRANS(gtlbfill)
+GEN_FALSE_TRANS(hvcl)
 
 #else
 
@@ -69,8 +79,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 +112,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) {
@@ -106,24 +147,27 @@ static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
     TCGv dest;
     const CSRInfo *csr;
     GenCSRRead readfn;
-    tcg_target_long offset;
 
     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) {
             readfn(dest, tcg_env);
         } else {
-            offset = get_csr_offset(csr, 0);
-            tcg_gen_ld_tl(dest, tcg_env, offset);
+            tcg_gen_ld_tl(dest, tcg_env, csr->offset);
         }
     }
     gen_set_gpr(a->rd, dest, EXT_NONE);
@@ -135,17 +179,21 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
     TCGv dest, src1;
     const CSRInfo *csr;
     GenCSRWrite writefn;
-    tcg_target_long offset;
 
     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;
@@ -157,9 +205,8 @@ static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
         writefn(dest, tcg_env, src1);
     } else {
         dest = tcg_temp_new();
-        offset = get_csr_offset(csr, 0);
-        tcg_gen_ld_tl(dest, tcg_env, offset);
-        tcg_gen_st_tl(src1, tcg_env, offset);
+        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;
@@ -170,25 +217,140 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg 
*a)
     TCGv src1, mask, oldv, newv, temp;
     const CSRInfo *csr;
     GenCSRWrite writefn;
-    tcg_target_long offset;
 
     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();
+
+    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);
+
+    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_gcsrrd(DisasContext *ctx, arg_gcsrrd *a)
+{
+    TCGv dest;
+    const CSRInfo *csr;
+    GenCSRRead readfn;
+
+    if (check_plv(ctx) || !avail_LVZ(ctx)) {
+        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) || !avail_LVZ(ctx)) {
+        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) || !avail_LVZ(ctx)) {
+        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);
@@ -196,8 +358,12 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg 
*a)
     newv = tcg_temp_new();
     temp = tcg_temp_new();
 
-    offset = get_csr_offset(csr, 0);
-    tcg_gen_ld_tl(oldv, tcg_env, offset);
+    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);
@@ -206,7 +372,7 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
     if (writefn) {
         writefn(oldv, tcg_env, newv);
     } else {
-        tcg_gen_st_tl(newv, tcg_env, offset);
+        tcg_gen_st_tl(newv, tcg_env, csr->offset);
     }
     gen_set_gpr(a->rd, oldv, EXT_NONE);
     return true;
@@ -218,6 +384,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;
     }
@@ -231,6 +402,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;
     }
@@ -249,7 +425,7 @@ TRANS64(iocsrwr_d, IOCSR, gen_iocsrwr, gen_helper_iocsrwr_d)
 
 static void check_mmu_idx(DisasContext *ctx)
 {
-    if (ctx->mem_idx != MMU_DA_IDX) {
+    if (ctx->mem_idx != MMU_DA_IDX && ctx->mem_idx != MMU_GUEST_DA_IDX) {
         tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
         ctx->base.is_jmp = DISAS_EXIT;
     }
@@ -273,6 +449,24 @@ static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a)
     return true;
 }
 
+static bool trans_gtlbsrch(DisasContext *ctx, arg_gtlbsrch *a)
+{
+    if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+    gen_helper_gtlbsrch(tcg_env);
+    return true;
+}
+
+static bool trans_gtlbrd(DisasContext *ctx, arg_gtlbrd *a)
+{
+    if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+    gen_helper_gtlbrd(tcg_env);
+    return true;
+}
+
 static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
 {
     if (check_plv(ctx)) {
@@ -283,6 +477,16 @@ static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
     return true;
 }
 
+static bool trans_gtlbwr(DisasContext *ctx, arg_gtlbwr *a)
+{
+    if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+    gen_helper_gtlbwr(tcg_env);
+    check_mmu_idx(ctx);
+    return true;
+}
+
 static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a)
 {
     if (check_plv(ctx)) {
@@ -293,6 +497,16 @@ static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill 
*a)
     return true;
 }
 
+static bool trans_gtlbfill(DisasContext *ctx, arg_gtlbfill *a)
+{
+    if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+    gen_helper_gtlbfill(tcg_env);
+    check_mmu_idx(ctx);
+    return true;
+}
+
 static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
 {
     if (check_plv(ctx)) {
@@ -303,6 +517,16 @@ static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
     return true;
 }
 
+static bool trans_gtlbclr(DisasContext *ctx, arg_gtlbclr *a)
+{
+    if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+    gen_helper_gtlbclr(tcg_env);
+    check_mmu_idx(ctx);
+    return true;
+}
+
 static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
 {
     if (check_plv(ctx)) {
@@ -313,6 +537,16 @@ static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush 
*a)
     return true;
 }
 
+static bool trans_gtlbflush(DisasContext *ctx, arg_gtlbflush *a)
+{
+    if (check_plv(ctx) || !avail_LVZ(ctx) || ctx->guest_mode) {
+        return false;
+    }
+    gen_helper_gtlbflush(tcg_env);
+    check_mmu_idx(ctx);
+    return true;
+}
+
 static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
 {
     TCGv rj = gpr_src(ctx, a->rj, EXT_NONE);
@@ -444,6 +678,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;
 }
@@ -454,9 +692,26 @@ 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_hvcl(DisasContext *ctx, arg_hvcl *a)
+{
+    if (!avail_LVZ(ctx) || !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.  */
-- 
2.52.0


Reply via email to