From patchwork Fri May 13 18:17:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Kumar Patra X-Patchwork-Id: 12849251 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 8ECCDC433F5 for ; Fri, 13 May 2022 18:39:11 +0000 (UTC) Received: from localhost ([::1]:42920 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1npaBy-0006j1-DR for qemu-devel@archiver.kernel.org; Fri, 13 May 2022 14:39:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58798) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1npZrR-0006xy-IG for qemu-devel@nongnu.org; Fri, 13 May 2022 14:17:57 -0400 Received: from mail-pl1-x630.google.com ([2607:f8b0:4864:20::630]:34519) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1npZrO-0000LI-RN for qemu-devel@nongnu.org; Fri, 13 May 2022 14:17:57 -0400 Received: by mail-pl1-x630.google.com with SMTP id n8so8720917plh.1 for ; Fri, 13 May 2022 11:17:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=H9HXlfUx5F9Mj/YCO0LUA0lvt+ciUTrvG+Mycab6D8A=; b=bRFkc/OLw6gTiPwV2G+9vOxY0jXiZTBwdVhrWTUxnWPliem6Oi8T3fThYiNJwproFI qeCJEyE5oZ7+U6o5SUfybABnpBeN0jM4V/3kQ8bwrKxEDEPPxubnmUtc12bCk3PC9XQZ RxPm3IFVxVxbnMMOAR9ENeoEavAHINVJEc0IDeJvL4phOZIUkhsAztdfoovSEZFgDelt vVzqoWJ2J3/EK1EFLS7iyJQHV3mGSTCsXXZ7IUYDxkKWCMEsryLt2RUoab6VaQu73EiA KQpoSJVwSWsQe0C/Kkignp9Wr+nn0zg98LRtooe9tBirjfTxXqsOj54renlm8oBu640N 06gA== 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=H9HXlfUx5F9Mj/YCO0LUA0lvt+ciUTrvG+Mycab6D8A=; b=iPGKyrDxh7S5Pj0t/bvw4Gs1YUhirmWUQhlfCfm1cyBHEz7SS84P5WD3R3/nzyNEg8 utQ1aKcaomB8k1VznOixEYkLf2MIu151IvmZpQdvUQ1iGupixlGN+H5v0LJfNgUvyiT5 bzC/mpqzr0XVKEET4wh4Bs1bkz3kbt4YnfEISBD3Cx0kTujoJd3Syqmn4tb97tPm5MVQ TnsJBYKVc6y3q6GDlTbmfmKcn5ZXSqtPOmiuyOHvU6sm+G6pYgSfQXQktjdkADrwbrU1 k6NjUcibK11q42mmlUQgWnQjRyZSHuGcFn4g4LlNZbkFjjytmxBUQ3LEjplvdXjMpyOQ driA== X-Gm-Message-State: AOAM531MsHey0b4rGmXO0xfPXULhKmdBP+ILsmXBSuM+cljSVgp1bkV9 T2kuDa76nafKSDSEmsZhYeD0jn7Vt65BNg== X-Google-Smtp-Source: ABdhPJzM6zp8UM6OTrGnBsLjNTH5FiHTGHmvVl2yxgH5R3Y0JDSy+Wu53rRaSFWI6hAurRIFR54wNg== X-Received: by 2002:a17:902:e5c8:b0:15e:c2e2:bff6 with SMTP id u8-20020a170902e5c800b0015ec2e2bff6mr6053813plf.74.1652465872887; Fri, 13 May 2022 11:17:52 -0700 (PDT) Received: from atishp.ba.rivosinc.com ([66.220.2.162]) by smtp.gmail.com with ESMTPSA id gg18-20020a17090b0a1200b001cd4989ff3fsm1907047pjb.6.2022.05.13.11.17.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 13 May 2022 11:17:52 -0700 (PDT) From: Atish Patra To: qemu-devel@nongnu.org Cc: Atish Patra , Anup Patel , Alistair Francis , Bin Meng , Palmer Dabbelt , qemu-riscv@nongnu.org Subject: [PATCH v4 1/3] hw/intc: Move mtimer/mtimecmp to aclint Date: Fri, 13 May 2022 11:17:46 -0700 Message-Id: <20220513181748.990645-2-atishp@rivosinc.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220513181748.990645-1-atishp@rivosinc.com> References: <20220513181748.990645-1-atishp@rivosinc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::630; envelope-from=atishp@rivosinc.com; helo=mail-pl1-x630.google.com 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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=unavailable 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Historically, The mtime/mtimecmp has been part of the CPU because they are per hart entities. However, they actually belong to aclint which is a MMIO device. Move them to the ACLINT device. This also emulates the real hardware more closely. Reviewed-by: Anup Patel Signed-off-by: Atish Patra Reviewed-by: Alistair Francis --- hw/intc/riscv_aclint.c | 41 ++++++++++++++++++++++++---------- hw/timer/ibex_timer.c | 18 ++++++--------- include/hw/intc/riscv_aclint.h | 2 ++ include/hw/timer/ibex_timer.h | 2 ++ target/riscv/cpu.h | 2 -- target/riscv/machine.c | 5 ++--- 6 files changed, 42 insertions(+), 28 deletions(-) diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c index 0412edc98257..83d317def395 100644 --- a/hw/intc/riscv_aclint.c +++ b/hw/intc/riscv_aclint.c @@ -32,6 +32,7 @@ #include "hw/intc/riscv_aclint.h" #include "qemu/timer.h" #include "hw/irq.h" +#include "migration/vmstate.h" typedef struct riscv_aclint_mtimer_callback { RISCVAclintMTimerState *s; @@ -65,8 +66,8 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer, uint64_t rtc_r = cpu_riscv_read_rtc(mtimer); - cpu->env.timecmp = value; - if (cpu->env.timecmp <= rtc_r) { + mtimer->timecmp[hartid] = value; + if (mtimer->timecmp[hartid] <= rtc_r) { /* * If we're setting an MTIMECMP value in the "past", * immediately raise the timer interrupt @@ -77,7 +78,7 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer, /* otherwise, set up the future timer interrupt */ qemu_irq_lower(mtimer->timer_irqs[hartid - mtimer->hartid_base]); - diff = cpu->env.timecmp - rtc_r; + diff = mtimer->timecmp[hartid] - rtc_r; /* back to ns (note args switched in muldiv64) */ uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq); @@ -102,7 +103,7 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer, next = MIN(next, INT64_MAX); } - timer_mod(cpu->env.timer, next); + timer_mod(mtimer->timers[hartid], next); } /* @@ -133,11 +134,11 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr, "aclint-mtimer: invalid hartid: %zu", hartid); } else if ((addr & 0x7) == 0) { /* timecmp_lo for RV32/RV64 or timecmp for RV64 */ - uint64_t timecmp = env->timecmp; + uint64_t timecmp = mtimer->timecmp[hartid]; return (size == 4) ? (timecmp & 0xFFFFFFFF) : timecmp; } else if ((addr & 0x7) == 4) { /* timecmp_hi */ - uint64_t timecmp = env->timecmp; + uint64_t timecmp = mtimer->timecmp[hartid]; return (timecmp >> 32) & 0xFFFFFFFF; } else { qemu_log_mask(LOG_UNIMP, @@ -177,7 +178,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, } else if ((addr & 0x7) == 0) { if (size == 4) { /* timecmp_lo for RV32/RV64 */ - uint64_t timecmp_hi = env->timecmp >> 32; + uint64_t timecmp_hi = mtimer->timecmp[hartid] >> 32; riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, timecmp_hi << 32 | (value & 0xFFFFFFFF)); } else { @@ -188,7 +189,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, } else if ((addr & 0x7) == 4) { if (size == 4) { /* timecmp_hi for RV32/RV64 */ - uint64_t timecmp_lo = env->timecmp; + uint64_t timecmp_lo = mtimer->timecmp[hartid]; riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), hartid, value << 32 | (timecmp_lo & 0xFFFFFFFF)); } else { @@ -233,7 +234,7 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr, continue; } riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu), - i, env->timecmp); + i, mtimer->timecmp[i]); } return; } @@ -283,6 +284,8 @@ static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp) s->timer_irqs = g_new(qemu_irq, s->num_harts); qdev_init_gpio_out(dev, s->timer_irqs, s->num_harts); + s->timers = g_malloc0(s->num_harts * sizeof(QEMUTimer)); + s->timecmp = g_new0(uint64_t, s->num_harts); /* Claim timer interrupt bits */ for (i = 0; i < s->num_harts; i++) { RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(s->hartid_base + i)); @@ -309,6 +312,18 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type) riscv_aclint_mtimer_write(mtimer, mtimer->time_base, 0, 8); } +static const VMStateDescription vmstate_riscv_mtimer = { + .name = "riscv_mtimer", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState, + num_harts, 0, + vmstate_info_uint64, uint64_t), + VMSTATE_END_OF_LIST() + } +}; + static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -316,6 +331,7 @@ static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, riscv_aclint_mtimer_properties); ResettableClass *rc = RESETTABLE_CLASS(klass); rc->phases.enter = riscv_aclint_mtimer_reset_enter; + dc->vmsd = &vmstate_riscv_mtimer; } static const TypeInfo riscv_aclint_mtimer_info = { @@ -335,6 +351,7 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size, { int i; DeviceState *dev = qdev_new(TYPE_RISCV_ACLINT_MTIMER); + RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev); assert(num_harts <= RISCV_ACLINT_MAX_HARTS); assert(!(addr & 0x7)); @@ -365,11 +382,11 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size, riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, dev); } - cb->s = RISCV_ACLINT_MTIMER(dev); + cb->s = s; cb->num = i; - env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + s->timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_aclint_mtimer_cb, cb); - env->timecmp = 0; + s->timecmp[i] = 0; qdev_connect_gpio_out(dev, i, qdev_get_gpio_in(DEVICE(rvcpu), IRQ_M_TIMER)); diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c index 8c2ca364daab..d8b8e4e1f602 100644 --- a/hw/timer/ibex_timer.c +++ b/hw/timer/ibex_timer.c @@ -60,8 +60,6 @@ static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq) static void ibex_timer_update_irqs(IbexTimerState *s) { - CPUState *cs = qemu_get_cpu(0); - RISCVCPU *cpu = RISCV_CPU(cs); uint64_t value = s->timer_compare_lower0 | ((uint64_t)s->timer_compare_upper0 << 32); uint64_t next, diff; @@ -73,9 +71,9 @@ static void ibex_timer_update_irqs(IbexTimerState *s) } /* Update the CPUs mtimecmp */ - cpu->env.timecmp = value; + s->mtimecmp = value; - if (cpu->env.timecmp <= now) { + if (s->mtimecmp <= now) { /* * If the mtimecmp was in the past raise the interrupt now. */ @@ -91,7 +89,7 @@ static void ibex_timer_update_irqs(IbexTimerState *s) qemu_irq_lower(s->m_timer_irq); qemu_set_irq(s->irq, false); - diff = cpu->env.timecmp - now; + diff = s->mtimecmp - now; next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + muldiv64(diff, NANOSECONDS_PER_SECOND, @@ -99,9 +97,9 @@ static void ibex_timer_update_irqs(IbexTimerState *s) if (next < qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) { /* We overflowed the timer, just set it as large as we can */ - timer_mod(cpu->env.timer, 0x7FFFFFFFFFFFFFFF); + timer_mod(s->mtimer, 0x7FFFFFFFFFFFFFFF); } else { - timer_mod(cpu->env.timer, next); + timer_mod(s->mtimer, next); } } @@ -120,11 +118,9 @@ static void ibex_timer_reset(DeviceState *dev) { IbexTimerState *s = IBEX_TIMER(dev); - CPUState *cpu = qemu_get_cpu(0); - CPURISCVState *env = cpu->env_ptr; - env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, + s->mtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &ibex_timer_cb, s); - env->timecmp = 0; + s->mtimecmp = 0; s->timer_ctrl = 0x00000000; s->timer_cfg0 = 0x00010000; diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h index 26d4048687fb..693415eb6def 100644 --- a/include/hw/intc/riscv_aclint.h +++ b/include/hw/intc/riscv_aclint.h @@ -32,6 +32,8 @@ typedef struct RISCVAclintMTimerState { /*< private >*/ SysBusDevice parent_obj; uint64_t time_delta; + uint64_t *timecmp; + QEMUTimer **timers; /*< public >*/ MemoryRegion mmio; diff --git a/include/hw/timer/ibex_timer.h b/include/hw/timer/ibex_timer.h index 1a0a28d5fab5..41f5c82a920b 100644 --- a/include/hw/timer/ibex_timer.h +++ b/include/hw/timer/ibex_timer.h @@ -33,6 +33,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IbexTimerState, IBEX_TIMER) struct IbexTimerState { /* */ SysBusDevice parent_obj; + uint64_t mtimecmp; + QEMUTimer *mtimer; /* Internal timer for M-mode interrupt */ /* */ MemoryRegion mmio; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 34c22d5d3be3..1119d5201066 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -275,7 +275,6 @@ struct CPUArchState { /* temporary htif regs */ uint64_t mfromhost; uint64_t mtohost; - uint64_t timecmp; /* physical memory protection */ pmp_table_t pmp_state; @@ -330,7 +329,6 @@ struct CPUArchState { float_status fp_status; /* Fields from here on are preserved across CPU reset. */ - QEMUTimer *timer; /* Internal timer */ hwaddr kernel_addr; hwaddr fdt_addr; diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 2a437b29a1ce..7d85de0b1d49 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -286,8 +286,8 @@ static const VMStateDescription vmstate_envcfg = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 3, - .minimum_version_id = 3, + .version_id = 4, + .minimum_version_id = 4, .post_load = riscv_cpu_post_load, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), @@ -334,7 +334,6 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.mscratch, RISCVCPU), VMSTATE_UINT64(env.mfromhost, RISCVCPU), VMSTATE_UINT64(env.mtohost, RISCVCPU), - VMSTATE_UINT64(env.timecmp, RISCVCPU), VMSTATE_END_OF_LIST() }, From patchwork Fri May 13 18:17:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Kumar Patra X-Patchwork-Id: 12849253 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 2F2CEC433F5 for ; Fri, 13 May 2022 18:42:55 +0000 (UTC) Received: from localhost ([::1]:45496 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1npaFa-0000fW-04 for qemu-devel@archiver.kernel.org; Fri, 13 May 2022 14:42:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58812) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1npZrS-00071K-DK for qemu-devel@nongnu.org; Fri, 13 May 2022 14:17:58 -0400 Received: from mail-pj1-x102d.google.com ([2607:f8b0:4864:20::102d]:40621) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1npZrP-0000LV-UY for qemu-devel@nongnu.org; Fri, 13 May 2022 14:17:58 -0400 Received: by mail-pj1-x102d.google.com with SMTP id iq2-20020a17090afb4200b001d93cf33ae9so11494594pjb.5 for ; Fri, 13 May 2022 11:17:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=aLkOPx6j5TUhDcZirqaTlydhJe+iXcoAS/+KSi808t8=; b=h4tBfKpYzHGk7X5MsGxnXqZIXTspWTlCt7d7c/95s3vKK9GD++B8wKEffpAkcMS6Rs Bo3PRJrnat2hU5h9iIqeIpEZtogTTk92P1IF7x8Zjblne1+2LBTaLX6wRFoEcF6bu0La 9fTXrP12Pay2+5wJ+0fl5shWc5alE+x0zFaQ3TRrojNtgFhj64VSSagacWn0V4Uqn/2F bsrwW7nN4cLA3aJ9fMwxfagdG3B4JCbxWASDTXMbWXIyyTPl7VhZtHldmcneEFh1/no4 slYxDZ5wuZH+QwACrBged1has4io349qYyN826GSGG9nk9btMHpLiFcUoDWMqaGD3vNR uMEQ== 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=aLkOPx6j5TUhDcZirqaTlydhJe+iXcoAS/+KSi808t8=; b=uk8VSaL6fdkdtnpCTwAQjiOHpUlGwEwBH8hU4x8VSaE0YxnC//koM3iL27GDCil695 XmFt+dcuWUzDyWPmNfMlqbqQtTFrhoaEQxADitsLVxQ2vq2yRXfR7uf05Lk2o71jEyZv ic5UPzMuaHVX+bGx85bkqKFZbIczufN2oC5TAWT3wVaukeEOUw73ZlmZ+rkmAXM29pdf Rf4FmuKlnrkNfRDtjdxeNOmBJJSziNNeduZRNI8PHU3BMhJ6idsWDPRtj4mi2ZKY8GsB ENn5kQg7AKuEFXUnOw2XLQniOOL7Esp2dABP/DXskUAg+LXDQ+d79odRu0ejdKzrIz/d 6/cw== X-Gm-Message-State: AOAM533AIvOKBuwV3xjdqWJ17XRvCmVqqn6FnXXN3Qf1mqKY+3bMzW8P 4jAriiyYpwZfvBz7HgUM4WRJAL4FEo0BaA== X-Google-Smtp-Source: ABdhPJyU9HC9MMEM+8w5/bcPOylEMwCDdaXoQlie9gm6QtPI2h/RorMDUh30BkPkq+TikNGnW2k4Ig== X-Received: by 2002:a17:90b:304:b0:1d9:752b:437f with SMTP id ay4-20020a17090b030400b001d9752b437fmr17260988pjb.242.1652465874107; Fri, 13 May 2022 11:17:54 -0700 (PDT) Received: from atishp.ba.rivosinc.com ([66.220.2.162]) by smtp.gmail.com with ESMTPSA id gg18-20020a17090b0a1200b001cd4989ff3fsm1907047pjb.6.2022.05.13.11.17.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 13 May 2022 11:17:53 -0700 (PDT) From: Atish Patra To: qemu-devel@nongnu.org Cc: Atish Patra , Alistair Francis , Bin Meng , Palmer Dabbelt , qemu-riscv@nongnu.org Subject: [PATCH v4 2/3] target/riscv: Add stimecmp support Date: Fri, 13 May 2022 11:17:47 -0700 Message-Id: <20220513181748.990645-3-atishp@rivosinc.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220513181748.990645-1-atishp@rivosinc.com> References: <20220513181748.990645-1-atishp@rivosinc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::102d; envelope-from=atishp@rivosinc.com; helo=mail-pj1-x102d.google.com 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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=unavailable 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" stimecmp allows the supervisor mode to update stimecmp CSR directly to program the next timer interrupt. This CSR is part of the Sstc extension which was ratified recently. Signed-off-by: Atish Patra --- target/riscv/cpu.c | 8 ++++ target/riscv/cpu.h | 7 +++ target/riscv/cpu_bits.h | 4 ++ target/riscv/csr.c | 92 +++++++++++++++++++++++++++++++++++ target/riscv/machine.c | 2 + target/riscv/meson.build | 3 +- target/riscv/time_helper.c | 98 ++++++++++++++++++++++++++++++++++++++ target/riscv/time_helper.h | 30 ++++++++++++ 8 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 target/riscv/time_helper.c create mode 100644 target/riscv/time_helper.h diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 19f4e8294042..d58dd2f857a7 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -23,6 +23,7 @@ #include "qemu/log.h" #include "cpu.h" #include "internals.h" +#include "time_helper.h" #include "exec/exec-all.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -779,7 +780,12 @@ static void riscv_cpu_init(Object *obj) #ifndef CONFIG_USER_ONLY qdev_init_gpio_in(DEVICE(cpu), riscv_cpu_set_irq, IRQ_LOCAL_MAX + IRQ_LOCAL_GUEST_MAX); + + if (cpu->cfg.ext_sstc) { + riscv_timer_init(cpu); + } #endif /* CONFIG_USER_ONLY */ + } static Property riscv_cpu_properties[] = { @@ -806,6 +812,7 @@ static Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), DEFINE_PROP_BOOL("debug", RISCVCPU, cfg.debug, true), + DEFINE_PROP_BOOL("sstc", RISCVCPU, cfg.ext_sstc, true), DEFINE_PROP_STRING("priv_spec", RISCVCPU, cfg.priv_spec), DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec), @@ -965,6 +972,7 @@ static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len) ISA_EDATA_ENTRY(zbs, ext_zbs), ISA_EDATA_ENTRY(zve32f, ext_zve32f), ISA_EDATA_ENTRY(zve64f, ext_zve64f), + ISA_EDATA_ENTRY(sstc, ext_sstc), ISA_EDATA_ENTRY(svinval, ext_svinval), ISA_EDATA_ENTRY(svnapot, ext_svnapot), ISA_EDATA_ENTRY(svpbmt, ext_svpbmt), diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 1119d5201066..9a01e6d0f587 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -276,6 +276,11 @@ struct CPUArchState { uint64_t mfromhost; uint64_t mtohost; + /* Sstc CSRs */ + uint64_t stimecmp; + /* For RV32 only */ + uint8_t stimecmp_wr_done; + /* physical memory protection */ pmp_table_t pmp_state; target_ulong mseccfg; @@ -329,6 +334,7 @@ struct CPUArchState { float_status fp_status; /* Fields from here on are preserved across CPU reset. */ + QEMUTimer *stimer; /* Internal timer for S-mode interrupt */ hwaddr kernel_addr; hwaddr fdt_addr; @@ -379,6 +385,7 @@ struct RISCVCPUConfig { bool ext_counters; bool ext_ifencei; bool ext_icsr; + bool ext_sstc; bool ext_svinval; bool ext_svnapot; bool ext_svpbmt; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 4e5b630f5965..29d0e4a1be01 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -215,6 +215,10 @@ #define CSR_STVAL 0x143 #define CSR_SIP 0x144 +/* Sstc supervisor CSRs */ +#define CSR_STIMECMP 0x14D +#define CSR_STIMECMPH 0x15D + /* Supervisor Protection and Translation */ #define CSR_SPTBR 0x180 #define CSR_SATP 0x180 diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 245f007e66e1..8952d1308008 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -21,6 +21,7 @@ #include "qemu/log.h" #include "qemu/timer.h" #include "cpu.h" +#include "time_helper.h" #include "qemu/main-loop.h" #include "exec/exec-all.h" #include "sysemu/cpu-timers.h" @@ -537,6 +538,87 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException sstc(CPURISCVState *env, int csrno) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (!cpu->cfg.ext_sstc || !env->rdtime_fn) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (env->priv == PRV_M) { + return RISCV_EXCP_NONE; + } + + if (env->priv != PRV_S) { + return RISCV_EXCP_ILLEGAL_INST; + } + + /* + * No need of separate function for rv32 as menvcfg stores both menvcfg + * menvcfgh for RV32. + */ + if (!(get_field(env->mcounteren, COUNTEREN_TM) && + get_field(env->menvcfg, MENVCFG_STCE))) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return RISCV_EXCP_NONE; +} + +static RISCVException read_stimecmp(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->stimecmp; + return RISCV_EXCP_NONE; +} + +static RISCVException read_stimecmph(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->stimecmp >> 32; + return RISCV_EXCP_NONE; +} + +static RISCVException write_stimecmp(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + if (riscv_cpu_mxl(env) == MXL_RV32) { + env->stimecmp = deposit64(env->stimecmp, 0, 32, (uint64_t)val); + env->stimecmp_wr_done |= 0x01; + if (env->stimecmp_wr_done != 0x03) { + return RISCV_EXCP_NONE; + } else { + env->stimecmp_wr_done = 0; + } + } else { + env->stimecmp = val; + } + + riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP); + + return RISCV_EXCP_NONE; +} + +static RISCVException write_stimecmph(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val); + env->stimecmp_wr_done |= 0x02; + if (env->stimecmp_wr_done != 0x03) { + return RISCV_EXCP_NONE; + } + env->stimecmp_wr_done = 0; + riscv_timer_write_timecmp(cpu, env->stimer, env->stimecmp, 0, MIP_STIP); + + return RISCV_EXCP_NONE; +} + /* Machine constants */ #define M_MODE_INTERRUPTS ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP)) @@ -1515,6 +1597,12 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno, new_val |= env->external_seip * MIP_SEIP; } + if (cpu->cfg.ext_sstc && (env->priv == PRV_M) && + get_field(env->menvcfg, MENVCFG_STCE)) { + /* sstc extension forbids STIP & VSTIP to be writeable in mip */ + mask = mask & ~(MIP_STIP | MIP_VSTIP); + } + if (mask) { old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask)); } else { @@ -3341,6 +3429,10 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_SCAUSE] = { "scause", smode, read_scause, write_scause }, [CSR_STVAL] = { "stval", smode, read_stval, write_stval }, [CSR_SIP] = { "sip", smode, NULL, NULL, rmw_sip }, + [CSR_STIMECMP] = { "stimecmp", sstc, read_stimecmp, write_stimecmp, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph, write_stimecmph, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Supervisor Protection and Translation */ [CSR_SATP] = { "satp", smode, read_satp, write_satp }, diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 7d85de0b1d49..1e775343a37b 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -334,6 +334,8 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.mscratch, RISCVCPU), VMSTATE_UINT64(env.mfromhost, RISCVCPU), VMSTATE_UINT64(env.mtohost, RISCVCPU), + VMSTATE_UINT64(env.stimecmp, RISCVCPU), + VMSTATE_UINT8(env.stimecmp_wr_done, RISCVCPU), VMSTATE_END_OF_LIST() }, diff --git a/target/riscv/meson.build b/target/riscv/meson.build index 2c20f3dd8e9c..1243d019148e 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -29,7 +29,8 @@ riscv_softmmu_ss.add(files( 'pmp.c', 'debug.c', 'monitor.c', - 'machine.c' + 'machine.c', + 'time_helper.c' )) target_arch += {'riscv': riscv_ss} diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c new file mode 100644 index 000000000000..f3fb5eac7b7b --- /dev/null +++ b/target/riscv/time_helper.c @@ -0,0 +1,98 @@ +/* + * RISC-V timer helper implementation. + * + * Copyright (c) 2022 Rivos Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu_bits.h" +#include "time_helper.h" +#include "hw/intc/riscv_aclint.h" + +static void riscv_stimer_cb(void *opaque) +{ + RISCVCPU *cpu = opaque; + riscv_cpu_update_mip(cpu, MIP_STIP, BOOL_TO_MASK(1)); +} + +/* + * Called when timecmp is written to update the QEMU timer or immediately + * trigger timer interrupt if mtimecmp <= current timer value. + */ +void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer, + uint64_t timecmp, uint64_t delta, + uint32_t timer_irq) +{ + uint64_t diff, ns_diff, next; + CPURISCVState *env = &cpu->env; + RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg; + uint32_t timebase_freq = mtimer->timebase_freq; + uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta; + + if (timecmp <= rtc_r) { + /* + * If we're setting an stimecmp value in the "past", + * immediately raise the timer interrupt + */ + riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1)); + return; + } + + /* Clear the [V]STIP bit in mip */ + riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0)); + + /* otherwise, set up the future timer interrupt */ + diff = timecmp - rtc_r; + /* back to ns (note args switched in muldiv64) */ + ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq); + + /* + * check if ns_diff overflowed and check if the addition would potentially + * overflow + */ + if ((NANOSECONDS_PER_SECOND > timebase_freq && ns_diff < diff) || + ns_diff > INT64_MAX) { + next = INT64_MAX; + } else { + /* + * as it is very unlikely qemu_clock_get_ns will return a value + * greater than INT64_MAX, no additional check is needed for an + * unsigned integer overflow. + */ + next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ns_diff; + /* + * if ns_diff is INT64_MAX next may still be outside the range + * of a signed integer. + */ + next = MIN(next, INT64_MAX); + } + + timer_mod(timer, next); +} + +void riscv_timer_init(RISCVCPU *cpu) +{ + CPURISCVState *env; + + if (!cpu) { + return; + } + + env = &cpu->env; + env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu); + env->stimecmp = 0; + +} diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h new file mode 100644 index 000000000000..7b3cdcc35020 --- /dev/null +++ b/target/riscv/time_helper.h @@ -0,0 +1,30 @@ +/* + * RISC-V timer header file. + * + * Copyright (c) 2022 Rivos Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef RISCV_TIME_HELPER_H +#define RISCV_TIME_HELPER_H + +#include "cpu.h" +#include "qemu/timer.h" + +void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer, + uint64_t timecmp, uint64_t delta, + uint32_t timer_irq); +void riscv_timer_init(RISCVCPU *cpu); + +#endif From patchwork Fri May 13 18:17:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Atish Kumar Patra X-Patchwork-Id: 12849254 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 05F5AC433F5 for ; Fri, 13 May 2022 18:45:48 +0000 (UTC) Received: from localhost ([::1]:47714 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1npaIM-0002ME-Ta for qemu-devel@archiver.kernel.org; Fri, 13 May 2022 14:45:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:58826) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1npZrT-00074c-Fp for qemu-devel@nongnu.org; Fri, 13 May 2022 14:17:59 -0400 Received: from mail-pj1-x1029.google.com ([2607:f8b0:4864:20::1029]:44924) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1npZrR-0000Lq-0a for qemu-devel@nongnu.org; Fri, 13 May 2022 14:17:59 -0400 Received: by mail-pj1-x1029.google.com with SMTP id c1-20020a17090a558100b001dca2694f23so8477844pji.3 for ; Fri, 13 May 2022 11:17:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=rivosinc-com.20210112.gappssmtp.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=5Fv+NZfqGnQ+LAexMFG7aIj2Qw1r8Yx6ZMyWz/jRvaw=; b=sz7MasyRgaqY2X2yBi7cEj1wmZBpC3Hm4GwUQHtiepDqzTTPeX+m6Kjc/89vYFPKuz o1Vja3YovHx9urXXX49/JqG/CLHYNtfuuRbvI/bvGuzQ0MVG3IYjkkSh7e+D49LFQm+a a7bDKZW60fuBi3XfgTlLQnzDFjK/GE8QPkiC7Lz/7VbfXGVHTP0QnwvRJYE09ejtCs2u p423YphXjiZcLnDmVkALJNj7iKzQAIXA+HpP5Z8g2nTJ6OS0u0H97D1yyUF4YCESuhyH i6L/qFFcrFKgDltvXQOxSPmAFJEzoKC+2ccqSgOCvrCV4OeVoWJxidKIzSXBrhyTFwCq v6ow== 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=5Fv+NZfqGnQ+LAexMFG7aIj2Qw1r8Yx6ZMyWz/jRvaw=; b=u6lXj1prWbvbcwvpndFpzq7YH6sbEdmNI4bXV2VnQMUnZg/SGaxUT8XfJDr4QsEDWC IoFpaLNAD38eFG4PZegm12gyVd/oLpZgb7ZDWUDFd4N+k80PldU9zkTV9hSnLYtD1bUW ynZUAcBiWThhTWD+8SDybKSFJDhrmK0UfF4j8E8+bPgzYvd/jlnNBx2QSfpDMjUYrOSh HHsSRiQpxNido0ayxFOK7jXmPuKnC3JJnr4LSRgaZ8m9JnpHbiH1gTfQHTc1RerkU7G5 PFV6iGLMDBNCXJu67R9YuU4uxsoyv7ZBAiFiuZynFtGSRbIUb0SpreSScpr006lijK8x WyuA== X-Gm-Message-State: AOAM530XUBvbHPWoSsdf3PCy7Y6H75CcgxdqvImCbrMqxcCrhqKswY6U bHPShfUf3lEuMNg9+iFnWR4hY3dxSFdWhg== X-Google-Smtp-Source: ABdhPJzlX8WWIqOuHlQnh2GGc/4pZwnbMwsTShNWytblwtjkQVQFmRUBKn8mjsHrNqa0nwJNcVXn5w== X-Received: by 2002:a17:903:2044:b0:15e:c057:d454 with SMTP id q4-20020a170903204400b0015ec057d454mr5950120pla.126.1652465875231; Fri, 13 May 2022 11:17:55 -0700 (PDT) Received: from atishp.ba.rivosinc.com ([66.220.2.162]) by smtp.gmail.com with ESMTPSA id gg18-20020a17090b0a1200b001cd4989ff3fsm1907047pjb.6.2022.05.13.11.17.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 13 May 2022 11:17:54 -0700 (PDT) From: Atish Patra To: qemu-devel@nongnu.org Cc: Atish Patra , Alistair Francis , Bin Meng , Palmer Dabbelt , qemu-riscv@nongnu.org Subject: [PATCH v4 3/3] target/riscv: Add vstimecmp support Date: Fri, 13 May 2022 11:17:48 -0700 Message-Id: <20220513181748.990645-4-atishp@rivosinc.com> X-Mailer: git-send-email 2.36.0 In-Reply-To: <20220513181748.990645-1-atishp@rivosinc.com> References: <20220513181748.990645-1-atishp@rivosinc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2607:f8b0:4864:20::1029; envelope-from=atishp@rivosinc.com; helo=mail-pj1-x1029.google.com 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, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=unavailable 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" vstimecmp CSR allows the guest OS or to program the next guest timer interrupt directly. Thus, hypervisor no longer need to inject the timer interrupt to the guest if vstimecmp is used. This was ratified as a part of the Sstc extension. Signed-off-by: Atish Patra --- target/riscv/cpu.h | 6 ++ target/riscv/cpu_bits.h | 4 ++ target/riscv/cpu_helper.c | 11 +++- target/riscv/csr.c | 112 ++++++++++++++++++++++++++++++++++++- target/riscv/machine.c | 2 + target/riscv/time_helper.c | 16 ++++++ 6 files changed, 146 insertions(+), 5 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 9a01e6d0f587..3582676d1d88 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -281,6 +281,10 @@ struct CPUArchState { /* For RV32 only */ uint8_t stimecmp_wr_done; + uint64_t vstimecmp; + /* For RV32 only */ + uint8_t vstimecmp_wr_done; + /* physical memory protection */ pmp_table_t pmp_state; target_ulong mseccfg; @@ -335,6 +339,8 @@ struct CPUArchState { /* Fields from here on are preserved across CPU reset. */ QEMUTimer *stimer; /* Internal timer for S-mode interrupt */ + QEMUTimer *vstimer; /* Internal timer for VS-mode interrupt */ + bool vstime_irq; hwaddr kernel_addr; hwaddr fdt_addr; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index 29d0e4a1be01..5c9f512872e1 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -272,6 +272,10 @@ #define CSR_VSIP 0x244 #define CSR_VSATP 0x280 +/* Sstc virtual CSRs */ +#define CSR_VSTIMECMP 0x24D +#define CSR_VSTIMECMPH 0x25D + #define CSR_MTINST 0x34a #define CSR_MTVAL2 0x34b diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index e1aa4f2097c1..2715021c022e 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -344,8 +344,9 @@ static uint64_t riscv_cpu_all_pending(CPURISCVState *env) { uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN); uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; + uint64_t vstip = (env->vstime_irq) ? MIP_VSTIP : 0; - return (env->mip | vsgein) & env->mie; + return (env->mip | vsgein | vstip) & env->mie; } int riscv_cpu_mirq_pending(CPURISCVState *env) @@ -604,7 +605,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) { CPURISCVState *env = &cpu->env; CPUState *cs = CPU(cpu); - uint64_t gein, vsgein = 0, old = env->mip; + uint64_t gein, vsgein = 0, vstip = 0, old = env->mip; bool locked = false; if (riscv_cpu_virt_enabled(env)) { @@ -612,6 +613,10 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; } + /* No need to update mip for VSTIP */ + mask = ((mask == MIP_VSTIP) && env->vstime_irq) ? 0 : mask; + vstip = env->vstime_irq ? MIP_VSTIP : 0; + if (!qemu_mutex_iothread_locked()) { locked = true; qemu_mutex_lock_iothread(); @@ -619,7 +624,7 @@ uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) env->mip = (env->mip & ~mask) | (value & mask); - if (env->mip | vsgein) { + if (env->mip | vsgein | vstip) { 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 8952d1308008..35eb2c4d84eb 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -567,17 +567,110 @@ static RISCVException sstc(CPURISCVState *env, int csrno) return RISCV_EXCP_NONE; } +static RISCVException sstc_hmode(CPURISCVState *env, int csrno) +{ + CPUState *cs = env_cpu(env); + RISCVCPU *cpu = RISCV_CPU(cs); + + if (!cpu->cfg.ext_sstc || !env->rdtime_fn) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (env->priv == PRV_M) { + return RISCV_EXCP_NONE; + } + + if (!(get_field(env->mcounteren, COUNTEREN_TM) & + get_field(env->menvcfg, MENVCFG_STCE))) { + return RISCV_EXCP_ILLEGAL_INST; + } + + if (!(get_field(env->hcounteren, COUNTEREN_TM) & + get_field(env->henvcfg, HENVCFG_STCE))) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + + return RISCV_EXCP_NONE; +} + +static RISCVException read_vstimecmp(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->vstimecmp; + + return RISCV_EXCP_NONE; +} + +static RISCVException read_vstimecmph(CPURISCVState *env, int csrno, + target_ulong *val) +{ + *val = env->vstimecmp >> 32; + + return RISCV_EXCP_NONE; +} + +static RISCVException write_vstimecmp(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + if (riscv_cpu_mxl(env) == MXL_RV32) { + env->vstimecmp = deposit64(env->vstimecmp, 0, 32, (uint64_t)val); + env->vstimecmp_wr_done |= 0x01; + if (env->vstimecmp_wr_done != 0x03) { + return RISCV_EXCP_NONE; + } else { + env->vstimecmp_wr_done = 0; + } + } else { + env->vstimecmp = val; + } + + riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + + return RISCV_EXCP_NONE; +} + +static RISCVException write_vstimecmph(CPURISCVState *env, int csrno, + target_ulong val) +{ + RISCVCPU *cpu = env_archcpu(env); + + env->vstimecmp = deposit64(env->vstimecmp, 32, 32, (uint64_t)val); + env->vstimecmp_wr_done |= 0x02; + if (env->vstimecmp_wr_done != 0x03) { + return RISCV_EXCP_NONE; + } + + env->vstimecmp_wr_done = 0; + riscv_timer_write_timecmp(cpu, env->vstimer, env->vstimecmp, + env->htimedelta, MIP_VSTIP); + + return RISCV_EXCP_NONE; +} + static RISCVException read_stimecmp(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->stimecmp; + if (riscv_cpu_virt_enabled(env)) { + *val = env->vstimecmp; + } else { + *val = env->stimecmp; + } + return RISCV_EXCP_NONE; } static RISCVException read_stimecmph(CPURISCVState *env, int csrno, target_ulong *val) { - *val = env->stimecmp >> 32; + if (riscv_cpu_virt_enabled(env)) { + *val = env->vstimecmp >> 32; + } else { + *val = env->stimecmp >> 32; + } + return RISCV_EXCP_NONE; } @@ -586,6 +679,10 @@ static RISCVException write_stimecmp(CPURISCVState *env, int csrno, { RISCVCPU *cpu = env_archcpu(env); + if (riscv_cpu_virt_enabled(env)) { + return write_vstimecmp(env, csrno, val); + } + if (riscv_cpu_mxl(env) == MXL_RV32) { env->stimecmp = deposit64(env->stimecmp, 0, 32, (uint64_t)val); env->stimecmp_wr_done |= 0x01; @@ -608,6 +705,10 @@ static RISCVException write_stimecmph(CPURISCVState *env, int csrno, { RISCVCPU *cpu = env_archcpu(env); + if (riscv_cpu_virt_enabled(env)) { + return write_vstimecmph(env, csrno, val); + } + env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val); env->stimecmp_wr_done |= 0x02; if (env->stimecmp_wr_done != 0x03) { @@ -1612,6 +1713,7 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno, if (csrno != CSR_HVIP) { gin = get_field(env->hstatus, HSTATUS_VGEIN); old_mip |= (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VSEIP : 0; + old_mip |= env->vstime_irq ? MIP_VSTIP : 0; } if (ret_val) { @@ -3433,6 +3535,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { .min_priv_ver = PRIV_VERSION_1_12_0 }, [CSR_STIMECMPH] = { "stimecmph", sstc, read_stimecmph, write_stimecmph, .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSTIMECMP] = { "vstimecmp", sstc_hmode, read_vstimecmp, + write_vstimecmp, + .min_priv_ver = PRIV_VERSION_1_12_0 }, + [CSR_VSTIMECMPH] = { "vstimecmph", sstc_hmode, read_vstimecmph, + write_vstimecmph, + .min_priv_ver = PRIV_VERSION_1_12_0 }, /* Supervisor Protection and Translation */ [CSR_SATP] = { "satp", smode, read_satp, write_satp }, diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 1e775343a37b..b2215dec69db 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -92,6 +92,8 @@ static const VMStateDescription vmstate_hyper = { VMSTATE_UINTTL(env.hgeie, RISCVCPU), VMSTATE_UINTTL(env.hgeip, RISCVCPU), VMSTATE_UINT64(env.htimedelta, RISCVCPU), + VMSTATE_UINT64(env.vstimecmp, RISCVCPU), + VMSTATE_UINT8(env.vstimecmp_wr_done, RISCVCPU), VMSTATE_UINTTL(env.hvictl, RISCVCPU), VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c index f3fb5eac7b7b..8cce667dfd47 100644 --- a/target/riscv/time_helper.c +++ b/target/riscv/time_helper.c @@ -22,6 +22,14 @@ #include "time_helper.h" #include "hw/intc/riscv_aclint.h" +static void riscv_vstimer_cb(void *opaque) +{ + RISCVCPU *cpu = opaque; + CPURISCVState *env = &cpu->env; + env->vstime_irq = 1; + riscv_cpu_update_mip(cpu, MIP_VSTIP, BOOL_TO_MASK(1)); +} + static void riscv_stimer_cb(void *opaque) { RISCVCPU *cpu = opaque; @@ -47,10 +55,16 @@ void riscv_timer_write_timecmp(RISCVCPU *cpu, QEMUTimer *timer, * If we're setting an stimecmp value in the "past", * immediately raise the timer interrupt */ + if (timer_irq == MIP_VSTIP) { + env->vstime_irq = 1; + } riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(1)); return; } + if (timer_irq == MIP_VSTIP) { + env->vstime_irq = 0; + } /* Clear the [V]STIP bit in mip */ riscv_cpu_update_mip(cpu, timer_irq, BOOL_TO_MASK(0)); @@ -95,4 +109,6 @@ void riscv_timer_init(RISCVCPU *cpu) env->stimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_stimer_cb, cpu); env->stimecmp = 0; + env->vstimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_cb, cpu); + env->vstimecmp = 0; }