we use CSR_ESTAT and CSR_ECFG bit 15 for msg interrupt.
and loongarch_cpu_do_interrupt support msg interrupts.

Signed-off-by: Song Gao <gaos...@loongson.cn>
---
 target/loongarch/cpu-csr.h |  3 ++-
 target/loongarch/cpu.c     | 35 ++++++++++++++++++++++++++++++-----
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
index 83f6cb081a..5a00cf3366 100644
--- a/target/loongarch/cpu-csr.h
+++ b/target/loongarch/cpu-csr.h
@@ -35,11 +35,12 @@ FIELD(CSR_MISC, DWPL, 16, 3)
 
 #define LOONGARCH_CSR_ECFG           0x4 /* Exception config */
 FIELD(CSR_ECFG, LIE, 0, 13)
+FIELD(CSR_ECFG, MSGINT, 14, 1)      /* used for msg */
 FIELD(CSR_ECFG, VS, 16, 3)
 
 #define LOONGARCH_CSR_ESTAT          0x5 /* Exception status */
 FIELD(CSR_ESTAT, IS, 0, 13)
-FIELD(CSR_ESTAT, MSGINT, 14, 1)
+FIELD(CSR_ESTAT, MSGINT, 14, 1)    /* used for msg */
 FIELD(CSR_ESTAT, ECODE, 16, 6)
 FIELD(CSR_ESTAT, ESUBCODE, 22, 9)
 
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 207d11266f..b92463101e 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -117,6 +117,13 @@ static vaddr loongarch_cpu_get_pc(CPUState *cs)
 #ifndef CONFIG_USER_ONLY
 #include "hw/loongarch/virt.h"
 
+static uint32_t loongarch_cpu_has_interrupt(CPULoongArchState *env)
+{
+    uint32_t ret = 0;
+    ret = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
+    ret |= FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, MSGINT);
+    return ret;
+}
 void loongarch_cpu_set_irq(void *opaque, int irq, int level)
 {
     LoongArchCPU *cpu = opaque;
@@ -134,21 +141,20 @@ void loongarch_cpu_set_irq(void *opaque, int irq, int 
level)
                 env->CSR_MSGIR = FIELD_DP64(env->CSR_MSGIR, CSR_MSGIR, INTNUM, 
i);
                 env->CSR_MSGIR = FIELD_DP64(env->CSR_MSGIR, CSR_MSGIR, ACTIVE, 
0);
                 env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, MSGINT, 
1);
-                cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+                env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, MSGINT, 1);
                 clear_bit(i, &(env->CSR_MSGIS[i / 64]));
             }
         }
     } else {
        env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, MSGINT, 0);
-       env->CSR_MSGIR = FIELD_DP64(env->CSR_MSGIR, CSR_MSGIR, ACTIVE, 1);
-       return;
+       env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, MSGINT, 0);
     }
 
     if (kvm_enabled()) {
         kvm_loongarch_set_interrupt(cpu, irq, level);
     } else if (tcg_enabled()) {
         env->CSR_ESTAT = deposit64(env->CSR_ESTAT, irq, 1, level != 0);
-        if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
+        if (loongarch_cpu_has_interrupt(env)) {
             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
         } else {
             cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
@@ -166,12 +172,24 @@ static inline bool 
cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env)
     return ret;
 }
 
+static inline bool cpu_loongarch_hw_interrupt_msg_pending(CPULoongArchState 
*env)
+{
+    bool pending_msg = 0;
+    bool status_msg = 0;
+
+    pending_msg = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, MSGINT);
+    status_msg = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, MSGINT);
+
+    return (pending_msg & status_msg) != 0;
+}
 /* Check if there is pending and not masked out interrupt */
 static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
 {
     uint32_t pending;
     uint32_t status;
-
+    if (cpu_loongarch_hw_interrupt_msg_pending(env)) {
+        return true;
+    }
     pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
     status  = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
 
@@ -285,6 +303,13 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
         uint32_t vector = 0;
         uint32_t pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
         pending &= FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
+        if (cpu_loongarch_hw_interrupt_msg_pending(env)) {
+            env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, MSGINT, 0);
+            env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, MSGINT, 0);
+            set_pc(env, env->CSR_EENTRY + \
+                   (EXCCODE_EXTERNAL_INT + INT_AVEC) * vec_size);
+            return;
+        }
 
         /* Find the highest-priority interrupt. */
         vector = 31 - clz32(pending);
-- 
2.34.1


Reply via email to