From patchwork Mon Jul 19 18:49:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386615 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 E1A64C07E95 for ; Mon, 19 Jul 2021 18:53:40 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 A1E8D610CC for ; Mon, 19 Jul 2021 18:53:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A1E8D610CC Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=Pkn3QL7nVILoVtrRHx1wE/8yL6CHqoyfZXHnc93NnuE=; b=WqhhuY2ApCLkxWnwZmOVMut/a4 LIttMwVv3r7LQH8jKE4ATzHjPvz7nbL3+phwXAOo+uEOKnRWQjj9RubJIAInE5s5ki8E2tqxBZdEv ykBTzgms6vrfcmIgwJhcCq89e6linUWcehYnY6a6adibWOXOgZL6KhkmhJ+eYJL6dAIKXk6XgM1FU LTKEDoIGNsCMMYcAsxpQKChDKKOcvY1lkADuiaBXtsTVSqYve+rS2jd5uwICgxgmoUIh8ZEdlExBY hfbU4QpoBY5fQE67vtxwJvDGdTnoZeBQ9NcOIQtmgqf//7SA0E+APyZ3N/AC60j0C9pr0+RSW/QHB OTpP3NTw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLy-00AwaO-N6; Mon, 19 Jul 2021 18:50:58 +0000 Received: from mail-qv1-xf4a.google.com ([2607:f8b0:4864:20::f4a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YL6-00AwLz-Eo for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:07 +0000 Received: by mail-qv1-xf4a.google.com with SMTP id z1-20020a0cfec10000b02902dbb4e0a8f2so1500923qvs.6 for ; Mon, 19 Jul 2021 11:50:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=WmFQqCYG7AcxWe1pr4fwUtigJmQCR7e0nSEWHDj1Hes=; b=MM5/EW3dU5nhpT4cIj0DDuGahi7u3lEd+VTdJIHIX7d3U7xpLaZripodUBPiOmZ9cR kjTlF+O2Wyq5Asougl8gByz6BOiXfKCJ5FcbsYSlLt9Vm8b10ePwmQEJ3yILluF6avwD 3ePi3BzEJ6FmBj834gyWQSx0zUgIPnHORPMwAouP2HZZ2uU0LS0I3xfhsK3P8Z8FZt17 iugA6xLW1VQs5JamNUUKo/eKFxIdbombt+/uONIiX33f4zbg86wmHU7ti5OuEMB7UOdN cXUrIvkzdhRrNRwnf3kO0llmueMKy/+9nMV1/XE+cGrHLIfgG0huQBswW1Ul00GtCdqD 1jhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=WmFQqCYG7AcxWe1pr4fwUtigJmQCR7e0nSEWHDj1Hes=; b=FDZZ4BUs2uld4OGj4GS3kSGN10GYDM2radJJ60E2v2Vi1waLCkl3cNiydJK4pjM24k 5Y42IDM/u9pnTvV9/CzfEQlCSGNqLlJHJ0lzRhLxDUR1CgKoD/k9MRLmVlT4AlfuK9Wi 22MJrz8ZgL3MgAxqrq29Psg1r8PP5mGWOf1O0s7QAgJqBfTGTYEGmiphWr8yB4GsekzI PCs4Ss5KIgPibwVAF+vpAtyU7yx6zzCsjMILm8vR2ZM7+zZMhjb+Ky8l/feD3K7yJAG/ 3IjxT5NgunKGdEj3mvI47dsX9uxxqIw4G2cqhmCUjs7dZBBbhJXqHq3UttQ84LUOorWQ Ukbw== X-Gm-Message-State: AOAM5328DUGW9VFhqb2vX+yGecDFor5OvCA+/s1TXS/iSp0OUI7ycPTX sFrKQ1eY2i4hTg68DgKEuUP/KX+sVGA= X-Google-Smtp-Source: ABdhPJxB9rOK0wVybvbKYBTAVFVh+t+nxs2BMJ/KRhqyzfiS5kPiWMjelwIQUfWQ2qz/3xteHhk3bF+H8nE= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:ad4:4d8f:: with SMTP id cv15mr26507188qvb.9.1626720601324; Mon, 19 Jul 2021 11:50:01 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:38 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-2-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 01/12] KVM: x86: Report host tsc and realtime values in KVM_GET_CLOCK From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115004_557032_2F6AE997 X-CRM114-Status: GOOD ( 26.17 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Handling the migration of TSCs correctly is difficult, in part because Linux does not provide userspace with the ability to retrieve a (TSC, realtime) clock pair for a single instant in time. In lieu of a more convenient facility, KVM can report similar information in the kvm_clock structure. Provide userspace with a host TSC & realtime pair iff the realtime clock is based on the TSC. If userspace provides KVM_SET_CLOCK with a valid realtime value, advance the KVM clock by the amount of elapsed time. Do not step the KVM clock backwards, though, as it is a monotonic oscillator. Signed-off-by: Oliver Upton --- Documentation/virt/kvm/api.rst | 42 +++++++-- arch/x86/include/asm/kvm_host.h | 3 + arch/x86/kvm/x86.c | 149 ++++++++++++++++++++------------ include/uapi/linux/kvm.h | 7 +- 4 files changed, 137 insertions(+), 64 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index b9ddce5638f5..70ccf68cd574 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -993,20 +993,34 @@ such as migration. When KVM_CAP_ADJUST_CLOCK is passed to KVM_CHECK_EXTENSION, it returns the set of bits that KVM can return in struct kvm_clock_data's flag member. -The only flag defined now is KVM_CLOCK_TSC_STABLE. If set, the returned -value is the exact kvmclock value seen by all VCPUs at the instant -when KVM_GET_CLOCK was called. If clear, the returned value is simply -CLOCK_MONOTONIC plus a constant offset; the offset can be modified -with KVM_SET_CLOCK. KVM will try to make all VCPUs follow this clock, -but the exact value read by each VCPU could differ, because the host -TSC is not stable. +FLAGS: + +KVM_CLOCK_TSC_STABLE. If set, the returned value is the exact kvmclock +value seen by all VCPUs at the instant when KVM_GET_CLOCK was called. +If clear, the returned value is simply CLOCK_MONOTONIC plus a constant +offset; the offset can be modified with KVM_SET_CLOCK. KVM will try +to make all VCPUs follow this clock, but the exact value read by each +VCPU could differ, because the host TSC is not stable. + +KVM_CLOCK_REALTIME. If set, the `realtime` field in the kvm_clock_data +structure is populated with the value of the host's real time +clocksource at the instant when KVM_GET_CLOCK was called. If clear, +the `realtime` field does not contain a value. + +KVM_CLOCK_HOST_TSC. If set, the `host_tsc` field in the kvm_clock_data +structure is populated with the value of the host's timestamp counter (TSC) +at the instant when KVM_GET_CLOCK was called. If clear, the `host_tsc` field +does not contain a value. :: struct kvm_clock_data { __u64 clock; /* kvmclock current value */ __u32 flags; - __u32 pad[9]; + __u32 pad0; + __u64 realtime; + __u64 host_tsc; + __u32 pad[4]; }; @@ -1023,12 +1037,22 @@ Sets the current timestamp of kvmclock to the value specified in its parameter. In conjunction with KVM_GET_CLOCK, it is used to ensure monotonicity on scenarios such as migration. +FLAGS: + +KVM_CLOCK_REALTIME. If set, KVM will compare the value of the `realtime` field +with the value of the host's real time clocksource at the instant when +KVM_SET_CLOCK was called. The difference in elapsed time is added to the final +kvmclock value that will be provided to guests. + :: struct kvm_clock_data { __u64 clock; /* kvmclock current value */ __u32 flags; - __u32 pad[9]; + __u32 pad0; + __u64 realtime; + __u64 host_tsc; + __u32 pad[4]; }; diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 974cbfb1eefe..3fb2b9270d01 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1936,4 +1936,7 @@ int kvm_cpu_dirty_log_size(void); int alloc_all_memslots_rmaps(struct kvm *kvm); +#define KVM_CLOCK_VALID_FLAGS \ + (KVM_CLOCK_TSC_STABLE | KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC) + #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c471b1375f36..bff78168d4a2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2780,17 +2780,24 @@ static void kvm_gen_update_masterclock(struct kvm *kvm) #endif } -u64 get_kvmclock_ns(struct kvm *kvm) +/* + * Returns true if realtime and TSC values were written back to the caller. + * Returns false if a clock triplet cannot be obtained, such as if the host's + * realtime clock is not based on the TSC. + */ +static bool get_kvmclock_and_realtime(struct kvm *kvm, u64 *kvmclock_ns, + u64 *realtime_ns, u64 *tsc) { struct kvm_arch *ka = &kvm->arch; struct pvclock_vcpu_time_info hv_clock; unsigned long flags; - u64 ret; + bool ret = false; spin_lock_irqsave(&ka->pvclock_gtod_sync_lock, flags); if (!ka->use_master_clock) { spin_unlock_irqrestore(&ka->pvclock_gtod_sync_lock, flags); - return get_kvmclock_base_ns() + ka->kvmclock_offset; + *kvmclock_ns = get_kvmclock_base_ns() + ka->kvmclock_offset; + return false; } hv_clock.tsc_timestamp = ka->master_cycle_now; @@ -2801,18 +2808,36 @@ u64 get_kvmclock_ns(struct kvm *kvm) get_cpu(); if (__this_cpu_read(cpu_tsc_khz)) { + struct timespec64 ts; + u64 tsc_val; + kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL, &hv_clock.tsc_shift, &hv_clock.tsc_to_system_mul); - ret = __pvclock_read_cycles(&hv_clock, rdtsc()); + + if (kvm_get_walltime_and_clockread(&ts, &tsc_val)) { + *realtime_ns = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec; + *tsc = tsc_val; + ret = true; + } + + *kvmclock_ns = __pvclock_read_cycles(&hv_clock, tsc_val); } else - ret = get_kvmclock_base_ns() + ka->kvmclock_offset; + *kvmclock_ns = get_kvmclock_base_ns() + ka->kvmclock_offset; put_cpu(); return ret; } +u64 get_kvmclock_ns(struct kvm *kvm) +{ + u64 kvmclock_ns, realtime_ns, tsc; + + get_kvmclock_and_realtime(kvm, &kvmclock_ns, &realtime_ns, &tsc); + return kvmclock_ns; +} + static void kvm_setup_pvclock_page(struct kvm_vcpu *v, struct gfn_to_hva_cache *cache, unsigned int offset) @@ -4031,7 +4056,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = KVM_SYNC_X86_VALID_FIELDS; break; case KVM_CAP_ADJUST_CLOCK: - r = KVM_CLOCK_TSC_STABLE; + r = KVM_CLOCK_VALID_FLAGS; break; case KVM_CAP_X86_DISABLE_EXITS: r |= KVM_X86_DISABLE_EXITS_HLT | KVM_X86_DISABLE_EXITS_PAUSE | @@ -5806,6 +5831,68 @@ int kvm_arch_pm_notifier(struct kvm *kvm, unsigned long state) } #endif /* CONFIG_HAVE_KVM_PM_NOTIFIER */ +static int kvm_vm_ioctl_get_clock(struct kvm *kvm, + void __user *argp) +{ + struct kvm_clock_data data; + + memset(&data, 0, sizeof(data)); + + if (get_kvmclock_and_realtime(kvm, &data.clock, &data.realtime, + &data.host_tsc)) + data.flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC; + + if (kvm->arch.use_master_clock) + data.flags |= KVM_CLOCK_TSC_STABLE; + + if (copy_to_user(argp, &data, sizeof(data))) + return -EFAULT; + + return 0; +} + +static int kvm_vm_ioctl_set_clock(struct kvm *kvm, + void __user *argp) +{ + struct kvm_arch *ka = &kvm->arch; + struct kvm_clock_data data; + u64 now_raw_ns; + + if (copy_from_user(&data, argp, sizeof(data))) + return -EFAULT; + + if (data.flags & ~KVM_CLOCK_REALTIME) + return -EINVAL; + + /* + * TODO: userspace has to take care of races with VCPU_RUN, so + * kvm_gen_update_masterclock() can be cut down to locked + * pvclock_update_vm_gtod_copy(). + */ + kvm_gen_update_masterclock(kvm); + + spin_lock_irq(&ka->pvclock_gtod_sync_lock); + if (data.flags & KVM_CLOCK_REALTIME) { + u64 now_real_ns = ktime_get_real_ns(); + + /* + * Avoid stepping the kvmclock backwards. + */ + if (now_real_ns > data.realtime) + data.clock += now_real_ns - data.realtime; + } + + if (ka->use_master_clock) + now_raw_ns = ka->master_kernel_ns; + else + now_raw_ns = get_kvmclock_base_ns(); + ka->kvmclock_offset = data.clock - now_raw_ns; + spin_unlock_irq(&ka->pvclock_gtod_sync_lock); + + kvm_make_all_cpus_request(kvm, KVM_REQ_CLOCK_UPDATE); + return 0; +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -6050,57 +6137,11 @@ long kvm_arch_vm_ioctl(struct file *filp, } #endif case KVM_SET_CLOCK: { - struct kvm_arch *ka = &kvm->arch; - struct kvm_clock_data user_ns; - u64 now_ns; - - r = -EFAULT; - if (copy_from_user(&user_ns, argp, sizeof(user_ns))) - goto out; - - r = -EINVAL; - if (user_ns.flags) - goto out; - - r = 0; - /* - * TODO: userspace has to take care of races with VCPU_RUN, so - * kvm_gen_update_masterclock() can be cut down to locked - * pvclock_update_vm_gtod_copy(). - */ - kvm_gen_update_masterclock(kvm); - - /* - * This pairs with kvm_guest_time_update(): when masterclock is - * in use, we use master_kernel_ns + kvmclock_offset to set - * unsigned 'system_time' so if we use get_kvmclock_ns() (which - * is slightly ahead) here we risk going negative on unsigned - * 'system_time' when 'user_ns.clock' is very small. - */ - spin_lock_irq(&ka->pvclock_gtod_sync_lock); - if (kvm->arch.use_master_clock) - now_ns = ka->master_kernel_ns; - else - now_ns = get_kvmclock_base_ns(); - ka->kvmclock_offset = user_ns.clock - now_ns; - spin_unlock_irq(&ka->pvclock_gtod_sync_lock); - - kvm_make_all_cpus_request(kvm, KVM_REQ_CLOCK_UPDATE); + r = kvm_vm_ioctl_set_clock(kvm, argp); break; } case KVM_GET_CLOCK: { - struct kvm_clock_data user_ns; - u64 now_ns; - - now_ns = get_kvmclock_ns(kvm); - user_ns.clock = now_ns; - user_ns.flags = kvm->arch.use_master_clock ? KVM_CLOCK_TSC_STABLE : 0; - memset(&user_ns.pad, 0, sizeof(user_ns.pad)); - - r = -EFAULT; - if (copy_to_user(argp, &user_ns, sizeof(user_ns))) - goto out; - r = 0; + r = kvm_vm_ioctl_get_clock(kvm, argp); break; } case KVM_MEMORY_ENCRYPT_OP: { diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index d9e4aabcb31a..53a49cb8616a 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1223,11 +1223,16 @@ struct kvm_irqfd { /* Do not use 1, KVM_CHECK_EXTENSION returned it before we had flags. */ #define KVM_CLOCK_TSC_STABLE 2 +#define KVM_CLOCK_REALTIME (1 << 2) +#define KVM_CLOCK_HOST_TSC (1 << 3) struct kvm_clock_data { __u64 clock; __u32 flags; - __u32 pad[9]; + __u32 pad0; + __u64 realtime; + __u64 host_tsc; + __u32 pad[4]; }; /* For KVM_CAP_SW_TLB */ From patchwork Mon Jul 19 18:49:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386607 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 209B9C07E9B for ; Mon, 19 Jul 2021 18:52:46 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 DAE2E60232 for ; Mon, 19 Jul 2021 18:52:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DAE2E60232 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=jG6tx4ETYfApy15OhAAJ0oJRv9O/src8AMxvY+sN02M=; b=FDLueUodmtsNwKry0hltJIVqGP a2RDT44t5JRp+lMf181uKRtf13FWre1YTZ9gkgVm++e5+ErvjZEh+pxbDhhzROAqYAD+j6LEOi1DJ NQBPEDIoTz8dVz6UaKjSq6lZNZSjiKzWlHsfjaCZvN/X6cv6C052DOKUo00+QomVaV3t0i/SS8hau 5TAwZgaNi+8ZaKP4huykG1Np1H5qOSg4A5FBYPsjew8WsnwkyWO83upjCETRtdtiXyyERINjVl9Py 6dv2rdTgFiWyPPEKigH7qKJTZTpuZ9XdoFmEVxn9gTT2qjXD48Qi5CvV0Rf1YvRLO4TiAo2Y2XYUZ y0XubgEQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLB-00AwO4-68; Mon, 19 Jul 2021 18:50:09 +0000 Received: from mail-io1-xd4a.google.com ([2607:f8b0:4864:20::d4a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YL6-00AwM9-B3 for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:05 +0000 Received: by mail-io1-xd4a.google.com with SMTP id i13-20020a5d88cd0000b02904e5ab8bdc6cso13302214iol.22 for ; Mon, 19 Jul 2021 11:50:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=GhOMvXrghMgrA5cJUDKp3N5lyADxOv1r/pHquF+79AY=; b=D/aYlVxo4gF+ngT2EhsxuBs4dLxMpsc59UY0ea+aZF7kV6yb0h6VJuouAJFhYN/W2V q67XWG04FbHwgm5fOnbL/VXz5mp4tx5GDfjliini9B8ijChsqmUhjZ+plrU/zmqfrx+3 Au91AOJPy2VNvDdARpgsaAt7/h2+A1wxSiqW8VNqqvSmb5Cx6kbqFFiD8m64G7G+mRq5 MZTaYqlzfxaS5qHKar7AkJnWiUZlVkVpnxfDOXBlmlYJBOcs5V2jE4ar1G1IsW/P/ehB zUn5sPy9uUJ1PCJcvTqOLbh9W52HkCfHG42kw4oiidiOsn4m4fz431A7RoIX8b4UZePK Tn/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=GhOMvXrghMgrA5cJUDKp3N5lyADxOv1r/pHquF+79AY=; b=uTxIrspTut1SUozNo03GLPoF3hugScOBWyMVwGsOsoP9GeiB7KIp+YXUfXWxS3H4W4 uIQScC8rdJkDW0dsYbvQg3QsK1Ju6JcWiVBENbVsWfYOTG77Xfwpn64ghveuFn8I5QQa uaLTg3qUj+J9HHyecVAjOxVbA3iW1HuqftTyXfT7lLJ+0wAD5S72rHyEdJxwPjKAYae9 4hj91RsfV7f+BjzwexfZJo/ESZc9/AwILUyqW1cb9C0KLIyM3qdAuV1bJEgRRd+S0igP Vhj3DZzHV9N1vRInVu/wpYGU4Izol1I7Kxt65NMwswxzJyxWc7dkx6zroKvg1n5ksOA3 i/YA== X-Gm-Message-State: AOAM531vCy0JDFYdjiP6q//jvpomQGAwM/JVMGvdebgukTz1bQoqGdsj 7aRlZaGqovDhMpH3qaiOoDXiX+1OvN4= X-Google-Smtp-Source: ABdhPJxhjeeV517I8G9SDrwYXwQAF4gak5x9fd2mxwZ6Dy0ItSFxpEA3vLF5SwT8/R+AMo1D7Kj5J29roqY= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a92:5409:: with SMTP id i9mr17763897ilb.138.1626720602384; Mon, 19 Jul 2021 11:50:02 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:39 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-3-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 02/12] KVM: x86: Refactor tsc synchronization code From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115004_433918_6F32C5EC X-CRM114-Status: GOOD ( 18.00 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Refactor kvm_synchronize_tsc to make a new function that allows callers to specify TSC parameters (offset, value, nanoseconds, etc.) explicitly for the sake of participating in TSC synchronization. This changes the locking semantics around TSC writes. Writes to the TSC will now take the pvclock gtod lock while holding the tsc write lock, whereas before these locks were disjoint. Reviewed-by: David Matlack Signed-off-by: Oliver Upton --- Documentation/virt/kvm/locking.rst | 11 +++ arch/x86/kvm/x86.c | 106 +++++++++++++++++------------ 2 files changed, 74 insertions(+), 43 deletions(-) diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst index 35eca377543d..ac62e1c76694 100644 --- a/Documentation/virt/kvm/locking.rst +++ b/Documentation/virt/kvm/locking.rst @@ -30,6 +30,9 @@ On x86: holding kvm->arch.mmu_lock (typically with ``read_lock``, otherwise there's no need to take kvm->arch.tdp_mmu_pages_lock at all). +- kvm->arch.tsc_write_lock is taken outside + kvm->arch.pvclock_gtod_sync_lock + Everything else is a leaf: no other lock is taken inside the critical sections. @@ -216,6 +219,14 @@ time it will be set using the Dirty tracking mechanism described above. :Comment: 'raw' because hardware enabling/disabling must be atomic /wrt migration. +:Name: kvm_arch::pvclock_gtod_sync_lock +:Type: raw_spinlock_t +:Arch: x86 +:Protects: kvm_arch::{cur_tsc_generation,cur_tsc_nsec,cur_tsc_write, + cur_tsc_offset,nr_vcpus_matched_tsc} +:Comment: 'raw' because updating the kvm master clock must not be + preempted. + :Name: kvm_arch::tsc_write_lock :Type: raw_spinlock :Arch: x86 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bff78168d4a2..580ba0e86687 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2441,13 +2441,73 @@ static inline bool kvm_check_tsc_unstable(void) return check_tsc_unstable(); } +/* + * Infers attempts to synchronize the guest's tsc from host writes. Sets the + * offset for the vcpu and tracks the TSC matching generation that the vcpu + * participates in. + * + * Must hold kvm->arch.tsc_write_lock to call this function. + */ +static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc, + u64 ns, bool matched) +{ + struct kvm *kvm = vcpu->kvm; + bool already_matched; + unsigned long flags; + + lockdep_assert_held(&kvm->arch.tsc_write_lock); + + already_matched = + (vcpu->arch.this_tsc_generation == kvm->arch.cur_tsc_generation); + + /* + * We track the most recent recorded KHZ, write and time to + * allow the matching interval to be extended at each write. + */ + kvm->arch.last_tsc_nsec = ns; + kvm->arch.last_tsc_write = tsc; + kvm->arch.last_tsc_khz = vcpu->arch.virtual_tsc_khz; + + vcpu->arch.last_guest_tsc = tsc; + + /* Keep track of which generation this VCPU has synchronized to */ + vcpu->arch.this_tsc_generation = kvm->arch.cur_tsc_generation; + vcpu->arch.this_tsc_nsec = kvm->arch.cur_tsc_nsec; + vcpu->arch.this_tsc_write = kvm->arch.cur_tsc_write; + + kvm_vcpu_write_tsc_offset(vcpu, offset); + + spin_lock_irqsave(&kvm->arch.pvclock_gtod_sync_lock, flags); + if (!matched) { + /* + * We split periods of matched TSC writes into generations. + * For each generation, we track the original measured + * nanosecond time, offset, and write, so if TSCs are in + * sync, we can match exact offset, and if not, we can match + * exact software computation in compute_guest_tsc() + * + * These values are tracked in kvm->arch.cur_xxx variables. + */ + kvm->arch.nr_vcpus_matched_tsc = 0; + kvm->arch.cur_tsc_generation++; + kvm->arch.cur_tsc_nsec = ns; + kvm->arch.cur_tsc_write = tsc; + kvm->arch.cur_tsc_offset = offset; + matched = false; + } else if (!already_matched) { + kvm->arch.nr_vcpus_matched_tsc++; + } + + kvm_track_tsc_matching(vcpu); + spin_unlock_irqrestore(&kvm->arch.pvclock_gtod_sync_lock, flags); +} + static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 data) { struct kvm *kvm = vcpu->kvm; u64 offset, ns, elapsed; unsigned long flags; - bool matched; - bool already_matched; + bool matched = false; bool synchronizing = false; raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); @@ -2493,51 +2553,11 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 data) offset = kvm_compute_l1_tsc_offset(vcpu, data); } matched = true; - already_matched = (vcpu->arch.this_tsc_generation == kvm->arch.cur_tsc_generation); - } else { - /* - * We split periods of matched TSC writes into generations. - * For each generation, we track the original measured - * nanosecond time, offset, and write, so if TSCs are in - * sync, we can match exact offset, and if not, we can match - * exact software computation in compute_guest_tsc() - * - * These values are tracked in kvm->arch.cur_xxx variables. - */ - kvm->arch.cur_tsc_generation++; - kvm->arch.cur_tsc_nsec = ns; - kvm->arch.cur_tsc_write = data; - kvm->arch.cur_tsc_offset = offset; - matched = false; } - /* - * We also track th most recent recorded KHZ, write and time to - * allow the matching interval to be extended at each write. - */ - kvm->arch.last_tsc_nsec = ns; - kvm->arch.last_tsc_write = data; - kvm->arch.last_tsc_khz = vcpu->arch.virtual_tsc_khz; - - vcpu->arch.last_guest_tsc = data; + __kvm_synchronize_tsc(vcpu, offset, data, ns, matched); - /* Keep track of which generation this VCPU has synchronized to */ - vcpu->arch.this_tsc_generation = kvm->arch.cur_tsc_generation; - vcpu->arch.this_tsc_nsec = kvm->arch.cur_tsc_nsec; - vcpu->arch.this_tsc_write = kvm->arch.cur_tsc_write; - - kvm_vcpu_write_tsc_offset(vcpu, offset); raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); - - spin_lock_irqsave(&kvm->arch.pvclock_gtod_sync_lock, flags); - if (!matched) { - kvm->arch.nr_vcpus_matched_tsc = 0; - } else if (!already_matched) { - kvm->arch.nr_vcpus_matched_tsc++; - } - - kvm_track_tsc_matching(vcpu); - spin_unlock_irqrestore(&kvm->arch.pvclock_gtod_sync_lock, flags); } static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, From patchwork Mon Jul 19 18:49:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386613 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 8BE8EC07E9B for ; Mon, 19 Jul 2021 18:53:40 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 5A9D660232 for ; Mon, 19 Jul 2021 18:53:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5A9D660232 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=qcSVondjrPpy8ioD+VAz6iync8YdsJlHZEvVvdYVKkI=; b=wjMn8jxUq1N6le69OXMi+cYLuw vU2OydHYKhphNAvXo3hdvNLkowR74/csH1HcuA5TEKmx1gCDtpMNS4gpZ95WGmlDe23mksiMD2cOs HLgnKN3zgOm59jhRU5mRV0fvmwEH6rMlnS6q7B2i0tcl9S+KyGYW1n9GuMLUKaAhvCg9vbPCQI/7S HR6Y0T/onDw4PIs5yISqkROAzi5jmPEsfN3IYm1HTGmHNB6rvQpP/ucnMZloIiZomlcb8lvRkMNm0 xI+My0MAlrTGZXGmHUkiz74pzuetzRYSMBwzSyQnUzJmbiocqNn0lhy8SxM8SR14Z3U1xZc1n1FHU ixrC/JBQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLk-00AwWf-Kb; Mon, 19 Jul 2021 18:50:44 +0000 Received: from mail-qk1-x749.google.com ([2607:f8b0:4864:20::749]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YL7-00AwMD-6J for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:07 +0000 Received: by mail-qk1-x749.google.com with SMTP id h22-20020a05620a13f6b02903b94aaa0909so4981064qkl.15 for ; Mon, 19 Jul 2021 11:50:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=gVY1OcKTRkdtAsXEWyCj2ppxRNB8jvE/V1F4Gd0MP+c=; b=rIe4EYIHZTwOJ/LUiUNHR7ZP9KqycOwxusCIiH31hPQqFcVGTBc1V7P3yBAW5nLMOf rVtsH9MK/R3IUquzLnJFycOUHo+NDeEQOzM3VNusblsfRBTvJvyA9sd/uVCjpaPYgN2Z Pqzh/O7c+NxCnojD2tFCdhNGFve1zeafT1c2aRlALZVA49Yfo4japt7RG6fVIAICydTj nAVp6rKK4uOqi8/bJIJm8Lkmta2iqxjy19MO47gej1GC/N5QLDS8F2hW84QKHy1HuqZo FOPG6e4fTJXX8F2b/SlCENE/xNxwWvK6F0wJDI3/YzAyW4CkWurni2c52QqsedvFxsJ2 vwMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=gVY1OcKTRkdtAsXEWyCj2ppxRNB8jvE/V1F4Gd0MP+c=; b=ijokyJ9d5glfTpjCG0T9fP6rPTgH8oqSTbzbEyNvPqH8Lj84uwr7B8eeUKZAB8+uo/ /p9VrNiRgf6NiptThu7LcD9XmXdi5aRG1c+vCvcwSLZpr8mln3rxw1bNVgDrMYXzLRrr Zrz11OkOS0i3JhUnqmvVeGc+eZyEo2ivVYtV2GZ/YFCF9mUgl5pezqXUngxcdLr7NoMK 2P2jtH4T2OJ3ROMm4t8sr3g5jV1j/UNuxc6epKvMLqmsZ9nlQyZHnYKijnAs3kBhmTEm Rn0Nn+fLyQgprNlL561g1ZKA0ZkdIjEZyj/Q9i6XchCz587i80WLLcwY9DZf0X2GuXGV MpEw== X-Gm-Message-State: AOAM532+G5roMEetKrVXmmoH8umU3B6fXUZjsM15BlJZuORQWOWLb+YG 8yIoWqolojDmlWCTS4JrUQKMiQdpIbI= X-Google-Smtp-Source: ABdhPJwMtLpMckHH8SI1H19lvBkJcK8ZOjmQJ0hNe6s1ExY+akygtzdlgbYmN9GT8ZpsFuaNtAn7yVUJPzI= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a05:6214:16ca:: with SMTP id d10mr25973873qvz.59.1626720603342; Mon, 19 Jul 2021 11:50:03 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:40 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-4-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 03/12] KVM: x86: Expose TSC offset controls to userspace From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115005_285258_EAE8A358 X-CRM114-Status: GOOD ( 24.34 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org To date, VMM-directed TSC synchronization and migration has been a bit messy. KVM has some baked-in heuristics around TSC writes to infer if the VMM is attempting to synchronize. This is problematic, as it depends on host userspace writing to the guest's TSC within 1 second of the last write. A much cleaner approach to configuring the guest's views of the TSC is to simply migrate the TSC offset for every vCPU. Offsets are idempotent, and thus not subject to change depending on when the VMM actually reads/writes values from/to KVM. The VMM can then read the TSC once with KVM_GET_CLOCK to capture a (realtime, host_tsc) pair at the instant when the guest is paused. Cc: David Matlack Signed-off-by: Oliver Upton --- Documentation/virt/kvm/devices/vcpu.rst | 57 ++++++++ arch/x86/include/asm/kvm_host.h | 1 + arch/x86/include/uapi/asm/kvm.h | 4 + arch/x86/kvm/x86.c | 167 ++++++++++++++++++++++++ 4 files changed, 229 insertions(+) diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/kvm/devices/vcpu.rst index 2acec3b9ef65..b46d5f742e69 100644 --- a/Documentation/virt/kvm/devices/vcpu.rst +++ b/Documentation/virt/kvm/devices/vcpu.rst @@ -161,3 +161,60 @@ Specifies the base address of the stolen time structure for this VCPU. The base address must be 64 byte aligned and exist within a valid guest memory region. See Documentation/virt/kvm/arm/pvtime.rst for more information including the layout of the stolen time structure. + +4. GROUP: KVM_VCPU_TSC_CTRL +=========================== + +:Architectures: x86 + +4.1 ATTRIBUTE: KVM_VCPU_TSC_OFFSET + +:Parameters: 64-bit unsigned TSC offset + +Returns: + + ======= ====================================== + -EFAULT Error reading/writing the provided + parameter address. + -ENXIO Attribute not supported + ======= ====================================== + +Specifies the guest's TSC offset relative to the host's TSC. The guest's +TSC is then derived by the following equation: + + guest_tsc = host_tsc + KVM_VCPU_TSC_OFFSET + +This attribute is useful for the precise migration of a guest's TSC. The +following describes a possible algorithm to use for the migration of a +guest's TSC: + +From the source VMM process: + +1. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (t_0), + kvmclock nanoseconds (k_0), and realtime nanoseconds (r_0). + +2. Read the KVM_VCPU_TSC_OFFSET attribute for every vCPU to record the + guest TSC offset (off_n). + +3. Invoke the KVM_GET_TSC_KHZ ioctl to record the frequency of the + guest's TSC (freq). + +From the destination VMM process: + +4. Invoke the KVM_SET_CLOCK ioctl, providing the kvmclock nanoseconds + (k_0) and realtime nanoseconds (r_0) in their respective fields. + Ensure that the KVM_CLOCK_REALTIME flag is set in the provided + structure. KVM will advance the VM's kvmclock to account for elapsed + time since recording the clock values. + +5. Invoke the KVM_GET_CLOCK ioctl to record the host TSC (t_1) and + kvmclock nanoseconds (k_1). + +6. Adjust the guest TSC offsets for every vCPU to account for (1) time + elapsed since recording state and (2) difference in TSCs between the + source and destination machine: + + new_off_n = t_0 + off_n = (k_1 - k_0) * freq - t_1 + +7. Write the KVM_VCPU_TSC_OFFSET attribute for every vCPU with the + respective value derived in the previous step. diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3fb2b9270d01..5f2e909b83eb 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1070,6 +1070,7 @@ struct kvm_arch { u64 last_tsc_nsec; u64 last_tsc_write; u32 last_tsc_khz; + u64 last_tsc_offset; u64 cur_tsc_nsec; u64 cur_tsc_write; u64 cur_tsc_offset; diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index a6c327f8ad9e..0b22e1e84e78 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -503,4 +503,8 @@ struct kvm_pmu_event_filter { #define KVM_PMU_EVENT_ALLOW 0 #define KVM_PMU_EVENT_DENY 1 +/* for KVM_{GET,SET,HAS}_DEVICE_ATTR */ +#define KVM_VCPU_TSC_CTRL 0 /* control group for the timestamp counter (TSC) */ +#define KVM_VCPU_TSC_OFFSET 0 /* attribute for the TSC offset */ + #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 580ba0e86687..9e7867410091 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2411,6 +2411,11 @@ static void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset) static_call(kvm_x86_write_tsc_offset)(vcpu, vcpu->arch.tsc_offset); } +static u64 kvm_vcpu_read_tsc_offset(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.l1_tsc_offset; +} + static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multiplier) { vcpu->arch.l1_tsc_scaling_ratio = l1_multiplier; @@ -2467,6 +2472,7 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc, kvm->arch.last_tsc_nsec = ns; kvm->arch.last_tsc_write = tsc; kvm->arch.last_tsc_khz = vcpu->arch.virtual_tsc_khz; + kvm->arch.last_tsc_offset = offset; vcpu->arch.last_guest_tsc = tsc; @@ -4914,6 +4920,137 @@ static int kvm_set_guest_paused(struct kvm_vcpu *vcpu) return 0; } +static int kvm_arch_tsc_has_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int r; + + switch (attr->attr) { + case KVM_VCPU_TSC_OFFSET: + r = 0; + break; + default: + r = -ENXIO; + } + + return r; +} + +static int kvm_arch_tsc_get_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + void __user *uaddr = (void __user *)attr->addr; + int r; + + switch (attr->attr) { + case KVM_VCPU_TSC_OFFSET: { + u64 offset; + + offset = kvm_vcpu_read_tsc_offset(vcpu); + r = -EFAULT; + if (copy_to_user(uaddr, &offset, sizeof(offset))) + break; + + r = 0; + break; + } + default: + r = -ENXIO; + } + + return r; +} + +static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + void __user *uaddr = (void __user *)attr->addr; + struct kvm *kvm = vcpu->kvm; + int r; + + switch (attr->attr) { + case KVM_VCPU_TSC_OFFSET: { + u64 offset, tsc, ns; + unsigned long flags; + bool matched; + + r = -EFAULT; + if (copy_from_user(&offset, uaddr, sizeof(offset))) + break; + + raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); + + matched = (vcpu->arch.virtual_tsc_khz && + kvm->arch.last_tsc_khz == vcpu->arch.virtual_tsc_khz && + kvm->arch.last_tsc_offset == offset); + + tsc = kvm_scale_tsc(vcpu, rdtsc(), vcpu->arch.l1_tsc_scaling_ratio) + offset; + ns = get_kvmclock_base_ns(); + + __kvm_synchronize_tsc(vcpu, offset, tsc, ns, matched); + raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); + + r = 0; + break; + } + default: + r = -ENXIO; + } + + return r; +} + +static int kvm_vcpu_ioctl_has_device_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int r; + + switch (attr->group) { + case KVM_VCPU_TSC_CTRL: + r = kvm_arch_tsc_has_attr(vcpu, attr); + break; + default: + r = -ENXIO; + break; + } + + return r; +} + +static int kvm_vcpu_ioctl_get_device_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int r; + + switch (attr->group) { + case KVM_VCPU_TSC_CTRL: + r = kvm_arch_tsc_get_attr(vcpu, attr); + break; + default: + r = -ENXIO; + break; + } + + return r; +} + +static int kvm_vcpu_ioctl_set_device_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int r; + + switch (attr->group) { + case KVM_VCPU_TSC_CTRL: + r = kvm_arch_tsc_set_attr(vcpu, attr); + break; + default: + r = -ENXIO; + break; + } + + return r; +} + static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, struct kvm_enable_cap *cap) { @@ -5368,6 +5505,36 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = __set_sregs2(vcpu, u.sregs2); break; } + case KVM_HAS_DEVICE_ATTR: { + struct kvm_device_attr attr; + + r = -EFAULT; + if (copy_from_user(&attr, argp, sizeof(attr))) + goto out; + + r = kvm_vcpu_ioctl_has_device_attr(vcpu, &attr); + break; + } + case KVM_GET_DEVICE_ATTR: { + struct kvm_device_attr attr; + + r = -EFAULT; + if (copy_from_user(&attr, argp, sizeof(attr))) + goto out; + + r = kvm_vcpu_ioctl_get_device_attr(vcpu, &attr); + break; + } + case KVM_SET_DEVICE_ATTR: { + struct kvm_device_attr attr; + + r = -EFAULT; + if (copy_from_user(&attr, argp, sizeof(attr))) + goto out; + + r = kvm_vcpu_ioctl_set_device_attr(vcpu, &attr); + break; + } default: r = -EINVAL; } From patchwork Mon Jul 19 18:49:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386611 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 6AE44C07E95 for ; Mon, 19 Jul 2021 18:53:32 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 242646109E for ; Mon, 19 Jul 2021 18:53:32 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 242646109E Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=XoCoJFnJfIsYRorB4aQrYxqb2npbXJvVMYhl2QZ/Z9A=; b=BUYR0gr7GTkVglUI0xMgUTSyPg OrhlkwSo/fTJjHcQwS1l2tvxSTLwe46OFkt3N7kG97mJhIAtLanBHMrzaI2WxKXkuMv1xbIPxcMSk C3g9aBrswkMnL2BKP1fAWQPlM4P4Fk8ixFDY2/eW+XVRVm2YjtsPZVymzBhvpHh2Df/eORHdJEw5l CHwqcX7QrXaslOXy/MF52rNg8G7ejea2OjbEmMWQ+iX5yOH7hELIT9RypaMYhK8p7tD4PKFP4FReI OlqUdU72gDknzwwE8VXjaKwSQt+3sR/bSBlWBQs9hZy28LtStE939FIpeAkOJ+NGuHvwcgLJZzPZU DF2YfsvQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLY-00AwU1-JO; Mon, 19 Jul 2021 18:50:32 +0000 Received: from mail-io1-xd49.google.com ([2607:f8b0:4864:20::d49]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YL8-00AwMt-16 for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:07 +0000 Received: by mail-io1-xd49.google.com with SMTP id v2-20020a5d94020000b02905058dc6c376so13287189ion.6 for ; Mon, 19 Jul 2021 11:50:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=hKuZx0cTa0hYyLOI0N9XgDCwLnUeCKFvR1f+63nkOr4=; b=YfmBW9QJQ4E1eUSAPYrO6dTqW4afwS4gdJJwKEDs3fkEfRpZQgCRzppR/LkZJuKMz6 KMkpU3j25Jwj8i9kH47D0ZKD7e2cbc4pg7sK6nONX6nMS/PWzoxiv8gvR65JzA/Y6Ry8 X8N70QKorlQd7xrM4UA0G4uWb+81RchqxXA983PAsTvYlIJF5fotLJmgkMgL7ze0WwIv ++IkRrG1p9tlMSpdgTKymWqegX0NSclBS+wQ59cZjTMoTLTePuV24g+H4EBQniCHwsr8 Bqr2QgQR9LSn5JO9BlqKzTqSFxMF7yOuzWhzL/eMVLlTzoNhdugxcKmM1D0WtFfdyi1a QhCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=hKuZx0cTa0hYyLOI0N9XgDCwLnUeCKFvR1f+63nkOr4=; b=Mx2+zG8PjqM0Zn0FfgYzJF4AZlmhICbUdH2L0u4QVzY4BCyVT6IYfeDAp+vXzKYIV6 9IZO4OegxT7bvwillyhxpMFi9AJkAGraf4jML0eJnO6Mj8pJTtFbqWtDYr4HJryeMVNe r/f9GpBpoNcRuPXfzRSxCo1DlnQbb3xiBodO3r8TvfNmOonFKZQrJmg57WNZNYnkMo2N jGUE3OxLWcSVKKitBwzj2mhBAxIZwM+sTTEjAp7RcJTutEpTlbvRPZlW6NoPz6S7J1Hl IlSSRIO9lgtg4rIJc7mRhMXTQ3A553+uvnikFox8uBcyKHqa6y22Usn1u3kW2o7zDOYl 1jWw== X-Gm-Message-State: AOAM530OU8k96xHO787RA7bUOURAJ4Q1CicknUO5JbTJURCEXdlNGf0h HDpnZBRB24K1wC3sFRFz7yJ6dvmjoBI= X-Google-Smtp-Source: ABdhPJw+/Exmcm61b1jNIxXuV0uoyEg/+USrYulAOxV227xM/rDF6u0hIeC0G5Vok7FG1UdemRFXaghQYx0= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a92:d346:: with SMTP id a6mr17903215ilh.249.1626720604461; Mon, 19 Jul 2021 11:50:04 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:41 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-5-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 04/12] tools: arch: x86: pull in pvclock headers From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115006_134589_CCC5EFFA X-CRM114-Status: GOOD ( 21.45 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Copy over approximately clean versions of the pvclock headers into tools. Reconcile headers/symbols missing in tools that are unneeded. Signed-off-by: Oliver Upton --- tools/arch/x86/include/asm/pvclock-abi.h | 48 +++++++++++ tools/arch/x86/include/asm/pvclock.h | 103 +++++++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 tools/arch/x86/include/asm/pvclock-abi.h create mode 100644 tools/arch/x86/include/asm/pvclock.h diff --git a/tools/arch/x86/include/asm/pvclock-abi.h b/tools/arch/x86/include/asm/pvclock-abi.h new file mode 100644 index 000000000000..1436226efe3e --- /dev/null +++ b/tools/arch/x86/include/asm/pvclock-abi.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_PVCLOCK_ABI_H +#define _ASM_X86_PVCLOCK_ABI_H +#ifndef __ASSEMBLY__ + +/* + * These structs MUST NOT be changed. + * They are the ABI between hypervisor and guest OS. + * Both Xen and KVM are using this. + * + * pvclock_vcpu_time_info holds the system time and the tsc timestamp + * of the last update. So the guest can use the tsc delta to get a + * more precise system time. There is one per virtual cpu. + * + * pvclock_wall_clock references the point in time when the system + * time was zero (usually boot time), thus the guest calculates the + * current wall clock by adding the system time. + * + * Protocol for the "version" fields is: hypervisor raises it (making + * it uneven) before it starts updating the fields and raises it again + * (making it even) when it is done. Thus the guest can make sure the + * time values it got are consistent by checking the version before + * and after reading them. + */ + +struct pvclock_vcpu_time_info { + u32 version; + u32 pad0; + u64 tsc_timestamp; + u64 system_time; + u32 tsc_to_system_mul; + s8 tsc_shift; + u8 flags; + u8 pad[2]; +} __attribute__((__packed__)); /* 32 bytes */ + +struct pvclock_wall_clock { + u32 version; + u32 sec; + u32 nsec; +} __attribute__((__packed__)); + +#define PVCLOCK_TSC_STABLE_BIT (1 << 0) +#define PVCLOCK_GUEST_STOPPED (1 << 1) +/* PVCLOCK_COUNTS_FROM_ZERO broke ABI and can't be used anymore. */ +#define PVCLOCK_COUNTS_FROM_ZERO (1 << 2) +#endif /* __ASSEMBLY__ */ +#endif /* _ASM_X86_PVCLOCK_ABI_H */ diff --git a/tools/arch/x86/include/asm/pvclock.h b/tools/arch/x86/include/asm/pvclock.h new file mode 100644 index 000000000000..2628f9a6330b --- /dev/null +++ b/tools/arch/x86/include/asm/pvclock.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_PVCLOCK_H +#define _ASM_X86_PVCLOCK_H + +#include +#include + +/* some helper functions for xen and kvm pv clock sources */ +u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src); +u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src); +void pvclock_set_flags(u8 flags); +unsigned long pvclock_tsc_khz(struct pvclock_vcpu_time_info *src); +void pvclock_resume(void); + +void pvclock_touch_watchdogs(void); + +static __always_inline +unsigned pvclock_read_begin(const struct pvclock_vcpu_time_info *src) +{ + unsigned version = src->version & ~1; + /* Make sure that the version is read before the data. */ + rmb(); + return version; +} + +static __always_inline +bool pvclock_read_retry(const struct pvclock_vcpu_time_info *src, + unsigned version) +{ + /* Make sure that the version is re-read after the data. */ + rmb(); + return version != src->version; +} + +/* + * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, + * yielding a 64-bit result. + */ +static inline u64 pvclock_scale_delta(u64 delta, u32 mul_frac, int shift) +{ + u64 product; +#ifdef __i386__ + u32 tmp1, tmp2; +#else + unsigned long tmp; +#endif + + if (shift < 0) + delta >>= -shift; + else + delta <<= shift; + +#ifdef __i386__ + __asm__ ( + "mul %5 ; " + "mov %4,%%eax ; " + "mov %%edx,%4 ; " + "mul %5 ; " + "xor %5,%5 ; " + "add %4,%%eax ; " + "adc %5,%%edx ; " + : "=A" (product), "=r" (tmp1), "=r" (tmp2) + : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) ); +#elif defined(__x86_64__) + __asm__ ( + "mulq %[mul_frac] ; shrd $32, %[hi], %[lo]" + : [lo]"=a"(product), + [hi]"=d"(tmp) + : "0"(delta), + [mul_frac]"rm"((u64)mul_frac)); +#else +#error implement me! +#endif + + return product; +} + +static __always_inline +u64 __pvclock_read_cycles(const struct pvclock_vcpu_time_info *src, u64 tsc) +{ + u64 delta = tsc - src->tsc_timestamp; + u64 offset = pvclock_scale_delta(delta, src->tsc_to_system_mul, + src->tsc_shift); + return src->system_time + offset; +} + +struct pvclock_vsyscall_time_info { + struct pvclock_vcpu_time_info pvti; +} __attribute__((__aligned__(64))); + +#define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info) + +#ifdef CONFIG_PARAVIRT_CLOCK +void pvclock_set_pvti_cpu0_va(struct pvclock_vsyscall_time_info *pvti); +struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void); +#else +static inline struct pvclock_vsyscall_time_info *pvclock_get_pvti_cpu0_va(void) +{ + return NULL; +} +#endif + +#endif /* _ASM_X86_PVCLOCK_H */ From patchwork Mon Jul 19 18:49:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386619 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=-15.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, UNWANTED_LANGUAGE_BODY,USER_AGENT_GIT autolearn=unavailable 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 859BCC07E95 for ; Mon, 19 Jul 2021 18:54:21 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 42F1F6108B for ; Mon, 19 Jul 2021 18:54:21 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 42F1F6108B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=789JLDFxzuEqlskjDxAKZmeGUyNPGB8rrFCGc40sIuA=; b=US7mXPjEuR3eKYutJm/J4OarYQ A21kP7VLFm/wl/h8D+DTQkmRU7Spd4RxjItHZFuJQtkaQExemuBZD8/UApz7Ju51RwqWnt+6IBtU0 iqOOW9SZNSB6sqhG6LIlNqU4VmgnxrvuRjtW+7ZB1LDxuI3IMMHXSrWvWxlfuXTcVw3GPkFVLAUF8 oLsjXI/g4cH9Nwxrk99/9UTG3IFvge/Ws4jZx7Tj4iPYfAa6xpirjc8ibrxyB83R/BPAET2BECz4X Rl4d4RngnXWcy6rNmw8Ex7eaPv0rUvDKNiRm5dLkR5IzJzv8k2AEeQJVfj0qnad528AhMl3PhzwSk UgMl6Sag==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YMC-00Aweb-5m; Mon, 19 Jul 2021 18:51:12 +0000 Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YL9-00AwND-9B for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:09 +0000 Received: by mail-yb1-xb49.google.com with SMTP id p63-20020a25d8420000b029055bc6fd5e5bso26626402ybg.9 for ; Mon, 19 Jul 2021 11:50:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=ZEDpe0ZAYcWsHrWESPLkcNChmXiD12rNhu+z9ayPSoQ=; b=S0k8GE9+Lo3g9spaUJzMaUW6So0qalo1Tt9AzLmD9/JTLzFb6q6AJ3uavSnWQCl2Xr UqWC2xfR/zu832YC8mBVbk0e5ZQ62hosKP28atf2GrszWnykGHHSgrwifPQ2V3wwuX5V nI1bZzZ7dRtAxMgvjJElL3+y673sRoITR9rw1aAVBORIVXma3FBOmArqwNpAyvCOhwCL EQ/XuIaCKd2wsEEgerw33BORLh3axtcFxydWnVY1aWNTyMWFQdSJF4UcU7X5he7iRBgU eLvIPrm61KFUV+P+6flpNv0qJASukinJr0WXDQAPYtKH78RdMkGY6PD9ahg22noP589L qEZw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=ZEDpe0ZAYcWsHrWESPLkcNChmXiD12rNhu+z9ayPSoQ=; b=XOnWElimkEcc0fkrClwbp26XREDQ0u34SIMsvNSfaayyfMxjTJtTmHpNX4KT/6hyPn GIdzX+TVPNi0UTnfrmnJpJjQLgc4mMyxG3fFPahAHW8jkwYruPprlOA2MDpab/ap8/PL uyeck00NI0Ves/me/F9IRBdfiMzigF19HiRCOoyDgAlg6n2GWuWea2wMdkdVOwv+UWDi RNjKyT8n+11FaMbBkDmBM1BZ194+6gKVwiQMMXP7KkjRPK/FV+B4i5zKju7mSFF04izx hnhBOJJrPiiQ4PnMqbnrb9fBayxhqIhqgfavmPrAtvOODeMMxeLWJ3Btm+q3PwOEe10l ZuLA== X-Gm-Message-State: AOAM533zp8L4WKwBpfeEoYGCgA1VFyX9V311XlT/s4WGq69jvnrvWJ8t sbfqcwWxAl1rI4gYhvmBP3WMGfiCZIk= X-Google-Smtp-Source: ABdhPJwPasorex0+a8JIBXajWIF3mFLthX7cLl02P10sAgrqBmaZhhOEmDRRXkUQJgo5VByslpl71DdSvnI= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a05:6902:136e:: with SMTP id bt14mr14483392ybb.384.1626720605605; Mon, 19 Jul 2021 11:50:05 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:42 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-6-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 05/12] selftests: KVM: Add test for KVM_{GET,SET}_CLOCK From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115007_377153_221B02F0 X-CRM114-Status: GOOD ( 22.83 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add a selftest for the new KVM clock UAPI that was introduced. Ensure that the KVM clock is consistent between userspace and the guest, and that the difference in realtime will only ever cause the KVM clock to advance forward. Signed-off-by: Oliver Upton --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../testing/selftests/kvm/include/kvm_util.h | 2 + .../selftests/kvm/x86_64/kvm_clock_test.c | 210 ++++++++++++++++++ 4 files changed, 214 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_clock_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 06a351b4f93b..d0877d01e771 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -11,6 +11,7 @@ /x86_64/emulator_error_test /x86_64/get_cpuid_test /x86_64/get_msr_index_features +/x86_64/kvm_clock_test /x86_64/kvm_pv_test /x86_64/hyperv_clock /x86_64/hyperv_cpuid diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index b853be2ae3c6..f7e24f334c6e 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -46,6 +46,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/get_cpuid_test TEST_GEN_PROGS_x86_64 += x86_64/hyperv_clock TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid TEST_GEN_PROGS_x86_64 += x86_64/hyperv_features +TEST_GEN_PROGS_x86_64 += x86_64/kvm_clock_test TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test TEST_GEN_PROGS_x86_64 += x86_64/mmu_role_test diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 010b59b13917..a8ac5d52e17b 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -19,6 +19,8 @@ #define KVM_DEV_PATH "/dev/kvm" #define KVM_MAX_VCPUS 512 +#define NSEC_PER_SEC 1000000000L + /* * Callers of kvm_util only have an incomplete/opaque description of the * structure kvm_util is using to maintain the state of a VM. diff --git a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c new file mode 100644 index 000000000000..12aef5725dc4 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021, Google LLC. + * + * Tests for adjusting the KVM clock from userspace + */ +#include +#include +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#define VCPU_ID 0 + +struct test_case { + uint64_t kvmclock_base; + int64_t realtime_offset; +}; + +static struct test_case test_cases[] = { + { .kvmclock_base = 0 }, + { .kvmclock_base = 180 * NSEC_PER_SEC }, + { .kvmclock_base = 0, .realtime_offset = -180 * NSEC_PER_SEC }, + { .kvmclock_base = 0, .realtime_offset = 180 * NSEC_PER_SEC }, +}; + +#define GUEST_SYNC_CLOCK(__stage, __val) \ + GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0) + +static void guest_main(vm_paddr_t pvti_pa, struct pvclock_vcpu_time_info *pvti) +{ + int i; + + wrmsr(MSR_KVM_SYSTEM_TIME_NEW, pvti_pa | KVM_MSR_ENABLED); + for (i = 0; i < ARRAY_SIZE(test_cases); i++) { + GUEST_SYNC_CLOCK(i, __pvclock_read_cycles(pvti, rdtsc())); + } + + GUEST_DONE(); +} + +#define EXPECTED_FLAGS (KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC) + +static inline void assert_flags(struct kvm_clock_data *data) +{ + TEST_ASSERT((data->flags & EXPECTED_FLAGS) == EXPECTED_FLAGS, + "unexpected clock data flags: %x (want set: %x)", + data->flags, EXPECTED_FLAGS); +} + +static void handle_sync(struct ucall *uc, struct kvm_clock_data *start, + struct kvm_clock_data *end) +{ + uint64_t obs, exp_lo, exp_hi; + + obs = uc->args[2]; + exp_lo = start->clock; + exp_hi = end->clock; + + assert_flags(start); + assert_flags(end); + + TEST_ASSERT(exp_lo <= obs && obs <= exp_hi, + "unexpected kvm-clock value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]", + obs, exp_lo, exp_hi); + + pr_info("kvm-clock value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n", + obs, exp_lo, exp_hi); +} + +static void handle_abort(struct ucall *uc) +{ + TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], + __FILE__, uc->args[1]); +} + +static void setup_clock(struct kvm_vm *vm, struct test_case *test_case) +{ + struct kvm_clock_data data; + + memset(&data, 0, sizeof(data)); + + data.clock = test_case->kvmclock_base; + if (test_case->realtime_offset) { + struct timespec ts; + int r; + + data.flags |= KVM_CLOCK_REALTIME; + do { + r = clock_gettime(CLOCK_REALTIME, &ts); + if (!r) + break; + } while (errno == EINTR); + + TEST_ASSERT(!r, "clock_gettime() failed: %d\n", r); + + data.realtime = ts.tv_sec * NSEC_PER_SEC; + data.realtime += ts.tv_nsec; + data.realtime += test_case->realtime_offset; + } + + vm_ioctl(vm, KVM_SET_CLOCK, &data); +} + +static void enter_guest(struct kvm_vm *vm) +{ + struct kvm_clock_data start, end; + struct kvm_run *run; + struct ucall uc; + int i, r; + + run = vcpu_state(vm, VCPU_ID); + + for (i = 0; i < ARRAY_SIZE(test_cases); i++) { + setup_clock(vm, &test_cases[i]); + + vm_ioctl(vm, KVM_GET_CLOCK, &start); + + r = _vcpu_run(vm, VCPU_ID); + vm_ioctl(vm, KVM_GET_CLOCK, &end); + + TEST_ASSERT(!r, "vcpu_run failed: %d\n", r); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "unexpected exit reason: %u (%s)", + run->exit_reason, exit_reason_str(run->exit_reason)); + + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_SYNC: + handle_sync(&uc, &start, &end); + break; + case UCALL_ABORT: + handle_abort(&uc); + return; + case UCALL_DONE: + return; + } + } +} + +#define CLOCKSOURCE_PATH "/sys/devices/system/clocksource/clocksource0/current_clocksource" + +static void check_clocksource(void) +{ + char *clk_name; + struct stat st; + FILE *fp; + + fp = fopen(CLOCKSOURCE_PATH, "r"); + if (!fp) { + pr_info("failed to open clocksource file: %d; assuming TSC.\n", + errno); + return; + } + + if (fstat(fileno(fp), &st)) { + pr_info("failed to stat clocksource file: %d; assuming TSC.\n", + errno); + goto out; + } + + clk_name = malloc(st.st_size); + TEST_ASSERT(clk_name, "failed to allocate buffer to read file\n"); + + if (!fgets(clk_name, st.st_size, fp)) { + pr_info("failed to read clocksource file: %d; assuming TSC.\n", + ferror(fp)); + goto out; + } + + TEST_ASSERT(!strncmp(clk_name, "tsc\n", st.st_size), + "clocksource not supported: %s", clk_name); +out: + fclose(fp); +} + +int main(void) +{ + struct kvm_cpuid2 *best; + vm_vaddr_t pvti_gva; + vm_paddr_t pvti_gpa; + struct kvm_vm *vm; + int flags; + + flags = kvm_check_cap(KVM_CAP_ADJUST_CLOCK); + if (!(flags & KVM_CLOCK_REALTIME)) { + print_skip("KVM_CLOCK_REALTIME not supported; flags: %x", + flags); + exit(KSFT_SKIP); + } + + check_clocksource(); + + vm = vm_create_default(VCPU_ID, 0, guest_main); + + best = kvm_get_supported_cpuid(); + vcpu_set_cpuid(vm, VCPU_ID, best); + + pvti_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000); + pvti_gpa = addr_gva2gpa(vm, pvti_gva); + vcpu_args_set(vm, VCPU_ID, 2, pvti_gpa, pvti_gva); + + enter_guest(vm); + kvm_vm_free(vm); +} From patchwork Mon Jul 19 18:49:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386617 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 8AC22C07E9D for ; Mon, 19 Jul 2021 18:54:05 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 602ED6108B for ; Mon, 19 Jul 2021 18:54:05 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 602ED6108B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=0HZK2Gt+drmP9GXZ829Aw7EYkWyC5JgmTsGzlHIRXIQ=; b=sVdY+1sOpGt9Nj+0F9vemDi/dY ZKZDVAP4qxAjPjjjDdubPJzoY7kTLVMD2XRJB86mGWk+M1Yogb7LDBjkQkOGTaW3NdpONU66/4gKj IMAdergPbZ17cG0da0DfXTsga2sACsx7x4+FgAYIWz4iC11nHpdbfPh5awNnDQG6byyjVPll+8ZW3 nJkN4CYBXlAmVOp2u4l2lU0TZynZPbkw/620v+xpfsTDCWbiy4Ktk1pT7jMmDPsxpB0b2Qn8M3pJ6 zy9WGMRKvawZ6ibLUDDSxLeXn5NSDMeVpWMmWkq9A3xNxItBJNaxX8+LOZc1gGYbcRPnleIKMHqpo EL6HB5HQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YMV-00Awm0-Ep; Mon, 19 Jul 2021 18:51:31 +0000 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLA-00AwNi-ET for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:09 +0000 Received: by mail-yb1-xb4a.google.com with SMTP id p63-20020a25d8420000b029055bc6fd5e5bso26626491ybg.9 for ; Mon, 19 Jul 2021 11:50:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=6oCR3RsSf0sSKA4Gfkr/K6wh2PtHCE6P4q0EDP+cPOQ=; b=Rs0E1+bX0JUBjrglpBzuz0teVGHiVpojaup2IZr9QAun13XkfiTisT25GYVX1NoBvR UzRc0YoYFejyTD+NvvgfL5FmG9oX3TVhKRUgTwDdBVPtAzS8DGmu6aB9P3s/tvadMZMR 5m8SxRU8nr0Xejaz/2GkzBI48N0FqHDOFWtnKxQdBCLNBV43jgo9exKLvTaW5+YP5ZJS Co9syFELKWorNMnweipBOlkAcub0Zy5XNqGL2lTwRA5NBAGOITkbcPUpdAUXT8DhO9qI hEbacZA0GlO5zGuzUC32kZ8IzOlhMu6+b9qzqnfy+yQ08JjjNy0F4itRMmM15clo7efV QO9g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=6oCR3RsSf0sSKA4Gfkr/K6wh2PtHCE6P4q0EDP+cPOQ=; b=rfSRnIuZ267LH9I84nAhAEsgkdemC6iAAfSKbwDVCDBWo5i2Kyk9EhMKSZT1S9FW2I rARG16Ol1BXZDqzaRcZPphm6YrRqVz9ItNJRLzgGExiJJ75kzVX9jS831ayFnP9rY3hi DxxQ95iIwmo0/GI6NCWsxZnCfWYxefm9YSks5P90jBNMcTfgu6UbwefSfSe6tUf8HJAk FK5pFQU5l2uHkd4QNVwmXrjFoA/4WpIddxpR3kf+DqzIttOp9fZ7Ug2Y9QxsdvHXDRDj pKZhyDHgbQGkpY70MnhqcVq9VTJ21JTRyCdfcGBNk3BZfwvWQXPfBrzyGKhtYPWNtkvh zhkQ== X-Gm-Message-State: AOAM531KdniltDKoIa7ejMx55IhLV82fzShnK1JBQPDC2SQGJp6TV/iL adg56eoU8a+80js4ctGE6o1lu9BCz9w= X-Google-Smtp-Source: ABdhPJz6ewTOkVfIXpWSdRPu0+HzbHh30XCUCUOAHHq2aNWnrTQ8xtbDRSs/M/Bhu1h/TrKSK91soYYMv7A= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a05:6902:1507:: with SMTP id q7mr34231518ybu.326.1626720606644; Mon, 19 Jul 2021 11:50:06 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:43 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-7-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 06/12] selftests: KVM: Add helpers for vCPU device attributes From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115008_516760_CB703D5A X-CRM114-Status: GOOD ( 10.04 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org vCPU file descriptors are abstracted away from test code in KVM selftests, meaning that tests cannot directly access a vCPU's device attributes. Add helpers that tests can use to get at vCPU device attributes. Signed-off-by: Oliver Upton --- .../testing/selftests/kvm/include/kvm_util.h | 9 +++++ tools/testing/selftests/kvm/lib/kvm_util.c | 38 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index a8ac5d52e17b..1b3ef5757819 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -240,6 +240,15 @@ int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, void *val, bool write); +int _vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr); +int vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr); +int _vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val, bool write); +int vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val, bool write); + const char *exit_reason_str(unsigned int exit_reason); void virt_pgd_alloc(struct kvm_vm *vm); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 10a8ed691c66..b595e7dc3fc5 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -2040,6 +2040,44 @@ int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, return ret; } +int _vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + + TEST_ASSERT(vcpu, "nonexistent vcpu id: %d", vcpuid); + + return _kvm_device_check_attr(vcpu->fd, group, attr); +} + +int vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr) +{ + int ret = _vcpu_has_device_attr(vm, vcpuid, group, attr); + + TEST_ASSERT(!ret, "KVM_HAS_DEVICE_ATTR IOCTL failed, rc: %i errno: %i", ret, errno); + return ret; +} + +int _vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val, bool write) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + + TEST_ASSERT(vcpu, "nonexistent vcpu id: %d", vcpuid); + + return _kvm_device_access(vcpu->fd, group, attr, val, write); +} + +int vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val, bool write) +{ + int ret = _vcpu_access_device_attr(vm, vcpuid, group, attr, val, write); + + TEST_ASSERT(!ret, "KVM_SET|GET_DEVICE_ATTR IOCTL failed, rc: %i errno: %i", ret, errno); + return ret; +} + /* * VM Dump * From patchwork Mon Jul 19 18:49:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386621 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=-15.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, UNWANTED_LANGUAGE_BODY,USER_AGENT_GIT autolearn=unavailable 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 60B8CC07E9B for ; Mon, 19 Jul 2021 18:54:35 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 2DA0E6108B for ; Mon, 19 Jul 2021 18:54:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2DA0E6108B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=lIQyN68li6IQxQBiyy3HinCeZyvYaENh6CegxV+MVZc=; b=so38o3fCTUAj+G5oGWHFKDv1Xz N835MKOitpQPo1+s4SjPYiAiX8S2lYtkQCAx4oXFcs1A4uKl5X26cJkrVswPBnemQJQBmHhSbuZgg KoUfegbZTZOeRQlSvl051/LUvRK1BkXqzC6AlWGpMCW6VCFMxRhHjQ70aJgr/qTwaF4NmQYsKTBnV HrJgKMWyi3qer20kPTq25qy+6aeKnuu0zvT1zNBx4IR6UGlkPjWPYqtmq7BNJPQGgrr1Z2S3SkBym HOqF3b/g8Jkgs8JPZgqcYwPTj5orVlPMl+IefHjzOZNWNkLP9UWIG+o58WReFaXuzrX8aZJ9hnsy6 +X+Nc51g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YMn-00AwuK-LX; Mon, 19 Jul 2021 18:51:49 +0000 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLB-00AwOE-1U for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:10 +0000 Received: by mail-yb1-xb4a.google.com with SMTP id l16-20020a25cc100000b0290558245b7eabso26771304ybf.10 for ; Mon, 19 Jul 2021 11:50:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=OVtBdE4SEQDS3BmRMBT7w6wSDOiGdRy1W//HIPm5dvA=; b=EW2fQbfqHYsIqRVs3pX7Adhz9hhvj9SG3BAfaIYoZid9btw1UIxZ9gYTgeZz8Rqx7e bQLw3TIO6uWVVB+5GOItAXVAK6wUdkh7EdPZdgropcpQKYYW+gvVvzl8vzlqJkAOmmdP MI/tD7TzZaztphS7rpqmtxLfO0v6xiwX5i/9EG6ydwSx/ut+qE1f+DsGaWv9zvksbVbx oIjlrny3DnTYJD+9E2xtggmeFaOKmgu4e3WG6r71+xFA22XW9CR0o71jrWrkkt7uugsn jrIcCqUUcPokDMXqhlr+/GZc9vTBUOelJLqaPESJR6zX0nk4fppW0r5KaLdKPTImvu6C 4xlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=OVtBdE4SEQDS3BmRMBT7w6wSDOiGdRy1W//HIPm5dvA=; b=VYbTo7z7fjdx3XG2f3pC7mxW/fl3tAkQsetWoATzbtB1NXEY8m2Q56UzbK7lJarqQz wH79P+uW6iMHJZ6B7MqOb0iRz0PiLnqWkUyj023d5ty3h/dt03g44ocvyb7rZusBoSC1 EWoMNHGix/3MTTQws9wfQ79wZY+KeEfmOXFHXky4Ff7Uae+eBQVZZoXNdRgT5CHugDRZ PB+NAMXOxl0NybjMpL2leU8LejkC5vpaHMxZuLqve9ETOvFSKzyRJxY+/dC53CVKlKQp ND6BQECtl91XLtnAyzsCLocBUdh4o1t6mHDzQ+UAe56IKVlGBPR6onDeu/F8MZzitN5y nruQ== X-Gm-Message-State: AOAM533iiw+A6WZF4CMV18InRW7+CiyKRPC1rwbDLec8yvbiqvkdrmxi D6emvkABKk1FKMhqVb8eBreAwtV+F2Y= X-Google-Smtp-Source: ABdhPJzuJjdG9Og5yhMZy1iwK0kp/5F8tiABSZCsSVX4UgMjLLzSFgiISZgLj1QZUOaWEH1viM3K8GEwKmk= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a25:ac8f:: with SMTP id x15mr34298007ybi.36.1626720607693; Mon, 19 Jul 2021 11:50:07 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:44 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-8-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 07/12] selftests: KVM: Introduce system counter offset test From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115009_149206_95352B97 X-CRM114-Status: GOOD ( 18.29 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Introduce a KVM selftest to verify that userspace manipulation of the TSC (via the new vCPU attribute) results in the correct behavior within the guest. Signed-off-by: Oliver Upton --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../kvm/system_counter_offset_test.c | 133 ++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 tools/testing/selftests/kvm/system_counter_offset_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index d0877d01e771..2752813d5090 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -50,3 +50,4 @@ /set_memory_region_test /steal_time /kvm_binary_stats_test +/system_counter_offset_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index f7e24f334c6e..7bf2e5fb1d5a 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -83,6 +83,7 @@ TEST_GEN_PROGS_x86_64 += memslot_perf_test TEST_GEN_PROGS_x86_64 += set_memory_region_test TEST_GEN_PROGS_x86_64 += steal_time TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test +TEST_GEN_PROGS_x86_64 += system_counter_offset_test TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c new file mode 100644 index 000000000000..7e9015770759 --- /dev/null +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021, Google LLC. + * + * Tests for adjusting the system counter from userspace + */ +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#define VCPU_ID 0 + +#ifdef __x86_64__ + +struct test_case { + uint64_t tsc_offset; +}; + +static struct test_case test_cases[] = { + { 0 }, + { 180 * NSEC_PER_SEC }, + { -180 * NSEC_PER_SEC }, +}; + +static void check_preconditions(struct kvm_vm *vm) +{ + if (!_vcpu_has_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET)) + return; + + print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test"); + exit(KSFT_SKIP); +} + +static void setup_system_counter(struct kvm_vm *vm, struct test_case *test) +{ + vcpu_access_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET, &test->tsc_offset, true); +} + +static uint64_t guest_read_system_counter(struct test_case *test) +{ + return rdtsc(); +} + +static uint64_t host_read_guest_system_counter(struct test_case *test) +{ + return rdtsc() + test->tsc_offset; +} + +#else /* __x86_64__ */ + +#error test not implemented for this architecture! + +#endif + +#define GUEST_SYNC_CLOCK(__stage, __val) \ + GUEST_SYNC_ARGS(__stage, __val, 0, 0, 0) + +static void guest_main(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(test_cases); i++) { + struct test_case *test = &test_cases[i]; + + GUEST_SYNC_CLOCK(i, guest_read_system_counter(test)); + } + + GUEST_DONE(); +} + +static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end) +{ + uint64_t obs = uc->args[2]; + + TEST_ASSERT(start <= obs && obs <= end, + "unexpected system counter value: %"PRIu64" expected range: [%"PRIu64", %"PRIu64"]", + obs, start, end); + + pr_info("system counter value: %"PRIu64" expected range [%"PRIu64", %"PRIu64"]\n", + obs, start, end); +} + +static void handle_abort(struct ucall *uc) +{ + TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], + __FILE__, uc->args[1]); +} + +static void enter_guest(struct kvm_vm *vm) +{ + uint64_t start, end; + struct ucall uc; + int i; + + for (i = 0; i < ARRAY_SIZE(test_cases); i++) { + struct test_case *test = &test_cases[i]; + + setup_system_counter(vm, test); + start = host_read_guest_system_counter(test); + vcpu_run(vm, VCPU_ID); + end = host_read_guest_system_counter(test); + + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_SYNC: + handle_sync(&uc, start, end); + break; + case UCALL_ABORT: + handle_abort(&uc); + return; + case UCALL_DONE: + return; + } + } +} + +int main(void) +{ + struct kvm_vm *vm; + + vm = vm_create_default(VCPU_ID, 0, guest_main); + check_preconditions(vm); + ucall_init(vm, NULL); + + enter_guest(vm); + kvm_vm_free(vm); +} From patchwork Mon Jul 19 18:49:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386623 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 520E5C07E95 for ; Mon, 19 Jul 2021 18:55:02 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 14CFE6108B for ; Mon, 19 Jul 2021 18:55:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 14CFE6108B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=Yc3rQ6IkVyj63O35ngu4VDf20kyfGQYMNvtZVfHfqV0=; b=rELKWp+ER1qtG7oisRlggQGpfd DaOk/8XV2tkI2Xx+o7XVTpIvDpADOJDyyNxPL3SMDXLkfdKEf/UfiEZm+4+X7PmPWiaz5y88Ay69p dsudQuTVWh2CSlDqu6ZIpX2BRg3VJVIX1vmQPeSI5p/d2NI9LBsgpUlC9yESwrHT0T0ERiXCPf+yj nwqg5UEzVJ48HJRtw9w9us2tdUptI3CI01CS10FfDXiZnefgFzh0FcpHUv4vZPpXNV/63DfC+znlI ar9rGMNgy7kAkS8s5HNDl39rMvv8bCqVZGgH43wI8XrUgrPvLJ2VTxfUn3bzZUhYR1teo4YZT6ZBv uyawfWYA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YNI-00Ax95-LU; Mon, 19 Jul 2021 18:52:20 +0000 Received: from mail-il1-x149.google.com ([2607:f8b0:4864:20::149]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLC-00AwOi-Aw for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:12 +0000 Received: by mail-il1-x149.google.com with SMTP id w2-20020a056e0213e2b029020f555eb3c6so11315754ilj.1 for ; Mon, 19 Jul 2021 11:50:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=92yThg6uO5wYmeILOZOePwh93S5XAe0V6zbbybcWJO0=; b=i8aV3pLEUHpV8nXWQejniH7FEzLP8jg949SwENv5zTVoiJGTZd5TwY/1w91ERZrox0 dlN3HwtTO31IwGn6e/B3TuSCOQQm7dKyNiUV40v7hxEjbFWEcyRcZxC168KOP6k1/OfS jxKYpIBm3d2p9W8ifhUVEwp1lD83DfArX3ITyaWijicrxxCBJMTO7Fi5HTNoxzRWdCeb EE+WfmCQTV60LLuIRSFP9gaxAN7buL4cIwzvgC6gcZfzZ3hKUE+R4RsZmIWW/axj9le0 HQjD41G7SS0PeezOqVyGly61uUTLoGTrnjv0d+tQNKIRhIkJ8oBIss8deXzS95QsbtGr sc9g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=92yThg6uO5wYmeILOZOePwh93S5XAe0V6zbbybcWJO0=; b=kuyMutb6hxRYVybHROJfLNNFpvJWxGv5/OAXedzmOfQmiHkQ9fxFty+7sYZgMPG6qX DYYqM1wArre/m0hNkSaVh5y1+L513RDC9vR/Wz1uN3RPxU1z7penhmwSP+Sbpew1kZoK jgz4lJmz5eYuWDQFsql41eDlY0Ekf6uEPewcq89jAvlADbNx8bMis8F3o2bvU+68wxo7 HWMkANxpg3QxGMj0NQ8IuwXYnrYpq0owz/d+vtSCCSmPzcZoxCFNtpf7xLdWCE7W496g 96d25XpjDCHEvUjlmliXAfkoItI+VqFKUyxU5HihNV91fQGHmB1AvJ8bP3A/XOvuOQ+q BXNg== X-Gm-Message-State: AOAM533f9gy0KLnx8O8dgROToIA7aHW+UU8BEM0SoD3jlgYP/nRRiEQx F1cl0uaOL/NsMinY+YXesYjH8V8l0J4= X-Google-Smtp-Source: ABdhPJyUcgnGwNxKx/wbpDMOBmF7XheuCQzfCiRREH/w9XfYAuChqvaYmfRLxURgaVhKUn8EYU62XV0YxJ8= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a92:ab0a:: with SMTP id v10mr3181975ilh.17.1626720608785; Mon, 19 Jul 2021 11:50:08 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:45 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-9-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 08/12] KVM: arm64: Allow userspace to configure a vCPU's virtual offset From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115010_449280_4FF0E8D9 X-CRM114-Status: GOOD ( 17.87 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add a new vCPU attribute that allows userspace to directly manipulate the virtual counter-timer offset. Exposing such an interface allows for the precise migration of guest virtual counter-timers, as it is an indepotent interface. Uphold the existing behavior of writes to CNTVOFF_EL2 for this new interface, wherein a write to a single vCPU is broadcasted to all vCPUs within a VM. Signed-off-by: Oliver Upton Reviewed-by: Andrew Jones --- Documentation/virt/kvm/devices/vcpu.rst | 22 ++++++++ arch/arm64/include/uapi/asm/kvm.h | 1 + arch/arm64/kvm/arch_timer.c | 68 ++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/kvm/devices/vcpu.rst index b46d5f742e69..7b57cba3416a 100644 --- a/Documentation/virt/kvm/devices/vcpu.rst +++ b/Documentation/virt/kvm/devices/vcpu.rst @@ -139,6 +139,28 @@ configured values on other VCPUs. Userspace should configure the interrupt numbers on at least one VCPU after creating all VCPUs and before running any VCPUs. +2.2. ATTRIBUTE: KVM_ARM_VCPU_TIMER_OFFSET_VTIMER +------------------------------------------------ + +:Parameters: Pointer to a 64-bit unsigned counter-timer offset. + +Returns: + + ======= ====================================== + -EFAULT Error reading/writing the provided + parameter address + -ENXIO Attribute not supported + ======= ====================================== + +Specifies the guest's virtual counter-timer offset from the host's +virtual counter. The guest's virtual counter is then derived by +the following equation: + + guest_cntvct = host_cntvct - KVM_ARM_VCPU_TIMER_OFFSET_VTIMER + +KVM does not allow the use of varying offset values for different vCPUs; +the last written offset value will be broadcasted to all vCPUs in a VM. + 3. GROUP: KVM_ARM_VCPU_PVTIME_CTRL ================================== diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index b3edde68bc3e..008d0518d2b1 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -365,6 +365,7 @@ struct kvm_arm_copy_mte_tags { #define KVM_ARM_VCPU_TIMER_CTRL 1 #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 +#define KVM_ARM_VCPU_TIMER_OFFSET_VTIMER 2 #define KVM_ARM_VCPU_PVTIME_CTRL 2 #define KVM_ARM_VCPU_PVTIME_IPA 0 diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 3df67c127489..d2b1b13af658 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -1305,7 +1305,7 @@ static void set_timer_irqs(struct kvm *kvm, int vtimer_irq, int ptimer_irq) } } -int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) +int kvm_arm_timer_set_attr_irq(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { int __user *uaddr = (int __user *)(long)attr->addr; struct arch_timer_context *vtimer = vcpu_vtimer(vcpu); @@ -1338,7 +1338,39 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) return 0; } -int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) +int kvm_arm_timer_set_attr_offset(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) +{ + u64 __user *uaddr = (u64 __user *)(long)attr->addr; + u64 offset; + + if (get_user(offset, uaddr)) + return -EFAULT; + + switch (attr->attr) { + case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: + update_vtimer_cntvoff(vcpu, offset); + break; + default: + return -ENXIO; + } + + return 0; +} + +int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) +{ + switch (attr->attr) { + case KVM_ARM_VCPU_TIMER_IRQ_VTIMER: + case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: + return kvm_arm_timer_set_attr_irq(vcpu, attr); + case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: + return kvm_arm_timer_set_attr_offset(vcpu, attr); + } + + return -ENXIO; +} + +int kvm_arm_timer_get_attr_irq(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { int __user *uaddr = (int __user *)(long)attr->addr; struct arch_timer_context *timer; @@ -1359,11 +1391,43 @@ int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) return put_user(irq, uaddr); } +int kvm_arm_timer_get_attr_offset(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) +{ + u64 __user *uaddr = (u64 __user *)(long)attr->addr; + struct arch_timer_context *timer; + u64 offset; + + switch (attr->attr) { + case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: + timer = vcpu_vtimer(vcpu); + break; + default: + return -ENXIO; + } + + offset = timer_get_offset(timer); + return put_user(offset, uaddr); +} + +int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) +{ + switch (attr->attr) { + case KVM_ARM_VCPU_TIMER_IRQ_VTIMER: + case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: + return kvm_arm_timer_get_attr_irq(vcpu, attr); + case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: + return kvm_arm_timer_get_attr_offset(vcpu, attr); + } + + return -ENXIO; +} + int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { switch (attr->attr) { case KVM_ARM_VCPU_TIMER_IRQ_VTIMER: case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: + case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: return 0; } From patchwork Mon Jul 19 18:49:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386625 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 B1656C07E95 for ; Mon, 19 Jul 2021 18:55:31 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 6FC1160232 for ; Mon, 19 Jul 2021 18:55:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6FC1160232 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=4mfJyAjemZKdljFzgIBj1KbRwvds3FOdrjKPx2RX/X8=; b=oQYJ4riZIwN+9FuxffsZP/n9To U254GJ/f3XldH3x9R/Zgb1z+eiizPUszJ/o7s5NIr8Zo3y3jqqzmCsaguFqTQW6zGVLVS7XAKaAUB 5Up4zp9+r3xn4Rt/E/i1GYOypDrLo1WZBqFBB5xZkC7+XWdpyE4S4+zfeZHAtaDb60zfJLG9JsZ6t H+pCoPsgJkro+HW2DchEBM65Z3Ty/dXQJs7Zl/IPvVouFRDUTFB7PuOi97gUvqzZmRjIoKuapaQX3 ge4o+94jO9rWge4p4vuBpFoaT1uw9lZz/qjdizL+syiMUTTjLUFDlYDBfpaJoLYrpnqNNhQoQybl5 HJgvN1Eg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YNk-00AxLh-CP; Mon, 19 Jul 2021 18:52:48 +0000 Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLD-00AwPM-8X for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:12 +0000 Received: by mail-yb1-xb49.google.com with SMTP id k11-20020a056902070bb029055a2303fc2dso26770290ybt.11 for ; Mon, 19 Jul 2021 11:50:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=fvZeuFhawOmKlopyx148igwfDYKa3P5KdvR9ULck4mI=; b=TeX8LKON226q4jIrJlx/WftDAJi2pY1OEqo3ZYuEZIlxxatjAaGewz4EyaxEKG/xTD MGQgvyGFusH9M/ADz/wyUqEaAavEcB2Bbyv56OseAIZOSxSIioZgaF83g7FDtp2qmXvG BZYpoS4ToO9PSDn+w18PdbkmmCL/tls1lwW4aKbY1GuW9ZH+dzE+T2Y4jol98qPwQv/m Y6ewFtdqJnknjFuL3jhd4DOBAkRj8WhzqFi8tyELP07VXyLkB0aFG+CzQ1Pavc3ZV77J 9hmai6MbVT/A0q5jl7VxBr20c/onp/SoQzY3g+mi/e/IFVyYlRUMHXCGbhgieitI7FoX 3ezA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=fvZeuFhawOmKlopyx148igwfDYKa3P5KdvR9ULck4mI=; b=EMZM8T+o/0QCUb5ONI4BxddcPZqIYV7fxRbbvf+ZeKF9wCbmU8swQtG4ZA10qTcfPP iqaZr1vPg1uDFMDj/IS/Q5b7mgwhU58YpH1n6XeJY0fccnyXpBuI5gAchvc5mUZop6tb KfdxBFya/eCa7YLYAPI6YDr+ujmwLGoYuhH/jpIfiboimOTN1cngVytrRh0zYV++xmzw Pfriy97ZRyX0Fv9WbBOzZEl4cYzwppr9Lb5pKBn5RwQT2sankxSQ6sPlAbFddiu8E/vA xmzQxnCLvxnkV0TqJpaV1UlkWokrQH7zepRNhTLbl4uSldfAY4DQMp5QL66tVkjUMc20 aPcQ== X-Gm-Message-State: AOAM5317hCz4x46Anu41KLjjFqwrEmQiaJ1VlPjfj40HzRSZsF9h8MmA y2qQ1iWe/WuRjtb1cQBOv0QDlYbt7J4= X-Google-Smtp-Source: ABdhPJyapdJfkrJhAGeUmrTv3NNW6zX92Vh5gia+jhMDC3UybLIWyyFrENJ2cGQn91HP0UTm8SnlfJC2tQc= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a25:a369:: with SMTP id d96mr33538392ybi.463.1626720609797; Mon, 19 Jul 2021 11:50:09 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:46 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-10-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 09/12] selftests: KVM: Add support for aarch64 to system_counter_offset_test From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115011_359414_3FBD00CA X-CRM114-Status: GOOD ( 15.74 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org KVM/arm64 now allows userspace to adjust the guest virtual counter-timer via a vCPU device attribute. Test that changes to the virtual counter-timer offset result in the correct view being presented to the guest. Signed-off-by: Oliver Upton Reviewed-by: Andrew Jones --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/aarch64/processor.h | 12 +++++ .../kvm/system_counter_offset_test.c | 54 ++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 7bf2e5fb1d5a..d89908108c97 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -96,6 +96,7 @@ TEST_GEN_PROGS_aarch64 += kvm_page_table_test TEST_GEN_PROGS_aarch64 += set_memory_region_test TEST_GEN_PROGS_aarch64 += steal_time TEST_GEN_PROGS_aarch64 += kvm_binary_stats_test +TEST_GEN_PROGS_aarch64 += system_counter_offset_test TEST_GEN_PROGS_s390x = s390x/memop TEST_GEN_PROGS_s390x += s390x/resets diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index 27dc5c2e56b9..3168cdbae6ee 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -129,4 +129,16 @@ void vm_install_sync_handler(struct kvm_vm *vm, #define isb() asm volatile("isb" : : : "memory") +static inline uint64_t read_cntvct_ordered(void) +{ + uint64_t r; + + __asm__ __volatile__("isb\n\t" + "mrs %0, cntvct_el0\n\t" + "isb\n\t" + : "=r"(r)); + + return r; +} + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index 7e9015770759..88ad997f5b69 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -53,7 +53,59 @@ static uint64_t host_read_guest_system_counter(struct test_case *test) return rdtsc() + test->tsc_offset; } -#else /* __x86_64__ */ +#elif __aarch64__ /* __x86_64__ */ + +enum arch_counter { + VIRTUAL, +}; + +struct test_case { + enum arch_counter counter; + uint64_t offset; +}; + +static struct test_case test_cases[] = { + { .counter = VIRTUAL, .offset = 0 }, + { .counter = VIRTUAL, .offset = 180 * NSEC_PER_SEC }, + { .counter = VIRTUAL, .offset = -180 * NSEC_PER_SEC }, +}; + +static void check_preconditions(struct kvm_vm *vm) +{ + if (!_vcpu_has_device_attr(vm, VCPU_ID, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_OFFSET_VTIMER)) + return; + + print_skip("KVM_ARM_VCPU_TIMER_OFFSET_VTIMER not supported; skipping test"); + exit(KSFT_SKIP); +} + +static void setup_system_counter(struct kvm_vm *vm, struct test_case *test) +{ + vcpu_access_device_attr(vm, VCPU_ID, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_OFFSET_VTIMER, &test->offset, + true); +} + +static uint64_t guest_read_system_counter(struct test_case *test) +{ + switch (test->counter) { + case VIRTUAL: + return read_cntvct_ordered(); + default: + GUEST_ASSERT(0); + } + + /* unreachable */ + return 0; +} + +static uint64_t host_read_guest_system_counter(struct test_case *test) +{ + return read_cntvct_ordered() - test->offset; +} + +#else /* __aarch64__ */ #error test not implemented for this architecture! From patchwork Mon Jul 19 18:49:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386627 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 4854AC07E95 for ; Mon, 19 Jul 2021 18:56:10 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 0AD2660232 for ; Mon, 19 Jul 2021 18:56:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0AD2660232 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=ycFwpcKjThvESmnOgTvp6GhwXW6mpFOv1RfkquxzfBQ=; b=dz/SKN01yB30sf7QXUY90aru6F 3fp8o0xBcK5DrUDPOUfwtwDdVuc492zTtfh1/Ujwsa6yEeVs1dwnhV5DDBMMbKGhpklw3IhBx6xL2 YEV5L4872zJLP1p71JdfntzjKYAxPfVLn8ECwnI6MPAVM/fZJl+gJ2Caxsq85DrEzBJkQHhsvjwyV o6Vw/gYwqgmfT/tF5TTWC1T2BW5vzKUw7piaflEpVW+w/X//sv2AK8DLdzlIDQ83K1mPWaCcwjdym wxvZXnupbdflmhad4Pl/KjZJtTJbzHygqCMMtOBj8rmFlr1x0WZP5ZivKJMLG/NU7wz9AbcU64vbj PCifZiuA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YOU-00AxhM-AG; Mon, 19 Jul 2021 18:53:35 +0000 Received: from mail-io1-xd49.google.com ([2607:f8b0:4864:20::d49]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLE-00AwPx-BE for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:14 +0000 Received: by mail-io1-xd49.google.com with SMTP id c25-20020a6bec190000b02905393057ad92so1737434ioh.20 for ; Mon, 19 Jul 2021 11:50:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=pjZrc+Mi3sbS5bI+tsGsqxmNKdHz4hcCStvsY2HBCP0=; b=ZsfWA7ksEOSjR9yWXf8VUI4vae4LLpdLIqAYD4AXrrGqDdlVxwRQrk+Ps0Aq8IVorH 4egeWpn6iokCPBScSVwrj5dEubHqYv5Su8sIFXZV0B61TiHcuzpHhHPZMyyuK3h2Y+PB T7z6KCSGv33JT8LCq2xds6OkwVhwrWTwQHaIVr7Qcf1oPHEW07WXl/qMO/VnSY4ogI5S EIqAsevUNtcaEOeeIJcn0AMDXLfNtgxvNj9Jt04lGVxOH5mawafMsafOrxFm9tuY7X5k aVWlyQBGLzbZMCF8fhSmhKhoSRXCuFbbF2/afm9bDWkf4aIXUK9Fi4GSPL3G3DNUU/6l h+zw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=pjZrc+Mi3sbS5bI+tsGsqxmNKdHz4hcCStvsY2HBCP0=; b=pk4bYnHDq1Bo2KGVX2I8Mg2rv2xn77IS04rhestguBz8oy6d71lMx7nOEzwIcqDsC/ 4fMq+ScInM9S1gTJpmZljDS4i2h/nIlQ/OXprnHS9yBtpf89gi7rmFiJBHJN9z5LW8Av M1fgbETgFswheWMABPcxKg8DVd1NaJIFtHz54T4NTnas4aDzuKeqxvooPcVgPGgcs7xx 5Ef8w71bUB0wBvQ+fkCnjZgwsyBpVoQqwn+uhIZu/WmIweoGDME6pZfap1s0m3EAcq9+ o8SrHsHMq8bd7lEdvqPmSDvi083A28EwYP/HaP6/5vEavTlj4akQrVKylEhk52S7IKEc 2BAw== X-Gm-Message-State: AOAM530JZsTsbAu+WRNpNiOvoCzhC1ptdw4Oy4ZSMLYY9i/PGcoQsJKa Fh1RuhuefUwE7sdfApm3/lQmWaSTQWo= X-Google-Smtp-Source: ABdhPJx0RrIgPqbzoe6/yrgR+/w3ttY4trmYHrLPuWvoKNJE1lnVSVZiW02JncD4gQJotfVnk98SNZgu8Yc= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a92:b003:: with SMTP id x3mr18117436ilh.93.1626720610823; Mon, 19 Jul 2021 11:50:10 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:47 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-11-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 10/12] KVM: arm64: Provide userspace access to the physical counter offset From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115012_475745_586ECB5B X-CRM114-Status: GOOD ( 30.78 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Presently, KVM provides no facilities for correctly migrating a guest that depends on the physical counter-timer. While most guests (barring NV, of course) should not depend on the physical counter-timer, an operator may still wish to provide a consistent view of the physical counter-timer across migrations. Provide userspace with a new vCPU attribute to modify the guest physical counter-timer offset. Since the base architecture doesn't provide a physical counter-timer offset register, emulate the correct behavior by trapping accesses to the physical counter-timer whenever the offset value is non-zero. Uphold the same behavior as CNTVOFF_EL2 and broadcast the physical offset to all vCPUs whenever written. This guarantees that the counter-timer we provide the guest remains architectural, wherein all views of the counter-timer are consistent across vCPUs. Reconfigure timer traps for VHE on every guest entry, as different VMs will now have different traps enabled. Enable physical counter traps for nVHE whenever the offset is nonzero (we already trap physical timer registers in nVHE). FEAT_ECV provides a guest physical counter-timer offset register (CNTPOFF_EL2), but ECV-enabled hardware is nonexistent at the time of writing so support for it was elided for the sake of the author :) Signed-off-by: Oliver Upton --- Documentation/virt/kvm/devices/vcpu.rst | 22 ++++++++++ arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/include/asm/kvm_hyp.h | 2 - arch/arm64/include/asm/sysreg.h | 1 + arch/arm64/include/uapi/asm/kvm.h | 1 + arch/arm64/kvm/arch_timer.c | 50 ++++++++++++++++++++--- arch/arm64/kvm/arm.c | 4 +- arch/arm64/kvm/hyp/include/hyp/switch.h | 23 +++++++++++ arch/arm64/kvm/hyp/include/hyp/timer-sr.h | 26 ++++++++++++ arch/arm64/kvm/hyp/nvhe/switch.c | 2 - arch/arm64/kvm/hyp/nvhe/timer-sr.c | 21 +++++----- arch/arm64/kvm/hyp/vhe/timer-sr.c | 27 ++++++++++++ include/kvm/arm_arch_timer.h | 2 - 13 files changed, 158 insertions(+), 24 deletions(-) create mode 100644 arch/arm64/kvm/hyp/include/hyp/timer-sr.h diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/kvm/devices/vcpu.rst index 7b57cba3416a..a8547ce09b47 100644 --- a/Documentation/virt/kvm/devices/vcpu.rst +++ b/Documentation/virt/kvm/devices/vcpu.rst @@ -161,6 +161,28 @@ the following equation: KVM does not allow the use of varying offset values for different vCPUs; the last written offset value will be broadcasted to all vCPUs in a VM. +2.3. ATTRIBUTE: KVM_ARM_VCPU_TIMER_OFFSET_PTIMER +------------------------------------------------ + +:Parameters: Pointer to a 64-bit unsigned counter-timer offset. + +Returns: + + ======= ====================================== + -EFAULT Error reading/writing the provided + parameter address + -ENXIO Attribute not supported + ======= ====================================== + +Specifies the guest's physical counter-timer offset from the host's +virtual counter. The guest's physical counter is then derived by +the following equation: + + guest_cntpct = host_cntvct - KVM_ARM_VCPU_TIMER_OFFSET_PTIMER + +KVM does not allow the use of varying offset values for different vCPUs; +the last written offset value will be broadcasted to all vCPUs in a VM. + 3. GROUP: KVM_ARM_VCPU_PVTIME_CTRL ================================== diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 41911585ae0c..de92fa678924 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -204,6 +204,7 @@ enum vcpu_sysreg { SP_EL1, SPSR_EL1, + CNTPOFF_EL2, CNTVOFF_EL2, CNTV_CVAL_EL0, CNTV_CTL_EL0, diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index 9d60b3006efc..01eb3864e50f 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -65,10 +65,8 @@ void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if); void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if); int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu); -#ifdef __KVM_NVHE_HYPERVISOR__ void __timer_enable_traps(struct kvm_vcpu *vcpu); void __timer_disable_traps(struct kvm_vcpu *vcpu); -#endif #ifdef __KVM_NVHE_HYPERVISOR__ void __sysreg_save_state_nvhe(struct kvm_cpu_context *ctxt); diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 347ccac2341e..243e36c088e7 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -505,6 +505,7 @@ #define SYS_AMEVCNTR0_MEM_STALL SYS_AMEVCNTR0_EL0(3) #define SYS_CNTFRQ_EL0 sys_reg(3, 3, 14, 0, 0) +#define SYS_CNTPCT_EL0 sys_reg(3, 3, 14, 0, 1) #define SYS_CNTP_TVAL_EL0 sys_reg(3, 3, 14, 2, 0) #define SYS_CNTP_CTL_EL0 sys_reg(3, 3, 14, 2, 1) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 008d0518d2b1..3e42c72d4c68 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -366,6 +366,7 @@ struct kvm_arm_copy_mte_tags { #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 #define KVM_ARM_VCPU_TIMER_OFFSET_VTIMER 2 +#define KVM_ARM_VCPU_TIMER_OFFSET_PTIMER 3 #define KVM_ARM_VCPU_PVTIME_CTRL 2 #define KVM_ARM_VCPU_PVTIME_IPA 0 diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index d2b1b13af658..05ec385e26b5 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -89,7 +89,10 @@ static u64 timer_get_offset(struct arch_timer_context *ctxt) switch(arch_timer_ctx_index(ctxt)) { case TIMER_VTIMER: return __vcpu_sys_reg(vcpu, CNTVOFF_EL2); + case TIMER_PTIMER: + return __vcpu_sys_reg(vcpu, CNTPOFF_EL2); default: + WARN_ONCE(1, "unrecognized timer index %ld", arch_timer_ctx_index(ctxt)); return 0; } } @@ -134,6 +137,9 @@ static void timer_set_offset(struct arch_timer_context *ctxt, u64 offset) case TIMER_VTIMER: __vcpu_sys_reg(vcpu, CNTVOFF_EL2) = offset; break; + case TIMER_PTIMER: + __vcpu_sys_reg(vcpu, CNTPOFF_EL2) = offset; + break; default: WARN(offset, "timer %ld\n", arch_timer_ctx_index(ctxt)); } @@ -144,9 +150,24 @@ u64 kvm_phys_timer_read(void) return timecounter->cc->read(timecounter->cc); } +static bool timer_emulation_required(struct arch_timer_context *ctx) +{ + enum kvm_arch_timers timer = arch_timer_ctx_index(ctx); + + switch (timer) { + case TIMER_VTIMER: + return false; + case TIMER_PTIMER: + return timer_get_offset(ctx); + default: + WARN_ONCE(1, "unrecognized timer index %ld\n", timer); + return false; + } +} + static void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map) { - if (has_vhe()) { + if (has_vhe() && !timer_emulation_required(vcpu_ptimer(vcpu))) { map->direct_vtimer = vcpu_vtimer(vcpu); map->direct_ptimer = vcpu_ptimer(vcpu); map->emul_ptimer = NULL; @@ -747,8 +768,9 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu) return 0; } -/* Make the updates of cntvoff for all vtimer contexts atomic */ -static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff) +/* Make the updates of offset for all timer contexts atomic */ +static void update_timer_offset(struct kvm_vcpu *vcpu, + enum kvm_arch_timers timer, u64 offset) { int i; struct kvm *kvm = vcpu->kvm; @@ -756,16 +778,26 @@ static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff) mutex_lock(&kvm->lock); kvm_for_each_vcpu(i, tmp, kvm) - timer_set_offset(vcpu_vtimer(tmp), cntvoff); + timer_set_offset(vcpu_get_timer(tmp, timer), offset); /* * When called from the vcpu create path, the CPU being created is not * included in the loop above, so we just set it here as well. */ - timer_set_offset(vcpu_vtimer(vcpu), cntvoff); + timer_set_offset(vcpu_get_timer(vcpu, timer), offset); mutex_unlock(&kvm->lock); } +static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff) +{ + update_timer_offset(vcpu, TIMER_VTIMER, cntvoff); +} + +static void update_ptimer_cntpoff(struct kvm_vcpu *vcpu, u64 cntpoff) +{ + update_timer_offset(vcpu, TIMER_PTIMER, cntpoff); +} + void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) { struct arch_timer_cpu *timer = vcpu_timer(vcpu); @@ -1350,6 +1382,9 @@ int kvm_arm_timer_set_attr_offset(struct kvm_vcpu *vcpu, struct kvm_device_attr case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: update_vtimer_cntvoff(vcpu, offset); break; + case KVM_ARM_VCPU_TIMER_OFFSET_PTIMER: + update_ptimer_cntpoff(vcpu, offset); + break; default: return -ENXIO; } @@ -1364,6 +1399,7 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: return kvm_arm_timer_set_attr_irq(vcpu, attr); case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: + case KVM_ARM_VCPU_TIMER_OFFSET_PTIMER: return kvm_arm_timer_set_attr_offset(vcpu, attr); } @@ -1400,6 +1436,8 @@ int kvm_arm_timer_get_attr_offset(struct kvm_vcpu *vcpu, struct kvm_device_attr switch (attr->attr) { case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: timer = vcpu_vtimer(vcpu); + case KVM_ARM_VCPU_TIMER_OFFSET_PTIMER: + timer = vcpu_ptimer(vcpu); break; default: return -ENXIO; @@ -1416,6 +1454,7 @@ int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: return kvm_arm_timer_get_attr_irq(vcpu, attr); case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: + case KVM_ARM_VCPU_TIMER_OFFSET_PTIMER: return kvm_arm_timer_get_attr_offset(vcpu, attr); } @@ -1428,6 +1467,7 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) case KVM_ARM_VCPU_TIMER_IRQ_VTIMER: case KVM_ARM_VCPU_TIMER_IRQ_PTIMER: case KVM_ARM_VCPU_TIMER_OFFSET_VTIMER: + case KVM_ARM_VCPU_TIMER_OFFSET_PTIMER: return 0; } diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index e0b81870ff2a..217f4c6038e8 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1549,9 +1549,7 @@ static void cpu_hyp_reinit(void) cpu_hyp_reset(); - if (is_kernel_in_hyp_mode()) - kvm_timer_init_vhe(); - else + if (!is_kernel_in_hyp_mode()) cpu_init_hyp_mode(); cpu_set_hyp_vector(); diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index e4a2f295a394..c3ae1e0614a2 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -8,6 +8,7 @@ #define __ARM64_KVM_HYP_SWITCH_H__ #include +#include #include #include @@ -113,6 +114,8 @@ static inline void ___activate_traps(struct kvm_vcpu *vcpu) if (cpus_have_final_cap(ARM64_HAS_RAS_EXTN) && (hcr & HCR_VSE)) write_sysreg_s(vcpu->arch.vsesr_el2, SYS_VSESR_EL2); + + __timer_enable_traps(vcpu); } static inline void ___deactivate_traps(struct kvm_vcpu *vcpu) @@ -127,6 +130,8 @@ static inline void ___deactivate_traps(struct kvm_vcpu *vcpu) vcpu->arch.hcr_el2 &= ~HCR_VSE; vcpu->arch.hcr_el2 |= read_sysreg(hcr_el2) & HCR_VSE; } + + __timer_disable_traps(vcpu); } static inline bool __translate_far_to_hpfar(u64 far, u64 *hpfar) @@ -405,6 +410,21 @@ static inline bool __hyp_handle_ptrauth(struct kvm_vcpu *vcpu) return true; } +static inline bool __hyp_handle_counter(struct kvm_vcpu *vcpu) +{ + u32 sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu)); + int rt = kvm_vcpu_sys_get_rt(vcpu); + u64 rv; + + if (sysreg != SYS_CNTPCT_EL0) + return false; + + rv = __timer_read_cntpct(vcpu); + vcpu_set_reg(vcpu, rt, rv); + __kvm_skip_instr(vcpu); + return true; +} + /* * Return true when we were able to fixup the guest exit and should return to * the guest, false when we should restore the host state and return to the @@ -439,6 +459,9 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code) if (*exit_code != ARM_EXCEPTION_TRAP) goto exit; + if (__hyp_handle_counter(vcpu)) + goto guest; + if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) && kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 && handle_tx2_tvm(vcpu)) diff --git a/arch/arm64/kvm/hyp/include/hyp/timer-sr.h b/arch/arm64/kvm/hyp/include/hyp/timer-sr.h new file mode 100644 index 000000000000..0b0d5d1039a4 --- /dev/null +++ b/arch/arm64/kvm/hyp/include/hyp/timer-sr.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 Google LLC + * Author: Oliver Upton + */ + +#ifndef __ARM64_KVM_HYP_TIMER_SR_H__ +#define __ARM64_KVM_HYP_TIMER_SR_H__ + +#include +#include + +#include +#include + +static inline bool __timer_physical_emulation_required(struct kvm_vcpu *vcpu) +{ + return __vcpu_sys_reg(vcpu, CNTPOFF_EL2); +} + +static inline u64 __timer_read_cntpct(struct kvm_vcpu *vcpu) +{ + return read_sysreg(cntpct_el0) - __vcpu_sys_reg(vcpu, CNTPOFF_EL2); +} + +#endif /* __ARM64_KVM_HYP_TIMER_SR_H__ */ diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c index f7af9688c1f7..4a190c932f8c 100644 --- a/arch/arm64/kvm/hyp/nvhe/switch.c +++ b/arch/arm64/kvm/hyp/nvhe/switch.c @@ -217,7 +217,6 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu) __activate_traps(vcpu); __hyp_vgic_restore_state(vcpu); - __timer_enable_traps(vcpu); __debug_switch_to_guest(vcpu); @@ -230,7 +229,6 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu) __sysreg_save_state_nvhe(guest_ctxt); __sysreg32_save_state(vcpu); - __timer_disable_traps(vcpu); __hyp_vgic_save_state(vcpu); __deactivate_traps(vcpu); diff --git a/arch/arm64/kvm/hyp/nvhe/timer-sr.c b/arch/arm64/kvm/hyp/nvhe/timer-sr.c index 9072e71693ba..ebc3f0d0908d 100644 --- a/arch/arm64/kvm/hyp/nvhe/timer-sr.c +++ b/arch/arm64/kvm/hyp/nvhe/timer-sr.c @@ -9,16 +9,13 @@ #include #include +#include void __kvm_timer_set_cntvoff(u64 cntvoff) { write_sysreg(cntvoff, cntvoff_el2); } -/* - * Should only be called on non-VHE systems. - * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe(). - */ void __timer_disable_traps(struct kvm_vcpu *vcpu) { u64 val; @@ -29,20 +26,24 @@ void __timer_disable_traps(struct kvm_vcpu *vcpu) write_sysreg(val, cnthctl_el2); } -/* - * Should only be called on non-VHE systems. - * VHE systems use EL2 timers and configure EL1 timers in kvm_timer_init_vhe(). - */ void __timer_enable_traps(struct kvm_vcpu *vcpu) { u64 val; /* * Disallow physical timer access for the guest - * Physical counter access is allowed */ val = read_sysreg(cnthctl_el2); val &= ~CNTHCTL_EL1PCEN; - val |= CNTHCTL_EL1PCTEN; + + /* + * Disallow physical counter access for the guest if offsetting is + * requested. + */ + if (__timer_physical_emulation_required(vcpu)) + val &= ~CNTHCTL_EL1PCTEN; + else + val |= CNTHCTL_EL1PCTEN; + write_sysreg(val, cnthctl_el2); } diff --git a/arch/arm64/kvm/hyp/vhe/timer-sr.c b/arch/arm64/kvm/hyp/vhe/timer-sr.c index 4cda674a8be6..10506f3ce8a1 100644 --- a/arch/arm64/kvm/hyp/vhe/timer-sr.c +++ b/arch/arm64/kvm/hyp/vhe/timer-sr.c @@ -4,9 +4,36 @@ * Author: Marc Zyngier */ +#include #include +#include void __kvm_timer_set_cntvoff(u64 cntvoff) { write_sysreg(cntvoff, cntvoff_el2); } + +void __timer_enable_traps(struct kvm_vcpu *vcpu) +{ + /* When HCR_EL2.E2H == 1, EL1PCEN nad EL1PCTEN are shifted by 10 */ + u32 cnthctl_shift = 10; + u64 val, mask; + + mask = CNTHCTL_EL1PCEN << cnthctl_shift; + mask |= CNTHCTL_EL1PCTEN << cnthctl_shift; + + val = read_sysreg(cnthctl_el2); + + /* + * VHE systems allow the guest direct access to the EL1 physical + * timer/counter if offsetting isn't requested. + */ + if (__timer_physical_emulation_required(vcpu)) + val &= ~mask; + else + val |= mask; + + write_sysreg(val, cnthctl_el2); +} + +void __timer_disable_traps(struct kvm_vcpu *vcpu) {} diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index 51c19381108c..f24fc435c401 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h @@ -83,8 +83,6 @@ u64 kvm_phys_timer_read(void); void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu); void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu); -void kvm_timer_init_vhe(void); - bool kvm_arch_timer_get_input_level(int vintid); #define vcpu_timer(v) (&(v)->arch.timer_cpu) From patchwork Mon Jul 19 18:49:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386631 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 6EAA6C07E95 for ; Mon, 19 Jul 2021 18:57:58 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 38F0E60232 for ; Mon, 19 Jul 2021 18:57:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 38F0E60232 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=VNGXk/pY1ZxlID+nmEhP4f/k4nr4vn6WrEGPdcyWKz4=; b=iS6jIugbcUYRCWd9BC/Uegud8u 0Jnvv8Nuql59oePD6yICpEIa6aOs821p5MytFKQlXqYTFMrkS0mjpHIYwveEZ6YlMarcfiYPjd+fa KuKOk61kIcRLVjO+fyvxAu8Iec49yq/ZosyEwO/n3FiFEGa/I1g9I7N7Z6vd1cmIdh6hs5F1swef5 cccpacGDw3ck9gerZdd8jWGVOqWNl1monr6OK2oVhRhVJCZNxpf0kCGHP2f1Ba9DS4tIje11GowRk XdM+Xaor4wpygHSOmT1tohaU2BAVLM+96EseOIpIkszfu30EQ4T/N6rIEdedm96NFt4nzYggI9QPl LkqqtxBg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YQb-00Aye7-SG; Mon, 19 Jul 2021 18:55:47 +0000 Received: from mail-oi1-x249.google.com ([2607:f8b0:4864:20::249]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLI-00AwQU-Bd for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:17 +0000 Received: by mail-oi1-x249.google.com with SMTP id l3-20020aca19030000b029025c7e6f8b64so1970424oii.6 for ; Mon, 19 Jul 2021 11:50:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=Js1tkzh0InHJDinhDdW8poSOxRWAClAIrtKK55u0+PE=; b=KUYAhBpQDsMooQkrz7c2zqbWLBcD1F57p/29Oql51TqngGSrTxE+wp2bi7H6WlPEpG 92P89yaUU/AuvB+jJXVMlSvqpqjjr04VSekq6Ex7An/nbaJaaqymAt7A+L4GmNbxWphk O9wNM44lF9ZUF0xacIlsBJ9n4+/rjQLxaNK2o0a4nYI1OeU0BtxMk6oCs6BhobrFEKrv TIYwsaDYVMZ9otssI1HiIuWC4z9qTat04n1lUCMuWtVWz7xek+ilPdS9nkS+NGd1GmiH sB/hX25SAUMnxbw4fILjiZQbUQbB6/H+iD/MltOVRChrpE1OkzQJIE5N8tvygqTbscR6 dPGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Js1tkzh0InHJDinhDdW8poSOxRWAClAIrtKK55u0+PE=; b=ImMWG0ps5qs1AyTx7DHUrJOBeTuJMr4QwFRt+SmFzOgbXuNaBLkr4qCiD0jEnLPhPh gKKvzka6jlzSWJfgLTVxH+6ICfSuLexGOMDpllYHbSytndxDV1Dk3P9NzfH+Thjt3TFS apTKVDPqOWX/cxiP1qXG+etgpFxaBRSRcChXmbcInAU29fCYMDdiGPp7szWWhKV5haPQ A3aqkaMa7lYTnR2Dgp85rDlNsgeo8KNWuPcebJMJz8r/8tIn9AmbYNf55c98PzIunrCn liLfLBbczyfD6vYlLd3l5VN7Web5rgjyKMuhnyZHaAmIN6RQGZNDmeI5P0feYJcamKQF tuxA== X-Gm-Message-State: AOAM532bTJ4AqarxxbPzU6bGElet78hlQHBp4417pHleNVUwFMnvqlrc sYgkO/e5v7909zpfUULNT/6+SGErUkY= X-Google-Smtp-Source: ABdhPJyU/b4AHJqg2AmHxiUKhxVMZZVmOLISQrCNLvElELkpv2SnrsueT4Y05a8t4GjE8ckwmm6/FWbJdVc= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:aca:b682:: with SMTP id g124mr18546043oif.138.1626720611974; Mon, 19 Jul 2021 11:50:11 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:48 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-12-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 11/12] selftests: KVM: Test physical counter offsetting From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115016_455039_310169E9 X-CRM114-Status: GOOD ( 13.56 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Test that userpace adjustment of the guest physical counter-timer results in the correct view of within the guest. Signed-off-by: Oliver Upton Reviewed-by: Andrew Jones --- .../selftests/kvm/include/aarch64/processor.h | 12 ++++++++ .../kvm/system_counter_offset_test.c | 29 ++++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index 3168cdbae6ee..7f53d90e9512 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -141,4 +141,16 @@ static inline uint64_t read_cntvct_ordered(void) return r; } +static inline uint64_t read_cntpct_ordered(void) +{ + uint64_t r; + + __asm__ __volatile__("isb\n\t" + "mrs %0, cntpct_el0\n\t" + "isb\n\t" + : "=r"(r)); + + return r; +} + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index 88ad997f5b69..3eed9dcb7693 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -57,6 +57,7 @@ static uint64_t host_read_guest_system_counter(struct test_case *test) enum arch_counter { VIRTUAL, + PHYSICAL, }; struct test_case { @@ -68,23 +69,41 @@ static struct test_case test_cases[] = { { .counter = VIRTUAL, .offset = 0 }, { .counter = VIRTUAL, .offset = 180 * NSEC_PER_SEC }, { .counter = VIRTUAL, .offset = -180 * NSEC_PER_SEC }, + { .counter = PHYSICAL, .offset = 0 }, + { .counter = PHYSICAL, .offset = 180 * NSEC_PER_SEC }, + { .counter = PHYSICAL, .offset = -180 * NSEC_PER_SEC }, }; static void check_preconditions(struct kvm_vm *vm) { if (!_vcpu_has_device_attr(vm, VCPU_ID, KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_OFFSET_VTIMER)) + KVM_ARM_VCPU_TIMER_OFFSET_VTIMER) && + !_vcpu_has_device_attr(vm, VCPU_ID, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_OFFSET_PTIMER)) return; - print_skip("KVM_ARM_VCPU_TIMER_OFFSET_VTIMER not supported; skipping test"); + print_skip("KVM_ARM_VCPU_TIMER_OFFSET_{VTIMER,PTIMER} not supported; skipping test"); exit(KSFT_SKIP); } static void setup_system_counter(struct kvm_vm *vm, struct test_case *test) { + u64 attr = 0; + + switch (test->counter) { + case VIRTUAL: + attr = KVM_ARM_VCPU_TIMER_OFFSET_VTIMER; + break; + case PHYSICAL: + attr = KVM_ARM_VCPU_TIMER_OFFSET_PTIMER; + break; + default: + TEST_ASSERT(false, "unrecognized counter index %u", + test->counter); + } + vcpu_access_device_attr(vm, VCPU_ID, KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_OFFSET_VTIMER, &test->offset, - true); + attr, &test->offset, true); } static uint64_t guest_read_system_counter(struct test_case *test) @@ -92,6 +111,8 @@ static uint64_t guest_read_system_counter(struct test_case *test) switch (test->counter) { case VIRTUAL: return read_cntvct_ordered(); + case PHYSICAL: + return read_cntpct_ordered(); default: GUEST_ASSERT(0); } From patchwork Mon Jul 19 18:49:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 12386629 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=-18.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=unavailable 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 A66F6C07E95 for ; Mon, 19 Jul 2021 18:56:56 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 606EE6108B for ; Mon, 19 Jul 2021 18:56:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 606EE6108B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:From:Subject:References: Mime-Version:Message-Id:In-Reply-To:Date:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=U3axds86IBYh3N2xGGr+r6yDG3GdE2aG6j9TYmuZ+5w=; b=WEPQU0YsFwfeGoyws0Cmg37Gwf FexrTTq46hJPKaPgxwrckR+3piX0B1yQFwbkA5fDuiseTgvZW+jIK1oQ9+2A6RDn9tux17YnOs+T2 FEQ1CLIHBpuLpErt5nMCiWuIya0uvncctdWqNsVBvQyN2epi4dN6YspN+POfucwe1vP9lgSoyybxE IHrElJqNSMh+l6SCiANG72ji6GiNwU+Os7Cta71WUC8a6gnVzJQ0SrZRn8RzSeaDSNTQOFiJ8q0fZ 6jqf9EYpOw5WJ5GY1s9muEWA6FCqdHl2gkUA7rj3Ja5p5NN71ZCcmhYvDC/UumWKeTRnkX+j49et1 ZM6jWsug==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YPI-00Ay4e-9C; Mon, 19 Jul 2021 18:54:25 +0000 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5YLG-00AwQp-Gf for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 18:50:16 +0000 Received: by mail-yb1-xb4a.google.com with SMTP id a4-20020a25f5040000b029054df41d5cceso26661267ybe.18 for ; Mon, 19 Jul 2021 11:50:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=Pe/S/uzS2wg1+TTNiX12UiCpgPQMvxwQXCZew3HD/LI=; b=ocMj+e/O27vwdOyI3ks0SRsLt9P1PGSjN+lkyhm6Xi0I9EW/F9tBe56YW2aauHv/Kk asdYA/+37iI4AsZGz1imZNOcDWgyOfB/abk4bUclvgnjLc2/p8rpgMyJSSeIzlnX59qk nE4XFwmvrgk6eza4WcEm7P2XSYy6Qt8cUGm5Ijo6T1t6cfGS5mMbwjrElbU2/vUZ2COR Plv2rFVLHYsoimVkbc5C1Bn0AWAVrnuqmiIzlX9VG+8+qDJZqmLQR2BJ55lCiQAnDDTQ 4rb6oKXqd5RjaabVBxL2+S3ZU3sH90YTMvmip0epx01EthkbyBHrfJi0uSwkHSTibclA mF6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Pe/S/uzS2wg1+TTNiX12UiCpgPQMvxwQXCZew3HD/LI=; b=dRm7HyreTreRlReFV0NVWkdRPQ4ew5P7/50c0wDFRA04Osd8kKZ2DKzLSYAPYNUUFI bu/lzBgEaa03KvqIP9cONHl6qBwl4yO1g6uiy/64qNrZQX4OqIeC+npEEMLQeK3LGM34 etICUt8qzOQSYJXDf07UhmO3YRPk3JWdCReAKU/ESmiChI65Ov9CrIIB3tkjOu4gUukF XpH6M2xDji7tSg4HJQYT5Tsir+LvHQOXbPh5wazICxwcOBEy/sVNl4mPw+mhXDRIKV0F kqLIDEOeSEb67WHSz0k3CVNmU7s9vPGIpP1PGGdirDIxUqVX3UVq+2fSbSJWpTRPQ9Ty UcGA== X-Gm-Message-State: AOAM531t5/Xr+e7RhPJDK1ffjoTT3dnA+tRMHkhgzMOD7+mRsquQzIH0 rmp8IKhzgDwAVr8Gair6+v0YDquRKQQ= X-Google-Smtp-Source: ABdhPJwOGMEIRvFFqt4m9XOjAh0/RyRXczBLXg4UlT7iKp+B6qZBSv2yzkH6ubJXWFBBQD9c7DLGzCqD1jY= X-Received: from oupton.c.googlers.com ([fda3:e722:ac3:cc00:2b:ff92:c0a8:404]) (user=oupton job=sendgmr) by 2002:a25:208b:: with SMTP id g133mr32514132ybg.211.1626720613054; Mon, 19 Jul 2021 11:50:13 -0700 (PDT) Date: Mon, 19 Jul 2021 18:49:49 +0000 In-Reply-To: <20210719184949.1385910-1-oupton@google.com> Message-Id: <20210719184949.1385910-13-oupton@google.com> Mime-Version: 1.0 References: <20210719184949.1385910-1-oupton@google.com> X-Mailer: git-send-email 2.32.0.402.g57bb445576-goog Subject: [PATCH v3 12/12] selftests: KVM: Add counter emulation benchmark From: Oliver Upton To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: Paolo Bonzini , Sean Christopherson , Marc Zyngier , Peter Shier , Jim Mattson , David Matlack , Ricardo Koller , Jing Zhang , Raghavendra Rao Anata , James Morse , Alexandru Elisei , Suzuki K Poulose , linux-arm-kernel@lists.infradead.org, Oliver Upton X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_115014_615973_0C026E83 X-CRM114-Status: GOOD ( 21.59 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add a test case for counter emulation on arm64. A side effect of how KVM handles physical counter offsetting on non-ECV systems is that the virtual counter will always hit hardware and the physical could be emulated. Force emulation by writing a nonzero offset to the physical counter and compare the elapsed cycles to a direct read of the hardware register. Reviewed-by: Ricardo Koller Signed-off-by: Oliver Upton --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../kvm/aarch64/counter_emulation_benchmark.c | 215 ++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 2752813d5090..1d811c6a769b 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only /aarch64/debug-exceptions +/aarch64/counter_emulation_benchmark /aarch64/get-reg-list /aarch64/vgic_init /s390x/memop diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index d89908108c97..e560a3e74bc2 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -86,6 +86,7 @@ TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test TEST_GEN_PROGS_x86_64 += system_counter_offset_test TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions +TEST_GEN_PROGS_aarch64 += aarch64/counter_emulation_benchmark TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list TEST_GEN_PROGS_aarch64 += aarch64/vgic_init TEST_GEN_PROGS_aarch64 += demand_paging_test diff --git a/tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c b/tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c new file mode 100644 index 000000000000..73aeb6cdebfe --- /dev/null +++ b/tools/testing/selftests/kvm/aarch64/counter_emulation_benchmark.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * counter_emulation_benchmark.c -- test to measure the effects of counter + * emulation on guest reads of the physical counter. + * + * Copyright (c) 2021, Google LLC. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "kvm_util.h" +#include "processor.h" +#include "test_util.h" + +#define VCPU_ID 0 + +static struct counter_values { + uint64_t cntvct_start; + uint64_t cntpct; + uint64_t cntvct_end; +} counter_values; + +static uint64_t nr_iterations = 1000; + +static void do_test(void) +{ + /* + * Open-coded approach instead of using helper methods to keep a tight + * interval around the physical counter read. + */ + asm volatile("isb\n\t" + "mrs %[cntvct_start], cntvct_el0\n\t" + "isb\n\t" + "mrs %[cntpct], cntpct_el0\n\t" + "isb\n\t" + "mrs %[cntvct_end], cntvct_el0\n\t" + "isb\n\t" + : [cntvct_start] "=r"(counter_values.cntvct_start), + [cntpct] "=r"(counter_values.cntpct), + [cntvct_end] "=r"(counter_values.cntvct_end)); +} + +static void guest_main(void) +{ + int i; + + for (i = 0; i < nr_iterations; i++) { + do_test(); + GUEST_SYNC(i); + } + + for (i = 0; i < nr_iterations; i++) { + do_test(); + GUEST_SYNC(i); + } + + GUEST_DONE(); +} + +static bool enter_guest(struct kvm_vm *vm) +{ + struct ucall uc; + + vcpu_ioctl(vm, VCPU_ID, KVM_RUN, NULL); + + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_DONE: + return true; + case UCALL_SYNC: + break; + case UCALL_ABORT: + TEST_ASSERT(false, "%s at %s:%ld", (const char *)uc.args[0], + __FILE__, uc.args[1]); + break; + default: + TEST_ASSERT(false, "unexpected exit: %s", + exit_reason_str(vcpu_state(vm, VCPU_ID)->exit_reason)); + break; + } + + /* more work to do in the guest */ + return false; +} + +static double counter_frequency(void) +{ + uint32_t freq; + + asm volatile("mrs %0, cntfrq_el0" + : "=r" (freq)); + + return freq / 1000000.0; +} + +static void log_csv(FILE *csv, bool trapped) +{ + double freq = counter_frequency(); + + fprintf(csv, "%s,%.02f,%lu,%lu,%lu\n", + trapped ? "true" : "false", freq, + counter_values.cntvct_start, + counter_values.cntpct, + counter_values.cntvct_end); +} + +static double run_loop(struct kvm_vm *vm, FILE *csv, bool trapped) +{ + double avg = 0; + int i; + + for (i = 0; i < nr_iterations; i++) { + uint64_t delta; + + TEST_ASSERT(!enter_guest(vm), "guest exited unexpectedly"); + sync_global_from_guest(vm, counter_values); + + if (csv) + log_csv(csv, trapped); + + delta = counter_values.cntvct_end - counter_values.cntvct_start; + avg = ((avg * i) + delta) / (i + 1); + } + + return avg; +} + +static void setup_counter(struct kvm_vm *vm, uint64_t offset) +{ + vcpu_access_device_attr(vm, VCPU_ID, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_OFFSET_PTIMER, &offset, + true); +} + +static void run_tests(struct kvm_vm *vm, FILE *csv) +{ + double avg_trapped, avg_native, freq; + + freq = counter_frequency(); + + if (csv) + fputs("trapped,freq_mhz,cntvct_start,cntpct,cntvct_end\n", csv); + + /* no physical offsetting; kvm allows reads of cntpct_el0 */ + setup_counter(vm, 0); + avg_native = run_loop(vm, csv, false); + + /* force emulation of the physical counter */ + setup_counter(vm, 1); + avg_trapped = run_loop(vm, csv, true); + + TEST_ASSERT(enter_guest(vm), "guest didn't run to completion"); + pr_info("%lu iterations: average cycles (@%.02fMHz) native: %.02f, trapped: %.02f\n", + nr_iterations, freq, avg_native, avg_trapped); +} + +static void usage(const char *program_name) +{ + fprintf(stderr, + "Usage: %s [-h] [-o csv_file] [-n iterations]\n" + " -h prints this message\n" + " -n number of test iterations (default: %lu)\n" + " -o csv file to write data\n", + program_name, nr_iterations); +} + +int main(int argc, char **argv) +{ + struct kvm_vm *vm; + FILE *csv = NULL; + int opt; + + while ((opt = getopt(argc, argv, "hn:o:")) != -1) { + switch (opt) { + case 'o': + csv = fopen(optarg, "w"); + if (!csv) { + fprintf(stderr, "failed to open file '%s': %d\n", + optarg, errno); + exit(1); + } + break; + case 'n': + nr_iterations = strtoul(optarg, NULL, 0); + break; + default: + fprintf(stderr, "unrecognized option: '-%c'\n", opt); + /* fallthrough */ + case 'h': + usage(argv[0]); + exit(1); + } + } + + vm = vm_create_default(VCPU_ID, 0, guest_main); + sync_global_to_guest(vm, nr_iterations); + ucall_init(vm, NULL); + + if (_vcpu_has_device_attr(vm, VCPU_ID, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_OFFSET_PTIMER)) { + print_skip("KVM_ARM_VCPU_TIMER_OFFSET_PTIMER not supported."); + exit(KSFT_SKIP); + } + + run_tests(vm, csv); + kvm_vm_free(vm); + + if (csv) + fclose(csv); +}