On 2026/10/9 上午11:05, SignKirigami wrote:
Route configured hardware interrupts into the guest CSR bank, track guest
interrupt requests separately, and expose guest pending and enable checks
to the TCG runtime.

Signed-off-by: SignKirigami <[email protected]>
Signed-off-by: Hengyu Yu <[email protected]>
---
  target/loongarch/cpu.c            | 35 +++++++++++++++++++--------
  target/loongarch/cpu.h            |  3 +++
  target/loongarch/internals.h      |  4 ++--
  target/loongarch/tcg/csr_helper.c |  2 +-
  target/loongarch/tcg/tcg_cpu.c    | 39 ++++++++++++++++++++++---------
  5 files changed, 59 insertions(+), 24 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 664763137d..5cef63a778 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -58,16 +58,20 @@ static vaddr loongarch_cpu_get_pc(CPUState *cs)
  #ifndef CONFIG_USER_ONLY
  #include "hw/loongarch/virt.h"
-void loongarch_cpu_update_irq(LoongArchCPU *cpu)
+void loongarch_cpu_update_irq(LoongArchCPU *cpu, int vm_level)
  {
      CPULoongArchState *env = &cpu->env;
      CPUState *cs = CPU(cpu);
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
+    int interrupt = vm_level ? CPU_INTERRUPT_GUEST : CPU_INTERRUPT_HARD;
+ if (vm_level == VM_LEVEL1 && env_vm_level(env) != VM_LEVEL1) {
+        return;
+    }
      if (FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS)) {
-        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+        cpu_interrupt(cs, interrupt);
      } else {
-        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(cs, interrupt);
      }
  }
@@ -75,21 +79,28 @@ static void loongarch_cpu_self_set_irq(CPUState *cs, run_on_cpu_data data)
  {
      LoongArchCPU *cpu = LOONGARCH_CPU(cs);
      CPULoongArchState *env = cpu_env(cs);
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys;
+    int vm_level = 0;
      int irq, level;
irq = data.host_int & ~BIT(31);
      level = (data.host_int >> 31) & 1;
+    if (irq >= N_IRQS) {
+        irq -= N_IRQS;
+        vm_level = 1;
+    }
+    sys = get_sys(env, vm_level);
      sys->CSR_ESTAT = deposit64(sys->CSR_ESTAT, irq, 1, level != 0);
-    loongarch_cpu_update_irq(cpu);
+    loongarch_cpu_update_irq(cpu, vm_level);
  }
void loongarch_cpu_set_irq(void *opaque, int irq, int level)
  {
      LoongArchCPU *cpu = opaque;
      CPUState *cs = CPU(cpu);
+    CPULoongArchState *env = cpu_env(cs);
- if (irq < 0 || irq >= N_IRQS) {
+    if (irq < 0 || irq >= (cpu_has_lvz(env) ? N_VIRQS : N_IRQS)) {
          return;
      }
@@ -103,11 +114,11 @@ void loongarch_cpu_set_irq(void *opaque, int irq, int level)
  }
/* Check if there is pending and not masked out interrupt */
-bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
+bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env, int vm_level)
  {
      uint32_t pending;
      uint32_t status;
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
pending = FIELD_EX64(sys->CSR_ESTAT, CSR_ESTAT, IS);
      status  = FIELD_EX64(sys->CSR_ECFG, CSR_ECFG, LIE);
@@ -122,7 +133,11 @@ bool loongarch_cpu_has_work(CPUState *cs)
      bool has_work = false;
if (cpu_test_interrupt(cs, CPU_INTERRUPT_HARD) &&
-        cpu_loongarch_hw_interrupts_pending(cpu_env(cs))) {
+        cpu_loongarch_hw_interrupts_pending(cpu_env(cs), VM_LEVEL0)) {
+        has_work = true;
+    }
+    if (cpu_test_interrupt(cs, CPU_INTERRUPT_GUEST) &&
+        cpu_loongarch_hw_interrupts_pending(cpu_env(cs), VM_LEVEL1)) {
          has_work = true;
      }
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 9eea1badaf..8939dbc748 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -20,6 +20,8 @@
  #include "cpu-csr.h"
  #include "cpu-qom.h"
+#define CPU_INTERRUPT_GUEST CPU_INTERRUPT_TGT_EXT_0
+
  #define FCSR0_M1    0x1f         /* FCSR1 mask, Enables */
  #define FCSR0_M2    0x1f1f0000   /* FCSR2 mask, Cause and Flags */
  #define FCSR0_M3    0x300        /* FCSR3 mask, Round Mode */
@@ -242,6 +244,7 @@ extern const char * const fregnames[32];
  #define IRQ_TIMER   11
  #define IRQ_IPI     12
  #define INT_DMSI    14
+#define N_VIRQS     (N_IRQS * 2)
#define MAX_PERF_EVENTS 16
  #define LOONGARCH_STLB         2048 /* 2048 STLB */
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index ff956823fd..c11cefc4ee 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -31,7 +31,7 @@ void restore_fp_status(CPULoongArchState *env);
  #ifndef CONFIG_USER_ONLY
  extern const VMStateDescription vmstate_loongarch_cpu;
-void loongarch_cpu_update_irq(LoongArchCPU *cpu);
+void loongarch_cpu_update_irq(LoongArchCPU *cpu, int vm_level);
  void loongarch_cpu_set_irq(void *opaque, int irq, int level);
void cpu_loongarch_timer_cb(void *opaque);
@@ -39,7 +39,7 @@ uint64_t cpu_loongarch_get_timer_counter(CPUTimerState 
*timer);
  uint64_t cpu_loongarch_get_timer_ticks(CPUTimerState *timer);
  void cpu_loongarch_set_timer_config(CPUTimerState *timer, uint64_t value);
  bool loongarch_cpu_has_work(CPUState *cs);
-bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env);
+bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env, int vm_level);
  #endif /* !CONFIG_USER_ONLY */
uint64_t read_fcc(CPULoongArchState *env);
diff --git a/target/loongarch/tcg/csr_helper.c 
b/target/loongarch/tcg/csr_helper.c
index 1a6919417f..ecfba63228 100644
--- a/target/loongarch/tcg/csr_helper.c
+++ b/target/loongarch/tcg/csr_helper.c
@@ -111,7 +111,7 @@ 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));
+        loongarch_cpu_update_irq(env_archcpu(env), false);
why is it false, I think it should be current VM_LEVEL.

          bql_unlock();
      }
diff --git a/target/loongarch/tcg/tcg_cpu.c b/target/loongarch/tcg/tcg_cpu.c
index b60d9e7cf8..101fe6fc7a 100644
--- a/target/loongarch/tcg/tcg_cpu.c
+++ b/target/loongarch/tcg/tcg_cpu.c
@@ -238,30 +238,47 @@ static void loongarch_cpu_do_transaction_failed(CPUState 
*cs, hwaddr physaddr,
      }
  }
-static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env)
+static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env, 
int vm_level)
  {
      bool ret = 0;
-    CPUSysState *sys = env_sys(env);
+    CPUSysState *sys = get_sys(env, vm_level);
+    CPUSysState *host = get_sys(env, VM_LEVEL0);
ret = (FIELD_EX64(sys->CSR_CRMD, CSR_CRMD, IE) &&
-          !(FIELD_EX64(sys->CSR_DBG, CSR_DBG, DST)));
+          !(FIELD_EX64(host->CSR_DBG, CSR_DBG, DST)));
why checking CSR_DBG of host here, it is a little strange.

Regards
Bibo Mao
return ret;
  }
static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
  {
+    CPULoongArchState *env = cpu_env(cs);
+    bool has_interrupt = false;
+
      if (interrupt_request & CPU_INTERRUPT_HARD) {
-        CPULoongArchState *env = cpu_env(cs);
-
-        if (cpu_loongarch_hw_interrupts_enabled(env) &&
-            cpu_loongarch_hw_interrupts_pending(env)) {
-            /* Raise it */
-            cs->exception_index = EXCCODE_INT;
-            loongarch_cpu_do_interrupt(cs);
-            return true;
+
+        if (cpu_loongarch_hw_interrupts_enabled(env, VM_LEVEL0) &&
+            cpu_loongarch_hw_interrupts_pending(env, VM_LEVEL0)) {
+            if (env_vm_level(env) != VM_LEVEL0) {
+                trigger_vm_exit(env);
+            }
+            has_interrupt = true;
          }
+    } else if (interrupt_request & CPU_INTERRUPT_GUEST) {
+        if (cpu_loongarch_hw_interrupts_enabled(env, VM_LEVEL1) &&
+            cpu_loongarch_hw_interrupts_pending(env, VM_LEVEL1) &&
+            env_vm_level(env) == VM_LEVEL1) {
+            has_interrupt = true;
+        }
+    }
+
+    if (has_interrupt) {
+        /* Raise it */
+        cs->exception_index = EXCCODE_INT;
+        loongarch_cpu_do_interrupt(cs);
+        return true;
      }
+
      return false;
  }


Reply via email to