From nobody Thu Sep 25 22:51:39 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1654079652670221.49071561400467; Wed, 1 Jun 2022 03:34:12 -0700 (PDT) Received: from localhost ([::1]:58506 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nwLg2-0004Zt-Jd for importer@patchew.org; Wed, 01 Jun 2022 06:34:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:49444) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nwLYC-00040x-D5 for qemu-devel@nongnu.org; Wed, 01 Jun 2022 06:26:05 -0400 Received: from mail.loongson.cn ([114.242.206.163]:40076 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nwLXs-0000fE-VZ for qemu-devel@nongnu.org; Wed, 01 Jun 2022 06:25:50 -0400 Received: from localhost.localdomain (unknown [10.2.5.185]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9Cxb+aGPpdibocLAA--.49716S25; Wed, 01 Jun 2022 18:25:37 +0800 (CST) From: Xiaojuan Yang To: qemu-devel@nongnu.org Cc: richard.henderson@linaro.org, gaosong@loongson.cn, maobibo@loongson.cn, mst@redhat.com, imammedo@redhat.com, ani@anisinha.ca, mark.cave-ayland@ilande.co.uk Subject: [PATCH v6 23/43] target/loongarch: Add LoongArch interrupt and exception handle Date: Wed, 1 Jun 2022 18:24:49 +0800 Message-Id: <20220601102509.985650-24-yangxiaojuan@loongson.cn> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220601102509.985650-1-yangxiaojuan@loongson.cn> References: <20220601102509.985650-1-yangxiaojuan@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9Cxb+aGPpdibocLAA--.49716S25 X-Coremail-Antispam: 1UD129KBjvJXoWfJryUKF1ftr18Kw13Gw4kJFb_yoWDXryrpF 1IkrW0yry5JrsrA343J398Crn8Zw1xGws2vay3CayFkr48Wry0qrWvqr9F9F17C3yrZrW7 uFs3Ary5u3WUAFJanT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: p1dqw5xldry3tdq6z05rqj20fqof0/ Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=114.242.206.163; envelope-from=yangxiaojuan@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZM-MESSAGEID: 1654079653537100003 Content-Type: text/plain; charset="utf-8" Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao Reviewed-by: Richard Henderson --- target/loongarch/cpu.c | 230 +++++++++++++++++++++++++++++++++++ target/loongarch/cpu.h | 2 + target/loongarch/internals.h | 2 + 3 files changed, 234 insertions(+) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 8c8b10d601..8d8dfdd961 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -80,6 +80,215 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr va= lue) env->pc =3D value; } =20 +void loongarch_cpu_set_irq(void *opaque, int irq, int level) +{ + LoongArchCPU *cpu =3D opaque; + CPULoongArchState *env =3D &cpu->env; + CPUState *cs =3D CPU(cpu); + + if (irq < 0 || irq >=3D N_IRQS) { + return; + } + + env->CSR_ESTAT =3D deposit64(env->CSR_ESTAT, irq, 1, level !=3D 0); + + if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) { + cpu_interrupt(cs, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); + } +} + +static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *= env) +{ + bool ret =3D 0; + + ret =3D (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE) && + !(FIELD_EX64(env->CSR_DBG, CSR_DBG, DST))); + + return ret; +} + +/* 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; + bool r; + + pending =3D FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS); + status =3D FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE); + + r =3D (pending & status) !=3D 0; + return r; +} + +static void loongarch_cpu_do_interrupt(CPUState *cs) +{ + LoongArchCPU *cpu =3D LOONGARCH_CPU(cs); + CPULoongArchState *env =3D &cpu->env; + bool update_badinstr =3D 1; + int cause =3D -1; + const char *name; + bool tlbfill =3D FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR); + uint32_t vec_size =3D FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS); + + if (cs->exception_index !=3D EXCCODE_INT) { + if (cs->exception_index < 0 || + cs->exception_index > ARRAY_SIZE(excp_names)) { + name =3D "unknown"; + } else { + name =3D excp_names[cs->exception_index]; + } + + qemu_log_mask(CPU_LOG_INT, + "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__, + env->pc, env->CSR_ERA, env->CSR_TLBRERA, name); + } + + switch (cs->exception_index) { + case EXCCODE_DBP: + env->CSR_DBG =3D FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1); + env->CSR_DBG =3D FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC); + goto set_DERA; + set_DERA: + env->CSR_DERA =3D env->pc; + env->CSR_DBG =3D FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1); + env->pc =3D env->CSR_EENTRY + 0x480; + break; + case EXCCODE_INT: + if (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { + env->CSR_DBG =3D FIELD_DP64(env->CSR_DBG, CSR_DBG, DEI, 1); + goto set_DERA; + } + QEMU_FALLTHROUGH; + case EXCCODE_PIF: + cause =3D cs->exception_index; + update_badinstr =3D 0; + break; + case EXCCODE_ADEM: + case EXCCODE_SYS: + case EXCCODE_BRK: + case EXCCODE_PIL: + case EXCCODE_PIS: + case EXCCODE_PME: + case EXCCODE_PNR: + case EXCCODE_PNX: + case EXCCODE_PPI: + case EXCCODE_INE: + case EXCCODE_IPE: + case EXCCODE_FPE: + cause =3D cs->exception_index; + break; + default: + qemu_log("Error: exception(%d) '%s' has not been supported\n", + cs->exception_index, excp_names[cs->exception_index]); + abort(); + } + + if (update_badinstr) { + env->CSR_BADI =3D cpu_ldl_code(env, env->pc); + } + + /* Save PLV and IE */ + if (tlbfill) { + env->CSR_TLBRPRMD =3D FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, = PPLV, + FIELD_EX64(env->CSR_CRMD, + CSR_CRMD, PLV)); + env->CSR_TLBRPRMD =3D FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, = PIE, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD,= IE)); + /* set the DA mode */ + env->CSR_CRMD =3D FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); + env->CSR_CRMD =3D FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); + env->CSR_TLBRERA =3D FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, + PC, (env->pc >> 2)); + } else { + env->CSR_ESTAT =3D FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE, ca= use); + env->CSR_PRMD =3D FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PPLV, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV= )); + env->CSR_PRMD =3D FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PIE, + FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE)= ); + env->CSR_ERA =3D env->pc; + } + + env->CSR_CRMD =3D FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); + env->CSR_CRMD =3D FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); + + if (cs->exception_index =3D=3D EXCCODE_INT) { + /* Interrupt */ + uint32_t vector =3D 0; + uint32_t pending =3D FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS); + pending &=3D FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE); + + /* Find the highest-priority interrupt. */ + vector =3D 31 - clz32(pending); + env->pc =3D env->CSR_EENTRY + (EXCCODE_EXTERNAL_INT + vector) * ve= c_size; + qemu_log_mask(CPU_LOG_INT, + "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " cause %d\n" " A " TARGET_FMT_lx " D " + TARGET_FMT_lx " vector =3D %d ExC " TARGET_FMT_lx "E= xS" + TARGET_FMT_lx "\n", + __func__, env->pc, env->CSR_ERA, + cause, env->CSR_BADV, env->CSR_DERA, vector, + env->CSR_ECFG, env->CSR_ESTAT); + } else { + if (tlbfill) { + env->pc =3D env->CSR_TLBRENTRY; + } else { + env->pc =3D env->CSR_EENTRY; + env->pc +=3D cause * vec_size; + } + qemu_log_mask(CPU_LOG_INT, + "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx + " cause %d%s\n, ESTAT " TARGET_FMT_lx + " EXCFG " TARGET_FMT_lx " BADVA " TARGET_FMT_lx + "BADI " TARGET_FMT_lx " SYS_NUM " TARGET_FMT_lu + " cpu %d asid " TARGET_FMT_lx "\n", __func__, env->p= c, + tlbfill ? env->CSR_TLBRERA : env->CSR_ERA, + cause, tlbfill ? "(refill)" : "", env->CSR_ESTAT, + env->CSR_ECFG, + tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV, + env->CSR_BADI, env->gpr[11], cs->cpu_index, + env->CSR_ASID); + } + cs->exception_index =3D -1; +} + +static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physa= ddr, + vaddr addr, unsigned size, + MMUAccessType access_type, + int mmu_idx, MemTxAttrs at= trs, + MemTxResult response, + uintptr_t retaddr) +{ + LoongArchCPU *cpu =3D LOONGARCH_CPU(cs); + CPULoongArchState *env =3D &cpu->env; + + if (access_type =3D=3D MMU_INST_FETCH) { + do_raise_exception(env, EXCCODE_ADEF, retaddr); + } else { + do_raise_exception(env, EXCCODE_ADEM, retaddr); + } +} + +static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_reque= st) +{ + if (interrupt_request & CPU_INTERRUPT_HARD) { + LoongArchCPU *cpu =3D LOONGARCH_CPU(cs); + CPULoongArchState *env =3D &cpu->env; + + if (cpu_loongarch_hw_interrupts_enabled(env) && + cpu_loongarch_hw_interrupts_pending(env)) { + /* Raise it */ + cs->exception_index =3D EXCCODE_INT; + loongarch_cpu_do_interrupt(cs); + return true; + } + } + return false; +} + #ifdef CONFIG_TCG static void loongarch_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) @@ -91,6 +300,20 @@ static void loongarch_cpu_synchronize_from_tb(CPUState = *cs, } #endif /* CONFIG_TCG */ =20 +static bool loongarch_cpu_has_work(CPUState *cs) +{ + LoongArchCPU *cpu =3D LOONGARCH_CPU(cs); + CPULoongArchState *env =3D &cpu->env; + bool has_work =3D false; + + if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && + cpu_loongarch_hw_interrupts_pending(env)) { + has_work =3D true; + } + + return has_work; +} + static void loongarch_la464_initfn(Object *obj) { LoongArchCPU *cpu =3D LOONGARCH_CPU(obj); @@ -232,6 +455,8 @@ static void loongarch_cpu_reset(DeviceState *dev) env->CSR_DMW[n] =3D FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0); } =20 + env->pc =3D 0x1c000000; + restore_fp_status(env); cs->exception_index =3D -1; } @@ -264,6 +489,7 @@ static void loongarch_cpu_init(Object *obj) LoongArchCPU *cpu =3D LOONGARCH_CPU(obj); =20 cpu_set_cpustate_pointers(cpu); + qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS); } =20 static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) @@ -332,6 +558,9 @@ static struct TCGCPUOps loongarch_tcg_ops =3D { .synchronize_from_tb =3D loongarch_cpu_synchronize_from_tb, =20 .tlb_fill =3D loongarch_cpu_tlb_fill, + .cpu_exec_interrupt =3D loongarch_cpu_exec_interrupt, + .do_interrupt =3D loongarch_cpu_do_interrupt, + .do_transaction_failed =3D loongarch_cpu_do_transaction_failed, }; #endif /* CONFIG_TCG */ =20 @@ -352,6 +581,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, vo= id *data) device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_r= eset); =20 cc->class_by_name =3D loongarch_cpu_class_by_name; + cc->has_work =3D loongarch_cpu_has_work; cc->dump_state =3D loongarch_cpu_dump_state; cc->set_pc =3D loongarch_cpu_set_pc; dc->vmsd =3D &vmstate_loongarch_cpu; diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index e0415d8929..b983ce241c 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -184,6 +184,8 @@ FIELD(CSR_CRMD, WE, 9, 1) extern const char * const regnames[32]; extern const char * const fregnames[32]; =20 +#define N_IRQS 13 + #define LOONGARCH_STLB 2048 /* 2048 STLB */ #define LOONGARCH_MTLB 64 /* 64 MTLB */ #define LOONGARCH_TLB_MAX (LOONGARCH_STLB + LOONGARCH_MTLB) diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 2fed768653..69183e8bb5 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -30,6 +30,8 @@ void restore_fp_status(CPULoongArchState *env); =20 extern const VMStateDescription vmstate_loongarch_cpu; =20 +void loongarch_cpu_set_irq(void *opaque, int irq, int level); + bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); --=20 2.31.1