From patchwork Wed Nov 28 14:45:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Price X-Patchwork-Id: 10702883 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 31B7C16B1 for ; Wed, 28 Nov 2018 15:31:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2143E2D336 for ; Wed, 28 Nov 2018 15:31:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 159222D909; Wed, 28 Nov 2018 15:31:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 616852D906 for ; Wed, 28 Nov 2018 15:31:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=+n09d3FRUFMKfS0tWzaKmm7cLQOOvlIN+AcrqM4L0L4=; b=MfWHHASuDHHiN0 apNJcBMZXtOS81WwaV2tOmpcfxwDlIYczUR3VEsksGNaRfcNSEP97k6p5zlyMvOJT82N6kzM7+WZn +vPISKdPx/LhODDn8cE7uL3xvEyJ26Lus4ZblWeTMU5IdtME2NoqEahQrK0LOBjZ+aZz8nZW7f+hk d1ycBEP4sxUAdK8znu9LjbFt9m58yMzUykJgW74hrdX74cV1Ygjyr5YZEVwW6hfG5Q/Fff3v3Wih9 rYEGu/Y4Gff59sqvknIdL8koHlA9fIIvR4ejFrAo6CjrJGNLa61xjH/1UiewSUy4kzmLrEdayAkXy rQxpIK+0sWarEMiTcXVA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1gS1oE-0004SA-C6; Wed, 28 Nov 2018 15:31:26 +0000 Received: from merlin.infradead.org ([2001:8b0:10b:1231::1]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1gS1oC-0004Rw-N0 for linux-arm-kernel@bombadil.infradead.org; Wed, 28 Nov 2018 15:31:24 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=merlin.20170209; h=Content-Transfer-Encoding:MIME-Version: References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To: Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=1RiuTcNBFi0/I14EvCpadXh4Il/w17S9vN2Du+ySo2g=; b=hpALCEET4goKXb/kTE37RqDeH9 xVMhgh21tRDk140bjlbbJPpcIKtFiTjTW2rwjVYV1Mj0mcjnoXCYDDZqNbDQMB+7Z4ioHsLyshvDo rqaZjdSY1/7GeXCx8nga8JPj8vQmf3C/EWIgX0STqr/B6qcUzX4020pQbqIBLtbpbDCxqs+w1dnQj OEBFUWVrRyG04Yzcdiyal+v8EDlIjWXDFUoETNs7DDIf//pJklvFZwNNtDGyv+E+MArwwhRAbeyCf BuYHYgTrzeHDNeeIv7LzrQh5qQdKONtwpDGeFXfF49aqpI2tItlieQY8x2vqandF20f3ibAeb3xEA TKC5FmNQ==; Received: from foss.arm.com ([217.140.101.70]) by merlin.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1gS177-0006bg-4L for linux-arm-kernel@lists.infradead.org; Wed, 28 Nov 2018 14:46:54 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 064D436B8; Wed, 28 Nov 2018 06:46:44 -0800 (PST) Received: from e112269-lin.arm.com (e112269-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 807A53F5AF; Wed, 28 Nov 2018 06:46:42 -0800 (PST) From: Steven Price To: kvmarm@lists.cs.columbia.edu, linux-arm-kernel@lists.infradead.org Subject: [PATCH 09/12] KVM: arm64: Support stolen time reporting via shared page Date: Wed, 28 Nov 2018 14:45:24 +0000 Message-Id: <20181128144527.44710-10-steven.price@arm.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181128144527.44710-1-steven.price@arm.com> References: <20181128144527.44710-1-steven.price@arm.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20181128_094653_503579_06F44682 X-CRM114-Status: GOOD ( 24.33 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Marc Zyngier , Catalin Marinas , Will Deacon , Christoffer Dall , Steven Price Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Implement the service call for configuring a shared page between a VCPU and the hypervisor in which the hypervisor can write the time stolen from the VCPU's execution time by other tasks on the host. We translate the IPA provided by user space (in a later patch) to the corresponding physical page on the host, which we pin in memory and kmap to the kernel's linear mapping. We can then use WRITE_ONCE() to ensure single copy atomicity of the 64-bit unsigned value that reports stolen time in nanoseconds. We make sure to update the page mapping if user space changes the memslots during execution by using the existing gfn_to_hva_cache feature and memslots generation counter. If the gfn to hva mapping changes, we update the pinned and mapped page accordingly. Whenever stolen time is enabled by the guest, the stolen time counter is reset. The stolen time itself is retrieved from the sched_info structure maintained by the Linux scheduler code. We enable SCHEDSTATS when selecting KVM Kconfig to ensure this value is meaningful. Signed-off-by: Steven Price --- arch/arm64/include/asm/kvm_host.h | 9 ++++ arch/arm64/kvm/Kconfig | 1 + include/kvm/arm_hypercalls.h | 1 + virt/kvm/arm/arm.c | 20 ++++++++- virt/kvm/arm/hypercalls.c | 70 +++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 827162b1fabf..c6bc1fc8ee00 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -48,6 +48,7 @@ #define KVM_REQ_SLEEP \ KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_IRQ_PENDING KVM_ARCH_REQ(1) +#define KVM_REQ_RECORD_STEAL KVM_ARCH_REQ(2) DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use); @@ -86,6 +87,8 @@ struct kvm_arch { gpa_t lpt_page; u32 lpt_fpv; + + gpa_t st_base; } pvtime; }; @@ -307,6 +310,12 @@ struct kvm_vcpu_arch { /* True when deferrable sysregs are loaded on the physical CPU, * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */ bool sysregs_loaded_on_cpu; + + /* Guest PV state */ + struct { + u64 steal; + u64 last_steal; + } steal; }; /* vcpu_arch flags field values: */ diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 47b23bf617c7..92676920d671 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -40,6 +40,7 @@ config KVM select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS select HAVE_KVM_VCPU_RUN_PID_CHANGE + select SCHEDSTATS ---help--- Support hosting virtualized guest machines. We don't support KVM with 16K page tables yet, due to the multiple diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h index e5f7f81196b6..2e03e993ad64 100644 --- a/include/kvm/arm_hypercalls.h +++ b/include/kvm/arm_hypercalls.h @@ -7,6 +7,7 @@ #include int kvm_hvc_call_handler(struct kvm_vcpu *vcpu); +int kvm_update_stolen_time(struct kvm_vcpu *vcpu); static inline u32 smccc_get_function(struct kvm_vcpu *vcpu) { diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 4c6355f21352..d4ba21d3e7a5 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -32,8 +32,6 @@ #include #include #include -#include -#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -52,6 +50,10 @@ #include #include +#include +#include +#include + #ifdef REQUIRES_VIRT __asm__(".arch_extension virt"); #endif @@ -150,6 +152,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) /* Set the PV Time addresses to invalid values */ kvm->arch.pvtime.lpt_page = GPA_INVALID; + kvm->arch.pvtime.st_base = GPA_INVALID; return ret; out_free_stage2_pgd: @@ -386,6 +389,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) kvm_timer_vcpu_load(vcpu); kvm_vcpu_load_sysregs(vcpu); kvm_arch_vcpu_load_fp(vcpu); + kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu); if (single_task_running()) vcpu_clear_wfe_traps(vcpu); @@ -634,6 +638,15 @@ static void vcpu_req_sleep(struct kvm_vcpu *vcpu) } } +static void vcpu_req_record_steal(struct kvm_vcpu *vcpu) +{ + int idx; + + idx = srcu_read_lock(&vcpu->kvm->srcu); + kvm_update_stolen_time(vcpu); + srcu_read_unlock(&vcpu->kvm->srcu, idx); +} + static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu) { return vcpu->arch.target >= 0; @@ -650,6 +663,9 @@ static void check_vcpu_requests(struct kvm_vcpu *vcpu) * that a VCPU sees new virtual interrupts. */ kvm_check_request(KVM_REQ_IRQ_PENDING, vcpu); + + if (kvm_check_request(KVM_REQ_RECORD_STEAL, vcpu)) + vcpu_req_record_steal(vcpu); } } diff --git a/virt/kvm/arm/hypercalls.c b/virt/kvm/arm/hypercalls.c index fdb1880ab4c6..513f2285b29a 100644 --- a/virt/kvm/arm/hypercalls.c +++ b/virt/kvm/arm/hypercalls.c @@ -150,6 +150,73 @@ static int kvm_hypercall_time_lpt(struct kvm_vcpu *vcpu) smccc_set_retval(vcpu, ret, 0, 0, 0); return 1; } + +static struct pvclock_vcpu_stolen_time_info *pvtime_get_st( + struct kvm_vcpu *vcpu) +{ + void *pv_page = vcpu->kvm->arch.pvtime.pv_page; + struct pvclock_vcpu_stolen_time_info *st; + + if (!pv_page) + return NULL; + + st = pv_page + PAGE_SIZE; + + return &st[kvm_vcpu_get_idx(vcpu)]; +} + +int kvm_update_stolen_time(struct kvm_vcpu *vcpu) +{ + u64 steal; + struct pvclock_vcpu_stolen_time_info *kaddr; + + if (vcpu->kvm->arch.pvtime.st_base == GPA_INVALID) + return -ENOTSUPP; + + kaddr = pvtime_get_st(vcpu); + + if (!kaddr) + return -ENOTSUPP; + + kaddr->revision = 0; + kaddr->attributes = 0; + + /* Let's do the local bookkeeping */ + steal = vcpu->arch.steal.steal; + steal += current->sched_info.run_delay - vcpu->arch.steal.last_steal; + vcpu->arch.steal.last_steal = current->sched_info.run_delay; + vcpu->arch.steal.steal = steal; + + /* Now write out the value to the shared page */ + WRITE_ONCE(kaddr->stolen_time, cpu_to_le64(steal)); + + return 0; +} + +static int kvm_hypercall_stolen_time(struct kvm_vcpu *vcpu) +{ + u64 ret; + int err; + + /* + * Start counting stolen time from the time the guest requests + * the feature enabled. + */ + vcpu->arch.steal.steal = 0; + vcpu->arch.steal.last_steal = current->sched_info.run_delay; + + err = kvm_update_stolen_time(vcpu); + + if (err) + ret = SMCCC_RET_NOT_SUPPORTED; + else + ret = vcpu->kvm->arch.pvtime.st_base + + (sizeof(struct pvclock_vcpu_stolen_time_info) * + kvm_vcpu_get_idx(vcpu)); + + smccc_set_retval(vcpu, ret, 0, 0, 0); + return 1; +} int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) { u32 func_id = smccc_get_function(vcpu); @@ -191,12 +258,15 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) switch (feature) { case ARM_SMCCC_HV_PV_FEATURES: case ARM_SMCCC_HV_PV_TIME_LPT: + case ARM_SMCCC_HV_PV_TIME_ST: val = SMCCC_RET_SUCCESS; break; } break; case ARM_SMCCC_HV_PV_TIME_LPT: return kvm_hypercall_time_lpt(vcpu); + case ARM_SMCCC_HV_PV_TIME_ST: + return kvm_hypercall_stolen_time(vcpu); default: return kvm_psci_call(vcpu); }