From patchwork Fri Feb 14 18:36:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Zyngier X-Patchwork-Id: 11382983 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E19B1186E for ; Fri, 14 Feb 2020 18:36:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C021C24649 for ; Fri, 14 Feb 2020 18:36:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1581705392; bh=U47Cim1m36ncRf1F2X4HkjZI4B/fxmPv0g5AophOpgA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=lwb8N/iDgtEANQSsLg36FpIWQAbxY15RE/1+n8LgPOF/di41esg5mpfhHlmrFN2qp GRNvAUuAlRoLxRsqQkrN0zHye14pG6NkpKwSq2O5KmajYWbz5sgLZB+Jzv54sXaunN l49jBT0GzZZVaYME8nLWOnUdjrNgbCLVjpe4ga1w= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388077AbgBNSgc (ORCPT ); Fri, 14 Feb 2020 13:36:32 -0500 Received: from mail.kernel.org ([198.145.29.99]:37388 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729602AbgBNSgb (ORCPT ); Fri, 14 Feb 2020 13:36:31 -0500 Received: from disco-boy.misterjones.org (disco-boy.misterjones.org [51.254.78.96]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 27CE1222C2; Fri, 14 Feb 2020 18:36:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1581705390; bh=U47Cim1m36ncRf1F2X4HkjZI4B/fxmPv0g5AophOpgA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eJhR293pkuXcdRUeLf+A+a5MOkH+eBfFE4Kwin/ZWZlOCyHu6DIus/kBknxlwLH58 tH2aUPG3KcPyZtTScRIDdIRvnIIrIqLgah7CS70dF4/bqz+Mf2n1buxSD3En2Qzhh3 2k2rqsfuW1010yFz/XHAZSuvJndRy49pEJckG08I= Received: from 78.163-31-62.static.virginmediabusiness.co.uk ([62.31.163.78] helo=why.lan) by disco-boy.misterjones.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1j2fpE-005J5c-Gy; Fri, 14 Feb 2020 18:36:28 +0000 From: Marc Zyngier To: linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Cc: James Morse , Julien Thierry , Suzuki K Poulose Subject: [PATCH 1/2] KVM: arm64: Add PMU event filtering infrastructure Date: Fri, 14 Feb 2020 18:36:14 +0000 Message-Id: <20200214183615.25498-2-maz@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200214183615.25498-1-maz@kernel.org> References: <20200214183615.25498-1-maz@kernel.org> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 62.31.163.78 X-SA-Exim-Rcpt-To: linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org, james.morse@arm.com, julien.thierry.kdev@gmail.com, suzuki.poulose@arm.com X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org It can be desirable to expose a PMU to a guest, and yet not want the guest to be able to count some of the implemented events (because this would give information on shared resources, for example. For this, let's extend the PMUv3 device API, and offer a way to setup a bitmap of the allowed events (the default being no bitmap, and thus no filtering). Userspace can thus allow/deny ranges of event. The default policy depends on the "polarity" of the first filter setup (default deny if the filter allows events, and default allow if the filter denies events). This allows to setup exactly what is allowed for a given guest. Note that although the ioctl is per-vcpu, the map of allowed events is global to the VM (it can be setup from any vcpu until the vcpu PMU is initialized). Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 6 +++ arch/arm64/include/uapi/asm/kvm.h | 16 +++++++ virt/kvm/arm/arm.c | 2 + virt/kvm/arm/pmu.c | 76 ++++++++++++++++++++++++++----- 4 files changed, 88 insertions(+), 12 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index d87aa609d2b6..b594c604215f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -91,6 +91,12 @@ struct kvm_arch { * supported. */ bool return_nisv_io_abort_to_user; + + /* + * VM-wide PMU filter, implemented as a bitmap and big enough + * for up to 65536 events + */ + unsigned long *pmu_filter; }; #define KVM_NR_MEM_OBJS 40 diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index ba85bb23f060..7b1511d6ce44 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -159,6 +159,21 @@ struct kvm_sync_regs { struct kvm_arch_memory_slot { }; +/* + * PMU filter structure. Describe a range of events with a particular + * action. To be used with KVM_ARM_VCPU_PMU_V3_FILTER. + */ +struct kvm_pmu_event_filter { + __u16 base_event; + __u16 nevents; + +#define KVM_PMU_EVENT_ALLOW 0 +#define KVM_PMU_EVENT_DENY 1 + + __u8 action; + __u8 pad[3]; +}; + /* for KVM_GET/SET_VCPU_EVENTS */ struct kvm_vcpu_events { struct { @@ -329,6 +344,7 @@ struct kvm_vcpu_events { #define KVM_ARM_VCPU_PMU_V3_CTRL 0 #define KVM_ARM_VCPU_PMU_V3_IRQ 0 #define KVM_ARM_VCPU_PMU_V3_INIT 1 +#define KVM_ARM_VCPU_PMU_V3_FILTER 2 #define KVM_ARM_VCPU_TIMER_CTRL 1 #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index d65a0faa46d8..9132f7508975 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -164,6 +164,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm) free_percpu(kvm->arch.last_vcpu_ran); kvm->arch.last_vcpu_ran = NULL; + bitmap_free(kvm->arch.pmu_filter); + for (i = 0; i < KVM_MAX_VCPUS; ++i) { if (kvm->vcpus[i]) { kvm_vcpu_destroy(kvm->vcpus[i]); diff --git a/virt/kvm/arm/pmu.c b/virt/kvm/arm/pmu.c index f0d0312c0a55..817f341ed9ad 100644 --- a/virt/kvm/arm/pmu.c +++ b/virt/kvm/arm/pmu.c @@ -585,6 +585,14 @@ static void kvm_pmu_create_perf_event(struct kvm_vcpu *vcpu, u64 select_idx) pmc->idx != ARMV8_PMU_CYCLE_IDX) return; + /* + * If we have a filter in place and that the event isn't allowed, do + * not install a perf event either. + */ + if (vcpu->kvm->arch.pmu_filter && + !test_bit(eventsel, vcpu->kvm->arch.pmu_filter)) + return; + memset(&attr, 0, sizeof(struct perf_event_attr)); attr.type = PERF_TYPE_RAW; attr.size = sizeof(attr); @@ -735,15 +743,6 @@ int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu) static int kvm_arm_pmu_v3_init(struct kvm_vcpu *vcpu) { - if (!kvm_arm_support_pmu_v3()) - return -ENODEV; - - if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features)) - return -ENXIO; - - if (vcpu->arch.pmu.created) - return -EBUSY; - if (irqchip_in_kernel(vcpu->kvm)) { int ret; @@ -794,8 +793,19 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq) return true; } +#define NR_EVENTS (ARMV8_PMU_EVTYPE_EVENT + 1) + int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) { + if (!kvm_arm_support_pmu_v3()) + return -ENODEV; + + if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features)) + return -ENODEV; + + if (vcpu->arch.pmu.created) + return -EBUSY; + switch (attr->attr) { case KVM_ARM_VCPU_PMU_V3_IRQ: { int __user *uaddr = (int __user *)(long)attr->addr; @@ -804,9 +814,6 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) if (!irqchip_in_kernel(vcpu->kvm)) return -EINVAL; - if (!test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features)) - return -ENODEV; - if (get_user(irq, uaddr)) return -EFAULT; @@ -824,6 +831,50 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) vcpu->arch.pmu.irq_num = irq; return 0; } + case KVM_ARM_VCPU_PMU_V3_FILTER: { + struct kvm_pmu_event_filter __user *uaddr; + struct kvm_pmu_event_filter filter; + + uaddr = (struct kvm_pmu_event_filter __user *)(long)attr->addr; + + if (copy_from_user(&filter, uaddr, sizeof(filter))) + return -EFAULT; + + if (((u32)filter.base_event + filter.nevents) > NR_EVENTS || + (filter.action != KVM_PMU_EVENT_ALLOW && + filter.action != KVM_PMU_EVENT_DENY)) + return -EINVAL; + + mutex_lock(&vcpu->kvm->lock); + + if (!vcpu->kvm->arch.pmu_filter) { + vcpu->kvm->arch.pmu_filter = bitmap_alloc(NR_EVENTS, GFP_KERNEL); + if (!vcpu->kvm->arch.pmu_filter) { + mutex_unlock(&vcpu->kvm->lock); + return -ENOMEM; + } + + /* + * The default depends on the first applied filter. + * If it allows events, the default is to deny. + * Conversely, if the first filter denies a set of + * events, the default is to allow. + */ + if (filter.action == KVM_PMU_EVENT_ALLOW) + bitmap_zero(vcpu->kvm->arch.pmu_filter, NR_EVENTS); + else + bitmap_fill(vcpu->kvm->arch.pmu_filter, NR_EVENTS); + } + + if (filter.action == KVM_PMU_EVENT_ALLOW) + bitmap_set(vcpu->kvm->arch.pmu_filter, filter.base_event, filter.nevents); + else + bitmap_clear(vcpu->kvm->arch.pmu_filter, filter.base_event, filter.nevents); + + mutex_unlock(&vcpu->kvm->lock); + + return 0; + } case KVM_ARM_VCPU_PMU_V3_INIT: return kvm_arm_pmu_v3_init(vcpu); } @@ -860,6 +911,7 @@ int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) switch (attr->attr) { case KVM_ARM_VCPU_PMU_V3_IRQ: case KVM_ARM_VCPU_PMU_V3_INIT: + case KVM_ARM_VCPU_PMU_V3_FILTER: if (kvm_arm_support_pmu_v3() && test_bit(KVM_ARM_VCPU_PMU_V3, vcpu->arch.features)) return 0; From patchwork Fri Feb 14 18:36:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Zyngier X-Patchwork-Id: 11382981 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A0E5E13A4 for ; Fri, 14 Feb 2020 18:36:32 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7F94A24650 for ; Fri, 14 Feb 2020 18:36:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1581705392; bh=5r08mBYS8Hs6Uwk0S9akLYX+TgV0QH11etUSJUNAJAg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-ID:From; b=MAALtfNUrOJw40O7rWP5/9x25PREhx5T335c2TUtri5v/tiXWHoIQzUUBWbDhtCLy 4YDyIGt/fMhnSiyL0Di2CsLr7kUFzCK/14gvBwmqVjSAaeYhXtnqq/lzC7oZJ0CFNd +XgFUk7jkybUo9vTUXIBO/afk9Iv2YzpWymJff/4= Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388007AbgBNSgb (ORCPT ); Fri, 14 Feb 2020 13:36:31 -0500 Received: from mail.kernel.org ([198.145.29.99]:37410 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729612AbgBNSgb (ORCPT ); Fri, 14 Feb 2020 13:36:31 -0500 Received: from disco-boy.misterjones.org (disco-boy.misterjones.org [51.254.78.96]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 8BF3222314; Fri, 14 Feb 2020 18:36:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1581705390; bh=5r08mBYS8Hs6Uwk0S9akLYX+TgV0QH11etUSJUNAJAg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tdi7bz73Nc2KbtvatmMJF6UVTvU1CDl+8gSh7qXOSUWOpcb1Xwwby3lsNEkIh3xaT goU3x/4YreWeMF6slHpFG57QGHydxBcLVF7Hw3teuPXowr+CtLZXcdIDYv2oFOmNAN FU45ndjeubj1JZCuasgIUUa1ylQRp59xiOIOsvVg= Received: from 78.163-31-62.static.virginmediabusiness.co.uk ([62.31.163.78] helo=why.lan) by disco-boy.misterjones.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1j2fpE-005J5c-Uf; Fri, 14 Feb 2020 18:36:29 +0000 From: Marc Zyngier To: linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org Cc: James Morse , Julien Thierry , Suzuki K Poulose Subject: [PATCH 2/2] KVM: arm64: Document PMU filtering API Date: Fri, 14 Feb 2020 18:36:15 +0000 Message-Id: <20200214183615.25498-3-maz@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200214183615.25498-1-maz@kernel.org> References: <20200214183615.25498-1-maz@kernel.org> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 62.31.163.78 X-SA-Exim-Rcpt-To: linux-arm-kernel@lists.infradead.org, kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org, james.morse@arm.com, julien.thierry.kdev@gmail.com, suzuki.poulose@arm.com X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add a small blurb describing how the event filtering API gets used. Signed-off-by: Marc Zyngier --- Documentation/virt/kvm/devices/vcpu.txt | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Documentation/virt/kvm/devices/vcpu.txt b/Documentation/virt/kvm/devices/vcpu.txt index 6f3bd64a05b0..76902e6bbc05 100644 --- a/Documentation/virt/kvm/devices/vcpu.txt +++ b/Documentation/virt/kvm/devices/vcpu.txt @@ -36,6 +36,34 @@ Request the initialization of the PMUv3. If using the PMUv3 with an in-kernel virtual GIC implementation, this must be done after initializing the in-kernel irqchip. +1.3 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_FILTER +Parameters: in kvm_device_attr.addr the address for a PMU event filter is a + pointer to a struct kvm_pmu_event_filter +Returns: -ENODEV: PMUv3 not supported or GIC not initialized + -ENXIO: PMUv3 not properly configured or in-kernel irqchip not + configured as required prior to calling this attribute + -EBUSY: PMUv3 already initialized + +Request the installation of a PMU event filter describe as follows: + +struct kvm_pmu_event_filter { + __u16 base_event; + __u16 nevents; + +#define KVM_PMU_EVENT_ALLOW 0 +#define KVM_PMU_EVENT_DENY 1 + + __u8 action; + __u8 pad[3]; +}; + +A filter range is defined as the range [base_event, base_event + nevents[, +together with an action (KVM_PMU_EVENT_ALLOW or KVM_PMU_EVENT_DENY). The +first registered range defines the global policy (global ALLOW if the first +action is DENY, global DENY if the first action is ALLOW). Multiple ranges +can be programmed, and but fit within the 16bit space defined by the ARMv8.1 +PMU architecture. + 2. GROUP: KVM_ARM_VCPU_TIMER_CTRL Architectures: ARM,ARM64