From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id ADAA0C433C1 for ; Mon, 22 Mar 2021 02:06:43 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DB8CE6190A for ; Mon, 22 Mar 2021 02:06:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DB8CE6190A Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=sifive.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:44604 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lO9xp-0006eJ-Os for qemu-devel@archiver.kernel.org; Sun, 21 Mar 2021 22:06:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51546) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lO9w4-0005cE-VO for qemu-devel@nongnu.org; Sun, 21 Mar 2021 22:04:53 -0400 Received: from mail-oi1-x235.google.com ([2607:f8b0:4864:20::235]:45973) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1lO9w1-0006uD-FL for qemu-devel@nongnu.org; Sun, 21 Mar 2021 22:04:52 -0400 Received: by mail-oi1-x235.google.com with SMTP id d12so11510926oiw.12 for ; Sun, 21 Mar 2021 19:04:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=HCyxe9DwAhXmP5gaPnNt0hy2GkCAxtG38r7L/2LZmMk=; b=koMx7egI/p11xp3ALK5tapmpC1DRBUcE40J9rh8xPFx3b+AXBQi1dkXtf6XwuK+4Cj Vg8qUrb+HN20y6UDhS15WUFM4tUNWgASB1+katCb0wow7PCxVPLnnb1iMu6O9x+hLE1x tQjsX/5cV1gVzNyh6RUMmCwLzdLq4L6Wj22MGSc5xAz9T/FI+gL8+nlSPNJKRgdJWb8J 4f1PjgWizFSKBKc+KWf5NIxDtjZlHINYv1RimfG8XK6ALf45Lfc0n+W0Am69AL1UBeIm PUZ+EIfsU5c5k+MEc71wRLREJKtgcxD26TRehu8u38xg2PWpyI4+nFbe/rDEtxsOuBgH fDXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=HCyxe9DwAhXmP5gaPnNt0hy2GkCAxtG38r7L/2LZmMk=; b=qWCXNutI2XIo+6cqUM6F5Sg9JjWAL22w5Lbxo3W7lfa8bRO18HCDnwHmY2DXajZeQE sUCz1LFbvborJOideRRFW31C+BF/b9hpiQq2A1PCqJq2mudZF8uhF/VUCMWDglqDnU4v n9GujwI02bxHWNJG8Gl1ie/P/IMH6jhbX05ATYNOMsD/Eidg2Z3OTEO0FQC81aHcCUha pCBgUz4x/LSaa7WxRwHiTNANaKDeYfjpFqb07g3adJLOC10FUebq2eak/lx+YaREDqKJ KD7XjEdukVGbUDJ3WNJZite8rYCdLj605qVaSLyoyOVS7y/LajHZ7l8JG7FRMwhxgdPA xgng== X-Gm-Message-State: AOAM533PXqUotEyR8M+PSN5+9c//6gh37LGyl9C84tncYCFdLJExnCtR BdAQi5ixsggb+vSn6IRXlcF9KtXzDYC7T/iD1t0u6A== X-Google-Smtp-Source: ABdhPJx8HYbclVTN6OzwsVgVRDIVZfjnyjSihglfi3Rj1+r4wt67ZKTmIp+Syu3iFLYD6Q+mnwbTPEtP+wXpy3MPH2o= X-Received: by 2002:aca:ef84:: with SMTP id n126mr8035380oih.78.1616378688302; Sun, 21 Mar 2021 19:04:48 -0700 (PDT) MIME-Version: 1.0 References: <20210309072925.4314-1-frank.chang@sifive.com> <20210309072925.4314-2-frank.chang@sifive.com> In-Reply-To: From: Frank Chang Date: Mon, 22 Mar 2021 10:04:37 +0800 Message-ID: Subject: Re: [RFC 1/1] target/riscv: add support of RNMI To: Alistair Francis Content-Type: multipart/alternative; boundary="0000000000008a05f105be167db2" Received-SPF: pass client-ip=2607:f8b0:4864:20::235; envelope-from=frank.chang@sifive.com; helo=mail-oi1-x235.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=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.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Keith Packard , "open list:RISC-V" , Sagar Karandikar , Bastian Koppelmann , Richard Henderson , "qemu-devel@nongnu.org Developers" , Alistair Francis , Paolo Bonzini , Palmer Dabbelt Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" --0000000000008a05f105be167db2 Content-Type: text/plain; charset="UTF-8" On Fri, Mar 19, 2021 at 9:29 PM Alistair Francis wrote: > On Tue, Mar 9, 2021 at 2:30 AM wrote: > > > > From: Frank Chang > > > > Signed-off-by: Frank Chang > > I had a quick look and this looks fine. I haven't compared it to the > spec yet though. > > When you send the patch series do you mind splitting it up a bit more? > It just makes it easier to review. > > Alistair > Sure, will do that. Thanks, Frank Chang > > > --- > > target/riscv/cpu.c | 40 +++++++++++++ > > target/riscv/cpu.h | 16 ++++- > > target/riscv/cpu_bits.h | 19 ++++++ > > target/riscv/cpu_helper.c | 47 +++++++++++++-- > > target/riscv/csr.c | 59 +++++++++++++++++++ > > target/riscv/helper.h | 1 + > > target/riscv/insn32.decode | 3 + > > .../riscv/insn_trans/trans_privileged.c.inc | 13 ++++ > > target/riscv/op_helper.c | 31 ++++++++++ > > 9 files changed, 224 insertions(+), 5 deletions(-) > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index ddea8fbeeb3..07ea2105200 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -137,6 +137,14 @@ static void set_feature(CPURISCVState *env, int > feature) > > env->features |= (1ULL << feature); > > } > > > > +static void set_rnmi_vectors(CPURISCVState *env, int irqvec, int > excpvec) > > +{ > > +#ifndef CONFIG_USER_ONLY > > + env->rnmi_irqvec = irqvec; > > + env->rnmi_excpvec = excpvec; > > +#endif > > +} > > + > > static void set_resetvec(CPURISCVState *env, int resetvec) > > { > > #ifndef CONFIG_USER_ONLY > > @@ -372,6 +380,23 @@ static void riscv_cpu_disas_set_info(CPUState *s, > disassemble_info *info) > > } > > } > > > > +#ifndef CONFIG_USER_ONLY > > +static void riscv_cpu_set_rnmi(void *opaque, int irq, int level) > > +{ > > + RISCVCPU *cpu = opaque; > > + CPURISCVState *env = &cpu->env; > > + CPUState *cs = CPU(cpu); > > + > > + if (level) { > > + env->nmip |= 1 << irq; > > + cpu_interrupt(cs, CPU_INTERRUPT_RNMI); > > + } else { > > + env->nmip &= ~(1 << irq); > > + cpu_reset_interrupt(cs, CPU_INTERRUPT_RNMI); > > + } > > +} > > +#endif > > + > > static void riscv_cpu_realize(DeviceState *dev, Error **errp) > > { > > CPUState *cs = CPU(dev); > > @@ -415,6 +440,16 @@ static void riscv_cpu_realize(DeviceState *dev, > Error **errp) > > > > set_resetvec(env, cpu->cfg.resetvec); > > > > + if (cpu->cfg.rnmi) { > > + set_feature(env, RISCV_FEATURE_RNMI); > > + set_rnmi_vectors(env, cpu->cfg.rnmi_irqvec, > cpu->cfg.rnmi_excpvec); > > +#ifndef CONFIG_USER_ONLY > > + env->nmie = true; > > + qdev_init_gpio_in_named(DEVICE(cpu), riscv_cpu_set_rnmi, > > + "rnmi", TARGET_LONG_BITS); > > +#endif > > + } > > + > > /* If only XLEN is set for misa, then set misa from properties */ > > if (env->misa == RV32 || env->misa == RV64) { > > /* Do some ISA extension error checking */ > > @@ -554,6 +589,11 @@ static Property riscv_cpu_properties[] = { > > DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), > > DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), > > DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, > DEFAULT_RSTVEC), > > + DEFINE_PROP_BOOL("rnmi", RISCVCPU, cfg.rnmi, false), > > + DEFINE_PROP_UINT64("rnmi_irqvec", RISCVCPU, cfg.rnmi_irqvec, > > + DEFAULT_RNMI_IRQVEC), > > + DEFINE_PROP_UINT64("rnmi_excpvec", RISCVCPU, cfg.rnmi_excpvec, > > + DEFAULT_RNMI_EXCPVEC), > > DEFINE_PROP_END_OF_LIST(), > > }; > > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > > index 0edb2826a27..b9aa403dfec 100644 > > --- a/target/riscv/cpu.h > > +++ b/target/riscv/cpu.h > > @@ -80,7 +80,8 @@ > > enum { > > RISCV_FEATURE_MMU, > > RISCV_FEATURE_PMP, > > - RISCV_FEATURE_MISA > > + RISCV_FEATURE_MISA, > > + RISCV_FEATURE_RNMI, > > }; > > > > #define PRIV_VERSION_1_10_0 0x00011000 > > @@ -178,6 +179,16 @@ struct CPURISCVState { > > target_ulong mcause; > > target_ulong mtval; /* since: priv-1.10.0 */ > > > > + /* NMI */ > > + target_ulong mnscratch; > > + target_ulong mnepc; > > + target_ulong mncause; /* mncause without bit XLEN-1 set to 1 */ > > + target_ulong mnstatus; > > + bool nmie; > > + target_ulong nmip; > > + target_ulong rnmi_irqvec; > > + target_ulong rnmi_excpvec; > > + > > /* Hypervisor CSRs */ > > target_ulong hstatus; > > target_ulong hedeleg; > > @@ -300,6 +311,9 @@ struct RISCVCPU { > > bool mmu; > > bool pmp; > > uint64_t resetvec; > > + bool rnmi; > > + uint64_t rnmi_irqvec; > > + uint64_t rnmi_excpvec; > > } cfg; > > }; > > > > diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h > > index caf45992070..94ab76c66b8 100644 > > --- a/target/riscv/cpu_bits.h > > +++ b/target/riscv/cpu_bits.h > > @@ -166,6 +166,12 @@ > > #define CSR_MTVAL 0x343 > > #define CSR_MIP 0x344 > > > > +/* NMI */ > > +#define CSR_MNSCRATCH 0x350 > > +#define CSR_MNEPC 0x351 > > +#define CSR_MNCAUSE 0x352 > > +#define CSR_MNSTATUS 0x353 > > + > > /* Legacy Machine Trap Handling (priv v1.9.1) */ > > #define CSR_MBADADDR 0x343 > > > > @@ -526,6 +532,12 @@ > > /* Default Reset Vector adress */ > > #define DEFAULT_RSTVEC 0x1000 > > > > +/* Default RNMI Interrupt Vector address */ > > +#define DEFAULT_RNMI_IRQVEC 0x1000 > > + > > +/* Default RNMI Exception Vector address */ > > +#define DEFAULT_RNMI_EXCPVEC 0x1000 > > + > > /* Exception causes */ > > #define EXCP_NONE -1 /* sentinel value */ > > #define RISCV_EXCP_INST_ADDR_MIS 0x0 > > @@ -552,6 +564,9 @@ > > #define RISCV_EXCP_INT_FLAG 0x80000000 > > #define RISCV_EXCP_INT_MASK 0x7fffffff > > > > +/* RNMI mnstatus CSR mask */ > > +#define MNSTATUS_MPP MSTATUS_MPP > > + > > /* Interrupt causes */ > > #define IRQ_U_SOFT 0 > > #define IRQ_S_SOFT 1 > > @@ -592,4 +607,8 @@ > > #define MIE_UTIE (1 << IRQ_U_TIMER) > > #define MIE_SSIE (1 << IRQ_S_SOFT) > > #define MIE_USIE (1 << IRQ_U_SOFT) > > + > > +/* RISC-V-specific interrupt pending bits */ > > +#define CPU_INTERRUPT_RNMI CPU_INTERRUPT_TGT_EXT_0 > > + > > #endif > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > > index 2f43939fb6d..f331c4b7032 100644 > > --- a/target/riscv/cpu_helper.c > > +++ b/target/riscv/cpu_helper.c > > @@ -38,6 +38,19 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool > ifetch) > > #ifndef CONFIG_USER_ONLY > > static int riscv_cpu_local_irq_pending(CPURISCVState *env) > > { > > + if (riscv_feature(env, RISCV_FEATURE_RNMI)) { > > + /* Priority: RNMI > Other interrupt. */ > > + if (env->nmip && env->nmie) { > > + return ctz64(env->nmip); /* since non-zero */ > > + } else if (!env->nmie) { > > + /* > > + * We are already in RNMI handler, > > + * other interrupts cannot preempt. > > + */ > > + return EXCP_NONE; > > + } > > + } > > + > > target_ulong irqs; > > > > target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE); > > @@ -80,7 +93,8 @@ static int riscv_cpu_local_irq_pending(CPURISCVState > *env) > > bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request) > > { > > #if !defined(CONFIG_USER_ONLY) > > - if (interrupt_request & CPU_INTERRUPT_HARD) { > > + if (interrupt_request & > > + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_RNMI)) { > > RISCVCPU *cpu = RISCV_CPU(cs); > > CPURISCVState *env = &cpu->env; > > int interruptno = riscv_cpu_local_irq_pending(env); > > @@ -847,6 +861,23 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > target_ulong tval = 0; > > target_ulong htval = 0; > > target_ulong mtval2 = 0; > > + target_ulong nextpc; > > + bool nmi_execp = false; > > + > > + if (riscv_feature(env, RISCV_FEATURE_RNMI)) { > > + nmi_execp = !env->nmie && !async; > > + > > + if (env->nmip && async) { > > + env->nmie = false; > > + env->mnstatus = set_field(env->mnstatus, MSTATUS_MPP, > > + env->priv); > > + env->mncause = cause; > > + env->mnepc = env->pc; > > + env->pc = env->rnmi_irqvec; > > + riscv_cpu_set_mode(env, PRV_M); > > + goto handled; > > + } > > + } > > > > if (cause == RISCV_EXCP_SEMIHOST) { > > if (env->priv >= PRV_S) { > > @@ -905,7 +936,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > __func__, env->mhartid, async, cause, env->pc, tval, > > riscv_cpu_get_trap_name(cause, async)); > > > > - if (env->priv <= PRV_S && > > + if (env->priv <= PRV_S && !nmi_execp && > > cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { > > /* handle the trap in S-mode */ > > if (riscv_has_ext(env, RVH)) { > > @@ -1005,8 +1036,15 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > env->mepc = env->pc; > > env->mbadaddr = tval; > > env->mtval2 = mtval2; > > - env->pc = (env->mtvec >> 2 << 2) + > > - ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); > > + > > + if (nmi_execp) { > > + nextpc = env->rnmi_excpvec; > > + } else { > > + nextpc = (env->mtvec >> 2 << 2) + > > + ((async && (env->mtvec & 3) == 1) ? cause * 4 : 0); > > + } > > + env->pc = nextpc; > > + > > riscv_cpu_set_mode(env, PRV_M); > > } > > > > @@ -1016,6 +1054,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > * RISC-V ISA Specification. > > */ > > > > +handled: > > #endif > > cs->exception_index = EXCP_NONE; /* mark handled to qemu */ > > } > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > > index fd2e6363f39..f67c50327ec 100644 > > --- a/target/riscv/csr.c > > +++ b/target/riscv/csr.c > > @@ -188,6 +188,11 @@ static int pmp(CPURISCVState *env, int csrno) > > { > > return -!riscv_feature(env, RISCV_FEATURE_PMP); > > } > > + > > +static int nmi(CPURISCVState *env, int csrno) > > +{ > > + return -!riscv_feature(env, RISCV_FEATURE_RNMI); > > +} > > #endif > > > > /* User Floating-Point CSRs */ > > @@ -712,6 +717,54 @@ static int write_mbadaddr(CPURISCVState *env, int > csrno, target_ulong val) > > return 0; > > } > > > > +static int read_mnscratch(CPURISCVState *env, int csrno, target_ulong > *val) > > +{ > > + *val = env->mnscratch; > > + return 0; > > +} > > + > > +static int write_mnscratch(CPURISCVState *env, int csrno, target_ulong > val) > > +{ > > + env->mnscratch = val; > > + return 0; > > +} > > + > > +static int read_mnepc(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + *val = env->mnepc; > > + return 0; > > +} > > + > > +static int write_mnepc(CPURISCVState *env, int csrno, target_ulong val) > > +{ > > + env->mnepc = val; > > + return 0; > > +} > > + > > +static int read_mncause(CPURISCVState *env, int csrno, target_ulong > *val) > > +{ > > + *val = env->mncause; > > + return 0; > > +} > > + > > +static int write_mncause(CPURISCVState *env, int csrno, target_ulong > val) > > +{ > > + env->mncause = val; > > + return 0; > > +} > > + > > +static int read_mnstatus(CPURISCVState *env, int csrno, target_ulong > *val) > > +{ > > + *val = env->mnstatus; > > + return 0; > > +} > > + > > +static int write_mnstatus(CPURISCVState *env, int csrno, target_ulong > val) > > +{ > > + env->mnstatus = val & MNSTATUS_MPP; > > + return 0; > > +} > > + > > static int rmw_mip(CPURISCVState *env, int csrno, target_ulong > *ret_value, > > target_ulong new_value, target_ulong write_mask) > > { > > @@ -1427,6 +1480,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > > [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr > }, > > [CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip > }, > > > > + /* NMI */ > > + [CSR_MNSCRATCH] = { "mnscratch", nmi, read_mnscratch, > write_mnscratch }, > > + [CSR_MNEPC] = { "mnepc", nmi, read_mnepc, write_mnepc > }, > > + [CSR_MNCAUSE] = { "mncause", nmi, read_mncause, > write_mncause }, > > + [CSR_MNSTATUS] = { "mnstatus", nmi, read_mnstatus, > write_mnstatus }, > > + > > /* Supervisor Trap Setup */ > > [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, > write_sstatus }, > > [CSR_SIE] = { "sie", smode, read_sie, > write_sie }, > > diff --git a/target/riscv/helper.h b/target/riscv/helper.h > > index e3f3f41e891..0914d777d6d 100644 > > --- a/target/riscv/helper.h > > +++ b/target/riscv/helper.h > > @@ -65,6 +65,7 @@ DEF_HELPER_4(csrrc, tl, env, tl, tl, tl) > > #ifndef CONFIG_USER_ONLY > > DEF_HELPER_2(sret, tl, env, tl) > > DEF_HELPER_2(mret, tl, env, tl) > > +DEF_HELPER_2(mnret, tl, env, tl) > > DEF_HELPER_1(wfi, void, env) > > DEF_HELPER_1(tlb_flush, void, env) > > #endif > > diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode > > index 84080dd18ca..557f3394276 100644 > > --- a/target/riscv/insn32.decode > > +++ b/target/riscv/insn32.decode > > @@ -97,6 +97,9 @@ wfi 0001000 00101 00000 000 00000 1110011 > > sfence_vma 0001001 ..... ..... 000 00000 1110011 @sfence_vma > > sfence_vm 0001000 00100 ..... 000 00000 1110011 @sfence_vm > > > > +# *** NMI *** > > +mnret 0111000 00010 00000 000 00000 1110011 > > + > > # *** RV32I Base Instruction Set *** > > lui .................... ..... 0110111 @u > > auipc .................... ..... 0010111 @u > > diff --git a/target/riscv/insn_trans/trans_privileged.c.inc > b/target/riscv/insn_trans/trans_privileged.c.inc > > index 32312be2024..63c49dfe6fb 100644 > > --- a/target/riscv/insn_trans/trans_privileged.c.inc > > +++ b/target/riscv/insn_trans/trans_privileged.c.inc > > @@ -106,6 +106,19 @@ static bool trans_mret(DisasContext *ctx, arg_mret > *a) > > #endif > > } > > > > +static bool trans_mnret(DisasContext *ctx, arg_mnret *a) > > +{ > > +#ifndef CONFIG_USER_ONLY > > + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next); > > + gen_helper_mnret(cpu_pc, cpu_env, cpu_pc); > > + exit_tb(ctx); /* no chaining */ > > + ctx->base.is_jmp = DISAS_NORETURN; > > + return true; > > +#else > > + return false; > > +#endif > > +} > > + > > static bool trans_wfi(DisasContext *ctx, arg_wfi *a) > > { > > #ifndef CONFIG_USER_ONLY > > diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c > > index 1eddcb94de7..b9601776153 100644 > > --- a/target/riscv/op_helper.c > > +++ b/target/riscv/op_helper.c > > @@ -175,6 +175,37 @@ target_ulong helper_mret(CPURISCVState *env, > target_ulong cpu_pc_deb) > > return retpc; > > } > > > > +target_ulong helper_mnret(CPURISCVState *env, target_ulong cpu_pc_deb) > > +{ > > + if (!riscv_feature(env, RISCV_FEATURE_RNMI)) { > > + /* RNMI feature is not presented. */ > > + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); > > + } > > + > > + if (!(env->priv >= PRV_M)) { > > + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); > > + } > > + > > + /* Get return PC from mnepc CSR. */ > > + target_ulong retpc = env->mnepc; > > + if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) { > > + riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC()); > > + } > > + > > + /* Get previous privilege level from mnstatus CSR. */ > > + target_ulong prev_priv = get_field(env->mnstatus, MNSTATUS_MPP); > > + > > + if (!pmp_get_num_rules(env) && (prev_priv != PRV_M)) { > > + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); > > + } > > + > > + riscv_cpu_set_mode(env, prev_priv); > > + > > + env->nmie = true; > > + > > + return retpc; > > +} > > + > > void helper_wfi(CPURISCVState *env) > > { > > CPUState *cs = env_cpu(env); > > -- > > 2.17.1 > > > > > --0000000000008a05f105be167db2 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
On Fri, Mar 19, 2021 at 9:29 PM Alistair = Francis <alistair23@gmail.com> wrote:
On Tue, Mar 9, 2021 at 2:30 AM <frank.chang@sifive.com> = wrote:
>
> From: Frank Chang <frank.chang@sifive.com>
>
> Signed-off-by: Frank Chang <frank.chang@sifive.com>

I had a quick look and this looks fine. I haven't compared it to the spec yet though.

When you send the patch series do you mind splitting it up a bit more?
It just makes it easier to review.

Alistair

Sure, will do that.
=
Thanks,
Frank Chang
=C2=A0

> ---
>=C2=A0 target/riscv/cpu.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | 40 +++++++++++++
>=C2=A0 target/riscv/cpu.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | 16 ++++-
>=C2=A0 target/riscv/cpu_bits.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| 19 ++++++
>=C2=A0 target/riscv/cpu_helper.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0| 47 +++++++++++++--
>=C2=A0 target/riscv/csr.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | 59 +++++++++++++++++= ++
>=C2=A0 target/riscv/helper.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 1 +
>=C2=A0 target/riscv/insn32.decode=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2=A0 3 +
>=C2=A0 .../riscv/insn_trans/trans_privileged.c.inc=C2=A0 =C2=A0| 13 +++= +
>=C2=A0 target/riscv/op_helper.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | 31 ++++++++++
>=C2=A0 9 files changed, 224 insertions(+), 5 deletions(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index ddea8fbeeb3..07ea2105200 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -137,6 +137,14 @@ static void set_feature(CPURISCVState *env, int f= eature)
>=C2=A0 =C2=A0 =C2=A0 env->features |=3D (1ULL << feature);
>=C2=A0 }
>
> +static void set_rnmi_vectors(CPURISCVState *env, int irqvec, int excp= vec)
> +{
> +#ifndef CONFIG_USER_ONLY
> +=C2=A0 =C2=A0 env->rnmi_irqvec =3D irqvec;
> +=C2=A0 =C2=A0 env->rnmi_excpvec =3D excpvec;
> +#endif
> +}
> +
>=C2=A0 static void set_resetvec(CPURISCVState *env, int resetvec)
>=C2=A0 {
>=C2=A0 #ifndef CONFIG_USER_ONLY
> @@ -372,6 +380,23 @@ static void riscv_cpu_disas_set_info(CPUState *s,= disassemble_info *info)
>=C2=A0 =C2=A0 =C2=A0 }
>=C2=A0 }
>
> +#ifndef CONFIG_USER_ONLY
> +static void riscv_cpu_set_rnmi(void *opaque, int irq, int level)
> +{
> +=C2=A0 =C2=A0 RISCVCPU *cpu =3D opaque;
> +=C2=A0 =C2=A0 CPURISCVState *env =3D &cpu->env;
> +=C2=A0 =C2=A0 CPUState *cs =3D CPU(cpu);
> +
> +=C2=A0 =C2=A0 if (level) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 env->nmip |=3D 1 << irq;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 cpu_interrupt(cs, CPU_INTERRUPT_RNMI); > +=C2=A0 =C2=A0 } else {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 env->nmip &=3D ~(1 << irq);<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 cpu_reset_interrupt(cs, CPU_INTERRUPT_RNM= I);
> +=C2=A0 =C2=A0 }
> +}
> +#endif
> +
>=C2=A0 static void riscv_cpu_realize(DeviceState *dev, Error **errp) >=C2=A0 {
>=C2=A0 =C2=A0 =C2=A0 CPUState *cs =3D CPU(dev);
> @@ -415,6 +440,16 @@ static void riscv_cpu_realize(DeviceState *dev, E= rror **errp)
>
>=C2=A0 =C2=A0 =C2=A0 set_resetvec(env, cpu->cfg.resetvec);
>
> +=C2=A0 =C2=A0 if (cpu->cfg.rnmi) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 set_feature(env, RISCV_FEATURE_RNMI);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 set_rnmi_vectors(env, cpu->cfg.rnmi_ir= qvec, cpu->cfg.rnmi_excpvec);
> +#ifndef CONFIG_USER_ONLY
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 env->nmie =3D true;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 qdev_init_gpio_in_named(DEVICE(cpu), risc= v_cpu_set_rnmi,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "rnmi", TARGET_LONG_BI= TS);
> +#endif
> +=C2=A0 =C2=A0 }
> +
>=C2=A0 =C2=A0 =C2=A0 /* If only XLEN is set for misa, then set misa fro= m properties */
>=C2=A0 =C2=A0 =C2=A0 if (env->misa =3D=3D RV32 || env->misa =3D= =3D RV64) {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Do some ISA extension error check= ing */
> @@ -554,6 +589,11 @@ static Property riscv_cpu_properties[] =3D {
>=C2=A0 =C2=A0 =C2=A0 DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mm= u, true),
>=C2=A0 =C2=A0 =C2=A0 DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pm= p, true),
>=C2=A0 =C2=A0 =C2=A0 DEFINE_PROP_UINT64("resetvec", RISCVCPU,= cfg.resetvec, DEFAULT_RSTVEC),
> +=C2=A0 =C2=A0 DEFINE_PROP_BOOL("rnmi", RISCVCPU, cfg.rnmi, = false),
> +=C2=A0 =C2=A0 DEFINE_PROP_UINT64("rnmi_irqvec", RISCVCPU, c= fg.rnmi_irqvec,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0DEFAULT_RNMI_IRQVEC),
> +=C2=A0 =C2=A0 DEFINE_PROP_UINT64("rnmi_excpvec", RISCVCPU, = cfg.rnmi_excpvec,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0DEFAULT_RNMI_EXCPVEC),
>=C2=A0 =C2=A0 =C2=A0 DEFINE_PROP_END_OF_LIST(),
>=C2=A0 };
>
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 0edb2826a27..b9aa403dfec 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -80,7 +80,8 @@
>=C2=A0 enum {
>=C2=A0 =C2=A0 =C2=A0 RISCV_FEATURE_MMU,
>=C2=A0 =C2=A0 =C2=A0 RISCV_FEATURE_PMP,
> -=C2=A0 =C2=A0 RISCV_FEATURE_MISA
> +=C2=A0 =C2=A0 RISCV_FEATURE_MISA,
> +=C2=A0 =C2=A0 RISCV_FEATURE_RNMI,
>=C2=A0 };
>
>=C2=A0 #define PRIV_VERSION_1_10_0 0x00011000
> @@ -178,6 +179,16 @@ struct CPURISCVState {
>=C2=A0 =C2=A0 =C2=A0 target_ulong mcause;
>=C2=A0 =C2=A0 =C2=A0 target_ulong mtval;=C2=A0 /* since: priv-1.10.0 */=
>
> +=C2=A0 =C2=A0 /* NMI */
> +=C2=A0 =C2=A0 target_ulong mnscratch;
> +=C2=A0 =C2=A0 target_ulong mnepc;
> +=C2=A0 =C2=A0 target_ulong mncause; /* mncause without bit XLEN-1 set= to 1 */
> +=C2=A0 =C2=A0 target_ulong mnstatus;
> +=C2=A0 =C2=A0 bool nmie;
> +=C2=A0 =C2=A0 target_ulong nmip;
> +=C2=A0 =C2=A0 target_ulong rnmi_irqvec;
> +=C2=A0 =C2=A0 target_ulong rnmi_excpvec;
> +
>=C2=A0 =C2=A0 =C2=A0 /* Hypervisor CSRs */
>=C2=A0 =C2=A0 =C2=A0 target_ulong hstatus;
>=C2=A0 =C2=A0 =C2=A0 target_ulong hedeleg;
> @@ -300,6 +311,9 @@ struct RISCVCPU {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool mmu;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool pmp;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 uint64_t resetvec;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 bool rnmi;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint64_t rnmi_irqvec;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 uint64_t rnmi_excpvec;
>=C2=A0 =C2=A0 =C2=A0 } cfg;
>=C2=A0 };
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index caf45992070..94ab76c66b8 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -166,6 +166,12 @@
>=C2=A0 #define CSR_MTVAL=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x343<= br> >=C2=A0 #define CSR_MIP=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00= x344
>
> +/* NMI */
> +#define CSR_MNSCRATCH=C2=A0 =C2=A0 =C2=A0 =C2=A00x350
> +#define CSR_MNEPC=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x351
> +#define CSR_MNCAUSE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x352
> +#define CSR_MNSTATUS=C2=A0 =C2=A0 =C2=A0 =C2=A0 0x353
> +
>=C2=A0 /* Legacy Machine Trap Handling (priv v1.9.1) */
>=C2=A0 #define CSR_MBADADDR=C2=A0 =C2=A0 =C2=A0 =C2=A0 0x343
>
> @@ -526,6 +532,12 @@
>=C2=A0 /* Default Reset Vector adress */
>=C2=A0 #define DEFAULT_RSTVEC=C2=A0 =C2=A0 =C2=A0 0x1000
>
> +/* Default RNMI Interrupt Vector address */
> +#define DEFAULT_RNMI_IRQVEC=C2=A0 =C2=A0 =C2=A00x1000
> +
> +/* Default RNMI Exception Vector address */
> +#define DEFAULT_RNMI_EXCPVEC=C2=A0 =C2=A0 0x1000
> +
>=C2=A0 /* Exception causes */
>=C2=A0 #define EXCP_NONE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 -1 /* se= ntinel value */
>=C2=A0 #define RISCV_EXCP_INST_ADDR_MIS=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00x0
> @@ -552,6 +564,9 @@
>=C2=A0 #define RISCV_EXCP_INT_FLAG=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 0x80000000
>=C2=A0 #define RISCV_EXCP_INT_MASK=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 0x7fffffff
>
> +/* RNMI mnstatus CSR mask */
> +#define MNSTATUS_MPP=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0MSTATUS_MPP
> +
>=C2=A0 /* Interrupt causes */
>=C2=A0 #define IRQ_U_SOFT=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00
>=C2=A0 #define IRQ_S_SOFT=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A01
> @@ -592,4 +607,8 @@
>=C2=A0 #define MIE_UTIE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(1 << IRQ_U_TIMER) >=C2=A0 #define MIE_SSIE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(1 << IRQ_S_SOFT) >=C2=A0 #define MIE_USIE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(1 << IRQ_U_SOFT) > +
> +/* RISC-V-specific interrupt pending bits */
> +#define CPU_INTERRUPT_RNMI=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0CPU_INTERRUPT_TGT_EXT_0
> +
>=C2=A0 #endif
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 2f43939fb6d..f331c4b7032 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -38,6 +38,19 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool if= etch)
>=C2=A0 #ifndef CONFIG_USER_ONLY
>=C2=A0 static int riscv_cpu_local_irq_pending(CPURISCVState *env)
>=C2=A0 {
> +=C2=A0 =C2=A0 if (riscv_feature(env, RISCV_FEATURE_RNMI)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Priority: RNMI > Other interrupt. *= /
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (env->nmip && env->nmie)= {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ctz64(env->nmip);= /* since non-zero */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 } else if (!env->nmie) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /*
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0* We are already in R= NMI handler,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0* other interrupts ca= nnot preempt.
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0*/
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return EXCP_NONE;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 }
> +
>=C2=A0 =C2=A0 =C2=A0 target_ulong irqs;
>
>=C2=A0 =C2=A0 =C2=A0 target_ulong mstatus_mie =3D get_field(env->mst= atus, MSTATUS_MIE);
> @@ -80,7 +93,8 @@ static int riscv_cpu_local_irq_pending(CPURISCVState= *env)
>=C2=A0 bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_reques= t)
>=C2=A0 {
>=C2=A0 #if !defined(CONFIG_USER_ONLY)
> -=C2=A0 =C2=A0 if (interrupt_request & CPU_INTERRUPT_HARD) {
> +=C2=A0 =C2=A0 if (interrupt_request &
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (CPU_INTERRUPT_HARD | CPU_I= NTERRUPT_RNMI)) {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 RISCVCPU *cpu =3D RISCV_CPU(cs);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 CPURISCVState *env =3D &cpu->= env;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int interruptno =3D riscv_cpu_local_= irq_pending(env);
> @@ -847,6 +861,23 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>=C2=A0 =C2=A0 =C2=A0 target_ulong tval =3D 0;
>=C2=A0 =C2=A0 =C2=A0 target_ulong htval =3D 0;
>=C2=A0 =C2=A0 =C2=A0 target_ulong mtval2 =3D 0;
> +=C2=A0 =C2=A0 target_ulong nextpc;
> +=C2=A0 =C2=A0 bool nmi_execp =3D false;
> +
> +=C2=A0 =C2=A0 if (riscv_feature(env, RISCV_FEATURE_RNMI)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 nmi_execp =3D !env->nmie && !a= sync;
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (env->nmip && async) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->nmie =3D false;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->mnstatus =3D set_fi= eld(env->mnstatus, MSTATUS_MPP,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->pri= v);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->mncause =3D cause;<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->mnepc =3D env->p= c;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->pc =3D env->rnmi= _irqvec;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 riscv_cpu_set_mode(env, PRV= _M);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto handled;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 }
>
>=C2=A0 =C2=A0 =C2=A0 if=C2=A0 (cause =3D=3D RISCV_EXCP_SEMIHOST) {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (env->priv >=3D PRV_S) { > @@ -905,7 +936,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 _= _func__, env->mhartid, async, cause, env->pc, tval,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 r= iscv_cpu_get_trap_name(cause, async));
>
> -=C2=A0 =C2=A0 if (env->priv <=3D PRV_S &&
> +=C2=A0 =C2=A0 if (env->priv <=3D PRV_S && !nmi_execp &a= mp;&
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 cause < TARGET_LONG= _BITS && ((deleg >> cause) & 1)) {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* handle the trap in S-mode */
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (riscv_has_ext(env, RVH)) {
> @@ -1005,8 +1036,15 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->mepc =3D env->pc;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->mbadaddr =3D tval;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 env->mtval2 =3D mtval2;
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 env->pc =3D (env->mtvec >> 2 = << 2) +
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((async && (env->= ;mtvec & 3) =3D=3D 1) ? cause * 4 : 0);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 if (nmi_execp) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 nextpc =3D env->rnmi_exc= pvec;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 } else {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 nextpc =3D (env->mtvec &= gt;> 2 << 2) +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((async &= & (env->mtvec & 3) =3D=3D 1) ? cause * 4 : 0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 env->pc =3D nextpc;
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 riscv_cpu_set_mode(env, PRV_M);
>=C2=A0 =C2=A0 =C2=A0 }
>
> @@ -1016,6 +1054,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0* RISC-V ISA Specification.
>=C2=A0 =C2=A0 =C2=A0 =C2=A0*/
>
> +handled:
>=C2=A0 #endif
>=C2=A0 =C2=A0 =C2=A0 cs->exception_index =3D EXCP_NONE; /* mark hand= led to qemu */
>=C2=A0 }
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index fd2e6363f39..f67c50327ec 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -188,6 +188,11 @@ static int pmp(CPURISCVState *env, int csrno)
>=C2=A0 {
>=C2=A0 =C2=A0 =C2=A0 return -!riscv_feature(env, RISCV_FEATURE_PMP); >=C2=A0 }
> +
> +static int nmi(CPURISCVState *env, int csrno)
> +{
> +=C2=A0 =C2=A0 return -!riscv_feature(env, RISCV_FEATURE_RNMI);
> +}
>=C2=A0 #endif
>
>=C2=A0 /* User Floating-Point CSRs */
> @@ -712,6 +717,54 @@ static int write_mbadaddr(CPURISCVState *env, int= csrno, target_ulong val)
>=C2=A0 =C2=A0 =C2=A0 return 0;
>=C2=A0 }
>
> +static int read_mnscratch(CPURISCVState *env, int csrno, target_ulong= *val)
> +{
> +=C2=A0 =C2=A0 *val =3D env->mnscratch;
> +=C2=A0 =C2=A0 return 0;
> +}
> +
> +static int write_mnscratch(CPURISCVState *env, int csrno, target_ulon= g val)
> +{
> +=C2=A0 =C2=A0 env->mnscratch =3D val;
> +=C2=A0 =C2=A0 return 0;
> +}
> +
> +static int read_mnepc(CPURISCVState *env, int csrno, target_ulong *va= l)
> +{
> +=C2=A0 =C2=A0 *val =3D env->mnepc;
> +=C2=A0 =C2=A0 return 0;
> +}
> +
> +static int write_mnepc(CPURISCVState *env, int csrno, target_ulong va= l)
> +{
> +=C2=A0 =C2=A0 env->mnepc =3D val;
> +=C2=A0 =C2=A0 return 0;
> +}
> +
> +static int read_mncause(CPURISCVState *env, int csrno, target_ulong *= val)
> +{
> +=C2=A0 =C2=A0 *val =3D env->mncause;
> +=C2=A0 =C2=A0 return 0;
> +}
> +
> +static int write_mncause(CPURISCVState *env, int csrno, target_ulong = val)
> +{
> +=C2=A0 =C2=A0 env->mncause =3D val;
> +=C2=A0 =C2=A0 return 0;
> +}
> +
> +static int read_mnstatus(CPURISCVState *env, int csrno, target_ulong = *val)
> +{
> +=C2=A0 =C2=A0 *val =3D env->mnstatus;
> +=C2=A0 =C2=A0 return 0;
> +}
> +
> +static int write_mnstatus(CPURISCVState *env, int csrno, target_ulong= val)
> +{
> +=C2=A0 =C2=A0 env->mnstatus =3D val & MNSTATUS_MPP;
> +=C2=A0 =C2=A0 return 0;
> +}
> +
>=C2=A0 static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *= ret_value,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0target_ulong new_value, target_ulong write_mask)
>=C2=A0 {
> @@ -1427,6 +1480,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = =3D {
>=C2=A0 =C2=A0 =C2=A0 [CSR_MBADADDR] =3D { "mbadaddr", any,=C2= =A0 read_mbadaddr, write_mbadaddr },
>=C2=A0 =C2=A0 =C2=A0 [CSR_MIP]=C2=A0 =C2=A0 =C2=A0 =3D { "mip"= ;,=C2=A0 =C2=A0 =C2=A0 any,=C2=A0 NULL,=C2=A0 =C2=A0 NULL, rmw_mip=C2=A0 = =C2=A0 =C2=A0 =C2=A0 },
>
> +=C2=A0 =C2=A0 /* NMI */
> +=C2=A0 =C2=A0 [CSR_MNSCRATCH] =3D { "mnscratch", nmi, read_= mnscratch, write_mnscratch },
> +=C2=A0 =C2=A0 [CSR_MNEPC]=C2=A0 =C2=A0 =C2=A0=3D { "mnepc",= =C2=A0 =C2=A0 =C2=A0nmi, read_mnepc,=C2=A0 =C2=A0 =C2=A0write_mnepc=C2=A0 = =C2=A0 =C2=A0},
> +=C2=A0 =C2=A0 [CSR_MNCAUSE]=C2=A0 =C2=A0=3D { "mncause",=C2= =A0 =C2=A0nmi, read_mncause,=C2=A0 =C2=A0write_mncause=C2=A0 =C2=A0},
> +=C2=A0 =C2=A0 [CSR_MNSTATUS]=C2=A0 =3D { "mnstatus",=C2=A0 = nmi, read_mnstatus,=C2=A0 write_mnstatus=C2=A0 },
> +
>=C2=A0 =C2=A0 =C2=A0 /* Supervisor Trap Setup */
>=C2=A0 =C2=A0 =C2=A0 [CSR_SSTATUS]=C2=A0 =C2=A0 =3D { "sstatus&quo= t;,=C2=A0 =C2=A0 smode, read_sstatus,=C2=A0 =C2=A0 write_sstatus=C2=A0 =C2= =A0 },
>=C2=A0 =C2=A0 =C2=A0 [CSR_SIE]=C2=A0 =C2=A0 =C2=A0 =C2=A0 =3D { "s= ie",=C2=A0 =C2=A0 =C2=A0 =C2=A0 smode, read_sie,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 write_sie=C2=A0 =C2=A0 =C2=A0 =C2=A0 },
> diff --git a/target/riscv/helper.h b/target/riscv/helper.h
> index e3f3f41e891..0914d777d6d 100644
> --- a/target/riscv/helper.h
> +++ b/target/riscv/helper.h
> @@ -65,6 +65,7 @@ DEF_HELPER_4(csrrc, tl, env, tl, tl, tl)
>=C2=A0 #ifndef CONFIG_USER_ONLY
>=C2=A0 DEF_HELPER_2(sret, tl, env, tl)
>=C2=A0 DEF_HELPER_2(mret, tl, env, tl)
> +DEF_HELPER_2(mnret, tl, env, tl)
>=C2=A0 DEF_HELPER_1(wfi, void, env)
>=C2=A0 DEF_HELPER_1(tlb_flush, void, env)
>=C2=A0 #endif
> diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode > index 84080dd18ca..557f3394276 100644
> --- a/target/riscv/insn32.decode
> +++ b/target/riscv/insn32.decode
> @@ -97,6 +97,9 @@ wfi=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A00001000=C2=A0 = =C2=A0 00101 00000 000 00000 1110011
>=C2=A0 sfence_vma=C2=A0 0001001=C2=A0 =C2=A0 ..... ..... 000 00000 1110= 011 @sfence_vma
>=C2=A0 sfence_vm=C2=A0 =C2=A00001000=C2=A0 =C2=A0 00100 ..... 000 00000= 1110011 @sfence_vm
>
> +# *** NMI ***
> +mnret=C2=A0 =C2=A0 =C2=A0 =C2=A00111000=C2=A0 =C2=A0 00010 00000 000 = 00000 1110011
> +
>=C2=A0 # *** RV32I Base Instruction Set ***
>=C2=A0 lui=C2=A0 =C2=A0 =C2=A0 ....................=C2=A0 =C2=A0 =C2=A0= =C2=A0..... 0110111 @u
>=C2=A0 auipc=C2=A0 =C2=A0 ....................=C2=A0 =C2=A0 =C2=A0 =C2= =A0..... 0010111 @u
> diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/r= iscv/insn_trans/trans_privileged.c.inc
> index 32312be2024..63c49dfe6fb 100644
> --- a/target/riscv/insn_trans/trans_privileged.c.inc
> +++ b/target/riscv/insn_trans/trans_privileged.c.inc
> @@ -106,6 +106,19 @@ static bool trans_mret(DisasContext *ctx, arg_mre= t *a)
>=C2=A0 #endif
>=C2=A0 }
>
> +static bool trans_mnret(DisasContext *ctx, arg_mnret *a)
> +{
> +#ifndef CONFIG_USER_ONLY
> +=C2=A0 =C2=A0 tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next);
> +=C2=A0 =C2=A0 gen_helper_mnret(cpu_pc, cpu_env, cpu_pc);
> +=C2=A0 =C2=A0 exit_tb(ctx); /* no chaining */
> +=C2=A0 =C2=A0 ctx->base.is_jmp =3D DISAS_NORETURN;
> +=C2=A0 =C2=A0 return true;
> +#else
> +=C2=A0 =C2=A0 return false;
> +#endif
> +}
> +
>=C2=A0 static bool trans_wfi(DisasContext *ctx, arg_wfi *a)
>=C2=A0 {
>=C2=A0 #ifndef CONFIG_USER_ONLY
> diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
> index 1eddcb94de7..b9601776153 100644
> --- a/target/riscv/op_helper.c
> +++ b/target/riscv/op_helper.c
> @@ -175,6 +175,37 @@ target_ulong helper_mret(CPURISCVState *env, targ= et_ulong cpu_pc_deb)
>=C2=A0 =C2=A0 =C2=A0 return retpc;
>=C2=A0 }
>
> +target_ulong helper_mnret(CPURISCVState *env, target_ulong cpu_pc_deb= )
> +{
> +=C2=A0 =C2=A0 if (!riscv_feature(env, RISCV_FEATURE_RNMI)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* RNMI feature is not presented. */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 riscv_raise_exception(env, RISCV_EXCP_ILL= EGAL_INST, GETPC());
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 if (!(env->priv >=3D PRV_M)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 riscv_raise_exception(env, RISCV_EXCP_ILL= EGAL_INST, GETPC());
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 /* Get return PC from mnepc CSR. */
> +=C2=A0 =C2=A0 target_ulong retpc =3D env->mnepc;
> +=C2=A0 =C2=A0 if (!riscv_has_ext(env, RVC) && (retpc & 0x= 3)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 riscv_raise_exception(env, RISCV_EXCP_INS= T_ADDR_MIS, GETPC());
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 /* Get previous privilege level from mnstatus CSR. */ > +=C2=A0 =C2=A0 target_ulong prev_priv =3D get_field(env->mnstatus, = MNSTATUS_MPP);
> +
> +=C2=A0 =C2=A0 if (!pmp_get_num_rules(env) && (prev_priv !=3D = PRV_M)) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 riscv_raise_exception(env, RISCV_EXCP_ILL= EGAL_INST, GETPC());
> +=C2=A0 =C2=A0 }
> +
> +=C2=A0 =C2=A0 riscv_cpu_set_mode(env, prev_priv);
> +
> +=C2=A0 =C2=A0 env->nmie =3D true;
> +
> +=C2=A0 =C2=A0 return retpc;
> +}
> +
>=C2=A0 void helper_wfi(CPURISCVState *env)
>=C2=A0 {
>=C2=A0 =C2=A0 =C2=A0 CPUState *cs =3D env_cpu(env);
> --
> 2.17.1
>
>
--0000000000008a05f105be167db2--