19ed24f4bSMarc Zyngier // SPDX-License-Identifier: GPL-2.0-only 29ed24f4bSMarc Zyngier /* 39ed24f4bSMarc Zyngier * VGIC: KVM DEVICE API 49ed24f4bSMarc Zyngier * 59ed24f4bSMarc Zyngier * Copyright (C) 2015 ARM Ltd. 69ed24f4bSMarc Zyngier * Author: Marc Zyngier <marc.zyngier@arm.com> 79ed24f4bSMarc Zyngier */ 89ed24f4bSMarc Zyngier #include <linux/kvm_host.h> 99ed24f4bSMarc Zyngier #include <kvm/arm_vgic.h> 109ed24f4bSMarc Zyngier #include <linux/uaccess.h> 119ed24f4bSMarc Zyngier #include <asm/kvm_mmu.h> 129ed24f4bSMarc Zyngier #include <asm/cputype.h> 139ed24f4bSMarc Zyngier #include "vgic.h" 149ed24f4bSMarc Zyngier 159ed24f4bSMarc Zyngier /* common helpers */ 169ed24f4bSMarc Zyngier 179ed24f4bSMarc Zyngier int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr, 189ed24f4bSMarc Zyngier phys_addr_t addr, phys_addr_t alignment) 199ed24f4bSMarc Zyngier { 209ed24f4bSMarc Zyngier if (addr & ~kvm_phys_mask(kvm)) 219ed24f4bSMarc Zyngier return -E2BIG; 229ed24f4bSMarc Zyngier 239ed24f4bSMarc Zyngier if (!IS_ALIGNED(addr, alignment)) 249ed24f4bSMarc Zyngier return -EINVAL; 259ed24f4bSMarc Zyngier 269ed24f4bSMarc Zyngier if (!IS_VGIC_ADDR_UNDEF(*ioaddr)) 279ed24f4bSMarc Zyngier return -EEXIST; 289ed24f4bSMarc Zyngier 299ed24f4bSMarc Zyngier return 0; 309ed24f4bSMarc Zyngier } 319ed24f4bSMarc Zyngier 32*f25c5e4dSRicardo Koller int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr, 33*f25c5e4dSRicardo Koller phys_addr_t addr, phys_addr_t alignment, 34*f25c5e4dSRicardo Koller phys_addr_t size) 35*f25c5e4dSRicardo Koller { 36*f25c5e4dSRicardo Koller int ret; 37*f25c5e4dSRicardo Koller 38*f25c5e4dSRicardo Koller ret = vgic_check_ioaddr(kvm, &ioaddr, addr, alignment); 39*f25c5e4dSRicardo Koller if (ret) 40*f25c5e4dSRicardo Koller return ret; 41*f25c5e4dSRicardo Koller 42*f25c5e4dSRicardo Koller if (!IS_ALIGNED(size, alignment)) 43*f25c5e4dSRicardo Koller return -EINVAL; 44*f25c5e4dSRicardo Koller 45*f25c5e4dSRicardo Koller if (addr + size < addr) 46*f25c5e4dSRicardo Koller return -EINVAL; 47*f25c5e4dSRicardo Koller 48*f25c5e4dSRicardo Koller if (addr + size > kvm_phys_size(kvm)) 49*f25c5e4dSRicardo Koller return -E2BIG; 50*f25c5e4dSRicardo Koller 51*f25c5e4dSRicardo Koller return 0; 52*f25c5e4dSRicardo Koller } 53*f25c5e4dSRicardo Koller 549ed24f4bSMarc Zyngier static int vgic_check_type(struct kvm *kvm, int type_needed) 559ed24f4bSMarc Zyngier { 569ed24f4bSMarc Zyngier if (kvm->arch.vgic.vgic_model != type_needed) 579ed24f4bSMarc Zyngier return -ENODEV; 589ed24f4bSMarc Zyngier else 599ed24f4bSMarc Zyngier return 0; 609ed24f4bSMarc Zyngier } 619ed24f4bSMarc Zyngier 629ed24f4bSMarc Zyngier /** 639ed24f4bSMarc Zyngier * kvm_vgic_addr - set or get vgic VM base addresses 649ed24f4bSMarc Zyngier * @kvm: pointer to the vm struct 659ed24f4bSMarc Zyngier * @type: the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX 669ed24f4bSMarc Zyngier * @addr: pointer to address value 679ed24f4bSMarc Zyngier * @write: if true set the address in the VM address space, if false read the 689ed24f4bSMarc Zyngier * address 699ed24f4bSMarc Zyngier * 709ed24f4bSMarc Zyngier * Set or get the vgic base addresses for the distributor and the virtual CPU 719ed24f4bSMarc Zyngier * interface in the VM physical address space. These addresses are properties 729ed24f4bSMarc Zyngier * of the emulated core/SoC and therefore user space initially knows this 739ed24f4bSMarc Zyngier * information. 749ed24f4bSMarc Zyngier * Check them for sanity (alignment, double assignment). We can't check for 759ed24f4bSMarc Zyngier * overlapping regions in case of a virtual GICv3 here, since we don't know 769ed24f4bSMarc Zyngier * the number of VCPUs yet, so we defer this check to map_resources(). 779ed24f4bSMarc Zyngier */ 789ed24f4bSMarc Zyngier int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) 799ed24f4bSMarc Zyngier { 809ed24f4bSMarc Zyngier int r = 0; 819ed24f4bSMarc Zyngier struct vgic_dist *vgic = &kvm->arch.vgic; 829ed24f4bSMarc Zyngier phys_addr_t *addr_ptr, alignment; 839ed24f4bSMarc Zyngier u64 undef_value = VGIC_ADDR_UNDEF; 849ed24f4bSMarc Zyngier 859ed24f4bSMarc Zyngier mutex_lock(&kvm->lock); 869ed24f4bSMarc Zyngier switch (type) { 879ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_DIST: 889ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); 899ed24f4bSMarc Zyngier addr_ptr = &vgic->vgic_dist_base; 909ed24f4bSMarc Zyngier alignment = SZ_4K; 919ed24f4bSMarc Zyngier break; 929ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_CPU: 939ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); 949ed24f4bSMarc Zyngier addr_ptr = &vgic->vgic_cpu_base; 959ed24f4bSMarc Zyngier alignment = SZ_4K; 969ed24f4bSMarc Zyngier break; 979ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_DIST: 989ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3); 999ed24f4bSMarc Zyngier addr_ptr = &vgic->vgic_dist_base; 1009ed24f4bSMarc Zyngier alignment = SZ_64K; 1019ed24f4bSMarc Zyngier break; 1029ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST: { 1039ed24f4bSMarc Zyngier struct vgic_redist_region *rdreg; 1049ed24f4bSMarc Zyngier 1059ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3); 1069ed24f4bSMarc Zyngier if (r) 1079ed24f4bSMarc Zyngier break; 1089ed24f4bSMarc Zyngier if (write) { 1099ed24f4bSMarc Zyngier r = vgic_v3_set_redist_base(kvm, 0, *addr, 0); 1109ed24f4bSMarc Zyngier goto out; 1119ed24f4bSMarc Zyngier } 11294ac0835SEric Auger rdreg = list_first_entry_or_null(&vgic->rd_regions, 1139ed24f4bSMarc Zyngier struct vgic_redist_region, list); 1149ed24f4bSMarc Zyngier if (!rdreg) 1159ed24f4bSMarc Zyngier addr_ptr = &undef_value; 1169ed24f4bSMarc Zyngier else 1179ed24f4bSMarc Zyngier addr_ptr = &rdreg->base; 1189ed24f4bSMarc Zyngier break; 1199ed24f4bSMarc Zyngier } 1209ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION: 1219ed24f4bSMarc Zyngier { 1229ed24f4bSMarc Zyngier struct vgic_redist_region *rdreg; 1239ed24f4bSMarc Zyngier u8 index; 1249ed24f4bSMarc Zyngier 1259ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3); 1269ed24f4bSMarc Zyngier if (r) 1279ed24f4bSMarc Zyngier break; 1289ed24f4bSMarc Zyngier 1299ed24f4bSMarc Zyngier index = *addr & KVM_VGIC_V3_RDIST_INDEX_MASK; 1309ed24f4bSMarc Zyngier 1319ed24f4bSMarc Zyngier if (write) { 1329ed24f4bSMarc Zyngier gpa_t base = *addr & KVM_VGIC_V3_RDIST_BASE_MASK; 1339ed24f4bSMarc Zyngier u32 count = (*addr & KVM_VGIC_V3_RDIST_COUNT_MASK) 1349ed24f4bSMarc Zyngier >> KVM_VGIC_V3_RDIST_COUNT_SHIFT; 1359ed24f4bSMarc Zyngier u8 flags = (*addr & KVM_VGIC_V3_RDIST_FLAGS_MASK) 1369ed24f4bSMarc Zyngier >> KVM_VGIC_V3_RDIST_FLAGS_SHIFT; 1379ed24f4bSMarc Zyngier 1389ed24f4bSMarc Zyngier if (!count || flags) 1399ed24f4bSMarc Zyngier r = -EINVAL; 1409ed24f4bSMarc Zyngier else 1419ed24f4bSMarc Zyngier r = vgic_v3_set_redist_base(kvm, index, 1429ed24f4bSMarc Zyngier base, count); 1439ed24f4bSMarc Zyngier goto out; 1449ed24f4bSMarc Zyngier } 1459ed24f4bSMarc Zyngier 1469ed24f4bSMarc Zyngier rdreg = vgic_v3_rdist_region_from_index(kvm, index); 1479ed24f4bSMarc Zyngier if (!rdreg) { 1489ed24f4bSMarc Zyngier r = -ENOENT; 1499ed24f4bSMarc Zyngier goto out; 1509ed24f4bSMarc Zyngier } 1519ed24f4bSMarc Zyngier 1529ed24f4bSMarc Zyngier *addr = index; 1539ed24f4bSMarc Zyngier *addr |= rdreg->base; 1549ed24f4bSMarc Zyngier *addr |= (u64)rdreg->count << KVM_VGIC_V3_RDIST_COUNT_SHIFT; 1559ed24f4bSMarc Zyngier goto out; 1569ed24f4bSMarc Zyngier } 1579ed24f4bSMarc Zyngier default: 1589ed24f4bSMarc Zyngier r = -ENODEV; 1599ed24f4bSMarc Zyngier } 1609ed24f4bSMarc Zyngier 1619ed24f4bSMarc Zyngier if (r) 1629ed24f4bSMarc Zyngier goto out; 1639ed24f4bSMarc Zyngier 1649ed24f4bSMarc Zyngier if (write) { 1659ed24f4bSMarc Zyngier r = vgic_check_ioaddr(kvm, addr_ptr, *addr, alignment); 1669ed24f4bSMarc Zyngier if (!r) 1679ed24f4bSMarc Zyngier *addr_ptr = *addr; 1689ed24f4bSMarc Zyngier } else { 1699ed24f4bSMarc Zyngier *addr = *addr_ptr; 1709ed24f4bSMarc Zyngier } 1719ed24f4bSMarc Zyngier 1729ed24f4bSMarc Zyngier out: 1739ed24f4bSMarc Zyngier mutex_unlock(&kvm->lock); 1749ed24f4bSMarc Zyngier return r; 1759ed24f4bSMarc Zyngier } 1769ed24f4bSMarc Zyngier 1779ed24f4bSMarc Zyngier static int vgic_set_common_attr(struct kvm_device *dev, 1789ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 1799ed24f4bSMarc Zyngier { 1809ed24f4bSMarc Zyngier int r; 1819ed24f4bSMarc Zyngier 1829ed24f4bSMarc Zyngier switch (attr->group) { 1839ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR: { 1849ed24f4bSMarc Zyngier u64 __user *uaddr = (u64 __user *)(long)attr->addr; 1859ed24f4bSMarc Zyngier u64 addr; 1869ed24f4bSMarc Zyngier unsigned long type = (unsigned long)attr->attr; 1879ed24f4bSMarc Zyngier 1889ed24f4bSMarc Zyngier if (copy_from_user(&addr, uaddr, sizeof(addr))) 1899ed24f4bSMarc Zyngier return -EFAULT; 1909ed24f4bSMarc Zyngier 1919ed24f4bSMarc Zyngier r = kvm_vgic_addr(dev->kvm, type, &addr, true); 1929ed24f4bSMarc Zyngier return (r == -ENODEV) ? -ENXIO : r; 1939ed24f4bSMarc Zyngier } 1949ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { 1959ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 1969ed24f4bSMarc Zyngier u32 val; 1979ed24f4bSMarc Zyngier int ret = 0; 1989ed24f4bSMarc Zyngier 1999ed24f4bSMarc Zyngier if (get_user(val, uaddr)) 2009ed24f4bSMarc Zyngier return -EFAULT; 2019ed24f4bSMarc Zyngier 2029ed24f4bSMarc Zyngier /* 2039ed24f4bSMarc Zyngier * We require: 2049ed24f4bSMarc Zyngier * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs 2059ed24f4bSMarc Zyngier * - at most 1024 interrupts 2069ed24f4bSMarc Zyngier * - a multiple of 32 interrupts 2079ed24f4bSMarc Zyngier */ 2089ed24f4bSMarc Zyngier if (val < (VGIC_NR_PRIVATE_IRQS + 32) || 2099ed24f4bSMarc Zyngier val > VGIC_MAX_RESERVED || 2109ed24f4bSMarc Zyngier (val & 31)) 2119ed24f4bSMarc Zyngier return -EINVAL; 2129ed24f4bSMarc Zyngier 2139ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock); 2149ed24f4bSMarc Zyngier 2159ed24f4bSMarc Zyngier if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis) 2169ed24f4bSMarc Zyngier ret = -EBUSY; 2179ed24f4bSMarc Zyngier else 2189ed24f4bSMarc Zyngier dev->kvm->arch.vgic.nr_spis = 2199ed24f4bSMarc Zyngier val - VGIC_NR_PRIVATE_IRQS; 2209ed24f4bSMarc Zyngier 2219ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock); 2229ed24f4bSMarc Zyngier 2239ed24f4bSMarc Zyngier return ret; 2249ed24f4bSMarc Zyngier } 2259ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL: { 2269ed24f4bSMarc Zyngier switch (attr->attr) { 2279ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_CTRL_INIT: 2289ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock); 2299ed24f4bSMarc Zyngier r = vgic_init(dev->kvm); 2309ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock); 2319ed24f4bSMarc Zyngier return r; 2329ed24f4bSMarc Zyngier } 2339ed24f4bSMarc Zyngier break; 2349ed24f4bSMarc Zyngier } 2359ed24f4bSMarc Zyngier } 2369ed24f4bSMarc Zyngier 2379ed24f4bSMarc Zyngier return -ENXIO; 2389ed24f4bSMarc Zyngier } 2399ed24f4bSMarc Zyngier 2409ed24f4bSMarc Zyngier static int vgic_get_common_attr(struct kvm_device *dev, 2419ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 2429ed24f4bSMarc Zyngier { 2439ed24f4bSMarc Zyngier int r = -ENXIO; 2449ed24f4bSMarc Zyngier 2459ed24f4bSMarc Zyngier switch (attr->group) { 2469ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR: { 2479ed24f4bSMarc Zyngier u64 __user *uaddr = (u64 __user *)(long)attr->addr; 2489ed24f4bSMarc Zyngier u64 addr; 2499ed24f4bSMarc Zyngier unsigned long type = (unsigned long)attr->attr; 2509ed24f4bSMarc Zyngier 25153b16dd6SEric Auger if (copy_from_user(&addr, uaddr, sizeof(addr))) 25253b16dd6SEric Auger return -EFAULT; 25353b16dd6SEric Auger 2549ed24f4bSMarc Zyngier r = kvm_vgic_addr(dev->kvm, type, &addr, false); 2559ed24f4bSMarc Zyngier if (r) 2569ed24f4bSMarc Zyngier return (r == -ENODEV) ? -ENXIO : r; 2579ed24f4bSMarc Zyngier 2589ed24f4bSMarc Zyngier if (copy_to_user(uaddr, &addr, sizeof(addr))) 2599ed24f4bSMarc Zyngier return -EFAULT; 2609ed24f4bSMarc Zyngier break; 2619ed24f4bSMarc Zyngier } 2629ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { 2639ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 2649ed24f4bSMarc Zyngier 2659ed24f4bSMarc Zyngier r = put_user(dev->kvm->arch.vgic.nr_spis + 2669ed24f4bSMarc Zyngier VGIC_NR_PRIVATE_IRQS, uaddr); 2679ed24f4bSMarc Zyngier break; 2689ed24f4bSMarc Zyngier } 2699ed24f4bSMarc Zyngier } 2709ed24f4bSMarc Zyngier 2719ed24f4bSMarc Zyngier return r; 2729ed24f4bSMarc Zyngier } 2739ed24f4bSMarc Zyngier 2749ed24f4bSMarc Zyngier static int vgic_create(struct kvm_device *dev, u32 type) 2759ed24f4bSMarc Zyngier { 2769ed24f4bSMarc Zyngier return kvm_vgic_create(dev->kvm, type); 2779ed24f4bSMarc Zyngier } 2789ed24f4bSMarc Zyngier 2799ed24f4bSMarc Zyngier static void vgic_destroy(struct kvm_device *dev) 2809ed24f4bSMarc Zyngier { 2819ed24f4bSMarc Zyngier kfree(dev); 2829ed24f4bSMarc Zyngier } 2839ed24f4bSMarc Zyngier 2849ed24f4bSMarc Zyngier int kvm_register_vgic_device(unsigned long type) 2859ed24f4bSMarc Zyngier { 2869ed24f4bSMarc Zyngier int ret = -ENODEV; 2879ed24f4bSMarc Zyngier 2889ed24f4bSMarc Zyngier switch (type) { 2899ed24f4bSMarc Zyngier case KVM_DEV_TYPE_ARM_VGIC_V2: 2909ed24f4bSMarc Zyngier ret = kvm_register_device_ops(&kvm_arm_vgic_v2_ops, 2919ed24f4bSMarc Zyngier KVM_DEV_TYPE_ARM_VGIC_V2); 2929ed24f4bSMarc Zyngier break; 2939ed24f4bSMarc Zyngier case KVM_DEV_TYPE_ARM_VGIC_V3: 2949ed24f4bSMarc Zyngier ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops, 2959ed24f4bSMarc Zyngier KVM_DEV_TYPE_ARM_VGIC_V3); 2969ed24f4bSMarc Zyngier 2979ed24f4bSMarc Zyngier if (ret) 2989ed24f4bSMarc Zyngier break; 2999ed24f4bSMarc Zyngier ret = kvm_vgic_register_its_device(); 3009ed24f4bSMarc Zyngier break; 3019ed24f4bSMarc Zyngier } 3029ed24f4bSMarc Zyngier 3039ed24f4bSMarc Zyngier return ret; 3049ed24f4bSMarc Zyngier } 3059ed24f4bSMarc Zyngier 3069ed24f4bSMarc Zyngier int vgic_v2_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, 3079ed24f4bSMarc Zyngier struct vgic_reg_attr *reg_attr) 3089ed24f4bSMarc Zyngier { 3099ed24f4bSMarc Zyngier int cpuid; 3109ed24f4bSMarc Zyngier 3119ed24f4bSMarc Zyngier cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >> 3129ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_CPUID_SHIFT; 3139ed24f4bSMarc Zyngier 3149ed24f4bSMarc Zyngier if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) 3159ed24f4bSMarc Zyngier return -EINVAL; 3169ed24f4bSMarc Zyngier 3179ed24f4bSMarc Zyngier reg_attr->vcpu = kvm_get_vcpu(dev->kvm, cpuid); 3189ed24f4bSMarc Zyngier reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; 3199ed24f4bSMarc Zyngier 3209ed24f4bSMarc Zyngier return 0; 3219ed24f4bSMarc Zyngier } 3229ed24f4bSMarc Zyngier 3239ed24f4bSMarc Zyngier /* unlocks vcpus from @vcpu_lock_idx and smaller */ 3249ed24f4bSMarc Zyngier static void unlock_vcpus(struct kvm *kvm, int vcpu_lock_idx) 3259ed24f4bSMarc Zyngier { 3269ed24f4bSMarc Zyngier struct kvm_vcpu *tmp_vcpu; 3279ed24f4bSMarc Zyngier 3289ed24f4bSMarc Zyngier for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) { 3299ed24f4bSMarc Zyngier tmp_vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx); 3309ed24f4bSMarc Zyngier mutex_unlock(&tmp_vcpu->mutex); 3319ed24f4bSMarc Zyngier } 3329ed24f4bSMarc Zyngier } 3339ed24f4bSMarc Zyngier 3349ed24f4bSMarc Zyngier void unlock_all_vcpus(struct kvm *kvm) 3359ed24f4bSMarc Zyngier { 3369ed24f4bSMarc Zyngier unlock_vcpus(kvm, atomic_read(&kvm->online_vcpus) - 1); 3379ed24f4bSMarc Zyngier } 3389ed24f4bSMarc Zyngier 3399ed24f4bSMarc Zyngier /* Returns true if all vcpus were locked, false otherwise */ 3409ed24f4bSMarc Zyngier bool lock_all_vcpus(struct kvm *kvm) 3419ed24f4bSMarc Zyngier { 3429ed24f4bSMarc Zyngier struct kvm_vcpu *tmp_vcpu; 3439ed24f4bSMarc Zyngier int c; 3449ed24f4bSMarc Zyngier 3459ed24f4bSMarc Zyngier /* 3469ed24f4bSMarc Zyngier * Any time a vcpu is run, vcpu_load is called which tries to grab the 3479ed24f4bSMarc Zyngier * vcpu->mutex. By grabbing the vcpu->mutex of all VCPUs we ensure 3489ed24f4bSMarc Zyngier * that no other VCPUs are run and fiddle with the vgic state while we 3499ed24f4bSMarc Zyngier * access it. 3509ed24f4bSMarc Zyngier */ 3519ed24f4bSMarc Zyngier kvm_for_each_vcpu(c, tmp_vcpu, kvm) { 3529ed24f4bSMarc Zyngier if (!mutex_trylock(&tmp_vcpu->mutex)) { 3539ed24f4bSMarc Zyngier unlock_vcpus(kvm, c - 1); 3549ed24f4bSMarc Zyngier return false; 3559ed24f4bSMarc Zyngier } 3569ed24f4bSMarc Zyngier } 3579ed24f4bSMarc Zyngier 3589ed24f4bSMarc Zyngier return true; 3599ed24f4bSMarc Zyngier } 3609ed24f4bSMarc Zyngier 3619ed24f4bSMarc Zyngier /** 3629ed24f4bSMarc Zyngier * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state 3639ed24f4bSMarc Zyngier * 3649ed24f4bSMarc Zyngier * @dev: kvm device handle 3659ed24f4bSMarc Zyngier * @attr: kvm device attribute 3669ed24f4bSMarc Zyngier * @reg: address the value is read or written 3679ed24f4bSMarc Zyngier * @is_write: true if userspace is writing a register 3689ed24f4bSMarc Zyngier */ 3699ed24f4bSMarc Zyngier static int vgic_v2_attr_regs_access(struct kvm_device *dev, 3709ed24f4bSMarc Zyngier struct kvm_device_attr *attr, 3719ed24f4bSMarc Zyngier u32 *reg, bool is_write) 3729ed24f4bSMarc Zyngier { 3739ed24f4bSMarc Zyngier struct vgic_reg_attr reg_attr; 3749ed24f4bSMarc Zyngier gpa_t addr; 3759ed24f4bSMarc Zyngier struct kvm_vcpu *vcpu; 3769ed24f4bSMarc Zyngier int ret; 3779ed24f4bSMarc Zyngier 3789ed24f4bSMarc Zyngier ret = vgic_v2_parse_attr(dev, attr, ®_attr); 3799ed24f4bSMarc Zyngier if (ret) 3809ed24f4bSMarc Zyngier return ret; 3819ed24f4bSMarc Zyngier 3829ed24f4bSMarc Zyngier vcpu = reg_attr.vcpu; 3839ed24f4bSMarc Zyngier addr = reg_attr.addr; 3849ed24f4bSMarc Zyngier 3859ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock); 3869ed24f4bSMarc Zyngier 3879ed24f4bSMarc Zyngier ret = vgic_init(dev->kvm); 3889ed24f4bSMarc Zyngier if (ret) 3899ed24f4bSMarc Zyngier goto out; 3909ed24f4bSMarc Zyngier 3919ed24f4bSMarc Zyngier if (!lock_all_vcpus(dev->kvm)) { 3929ed24f4bSMarc Zyngier ret = -EBUSY; 3939ed24f4bSMarc Zyngier goto out; 3949ed24f4bSMarc Zyngier } 3959ed24f4bSMarc Zyngier 3969ed24f4bSMarc Zyngier switch (attr->group) { 3979ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: 3989ed24f4bSMarc Zyngier ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg); 3999ed24f4bSMarc Zyngier break; 4009ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 4019ed24f4bSMarc Zyngier ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg); 4029ed24f4bSMarc Zyngier break; 4039ed24f4bSMarc Zyngier default: 4049ed24f4bSMarc Zyngier ret = -EINVAL; 4059ed24f4bSMarc Zyngier break; 4069ed24f4bSMarc Zyngier } 4079ed24f4bSMarc Zyngier 4089ed24f4bSMarc Zyngier unlock_all_vcpus(dev->kvm); 4099ed24f4bSMarc Zyngier out: 4109ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock); 4119ed24f4bSMarc Zyngier return ret; 4129ed24f4bSMarc Zyngier } 4139ed24f4bSMarc Zyngier 4149ed24f4bSMarc Zyngier static int vgic_v2_set_attr(struct kvm_device *dev, 4159ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 4169ed24f4bSMarc Zyngier { 4179ed24f4bSMarc Zyngier int ret; 4189ed24f4bSMarc Zyngier 4199ed24f4bSMarc Zyngier ret = vgic_set_common_attr(dev, attr); 4209ed24f4bSMarc Zyngier if (ret != -ENXIO) 4219ed24f4bSMarc Zyngier return ret; 4229ed24f4bSMarc Zyngier 4239ed24f4bSMarc Zyngier switch (attr->group) { 4249ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 4259ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { 4269ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 4279ed24f4bSMarc Zyngier u32 reg; 4289ed24f4bSMarc Zyngier 4299ed24f4bSMarc Zyngier if (get_user(reg, uaddr)) 4309ed24f4bSMarc Zyngier return -EFAULT; 4319ed24f4bSMarc Zyngier 4329ed24f4bSMarc Zyngier return vgic_v2_attr_regs_access(dev, attr, ®, true); 4339ed24f4bSMarc Zyngier } 4349ed24f4bSMarc Zyngier } 4359ed24f4bSMarc Zyngier 4369ed24f4bSMarc Zyngier return -ENXIO; 4379ed24f4bSMarc Zyngier } 4389ed24f4bSMarc Zyngier 4399ed24f4bSMarc Zyngier static int vgic_v2_get_attr(struct kvm_device *dev, 4409ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 4419ed24f4bSMarc Zyngier { 4429ed24f4bSMarc Zyngier int ret; 4439ed24f4bSMarc Zyngier 4449ed24f4bSMarc Zyngier ret = vgic_get_common_attr(dev, attr); 4459ed24f4bSMarc Zyngier if (ret != -ENXIO) 4469ed24f4bSMarc Zyngier return ret; 4479ed24f4bSMarc Zyngier 4489ed24f4bSMarc Zyngier switch (attr->group) { 4499ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 4509ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { 4519ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 4529ed24f4bSMarc Zyngier u32 reg = 0; 4539ed24f4bSMarc Zyngier 4549ed24f4bSMarc Zyngier ret = vgic_v2_attr_regs_access(dev, attr, ®, false); 4559ed24f4bSMarc Zyngier if (ret) 4569ed24f4bSMarc Zyngier return ret; 4579ed24f4bSMarc Zyngier return put_user(reg, uaddr); 4589ed24f4bSMarc Zyngier } 4599ed24f4bSMarc Zyngier } 4609ed24f4bSMarc Zyngier 4619ed24f4bSMarc Zyngier return -ENXIO; 4629ed24f4bSMarc Zyngier } 4639ed24f4bSMarc Zyngier 4649ed24f4bSMarc Zyngier static int vgic_v2_has_attr(struct kvm_device *dev, 4659ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 4669ed24f4bSMarc Zyngier { 4679ed24f4bSMarc Zyngier switch (attr->group) { 4689ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR: 4699ed24f4bSMarc Zyngier switch (attr->attr) { 4709ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_DIST: 4719ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_CPU: 4729ed24f4bSMarc Zyngier return 0; 4739ed24f4bSMarc Zyngier } 4749ed24f4bSMarc Zyngier break; 4759ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 4769ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: 4779ed24f4bSMarc Zyngier return vgic_v2_has_attr_regs(dev, attr); 4789ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: 4799ed24f4bSMarc Zyngier return 0; 4809ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL: 4819ed24f4bSMarc Zyngier switch (attr->attr) { 4829ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_CTRL_INIT: 4839ed24f4bSMarc Zyngier return 0; 4849ed24f4bSMarc Zyngier } 4859ed24f4bSMarc Zyngier } 4869ed24f4bSMarc Zyngier return -ENXIO; 4879ed24f4bSMarc Zyngier } 4889ed24f4bSMarc Zyngier 4899ed24f4bSMarc Zyngier struct kvm_device_ops kvm_arm_vgic_v2_ops = { 4909ed24f4bSMarc Zyngier .name = "kvm-arm-vgic-v2", 4919ed24f4bSMarc Zyngier .create = vgic_create, 4929ed24f4bSMarc Zyngier .destroy = vgic_destroy, 4939ed24f4bSMarc Zyngier .set_attr = vgic_v2_set_attr, 4949ed24f4bSMarc Zyngier .get_attr = vgic_v2_get_attr, 4959ed24f4bSMarc Zyngier .has_attr = vgic_v2_has_attr, 4969ed24f4bSMarc Zyngier }; 4979ed24f4bSMarc Zyngier 4989ed24f4bSMarc Zyngier int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, 4999ed24f4bSMarc Zyngier struct vgic_reg_attr *reg_attr) 5009ed24f4bSMarc Zyngier { 5019ed24f4bSMarc Zyngier unsigned long vgic_mpidr, mpidr_reg; 5029ed24f4bSMarc Zyngier 5039ed24f4bSMarc Zyngier /* 5049ed24f4bSMarc Zyngier * For KVM_DEV_ARM_VGIC_GRP_DIST_REGS group, 5059ed24f4bSMarc Zyngier * attr might not hold MPIDR. Hence assume vcpu0. 5069ed24f4bSMarc Zyngier */ 5079ed24f4bSMarc Zyngier if (attr->group != KVM_DEV_ARM_VGIC_GRP_DIST_REGS) { 5089ed24f4bSMarc Zyngier vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >> 5099ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT; 5109ed24f4bSMarc Zyngier 5119ed24f4bSMarc Zyngier mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr); 5129ed24f4bSMarc Zyngier reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg); 5139ed24f4bSMarc Zyngier } else { 5149ed24f4bSMarc Zyngier reg_attr->vcpu = kvm_get_vcpu(dev->kvm, 0); 5159ed24f4bSMarc Zyngier } 5169ed24f4bSMarc Zyngier 5179ed24f4bSMarc Zyngier if (!reg_attr->vcpu) 5189ed24f4bSMarc Zyngier return -EINVAL; 5199ed24f4bSMarc Zyngier 5209ed24f4bSMarc Zyngier reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; 5219ed24f4bSMarc Zyngier 5229ed24f4bSMarc Zyngier return 0; 5239ed24f4bSMarc Zyngier } 5249ed24f4bSMarc Zyngier 5259ed24f4bSMarc Zyngier /* 5269ed24f4bSMarc Zyngier * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state 5279ed24f4bSMarc Zyngier * 5289ed24f4bSMarc Zyngier * @dev: kvm device handle 5299ed24f4bSMarc Zyngier * @attr: kvm device attribute 5309ed24f4bSMarc Zyngier * @reg: address the value is read or written 5319ed24f4bSMarc Zyngier * @is_write: true if userspace is writing a register 5329ed24f4bSMarc Zyngier */ 5339ed24f4bSMarc Zyngier static int vgic_v3_attr_regs_access(struct kvm_device *dev, 5349ed24f4bSMarc Zyngier struct kvm_device_attr *attr, 5359ed24f4bSMarc Zyngier u64 *reg, bool is_write) 5369ed24f4bSMarc Zyngier { 5379ed24f4bSMarc Zyngier struct vgic_reg_attr reg_attr; 5389ed24f4bSMarc Zyngier gpa_t addr; 5399ed24f4bSMarc Zyngier struct kvm_vcpu *vcpu; 5409ed24f4bSMarc Zyngier int ret; 5419ed24f4bSMarc Zyngier u32 tmp32; 5429ed24f4bSMarc Zyngier 5439ed24f4bSMarc Zyngier ret = vgic_v3_parse_attr(dev, attr, ®_attr); 5449ed24f4bSMarc Zyngier if (ret) 5459ed24f4bSMarc Zyngier return ret; 5469ed24f4bSMarc Zyngier 5479ed24f4bSMarc Zyngier vcpu = reg_attr.vcpu; 5489ed24f4bSMarc Zyngier addr = reg_attr.addr; 5499ed24f4bSMarc Zyngier 5509ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock); 5519ed24f4bSMarc Zyngier 5529ed24f4bSMarc Zyngier if (unlikely(!vgic_initialized(dev->kvm))) { 5539ed24f4bSMarc Zyngier ret = -EBUSY; 5549ed24f4bSMarc Zyngier goto out; 5559ed24f4bSMarc Zyngier } 5569ed24f4bSMarc Zyngier 5579ed24f4bSMarc Zyngier if (!lock_all_vcpus(dev->kvm)) { 5589ed24f4bSMarc Zyngier ret = -EBUSY; 5599ed24f4bSMarc Zyngier goto out; 5609ed24f4bSMarc Zyngier } 5619ed24f4bSMarc Zyngier 5629ed24f4bSMarc Zyngier switch (attr->group) { 5639ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 5649ed24f4bSMarc Zyngier if (is_write) 5659ed24f4bSMarc Zyngier tmp32 = *reg; 5669ed24f4bSMarc Zyngier 5679ed24f4bSMarc Zyngier ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32); 5689ed24f4bSMarc Zyngier if (!is_write) 5699ed24f4bSMarc Zyngier *reg = tmp32; 5709ed24f4bSMarc Zyngier break; 5719ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: 5729ed24f4bSMarc Zyngier if (is_write) 5739ed24f4bSMarc Zyngier tmp32 = *reg; 5749ed24f4bSMarc Zyngier 5759ed24f4bSMarc Zyngier ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32); 5769ed24f4bSMarc Zyngier if (!is_write) 5779ed24f4bSMarc Zyngier *reg = tmp32; 5789ed24f4bSMarc Zyngier break; 5799ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { 5809ed24f4bSMarc Zyngier u64 regid; 5819ed24f4bSMarc Zyngier 5829ed24f4bSMarc Zyngier regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK); 5839ed24f4bSMarc Zyngier ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write, 5849ed24f4bSMarc Zyngier regid, reg); 5859ed24f4bSMarc Zyngier break; 5869ed24f4bSMarc Zyngier } 5879ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { 5889ed24f4bSMarc Zyngier unsigned int info, intid; 5899ed24f4bSMarc Zyngier 5909ed24f4bSMarc Zyngier info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >> 5919ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT; 5929ed24f4bSMarc Zyngier if (info == VGIC_LEVEL_INFO_LINE_LEVEL) { 5939ed24f4bSMarc Zyngier intid = attr->attr & 5949ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK; 5959ed24f4bSMarc Zyngier ret = vgic_v3_line_level_info_uaccess(vcpu, is_write, 5969ed24f4bSMarc Zyngier intid, reg); 5979ed24f4bSMarc Zyngier } else { 5989ed24f4bSMarc Zyngier ret = -EINVAL; 5999ed24f4bSMarc Zyngier } 6009ed24f4bSMarc Zyngier break; 6019ed24f4bSMarc Zyngier } 6029ed24f4bSMarc Zyngier default: 6039ed24f4bSMarc Zyngier ret = -EINVAL; 6049ed24f4bSMarc Zyngier break; 6059ed24f4bSMarc Zyngier } 6069ed24f4bSMarc Zyngier 6079ed24f4bSMarc Zyngier unlock_all_vcpus(dev->kvm); 6089ed24f4bSMarc Zyngier out: 6099ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock); 6109ed24f4bSMarc Zyngier return ret; 6119ed24f4bSMarc Zyngier } 6129ed24f4bSMarc Zyngier 6139ed24f4bSMarc Zyngier static int vgic_v3_set_attr(struct kvm_device *dev, 6149ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 6159ed24f4bSMarc Zyngier { 6169ed24f4bSMarc Zyngier int ret; 6179ed24f4bSMarc Zyngier 6189ed24f4bSMarc Zyngier ret = vgic_set_common_attr(dev, attr); 6199ed24f4bSMarc Zyngier if (ret != -ENXIO) 6209ed24f4bSMarc Zyngier return ret; 6219ed24f4bSMarc Zyngier 6229ed24f4bSMarc Zyngier switch (attr->group) { 6239ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 6249ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: { 6259ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 6269ed24f4bSMarc Zyngier u32 tmp32; 6279ed24f4bSMarc Zyngier u64 reg; 6289ed24f4bSMarc Zyngier 6299ed24f4bSMarc Zyngier if (get_user(tmp32, uaddr)) 6309ed24f4bSMarc Zyngier return -EFAULT; 6319ed24f4bSMarc Zyngier 6329ed24f4bSMarc Zyngier reg = tmp32; 6339ed24f4bSMarc Zyngier return vgic_v3_attr_regs_access(dev, attr, ®, true); 6349ed24f4bSMarc Zyngier } 6359ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { 6369ed24f4bSMarc Zyngier u64 __user *uaddr = (u64 __user *)(long)attr->addr; 6379ed24f4bSMarc Zyngier u64 reg; 6389ed24f4bSMarc Zyngier 6399ed24f4bSMarc Zyngier if (get_user(reg, uaddr)) 6409ed24f4bSMarc Zyngier return -EFAULT; 6419ed24f4bSMarc Zyngier 6429ed24f4bSMarc Zyngier return vgic_v3_attr_regs_access(dev, attr, ®, true); 6439ed24f4bSMarc Zyngier } 6449ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { 6459ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 6469ed24f4bSMarc Zyngier u64 reg; 6479ed24f4bSMarc Zyngier u32 tmp32; 6489ed24f4bSMarc Zyngier 6499ed24f4bSMarc Zyngier if (get_user(tmp32, uaddr)) 6509ed24f4bSMarc Zyngier return -EFAULT; 6519ed24f4bSMarc Zyngier 6529ed24f4bSMarc Zyngier reg = tmp32; 6539ed24f4bSMarc Zyngier return vgic_v3_attr_regs_access(dev, attr, ®, true); 6549ed24f4bSMarc Zyngier } 6559ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL: { 6569ed24f4bSMarc Zyngier int ret; 6579ed24f4bSMarc Zyngier 6589ed24f4bSMarc Zyngier switch (attr->attr) { 6599ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES: 6609ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock); 6619ed24f4bSMarc Zyngier 6629ed24f4bSMarc Zyngier if (!lock_all_vcpus(dev->kvm)) { 6639ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock); 6649ed24f4bSMarc Zyngier return -EBUSY; 6659ed24f4bSMarc Zyngier } 6669ed24f4bSMarc Zyngier ret = vgic_v3_save_pending_tables(dev->kvm); 6679ed24f4bSMarc Zyngier unlock_all_vcpus(dev->kvm); 6689ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock); 6699ed24f4bSMarc Zyngier return ret; 6709ed24f4bSMarc Zyngier } 6719ed24f4bSMarc Zyngier break; 6729ed24f4bSMarc Zyngier } 6739ed24f4bSMarc Zyngier } 6749ed24f4bSMarc Zyngier return -ENXIO; 6759ed24f4bSMarc Zyngier } 6769ed24f4bSMarc Zyngier 6779ed24f4bSMarc Zyngier static int vgic_v3_get_attr(struct kvm_device *dev, 6789ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 6799ed24f4bSMarc Zyngier { 6809ed24f4bSMarc Zyngier int ret; 6819ed24f4bSMarc Zyngier 6829ed24f4bSMarc Zyngier ret = vgic_get_common_attr(dev, attr); 6839ed24f4bSMarc Zyngier if (ret != -ENXIO) 6849ed24f4bSMarc Zyngier return ret; 6859ed24f4bSMarc Zyngier 6869ed24f4bSMarc Zyngier switch (attr->group) { 6879ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 6889ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: { 6899ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 6909ed24f4bSMarc Zyngier u64 reg; 6919ed24f4bSMarc Zyngier u32 tmp32; 6929ed24f4bSMarc Zyngier 6939ed24f4bSMarc Zyngier ret = vgic_v3_attr_regs_access(dev, attr, ®, false); 6949ed24f4bSMarc Zyngier if (ret) 6959ed24f4bSMarc Zyngier return ret; 6969ed24f4bSMarc Zyngier tmp32 = reg; 6979ed24f4bSMarc Zyngier return put_user(tmp32, uaddr); 6989ed24f4bSMarc Zyngier } 6999ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { 7009ed24f4bSMarc Zyngier u64 __user *uaddr = (u64 __user *)(long)attr->addr; 7019ed24f4bSMarc Zyngier u64 reg; 7029ed24f4bSMarc Zyngier 7039ed24f4bSMarc Zyngier ret = vgic_v3_attr_regs_access(dev, attr, ®, false); 7049ed24f4bSMarc Zyngier if (ret) 7059ed24f4bSMarc Zyngier return ret; 7069ed24f4bSMarc Zyngier return put_user(reg, uaddr); 7079ed24f4bSMarc Zyngier } 7089ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { 7099ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 7109ed24f4bSMarc Zyngier u64 reg; 7119ed24f4bSMarc Zyngier u32 tmp32; 7129ed24f4bSMarc Zyngier 7139ed24f4bSMarc Zyngier ret = vgic_v3_attr_regs_access(dev, attr, ®, false); 7149ed24f4bSMarc Zyngier if (ret) 7159ed24f4bSMarc Zyngier return ret; 7169ed24f4bSMarc Zyngier tmp32 = reg; 7179ed24f4bSMarc Zyngier return put_user(tmp32, uaddr); 7189ed24f4bSMarc Zyngier } 7199ed24f4bSMarc Zyngier } 7209ed24f4bSMarc Zyngier return -ENXIO; 7219ed24f4bSMarc Zyngier } 7229ed24f4bSMarc Zyngier 7239ed24f4bSMarc Zyngier static int vgic_v3_has_attr(struct kvm_device *dev, 7249ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 7259ed24f4bSMarc Zyngier { 7269ed24f4bSMarc Zyngier switch (attr->group) { 7279ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR: 7289ed24f4bSMarc Zyngier switch (attr->attr) { 7299ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_DIST: 7309ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST: 7319ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION: 7329ed24f4bSMarc Zyngier return 0; 7339ed24f4bSMarc Zyngier } 7349ed24f4bSMarc Zyngier break; 7359ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 7369ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: 7379ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 7389ed24f4bSMarc Zyngier return vgic_v3_has_attr_regs(dev, attr); 7399ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: 7409ed24f4bSMarc Zyngier return 0; 7419ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { 7429ed24f4bSMarc Zyngier if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >> 7439ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) == 7449ed24f4bSMarc Zyngier VGIC_LEVEL_INFO_LINE_LEVEL) 7459ed24f4bSMarc Zyngier return 0; 7469ed24f4bSMarc Zyngier break; 7479ed24f4bSMarc Zyngier } 7489ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL: 7499ed24f4bSMarc Zyngier switch (attr->attr) { 7509ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_CTRL_INIT: 7519ed24f4bSMarc Zyngier return 0; 7529ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES: 7539ed24f4bSMarc Zyngier return 0; 7549ed24f4bSMarc Zyngier } 7559ed24f4bSMarc Zyngier } 7569ed24f4bSMarc Zyngier return -ENXIO; 7579ed24f4bSMarc Zyngier } 7589ed24f4bSMarc Zyngier 7599ed24f4bSMarc Zyngier struct kvm_device_ops kvm_arm_vgic_v3_ops = { 7609ed24f4bSMarc Zyngier .name = "kvm-arm-vgic-v3", 7619ed24f4bSMarc Zyngier .create = vgic_create, 7629ed24f4bSMarc Zyngier .destroy = vgic_destroy, 7639ed24f4bSMarc Zyngier .set_attr = vgic_v3_set_attr, 7649ed24f4bSMarc Zyngier .get_attr = vgic_v3_get_attr, 7659ed24f4bSMarc Zyngier .has_attr = vgic_v3_has_attr, 7669ed24f4bSMarc Zyngier }; 767