Add will_return_to_guest() function, and handle process of return to guest at
end of helper_ertn().

Signed-off-by: SignKirigami <[email protected]>
Signed-off-by: Hengyu Yu <[email protected]>
---
 target/loongarch/cpu.h           |  8 ++++++++
 target/loongarch/tcg/op_helper.c | 14 ++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ba28d80272..891eea47bd 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -573,6 +573,14 @@ static inline void trigger_vm_exit(CPULoongArchState *env)
     env->vm_exit = true;
 }
 
+static inline bool will_return_to_guest(CPULoongArchState *env)
+{
+    if (!cpu_has_lvz(env) || env_vm_level(env) == VM_LEVEL1) {
+        return false;
+    }
+    return FIELD_EX64(get_sys(env, VM_LEVEL0)->CSR_GSTAT, CSR_GSTAT, PVM);
+}
+
 static inline CPUTimerState *env_timer(CPULoongArchState *env)
 {
     return &env->sys_states[0].timer_state;
diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c
index f98fe4d4a1..3035dfa08d 100644
--- a/target/loongarch/tcg/op_helper.c
+++ b/target/loongarch/tcg/op_helper.c
@@ -12,6 +12,7 @@
 #include "exec/helper-proto.h"
 #include "accel/tcg/cpu-ldst.h"
 #include "internals.h"
+#include "qemu/main-loop.h"
 #include "qemu/crc32c.h"
 #include <zlib.h> /* for crc32 */
 #include "cpu-csr.h"
@@ -90,6 +91,8 @@ void helper_ertn(CPULoongArchState *env)
 {
     uint64_t csr_pplv, csr_pie;
     CPUSysState *sys = env_sys(env);
+    CPUSysState *host = get_sys(env, VM_LEVEL0);
+    CPUSysState *guest = get_sys(env, VM_LEVEL1);
 
     if (FIELD_EX64(sys->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
         csr_pplv = FIELD_EX64(sys->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV);
@@ -113,6 +116,17 @@ void helper_ertn(CPULoongArchState *env)
     sys->CSR_CRMD = FIELD_DP64(sys->CSR_CRMD, CSR_CRMD, IE, csr_pie);
 
     env->lladdr = 1;
+    if (will_return_to_guest(env)) {
+        host->CSR_GSTAT = FIELD_DP64(host->CSR_GSTAT, CSR_GSTAT, VM, 1);
+        set_sys(env, VM_LEVEL1);
+        bql_lock();
+        if (FIELD_EX64(guest->CSR_ESTAT, CSR_ESTAT, IS)) {
+            cpu_interrupt(env_cpu(env), CPU_INTERRUPT_GUEST);
+        } else {
+            cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_GUEST);
+        }
+        bql_unlock();
+    }
 }
 
 void helper_idle(CPULoongArchState *env)
-- 
2.55.0


Reply via email to