From patchwork Thu Dec 30 12:35:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anup Patel X-Patchwork-Id: 12701426 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 6D133C433EF for ; Thu, 30 Dec 2021 12:45:47 +0000 (UTC) Received: from localhost ([::1]:41996 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1n2uoU-0002C3-4u for qemu-devel@archiver.kernel.org; Thu, 30 Dec 2021 07:45:46 -0500 Received: from eggs.gnu.org ([209.51.188.92]:53856) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1n2uf3-0001eU-Is for qemu-devel@nongnu.org; Thu, 30 Dec 2021 07:36:02 -0500 Received: from [2607:f8b0:4864:20::631] (port=42568 helo=mail-pl1-x631.google.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1n2uf1-0003FE-Gx for qemu-devel@nongnu.org; Thu, 30 Dec 2021 07:36:01 -0500 Received: by mail-pl1-x631.google.com with SMTP id u16so18160962plg.9 for ; Thu, 30 Dec 2021 04:35:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=brainfault-org.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=qyAIoMA9XH3kUtYuYw89hHxER+TVcF1u1qmVyAU4cUc=; b=tK/zQqinyt5eUj7dq6TkcXuZ674kIozATN1+UMtStMuw7ArOVEJ9eD4Ae+rPpwUW6Q C6AFAirmbM2ET1BH7tFgF3DKcRmYY20y06nPAOD2JMulitIi4KK05nudXsD7dalcugOP D72TxPa7E7unTZJ1KcOUjiHgK79mVoxWRQE1Ejg4JdTbT2nR2sKZAl4ld8Ul0rtOZjJg 2ysC6AgS2D96VTsgbFaQsIFWF+bLV4zJ2KkWyC8W1u+EmEdHbT/mfwwxLOIN6pcewYV2 YVOyNkuQPEYrT7B1Td3U5BGpTfjtuzMTgUIauQPONsm1O7Y3keC6Ozsd3SxtEf2Ra3kK ib7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=qyAIoMA9XH3kUtYuYw89hHxER+TVcF1u1qmVyAU4cUc=; b=0idcyt+6nDMr8M/QJzSh5bl4VB+L1x6G5kRjrLPXA/bMD6IJRGYa45gZMD54l7/hz2 okh7hO4wQrUO46PTwvMH9PkuIDl2htNObKoYsY64aUOMnIUX2jfABOAqsaNk6FLkjcK7 XyOFDVn9Xm1tScz+rdWQ+Sn9GQvhebTYqIVUTJSc/KMCOkxOC3xYpQxVKGMFFIfdDozY omXfXPcZHRue13PgsbMeAGvi237oJ4K1Wed7/bsPtO6syQt8EoE88qDk7IgP4R0sHr9x U/CFF7sJDV/YEMacRMvIAlUvIHKGUOVSsihaCpLoTK/fzhDSWl0NCw4CZ4prn21gLZJ3 FtjA== X-Gm-Message-State: AOAM532V0pBn/fgEJLEct7lG3jNv+NnZ8ZUHi1iLaj3YROJ7YPcEF3G5 Eof5+xB9r6f9w+1CwUMxGZPQ41350GHr6w== X-Google-Smtp-Source: ABdhPJzHYriXjlb2G6R0lGl9tpHDx6ZoJ4MVVrr4VLQuk7ai0cjN2vLndBTpmNL1AZVJ/JpCI3ny+g== X-Received: by 2002:a17:902:aa0a:b0:149:5f4d:bd55 with SMTP id be10-20020a170902aa0a00b001495f4dbd55mr27351181plb.12.1640867758196; Thu, 30 Dec 2021 04:35:58 -0800 (PST) Received: from localhost.localdomain ([171.61.71.9]) by smtp.gmail.com with ESMTPSA id a3sm28588348pfv.47.2021.12.30.04.35.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Dec 2021 04:35:57 -0800 (PST) From: Anup Patel To: Peter Maydell , Palmer Dabbelt , Alistair Francis , Sagar Karandikar Subject: [PATCH v6 03/23] target/riscv: Implement hgeie and hgeip CSRs Date: Thu, 30 Dec 2021 18:05:19 +0530 Message-Id: <20211230123539.52786-4-anup@brainfault.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211230123539.52786-1-anup@brainfault.org> References: <20211230123539.52786-1-anup@brainfault.org> MIME-Version: 1.0 X-Host-Lookup-Failed: Reverse DNS lookup failed for 2607:f8b0:4864:20::631 (failed) Received-SPF: none client-ip=2607:f8b0:4864:20::631; envelope-from=anup@brainfault.org; helo=mail-pl1-x631.google.com X-Spam_score_int: 8 X-Spam_score: 0.8 X-Spam_bar: / X-Spam_report: (0.8 / 5.0 requ) DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=no 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: qemu-riscv@nongnu.org, Anup Patel , qemu-devel@nongnu.org, Alistair Francis , Atish Patra , Bin Meng Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Anup Patel The hgeie and hgeip CSRs are required for emulating an external interrupt controller capable of injecting virtual external interrupt to Guest/VM running at VS-level. Signed-off-by: Anup Patel Signed-off-by: Anup Patel Reviewed-by: Alistair Francis Reviewed-by: Frank Chang --- target/riscv/cpu.c | 61 ++++++++++++++++++++++++++++----------- target/riscv/cpu.h | 5 ++++ target/riscv/cpu_bits.h | 1 + target/riscv/cpu_helper.c | 37 ++++++++++++++++++++++-- target/riscv/csr.c | 43 ++++++++++++++++++--------- target/riscv/machine.c | 6 ++-- 6 files changed, 118 insertions(+), 35 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7d92ce7555..f4dbc766c2 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -582,23 +582,49 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp) static void riscv_cpu_set_irq(void *opaque, int irq, int level) { RISCVCPU *cpu = RISCV_CPU(opaque); + CPURISCVState *env = &cpu->env; - switch (irq) { - case IRQ_U_SOFT: - case IRQ_S_SOFT: - case IRQ_VS_SOFT: - case IRQ_M_SOFT: - case IRQ_U_TIMER: - case IRQ_S_TIMER: - case IRQ_VS_TIMER: - case IRQ_M_TIMER: - case IRQ_U_EXT: - case IRQ_S_EXT: - case IRQ_VS_EXT: - case IRQ_M_EXT: - riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level)); - break; - default: + if (irq < IRQ_LOCAL_MAX) { + switch (irq) { + case IRQ_U_SOFT: + case IRQ_S_SOFT: + case IRQ_VS_SOFT: + case IRQ_M_SOFT: + case IRQ_U_TIMER: + case IRQ_S_TIMER: + case IRQ_VS_TIMER: + case IRQ_M_TIMER: + case IRQ_U_EXT: + case IRQ_S_EXT: + case IRQ_VS_EXT: + case IRQ_M_EXT: + riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level)); + break; + default: + g_assert_not_reached(); + } + } else if (irq < (IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX)) { + /* Require H-extension for handling guest local interrupts */ + if (!riscv_has_ext(env, RVH)) { + g_assert_not_reached(); + } + + /* Compute bit position in HGEIP CSR */ + irq = irq - IRQ_LOCAL_MAX + 1; + if (env->geilen < irq) { + g_assert_not_reached(); + } + + /* Update HGEIP CSR */ + env->hgeip &= ~((target_ulong)1 << irq); + if (level) { + env->hgeip |= (target_ulong)1 << irq; + } + + /* Update mip.SGEIP bit */ + riscv_cpu_update_mip(cpu, MIP_SGEIP, + BOOL_TO_MASK(!!(env->hgeie & env->hgeip))); + } else { g_assert_not_reached(); } } @@ -611,7 +637,8 @@ static void riscv_cpu_init(Object *obj) cpu_set_cpustate_pointers(cpu); #ifndef CONFIG_USER_ONLY - qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq, IRQ_LOCAL_MAX); + qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq, + IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX); #endif /* CONFIG_USER_ONLY */ } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index dc10f27093..6895ac138c 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -151,6 +151,7 @@ struct CPURISCVState { target_ulong priv; /* This contains QEMU specific information about the virt state. */ target_ulong virt; + target_ulong geilen; target_ulong resetvec; target_ulong mhartid; @@ -188,6 +189,8 @@ struct CPURISCVState { target_ulong htval; target_ulong htinst; target_ulong hgatp; + target_ulong hgeie; + target_ulong hgeip; uint64_t htimedelta; /* Virtual CSRs */ @@ -355,6 +358,8 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); bool riscv_cpu_fp_enabled(CPURISCVState *env); +target_ulong riscv_cpu_get_geilen(CPURISCVState *env); +void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen); bool riscv_cpu_vector_enabled(CPURISCVState *env); bool riscv_cpu_virt_enabled(CPURISCVState *env); void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable); diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index fe276d4b34..f32159a19d 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -536,6 +536,7 @@ typedef enum RISCVException { #define IRQ_M_EXT 11 #define IRQ_S_GEXT 12 #define IRQ_LOCAL_MAX 16 +#define IRQ_LOCAL_GUEST_MAX (TARGET_LONG_BITS - 1) /* mip masks */ #define MIP_USIP (1 << IRQ_U_SOFT) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 10f3baba53..bf50699b1f 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -158,7 +158,11 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env) target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE); target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE); - target_ulong pending = env->mip & env->mie; + target_ulong vsgemask = + (target_ulong)1 << get_field(env->hstatus, HSTATUS_VGEIN); + target_ulong vsgein = (env->hgeip & vsgemask) ? MIP_VSEIP : 0; + + target_ulong pending = (env->mip | vsgein) & env->mie; target_ulong mie = env->priv < PRV_M || (env->priv == PRV_M && mstatus_mie); @@ -278,6 +282,28 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env) } } +target_ulong riscv_cpu_get_geilen(CPURISCVState *env) +{ + if (!riscv_has_ext(env, RVH)) { + return 0; + } + + return env->geilen; +} + +void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen) +{ + if (!riscv_has_ext(env, RVH)) { + return; + } + + if (geilen > (TARGET_LONG_BITS - 1)) { + return; + } + + env->geilen = geilen; +} + bool riscv_cpu_virt_enabled(CPURISCVState *env) { if (!riscv_has_ext(env, RVH)) { @@ -321,9 +347,14 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) { CPURISCVState *env = &cpu->env; CPUState *cs = CPU(cpu); - uint32_t old = env->mip; + uint32_t gein, vsgein = 0, old = env->mip; bool locked = false; + if (riscv_cpu_virt_enabled(env)) { + gein = get_field(env->hstatus, HSTATUS_VGEIN); + vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; + } + if (!qemu_mutex_iothread_locked()) { locked = true; qemu_mutex_lock_iothread(); @@ -331,7 +362,7 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) env->mip = (env->mip & ~mask) | (value & mask); - if (env->mip) { + if (env->mip | vsgein) { cpu_interrupt(cs, CPU_INTERRUPT_HARD); } else { cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index a4028f28e0..50424a8344 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -832,7 +832,7 @@ static RISCVException rmw_mip(CPURISCVState *env, int csrno, RISCVCPU *cpu = env_archcpu(env); /* Allow software control of delegable interrupts not claimed by hardware */ target_ulong mask = write_mask & delegable_ints & ~env->miclaim; - uint32_t old_mip; + uint32_t gin, old_mip; if (mask) { old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); @@ -840,6 +840,11 @@ static RISCVException rmw_mip(CPURISCVState *env, int csrno, old_mip = env->mip; } + if (csrno != CSR_HVIP) { + gin = get_field(env->hstatus, HSTATUS_VGEIN); + old_mip |= (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VSEIP : 0; + } + if (ret_value) { *ret_value = old_mip; } @@ -1002,7 +1007,7 @@ static RISCVException rmw_vsip(CPURISCVState *env, int csrno, target_ulong new_value, target_ulong write_mask) { /* Shift the S bits to their VS bit location in mip */ - int ret = rmw_mip(env, 0, ret_value, new_value << 1, + int ret = rmw_mip(env, csrno, ret_value, new_value << 1, (write_mask << 1) & vsip_writable_mask & env->hideleg); if (ret_value) { @@ -1022,7 +1027,7 @@ static RISCVException rmw_sip(CPURISCVState *env, int csrno, if (riscv_cpu_virt_enabled(env)) { ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); } else { - ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, + ret = rmw_mip(env, csrno, ret_value, new_value, write_mask & env->mideleg & sip_writable_mask); } @@ -1141,7 +1146,7 @@ static RISCVException rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { - int ret = rmw_mip(env, 0, ret_value, new_value, + int ret = rmw_mip(env, csrno, ret_value, new_value, write_mask & hvip_writable_mask); if (ret_value) { @@ -1154,7 +1159,7 @@ static RISCVException rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { - int ret = rmw_mip(env, 0, ret_value, new_value, + int ret = rmw_mip(env, csrno, ret_value, new_value, write_mask & hip_writable_mask); if (ret_value) { @@ -1191,15 +1196,27 @@ static RISCVException write_hcounteren(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException write_hgeie(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException read_hgeie(CPURISCVState *env, int csrno, + target_ulong *val) { if (val) { - qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); + *val = env->hgeie; } return RISCV_EXCP_NONE; } +static RISCVException write_hgeie(CPURISCVState *env, int csrno, + target_ulong val) +{ + /* Only GEILEN:1 bits implemented and BIT0 is never implemented */ + val &= ((((target_ulong)1) << env->geilen) - 1) << 1; + env->hgeie = val; + /* Update mip.SGEIP bit */ + riscv_cpu_update_mip(env_archcpu(env), MIP_SGEIP, + BOOL_TO_MASK(!!(env->hgeie & env->hgeip))); + return RISCV_EXCP_NONE; +} + static RISCVException read_htval(CPURISCVState *env, int csrno, target_ulong *val) { @@ -1227,11 +1244,11 @@ static RISCVException write_htinst(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException write_hgeip(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException read_hgeip(CPURISCVState *env, int csrno, + target_ulong *val) { if (val) { - qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); + *val = env->hgeip; } return RISCV_EXCP_NONE; } @@ -1922,10 +1939,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip }, [CSR_HIE] = { "hie", hmode, read_hie, write_hie }, [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, write_hcounteren }, - [CSR_HGEIE] = { "hgeie", hmode, read_zero, write_hgeie }, + [CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie }, [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval }, [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst }, - [CSR_HGEIP] = { "hgeip", hmode, read_zero, write_hgeip }, + [CSR_HGEIP] = { "hgeip", hmode, read_hgeip, NULL }, [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp }, [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, write_htimedelta }, [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, write_htimedeltah }, diff --git a/target/riscv/machine.c b/target/riscv/machine.c index ad8248ebfd..76dd0d415c 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -78,8 +78,8 @@ static bool hyper_needed(void *opaque) static const VMStateDescription vmstate_hyper = { .name = "cpu/hyper", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = hyper_needed, .fields = (VMStateField[]) { VMSTATE_UINTTL(env.hstatus, RISCVCPU), @@ -89,6 +89,8 @@ static const VMStateDescription vmstate_hyper = { VMSTATE_UINTTL(env.htval, RISCVCPU), VMSTATE_UINTTL(env.htinst, RISCVCPU), VMSTATE_UINTTL(env.hgatp, RISCVCPU), + VMSTATE_UINTTL(env.hgeie, RISCVCPU), + VMSTATE_UINTTL(env.hgeip, RISCVCPU), VMSTATE_UINT64(env.htimedelta, RISCVCPU), VMSTATE_UINT64(env.vsstatus, RISCVCPU),