From nobody Fri Sep 26 06:00: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 1641634133478109.43621452072296; Sat, 8 Jan 2022 01:28:53 -0800 (PST) Received: from localhost ([::1]:44954 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1n681r-0007Gp-Iu for importer@patchew.org; Sat, 08 Jan 2022 04:28:51 -0500 Received: from eggs.gnu.org ([209.51.188.92]:50286) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1n67oL-0003j1-1G for qemu-devel@nongnu.org; Sat, 08 Jan 2022 04:14:53 -0500 Received: from mail.loongson.cn ([114.242.206.163]:38968 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1n67oB-0000rI-Nt for qemu-devel@nongnu.org; Sat, 08 Jan 2022 04:14:50 -0500 Received: from localhost.localdomain (unknown [10.2.5.185]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxKMrrVdlhvLMAAA--.1341S13; Sat, 08 Jan 2022 17:14:40 +0800 (CST) From: Xiaojuan Yang To: qemu-devel@nongnu.org Subject: [RFC PATCH v4 11/30] target/loongarch: Add LoongArch interrupt and exception handle Date: Sat, 8 Jan 2022 04:14:00 -0500 Message-Id: <20220108091419.2027710-12-yangxiaojuan@loongson.cn> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20220108091419.2027710-1-yangxiaojuan@loongson.cn> References: <20220108091419.2027710-1-yangxiaojuan@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxKMrrVdlhvLMAAA--.1341S13 X-Coremail-Antispam: 1UD129KBjvAXoW3tr1xXr1UuFW8tF45Gw4rXwb_yoW8JF45Zo W7Ca1rA3W5Xr1FkFn0krnYqa1jqFykCw4vkr98ZwsxWa18Cry5G348K34Fq3y3ZF4rXFWr AFyI9Fn5XFZrJryfn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= 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 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: , Cc: philmd@redhat.com, mark.cave-ayland@ilande.co.uk, richard.henderson@linaro.org, Song Gao Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZM-MESSAGEID: 1641634136103100001 Content-Type: text/plain; charset="utf-8" 1.This patch Add loongarch interrupt and exception handle. 2.Rename the user excp to the exccode from the csr defintions. Signed-off-by: Xiaojuan Yang Signed-off-by: Song Gao --- linux-user/loongarch64/cpu_loop.c | 8 +- target/loongarch/cpu.c | 252 +++++++++++++++++- target/loongarch/cpu.h | 11 - target/loongarch/fpu_helper.c | 2 +- target/loongarch/insn_trans/trans_extra.c.inc | 4 +- target/loongarch/translate.c | 2 +- 6 files changed, 254 insertions(+), 25 deletions(-) diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu= _loop.c index 6628d215ca..dd58eb048f 100644 --- a/linux-user/loongarch64/cpu_loop.c +++ b/linux-user/loongarch64/cpu_loop.c @@ -28,7 +28,7 @@ void cpu_loop(CPULoongArchState *env) case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; - case EXCP_SYSCALL: + case EXCCODE_SYS: env->pc +=3D 4; ret =3D do_syscall(env, env->gpr[11], env->gpr[4], env->gpr[5], @@ -48,10 +48,10 @@ void cpu_loop(CPULoongArchState *env) } env->gpr[4] =3D ret; break; - case EXCP_INE: + case EXCCODE_INE: force_sig_fault(TARGET_SIGILL, 0, env->pc); break; - case EXCP_FPE: + case EXCCODE_FPE: si_code =3D TARGET_FPE_FLTUNK; if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) { si_code =3D TARGET_FPE_FLTINV; @@ -67,7 +67,7 @@ void cpu_loop(CPULoongArchState *env) force_sig_fault(TARGET_SIGFPE, si_code, env->pc); break; case EXCP_DEBUG: - case EXCP_BREAK: + case EXCCODE_BRK: force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; case EXCP_ATOMIC: diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 571092ce53..caab59b83a 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -30,11 +30,23 @@ const char * const fregnames[32] =3D { "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; =20 -static const char * const excp_names[EXCP_LAST + 1] =3D { - [EXCP_SYSCALL] =3D "Syscall", - [EXCP_BREAK] =3D "Break", - [EXCP_INE] =3D "Instruction Non-existent", - [EXCP_FPE] =3D "Floating Point Exception", +static const char * const excp_names[] =3D { + [EXCCODE_INT] =3D "Interrupt", + [EXCCODE_PIL] =3D "TLB load page invalid", + [EXCCODE_PIS] =3D "TLB store page invalid", + [EXCCODE_PIF] =3D "TLB Fetch page invalid", + [EXCCODE_PME] =3D "TLB Page modify", + [EXCCODE_PNR] =3D "TLB read-inhibit", + [EXCCODE_PNX] =3D "TLB execute-inhibit", + [EXCCODE_PPI] =3D "TLB priviledged error", + [EXCCODE_ADEF] =3D "Fetch instruction error", + [EXCCODE_ADEM] =3D "Memory access error", + [EXCCODE_SYS] =3D "Syscall", + [EXCCODE_BRK] =3D "Break", + [EXCCODE_INE] =3D "Instruction Non-existent", + [EXCCODE_IPE] =3D "Instruction priveiledged error", + [EXCCODE_FPE] =3D "Floating Point Exception", + [EXCCODE_DBP] =3D "Debug breakpoint", }; =20 const char *loongarch_exception_name(int32_t exception) @@ -66,6 +78,215 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr va= lue) env->pc =3D value; } =20 +#if !defined(CONFIG_USER_ONLY) +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 inline unsigned int get_vint_size(CPULoongArchState *env) +{ + uint64_t vs =3D FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS); + uint64_t size =3D 0; + + if (vs =3D=3D 0) { + return 0; + } + + if (vs < 8) { + size =3D 1 << (vs + 2); + } + + if (vs > 8) { + qemu_log("%s: unexpected value", __func__); + assert(0); + } + + return size; +} + +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); + + 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); + 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: + 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_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); + + uint32_t vec_size =3D get_vint_size(env); + env->pc =3D env->CSR_EENTRY; + env->pc +=3D cause * vec_size; + if (tlbfill) { + /* TLB Refill */ + env->pc =3D env->CSR_TLBRENTRY; + } + 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. */ + while (pending >>=3D 1) { + vector++; + } + 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 %08lx ExS %08lx\n", + __func__, env->pc, env->CSR_ERA, + cause, env->CSR_BADV, env->CSR_DERA, vector, + env->CSR_ECFG, env->CSR_ESTAT); + } + + /* Excode */ + env->CSR_ESTAT =3D FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE, cause); + + if (cs->exception_index !=3D EXCCODE_INT) { + 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 0x%lx" "\n", __func__, env->pc, + 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 attrs, + MemTxResult response, uintptr_t retadd= r) +{ + 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; +} +#endif + #ifdef CONFIG_TCG static void loongarch_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) @@ -79,7 +300,20 @@ static void loongarch_cpu_synchronize_from_tb(CPUState = *cs, =20 static bool loongarch_cpu_has_work(CPUState *cs) { +#ifdef CONFIG_USER_ONLY return true; +#else + 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; +#endif } =20 static void loongarch_3a5000_initfn(Object *obj) @@ -228,8 +462,11 @@ static void loongarch_cpu_reset(DeviceState *dev) env->CSR_DMW[n] =3D FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0); } =20 +#ifndef CONFIG_USER_ONLY + env->pc =3D 0x1c000000; +#endif restore_fp_status(env); - cs->exception_index =3D EXCP_NONE; + cs->exception_index =3D -1; } =20 static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *in= fo) @@ -342,6 +579,9 @@ static struct TCGCPUOps loongarch_tcg_ops =3D { =20 #if !defined(CONFIG_USER_ONLY) .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_USER_ONLY */ }; #endif /* CONFIG_TCG */ diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 2d5bae1af4..e623e358ec 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -431,17 +431,6 @@ typedef LoongArchCPU ArchCPU; =20 #include "exec/cpu-all.h" =20 -/* Exceptions */ -enum { - EXCP_NONE =3D -1, - EXCP_SYSCALL =3D 0, - EXCP_BREAK, - EXCP_INE, - EXCP_FPE, - - EXCP_LAST =3D EXCP_FPE, -}; - #define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 =20 #define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index 9f5235c4f8..1baf012ef7 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -74,7 +74,7 @@ static void update_fcsr0_mask(CPULoongArchState *env, uin= tptr_t pc, int mask) } =20 if (GET_FP_ENABLES(env->fcsr0) & flags) { - do_raise_exception(env, EXCP_FPE, pc); + do_raise_exception(env, EXCCODE_FPE, pc); } else { UPDATE_FP_FLAGS(env->fcsr0, flags); } diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongar= ch/insn_trans/trans_extra.c.inc index bc622ced23..2ce95d3382 100644 --- a/target/loongarch/insn_trans/trans_extra.c.inc +++ b/target/loongarch/insn_trans/trans_extra.c.inc @@ -5,13 +5,13 @@ =20 static bool trans_break(DisasContext *ctx, arg_break *a) { - generate_exception(ctx, EXCP_BREAK); + generate_exception(ctx, EXCCODE_BRK); return true; } =20 static bool trans_syscall(DisasContext *ctx, arg_syscall *a) { - generate_exception(ctx, EXCP_SYSCALL); + generate_exception(ctx, EXCCODE_SYS); return true; } =20 diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 09771ee43f..ddb97661fa 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -185,7 +185,7 @@ static void loongarch_tr_translate_insn(DisasContextBas= e *dcbase, CPUState *cs) if (!decode(ctx, ctx->opcode)) { qemu_log_mask(LOG_UNIMP, "Error: unkown opcode. 0x%lx: 0x%x\n", ctx->base.pc_next, ctx->opcode); - generate_exception(ctx, EXCP_INE); + generate_exception(ctx, EXCCODE_INE); } =20 for (int i =3D ctx->ntemp - 1; i >=3D 0; --i) { --=20 2.27.0