From mboxrd@z Thu Jan 1 00:00:00 1970 From: Christoffer Dall Subject: [PATCH v2 2/3] KVM: ARM: Introduce KVM_SET_DEVICE_ADDRESS ioctl Date: Sat, 20 Oct 2012 10:14:25 -0400 Message-ID: <20121020141425.24046.36398.stgit@ubuntu> References: <20121020141255.24046.20020.stgit@ubuntu> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: kvm@vger.kernel.org To: kvmarm@lists.cs.columbia.edu Return-path: 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) In-Reply-To: <20121020141255.24046.20020.stgit@ubuntu> Sender: kvm-owner@vger.kernel.org List-ID: 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(-) 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. =20 =20 +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 g= uests +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 ty= pe id +specific to the individual device. + + =C2=A0bits: | 31 ... 16 | 15 ... 0 | + field: | device id | addr type id | + +ARM currently only require this when using the in-kernel GIC support f= or 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 C= PU +and distributor interface, the ioctl must be called after calling +KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. C= alling +this ioctl twice for any of the base addresses will return -EEXIST. + + 5. The kvm_run structure ------------------------ =20 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 =20 +/* 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)) =20 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; =20 #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; } =20 +static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long typ= e, 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 =3D KVM_COALESCED_MMIO_PAGE_OFFSET; break; + case KVM_CAP_SET_DEVICE_ADDR: + r =3D 1; + break; default: r =3D 0; break; @@ -858,20 +861,46 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, s= truct kvm_dirty_log *log) return -EINVAL; } =20 +static int kvm_vm_ioctl_set_device_address(struct kvm *kvm, + struct kvm_device_address *dev_addr) +{ + unsigned long dev_id, type; + + dev_id =3D (dev_addr->id & KVM_DEVICE_ID_MASK) >> KVM_DEVICE_ID_SHIFT= ; + type =3D (dev_addr->id & KVM_DEVICE_TYPE_MASK) >> KVM_DEVICE_TYPE_SHI= =46T; + + 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 =3D filp->private_data; + void __user *argp =3D (void __user *)arg; =20 switch (ioctl) { #ifdef CONFIG_KVM_ARM_VGIC case KVM_CREATE_IRQCHIP: { - struct kvm *kvm =3D 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: =20 return ret; } + +int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) +{ + int r =3D 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 !=3D VGIC_DIST_BASE) + return -EINVAL; + break; + case KVM_VGIC_V2_ADDR_TYPE_CPU: + if (addr !=3D VGIC_CPU_BASE) + return -EINVAL; + break; + default: + r =3D -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 =20 #ifdef KVM_CAP_IRQ_ROUTING =20 @@ -764,6 +765,11 @@ struct kvm_msi { __u8 pad[16]; }; =20 +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) =20 /* * ioctls for vcpu fds