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


Reply via email to