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 <gaosong@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
On 2025/6/9 下午6:48, Song Gao wrote:
> 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 <gaosong@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 */
how about only modify LIE such as FIELD(CSR_ECFG, LIE, 0, 15)?
> 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 */
ditto, how about modify IS such as FIELD(CSR_ESTAT, IS, 0, 15)?
Regards
Bibo Mao
> 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);
>
© 2016 - 2025 Red Hat, Inc.