From patchwork Sat Oct 20 14:14:25 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 1621491 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 33930DF26F for ; Sat, 20 Oct 2012 14:14:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932083Ab2JTOOQ (ORCPT ); Sat, 20 Oct 2012 10:14:16 -0400 Received: from mail-vc0-f174.google.com ([209.85.220.174]:52888 "EHLO mail-vc0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754929Ab2JTOOP (ORCPT ); Sat, 20 Oct 2012 10:14:15 -0400 Received: by mail-vc0-f174.google.com with SMTP id fk26so1480447vcb.19 for ; Sat, 20 Oct 2012 07:14:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=subject:to:from:cc:date:message-id:in-reply-to:references :user-agent:mime-version:content-type:content-transfer-encoding :x-gm-message-state; bh=Of1arRrz+Uj+SZ0MATSvzdgI3ZC+N/uHSO92LlyT13E=; b=lXeE3o1bYkJnFY3j6f7XjuGUEJkiZhXZ55WNR8GqEznk0Z3hDAJlJD1XhnApsMWuv/ XKJ2/EyYNZgZlkVoj8/Y+t/l7o0Oo13iQcKasL5IQCrX9WTwRRPx92r0j8ha4hEXIDVZ 8rJIPzLlxr1h5lK81ymnKyslLAJ+ZACZPGgiVdSt6x7snpWtoRq3MCLNuizaEiCTTvtd h5mGExPdgZE3h4D6hAlKcHHm3E1NB56LoeiOq7F2VXd1L+/FElOWW7/fdlm5qkqX4z0P yOzw7132V/9ahTTeudYWW3RXQqXO5R0pFBVkF9cFaqWEY6hr8quBmmUGPco+Oq92wWPq DR5A== Received: by 10.58.252.67 with SMTP id zq3mr626174vec.43.1350742455180; Sat, 20 Oct 2012 07:14:15 -0700 (PDT) Received: from [127.0.1.1] (pool-72-80-83-148.nycmny.fios.verizon.net. [72.80.83.148]) by mx.google.com with ESMTPS id w10sm4143119vef.5.2012.10.20.07.14.14 (version=TLSv1/SSLv3 cipher=OTHER); Sat, 20 Oct 2012 07:14:14 -0700 (PDT) Subject: [PATCH v2 2/3] KVM: ARM: Introduce KVM_SET_DEVICE_ADDRESS ioctl To: kvmarm@lists.cs.columbia.edu From: Christoffer Dall Cc: kvm@vger.kernel.org Date: Sat, 20 Oct 2012 10:14:25 -0400 Message-ID: <20121020141425.24046.36398.stgit@ubuntu> In-Reply-To: <20121020141255.24046.20020.stgit@ubuntu> References: <20121020141255.24046.20020.stgit@ubuntu> User-Agent: StGit/0.16-2-g0d85 MIME-Version: 1.0 X-Gm-Message-State: ALoCoQmkIxOoyYS2KQo3yD1D2nvphyiucuDFnfHKTWldExETXHVB52SvF0j61VkA3/ugBY+1nSb1 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org On ARM (and possibly other architectures) some bits are specific to the model being emulated for the guest and user space needs a way to tell the kernel about those bits. An example is mmio device base addresses, where KVM must know the base address for a given device to properly emulate mmio accesses within a certain address range or directly map a device with virtualiation extensions into the guest address space. We try to make this API slightly more generic than for our specific use, but so far only the VGIC uses this feature. Signed-off-by: Christoffer Dall --- Documentation/virtual/kvm/api.txt | 37 +++++++++++++++++++++++++++++++++++++ arch/arm/include/asm/kvm.h | 13 +++++++++++++ arch/arm/include/asm/kvm_mmu.h | 2 ++ arch/arm/include/asm/kvm_vgic.h | 6 ++++++ arch/arm/kvm/arm.c | 31 ++++++++++++++++++++++++++++++- arch/arm/kvm/vgic.c | 28 ++++++++++++++++++++++++++++ include/linux/kvm.h | 8 ++++++++ 7 files changed, 124 insertions(+), 1 deletion(-) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 0aa4d83..dae4f05 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2102,6 +2102,43 @@ This ioctl returns the guest registers that are supported for the KVM_GET_ONE_REG/KVM_SET_ONE_REG calls. +4.80 KVM_SET_DEVICE_ADDRESS + +Capability: KVM_CAP_SET_DEVICE_ADDRESS +Architectures: arm +Type: vm ioctl +Parameters: struct kvm_device_address (in) +Returns: 0 on success, -1 on error +Errors: + ENODEV: The device id is unknown + ENXIO: Device not supported on current system + EEXIST: Address already set + E2BIG: Address outside guest physical address space + +struct kvm_device_address { + __u32 id; + __u64 addr; +}; + +Specify a device address in the guest's physical address space where guests +can access emulated or directly exposed devices, which the host kernel needs +to know about. The id field is an architecture specific identifier for a +specific device. + +ARM divides the id field into two parts, a device id and an address type id +specific to the individual device. + +  bits: | 31 ... 16 | 15 ... 0 | + field: | device id | addr type id | + +ARM currently only require this when using the in-kernel GIC support for the +hardware vGIC features, using KVM_ARM_DEVICE_VGIC_V2 as the device id. When +setting the base address for the guest's mapping of the vGIC virtual CPU +and distributor interface, the ioctl must be called after calling +KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling +this ioctl twice for any of the base addresses will return -EEXIST. + + 5. The kvm_run structure ------------------------ diff --git a/arch/arm/include/asm/kvm.h b/arch/arm/include/asm/kvm.h index fb41608..a7ae073 100644 --- a/arch/arm/include/asm/kvm.h +++ b/arch/arm/include/asm/kvm.h @@ -42,6 +42,19 @@ struct kvm_regs { #define KVM_ARM_TARGET_CORTEX_A15 0 #define KVM_ARM_NUM_TARGETS 1 +/* KVM_SET_DEVICE_ADDRESS ioctl id encoding */ +#define KVM_DEVICE_TYPE_SHIFT 0 +#define KVM_DEVICE_TYPE_MASK (0xffff << KVM_DEVICE_TYPE_SHIFT) +#define KVM_DEVICE_ID_SHIFT 16 +#define KVM_DEVICE_ID_MASK (0xffff << KVM_DEVICE_ID_SHIFT) + +/* Supported device IDs */ +#define KVM_ARM_DEVICE_VGIC_V2 0 + +/* Supported VGIC address types */ +#define KVM_VGIC_V2_ADDR_TYPE_DIST 0 +#define KVM_VGIC_V2_ADDR_TYPE_CPU 1 + struct kvm_vcpu_init { __u32 target; __u32 features[7]; diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index 9bd0508..0800531 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -26,6 +26,8 @@ * To save a bit of memory and to avoid alignment issues we assume 39-bit IPA * for now, but remember that the level-1 table must be aligned to its size. */ +#define KVM_PHYS_SHIFT (38) +#define KVM_PHYS_MASK ((1ULL << KVM_PHYS_SHIFT) - 1) #define PTRS_PER_PGD2 512 #define PGD2_ORDER get_order(PTRS_PER_PGD2 * sizeof(pgd_t)) diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h index 588c637..a688132 100644 --- a/arch/arm/include/asm/kvm_vgic.h +++ b/arch/arm/include/asm/kvm_vgic.h @@ -242,6 +242,7 @@ struct kvm_exit_mmio; #ifdef CONFIG_KVM_ARM_VGIC int kvm_vgic_hyp_init(void); +int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr); int kvm_vgic_init(struct kvm *kvm); void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu); void kvm_vgic_sync_to_cpu(struct kvm_vcpu *vcpu); @@ -261,6 +262,11 @@ static inline int kvm_vgic_hyp_init(void) return 0; } +static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) +{ + return 0; +} + static inline int kvm_vgic_init(struct kvm *kvm) { return 0; diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index d552b94..282794e 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -206,6 +206,9 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_COALESCED_MMIO: r = KVM_COALESCED_MMIO_PAGE_OFFSET; break; + case KVM_CAP_SET_DEVICE_ADDR: + r = 1; + break; default: r = 0; break; @@ -858,20 +861,46 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) return -EINVAL; } +static int kvm_vm_ioctl_set_device_address(struct kvm *kvm, + struct kvm_device_address *dev_addr) +{ + unsigned long dev_id, type; + + dev_id = (dev_addr->id & KVM_DEVICE_ID_MASK) >> KVM_DEVICE_ID_SHIFT; + type = (dev_addr->id & KVM_DEVICE_TYPE_MASK) >> KVM_DEVICE_TYPE_SHIFT; + + switch (dev_id) { + case KVM_ARM_DEVICE_VGIC_V2: + if (!vgic_present) + return -ENXIO; + return kvm_vgic_set_addr(kvm, type, dev_addr->addr); + default: + return -ENODEV; + } +} + long kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { + struct kvm *kvm = filp->private_data; + void __user *argp = (void __user *)arg; switch (ioctl) { #ifdef CONFIG_KVM_ARM_VGIC case KVM_CREATE_IRQCHIP: { - struct kvm *kvm = filp->private_data; if (vgic_present) return kvm_vgic_init(kvm); else return -EINVAL; } #endif + case KVM_SET_DEVICE_ADDRESS: { + struct kvm_device_address dev_addr; + + if (copy_from_user(&dev_addr, argp, sizeof(dev_addr))) + return -EFAULT; + return kvm_vm_ioctl_set_device_address(kvm, &dev_addr); + } default: return -EINVAL; } diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c index b669b85..82fba58 100644 --- a/arch/arm/kvm/vgic.c +++ b/arch/arm/kvm/vgic.c @@ -1140,3 +1140,31 @@ out: return ret; } + +int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) +{ + int r = 0; + + if (addr & ~KVM_PHYS_MASK) + return -E2BIG; + + if (addr & ~PAGE_MASK) + return -EINVAL; + + mutex_lock(&kvm->lock); + switch (type) { + case KVM_VGIC_V2_ADDR_TYPE_DIST: + if (addr != VGIC_DIST_BASE) + return -EINVAL; + break; + case KVM_VGIC_V2_ADDR_TYPE_CPU: + if (addr != VGIC_CPU_BASE) + return -EINVAL; + break; + default: + r = -ENODEV; + } + + mutex_unlock(&kvm->lock); + return r; +} diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 172cc10..72d5594 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -626,6 +626,7 @@ struct kvm_ppc_smmu_info { #ifdef __KVM_HAVE_READONLY_MEM #define KVM_CAP_READONLY_MEM 81 #endif +#define KVM_CAP_SET_DEVICE_ADDR 82 #ifdef KVM_CAP_IRQ_ROUTING @@ -764,6 +765,11 @@ struct kvm_msi { __u8 pad[16]; }; +struct kvm_device_address { + __u32 id; + __u64 addr; +}; + /* * ioctls for VM fds */ @@ -844,6 +850,8 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info) /* Available with KVM_CAP_PPC_ALLOC_HTAB */ #define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32) +/* Available with KVM_CAP_SET_DEVICE_ADDR */ +#define KVM_SET_DEVICE_ADDRESS _IOW(KVMIO, 0xa8, struct kvm_device_address) /* * ioctls for vcpu fds