aboutsummaryrefslogtreecommitdiff
path: root/target/riscv/cpu_helper.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2023-11-07 11:08:16 +0800
committerStefan Hajnoczi <stefanha@redhat.com>2023-11-07 11:08:16 +0800
commit8aba939e77daca10eac99d9d467f65ba7df5ab3e (patch)
tree8070c399c69c6b7ebf1242608e04ca722c1e7ee9 /target/riscv/cpu_helper.c
parent74949263a54a1382309afba952683255c1c22ef7 (diff)
parentbc5e8445342fee35b35f2ed9a9f2249e060b8776 (diff)
Merge tag 'pull-riscv-to-apply-20231107' of https://github.com/alistair23/qemu into staging
Third RISC-V PR for 8.2 * Rename ext_icboz to ext_zicboz * Rename ext_icbom to ext_zicbom * Rename ext_icsr to ext_zicsr * Rename ext_ifencei to ext_zifencei * Add RISC-V Virtual IRQs and IRQ filtering support * Change default linux-user cpu to 'max' * Update 'virt' machine core limit * Add query-cpu-model-expansion API * Rename epmp to smepmp and expose the extension * Clear pmp/smepmp bits on reset * Ignore pmp writes when RW=01 * Support zicntr/zihpm flags and disable support * Correct CSR_MSECCFG operations * Update mail address for Weiwei Li * Update RISC-V vector crypto to ratified v1.0.0 * Clear the Ibex/OpenTitan SPI interrupts even if disabled * Set the OpenTitan priv to 1.12.0 * Support discontinuous PMU counters # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmVJoOEACgkQr3yVEwxT # gBPwcw/5AXgSVu521IHpobofq4Skc2rpO9P0Hep3IniBuS+5+h2XM3fwWNBaeeGj # LZgdXDrCfcCnPuFh2I5j1D885xJDncDF4LET9EFtxK+BTT8eC5JpaCnORdV3Zd2T # C7qdq1r4J/wKBel3cAz1jlLXc2Pssle4NFaMZGmOGlNX/mLJUYkI6BwKG9wNiCI+ # cCRQW5bEv9g8XzPYPsIKhX9aTegDKdV5x4Xj3YyVs8qkZTVM7Ona8GTpy6eShNfL # h/RW+yvSxLwfKC9YJHesjI1oqhLsAuA7hFu5AVHiedFNAD5FevMZsZwrqjrmeBOG # 5awBw9XgfXFFl7jQ0VQVRknt/PFANzTmGGbjLUkaXgJ6iTmH7oIMzwbkx2pM/0Qd # HV2EboUPe5rJl0SNhcDMCJkYJYpt4z6TVXFpN5p10WU4K1AJXZf9P3YkChcxWiSK # B4DlY4ax3W77voySwbKCvJRIRWCFQZmtl7doFY5dEQz2ERcNfI7VIB1GKIj7BlGm # AVTCc5G9KghsaB8q0BzYbDplzCggdaaUBRgpIgLS/n22GKJlOisFwMCawWquPkEw # i0t3ftt+Ket4Qnnq+dO4W3ehR4qW1/XatCWgQ3NCSgUeS4/9VK3h/nz5t+L7iKwp # mjp86gNN11wcJRsBIIV7nOAmSAs9ybCm2F4J6YAyh3n1IlRVN0Q= # =2A+W # -----END PGP SIGNATURE----- # gpg: Signature made Tue 07 Nov 2023 10:28:49 HKT # gpg: using RSA key 6AE902B6A7CA877D6D659296AF7C95130C538013 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 6AE9 02B6 A7CA 877D 6D65 9296 AF7C 9513 0C53 8013 * tag 'pull-riscv-to-apply-20231107' of https://github.com/alistair23/qemu: (49 commits) docs/about/deprecated: Document RISC-V "pmu-num" deprecation target/riscv: Add "pmu-mask" property to replace "pmu-num" target/riscv: Use existing PMU counter mask in FDT generation target/riscv: Don't assume PMU counters are continuous target/riscv: Propagate error from PMU setup target/riscv: cpu: Set the OpenTitan priv to 1.12.0 hw/ssi: ibex_spi_host: Clear the interrupt even if disabled disas/riscv: Replace TABs with space disas/riscv: Add support for vector crypto extensions disas/riscv: Add rv_codec_vror_vi for vror.vi disas/riscv: Add rv_fmt_vd_vs2_uimm format target/riscv: Move vector crypto extensions to riscv_cpu_extensions target/riscv: Expose Zvks[c|g] extnesion properties target/riscv: Add cfg properties for Zvks[c|g] extensions target/riscv: Expose Zvkn[c|g] extnesion properties target/riscv: Add cfg properties for Zvkn[c|g] extensions target/riscv: Expose Zvkb extension property target/riscv: Replace Zvbb checking by Zvkb target/riscv: Add cfg property for Zvkb extension target/riscv: Expose Zvkt extension property ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'target/riscv/cpu_helper.c')
-rw-r--r--target/riscv/cpu_helper.c99
1 files changed, 73 insertions, 26 deletions
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 8c28241c18..b7af69de53 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -376,6 +376,11 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
return best_irq;
}
+/*
+ * Doesn't report interrupts inserted using mvip from M-mode firmware or
+ * using hvip bits 13:63 from HS-mode. Those are returned in
+ * riscv_cpu_sirq_pending() and riscv_cpu_vsirq_pending().
+ */
uint64_t riscv_cpu_all_pending(CPURISCVState *env)
{
uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -398,24 +403,32 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
{
uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+ uint64_t irqs_f = env->mvip & env->mvien & ~env->mideleg & env->sie;
return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
- irqs, env->siprio);
+ irqs | irqs_f, env->siprio);
}
int riscv_cpu_vsirq_pending(CPURISCVState *env)
{
- uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
- (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
+ uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg & env->hideleg;
+ uint64_t irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+ uint64_t vsbits;
+
+ /* Bring VS-level bits to correct position */
+ vsbits = irqs & VS_MODE_INTERRUPTS;
+ irqs &= ~VS_MODE_INTERRUPTS;
+ irqs |= vsbits >> 1;
return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
- irqs >> 1, env->hviprio);
+ (irqs | irqs_f_vs), env->hviprio);
}
static int riscv_cpu_local_irq_pending(CPURISCVState *env)
{
+ uint64_t irqs, pending, mie, hsie, vsie, irqs_f, irqs_f_vs;
+ uint64_t vsbits, irq_delegated;
int virq;
- uint64_t irqs, pending, mie, hsie, vsie;
/* Determine interrupt enable state of all privilege modes */
if (env->virt_enabled) {
@@ -441,19 +454,36 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
irqs, env->miprio);
}
+ /* Check for virtual S-mode interrupts. */
+ irqs_f = env->mvip & (env->mvien & ~env->mideleg) & env->sie;
+
/* Check HS-mode interrupts */
- irqs = pending & env->mideleg & ~env->hideleg & -hsie;
+ irqs = ((pending & env->mideleg & ~env->hideleg) | irqs_f) & -hsie;
if (irqs) {
return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
irqs, env->siprio);
}
+ /* Check for virtual VS-mode interrupts. */
+ irqs_f_vs = env->hvip & env->hvien & ~env->hideleg & env->vsie;
+
/* Check VS-mode interrupts */
- irqs = pending & env->mideleg & env->hideleg & -vsie;
+ irq_delegated = pending & env->mideleg & env->hideleg;
+
+ /* Bring VS-level bits to correct position */
+ vsbits = irq_delegated & VS_MODE_INTERRUPTS;
+ irq_delegated &= ~VS_MODE_INTERRUPTS;
+ irq_delegated |= vsbits >> 1;
+
+ irqs = (irq_delegated | irqs_f_vs) & -vsie;
if (irqs) {
virq = riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
- irqs >> 1, env->hviprio);
- return (virq <= 0) ? virq : virq + 1;
+ irqs, env->hviprio);
+ if (virq <= 0 || (virq > 12 && virq <= 63)) {
+ return virq;
+ } else {
+ return virq + 1;
+ }
}
/* Indicate no pending interrupt */
@@ -620,28 +650,42 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
}
}
-uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask,
- uint64_t value)
+void riscv_cpu_interrupt(CPURISCVState *env)
{
+ uint64_t gein, vsgein = 0, vstip = 0, irqf = 0;
CPUState *cs = env_cpu(env);
- uint64_t gein, vsgein = 0, vstip = 0, old = env->mip;
+
+ QEMU_IOTHREAD_LOCK_GUARD();
if (env->virt_enabled) {
gein = get_field(env->hstatus, HSTATUS_VGEIN);
vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
+ irqf = env->hvien & env->hvip & env->vsie;
+ } else {
+ irqf = env->mvien & env->mvip & env->sie;
}
vstip = env->vstime_irq ? MIP_VSTIP : 0;
- QEMU_IOTHREAD_LOCK_GUARD();
-
- env->mip = (env->mip & ~mask) | (value & mask);
-
- if (env->mip | vsgein | vstip) {
+ if (env->mip | vsgein | vstip | irqf) {
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
+}
+
+uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t value)
+{
+ uint64_t old = env->mip;
+
+ /* No need to update mip for VSTIP */
+ mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask;
+
+ QEMU_IOTHREAD_LOCK_GUARD();
+
+ env->mip = (env->mip & ~mask) | (value & mask);
+
+ riscv_cpu_interrupt(env);
return old;
}
@@ -1600,20 +1644,22 @@ void riscv_cpu_do_interrupt(CPUState *cs)
bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
uint64_t deleg = async ? env->mideleg : env->medeleg;
+ bool s_injected = env->mvip & (1 << cause) & env->mvien &&
+ !(env->mip & (1 << cause));
+ bool vs_injected = env->hvip & (1 << cause) & env->hvien &&
+ !(env->mip & (1 << cause));
target_ulong tval = 0;
target_ulong tinst = 0;
target_ulong htval = 0;
target_ulong mtval2 = 0;
- if (cause == RISCV_EXCP_SEMIHOST) {
- do_common_semihosting(cs);
- env->pc += 4;
- return;
- }
-
if (!async) {
/* set tval to badaddr for traps with address information */
switch (cause) {
+ case RISCV_EXCP_SEMIHOST:
+ do_common_semihosting(cs);
+ env->pc += 4;
+ return;
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
case RISCV_EXCP_LOAD_ADDR_MIS:
@@ -1690,13 +1736,14 @@ 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 &&
- cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
+ if (env->priv <= PRV_S && cause < 64 &&
+ (((deleg >> cause) & 1) || s_injected || vs_injected)) {
/* handle the trap in S-mode */
if (riscv_has_ext(env, RVH)) {
uint64_t hdeleg = async ? env->hideleg : env->hedeleg;
- if (env->virt_enabled && ((hdeleg >> cause) & 1)) {
+ if (env->virt_enabled &&
+ (((hdeleg >> cause) & 1) || vs_injected)) {
/* Trap to VS mode */
/*
* See if we need to adjust cause. Yes if its VS mode interrupt