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