When vm level 0 fpe, sxe and asxe is set to 0, although on vm level 1 these are enabled, in TCGTBCPUState flags corresponding bit should not be set, and when handling exceptions, executing trigger_vm_exit() in this situation.
Signed-off-by: SignKirigami <[email protected]> --- target/loongarch/tcg/op_helper.c | 20 ++++++++++++++++++++ target/loongarch/tcg/tcg_cpu.c | 17 ++++++++++++----- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c index e2fe4b212f..a24a9b8b6a 100644 --- a/target/loongarch/tcg/op_helper.c +++ b/target/loongarch/tcg/op_helper.c @@ -20,9 +20,29 @@ /* Exceptions helpers */ void helper_raise_exception(CPULoongArchState *env, uint32_t exception) { + CPUSysState *host; + int vm_exit = 0; + if (exception == EXCCODE_GSPR || exception == EXCCODE_HVC) { + vm_exit = 1; + } else if (env_vm_level(env)) { + host = get_sys(env, VM_LEVEL0); + if (exception == EXCCODE_FPD && + FIELD_EX64(host->CSR_EUEN, CSR_EUEN, FPE) == 0) { + vm_exit = 1; + } else if (exception == EXCCODE_SXD && + FIELD_EX64(host->CSR_EUEN, CSR_EUEN, SXE) == 0) { + vm_exit = 1; + } + if (exception == EXCCODE_ASXD && + FIELD_EX64(host->CSR_EUEN, CSR_EUEN, ASXE) == 0) { + vm_exit = 1; + } + } + if (vm_exit) { trigger_vm_exit(env); } + do_raise_exception(env, exception, GETPC()); } diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c index 6f1ba12edb..f70efaad78 100644 --- a/target/loongarch/tcg/tcg_cpu.c +++ b/target/loongarch/tcg/tcg_cpu.c @@ -304,16 +304,23 @@ static vaddr loongarch_pointer_wrap(CPUState *cs, int mmu_idx, static TCGTBCPUState loongarch_get_tb_cpu_state(CPUState *cs) { CPULoongArchState *env = cpu_env(cs); - CPUSysState *sys = env_sys(env); - uint32_t flags; + CPUSysState *sys = env_sys(env), *host; + uint32_t flags, fpe, sxe, asxe; flags = sys->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK); + fpe = FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, FPE); + sxe = FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, SXE); + asxe = FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, ASXE); if (env_vm_level(env) == VM_LEVEL1) { flags |= HW_FLAGS_GUEST_MODE; + host = get_sys(env, VM_LEVEL0); + fpe &= FIELD_EX64(host->CSR_EUEN, CSR_EUEN, FPE); + sxe &= FIELD_EX64(host->CSR_EUEN, CSR_EUEN, SXE); + asxe &= FIELD_EX64(host->CSR_EUEN, CSR_EUEN, ASXE); } - flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE; - flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SXE; - flags |= FIELD_EX64(sys->CSR_EUEN, CSR_EUEN, ASXE) * HW_FLAGS_EUEN_ASXE; + flags |= fpe * HW_FLAGS_EUEN_FPE; + flags |= sxe * HW_FLAGS_EUEN_SXE; + flags |= asxe * HW_FLAGS_EUEN_ASXE; flags |= is_va32(env) * HW_FLAGS_VA32; return (TCGTBCPUState){ .pc = env->pc, .flags = flags }; -- 2.55.0
