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 17f25c5e4dSRicardo Koller int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr, 18f25c5e4dSRicardo Koller phys_addr_t addr, phys_addr_t alignment, 19f25c5e4dSRicardo Koller phys_addr_t size) 20f25c5e4dSRicardo Koller { 2196e90389SRicardo Koller if (!IS_VGIC_ADDR_UNDEF(ioaddr)) 2296e90389SRicardo Koller return -EEXIST; 23f25c5e4dSRicardo Koller 2496e90389SRicardo Koller if (!IS_ALIGNED(addr, alignment) || !IS_ALIGNED(size, alignment)) 25f25c5e4dSRicardo Koller return -EINVAL; 26f25c5e4dSRicardo Koller 27f25c5e4dSRicardo Koller if (addr + size < addr) 28f25c5e4dSRicardo Koller return -EINVAL; 29f25c5e4dSRicardo Koller 3096e90389SRicardo Koller if (addr & ~kvm_phys_mask(kvm) || addr + size > kvm_phys_size(kvm)) 31f25c5e4dSRicardo Koller return -E2BIG; 32f25c5e4dSRicardo Koller 33f25c5e4dSRicardo Koller return 0; 34f25c5e4dSRicardo Koller } 35f25c5e4dSRicardo Koller 369ed24f4bSMarc Zyngier static int vgic_check_type(struct kvm *kvm, int type_needed) 379ed24f4bSMarc Zyngier { 389ed24f4bSMarc Zyngier if (kvm->arch.vgic.vgic_model != type_needed) 399ed24f4bSMarc Zyngier return -ENODEV; 409ed24f4bSMarc Zyngier else 419ed24f4bSMarc Zyngier return 0; 429ed24f4bSMarc Zyngier } 439ed24f4bSMarc Zyngier 449f968c92SMarc Zyngier int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr) 459f968c92SMarc Zyngier { 469f968c92SMarc Zyngier struct vgic_dist *vgic = &kvm->arch.vgic; 479f968c92SMarc Zyngier int r; 489f968c92SMarc Zyngier 49f0032773SOliver Upton mutex_lock(&kvm->arch.config_lock); 509f968c92SMarc Zyngier switch (FIELD_GET(KVM_ARM_DEVICE_TYPE_MASK, dev_addr->id)) { 519f968c92SMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_DIST: 529f968c92SMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); 539f968c92SMarc Zyngier if (!r) 549f968c92SMarc Zyngier r = vgic_check_iorange(kvm, vgic->vgic_dist_base, dev_addr->addr, 559f968c92SMarc Zyngier SZ_4K, KVM_VGIC_V2_DIST_SIZE); 569f968c92SMarc Zyngier if (!r) 579f968c92SMarc Zyngier vgic->vgic_dist_base = dev_addr->addr; 589f968c92SMarc Zyngier break; 599f968c92SMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_CPU: 609f968c92SMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); 619f968c92SMarc Zyngier if (!r) 629f968c92SMarc Zyngier r = vgic_check_iorange(kvm, vgic->vgic_cpu_base, dev_addr->addr, 639f968c92SMarc Zyngier SZ_4K, KVM_VGIC_V2_CPU_SIZE); 649f968c92SMarc Zyngier if (!r) 659f968c92SMarc Zyngier vgic->vgic_cpu_base = dev_addr->addr; 669f968c92SMarc Zyngier break; 679f968c92SMarc Zyngier default: 689f968c92SMarc Zyngier r = -ENODEV; 699f968c92SMarc Zyngier } 709f968c92SMarc Zyngier 71f0032773SOliver Upton mutex_unlock(&kvm->arch.config_lock); 729f968c92SMarc Zyngier 739f968c92SMarc Zyngier return r; 749f968c92SMarc Zyngier } 759f968c92SMarc Zyngier 769ed24f4bSMarc Zyngier /** 779ed24f4bSMarc Zyngier * kvm_vgic_addr - set or get vgic VM base addresses 789ed24f4bSMarc Zyngier * @kvm: pointer to the vm struct 794b85080fSMarc Zyngier * @attr: pointer to the attribute being retrieved/updated 809ed24f4bSMarc Zyngier * @write: if true set the address in the VM address space, if false read the 819ed24f4bSMarc Zyngier * address 829ed24f4bSMarc Zyngier * 839ed24f4bSMarc Zyngier * Set or get the vgic base addresses for the distributor and the virtual CPU 849ed24f4bSMarc Zyngier * interface in the VM physical address space. These addresses are properties 859ed24f4bSMarc Zyngier * of the emulated core/SoC and therefore user space initially knows this 869ed24f4bSMarc Zyngier * information. 879ed24f4bSMarc Zyngier * Check them for sanity (alignment, double assignment). We can't check for 889ed24f4bSMarc Zyngier * overlapping regions in case of a virtual GICv3 here, since we don't know 899ed24f4bSMarc Zyngier * the number of VCPUs yet, so we defer this check to map_resources(). 909ed24f4bSMarc Zyngier */ 914b85080fSMarc Zyngier static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool write) 929ed24f4bSMarc Zyngier { 934b85080fSMarc Zyngier u64 __user *uaddr = (u64 __user *)attr->addr; 949ed24f4bSMarc Zyngier struct vgic_dist *vgic = &kvm->arch.vgic; 95c56a87daSRicardo Koller phys_addr_t *addr_ptr, alignment, size; 969ed24f4bSMarc Zyngier u64 undef_value = VGIC_ADDR_UNDEF; 974b85080fSMarc Zyngier u64 addr; 984b85080fSMarc Zyngier int r; 994b85080fSMarc Zyngier 1004b85080fSMarc Zyngier /* Reading a redistributor region addr implies getting the index */ 1014b85080fSMarc Zyngier if (write || attr->attr == KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION) 1024b85080fSMarc Zyngier if (get_user(addr, uaddr)) 1034b85080fSMarc Zyngier return -EFAULT; 1049ed24f4bSMarc Zyngier 105*59112e9cSJean-Philippe Brucker /* 106*59112e9cSJean-Philippe Brucker * Since we can't hold config_lock while registering the redistributor 107*59112e9cSJean-Philippe Brucker * iodevs, take the slots_lock immediately. 108*59112e9cSJean-Philippe Brucker */ 109*59112e9cSJean-Philippe Brucker mutex_lock(&kvm->slots_lock); 1104b85080fSMarc Zyngier switch (attr->attr) { 1119ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_DIST: 1129ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); 1139ed24f4bSMarc Zyngier addr_ptr = &vgic->vgic_dist_base; 1149ed24f4bSMarc Zyngier alignment = SZ_4K; 115c56a87daSRicardo Koller size = KVM_VGIC_V2_DIST_SIZE; 1169ed24f4bSMarc Zyngier break; 1179ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_CPU: 1189ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); 1199ed24f4bSMarc Zyngier addr_ptr = &vgic->vgic_cpu_base; 1209ed24f4bSMarc Zyngier alignment = SZ_4K; 121c56a87daSRicardo Koller size = KVM_VGIC_V2_CPU_SIZE; 1229ed24f4bSMarc Zyngier break; 1239ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_DIST: 1249ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3); 1259ed24f4bSMarc Zyngier addr_ptr = &vgic->vgic_dist_base; 1269ed24f4bSMarc Zyngier alignment = SZ_64K; 127c56a87daSRicardo Koller size = KVM_VGIC_V3_DIST_SIZE; 1289ed24f4bSMarc Zyngier break; 1299ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST: { 1309ed24f4bSMarc Zyngier struct vgic_redist_region *rdreg; 1319ed24f4bSMarc Zyngier 1329ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3); 1339ed24f4bSMarc Zyngier if (r) 1349ed24f4bSMarc Zyngier break; 1359ed24f4bSMarc Zyngier if (write) { 1364b85080fSMarc Zyngier r = vgic_v3_set_redist_base(kvm, 0, addr, 0); 1379ed24f4bSMarc Zyngier goto out; 1389ed24f4bSMarc Zyngier } 13994ac0835SEric Auger rdreg = list_first_entry_or_null(&vgic->rd_regions, 1409ed24f4bSMarc Zyngier struct vgic_redist_region, list); 1419ed24f4bSMarc Zyngier if (!rdreg) 1429ed24f4bSMarc Zyngier addr_ptr = &undef_value; 1439ed24f4bSMarc Zyngier else 1449ed24f4bSMarc Zyngier addr_ptr = &rdreg->base; 1459ed24f4bSMarc Zyngier break; 1469ed24f4bSMarc Zyngier } 1479ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION: 1489ed24f4bSMarc Zyngier { 1499ed24f4bSMarc Zyngier struct vgic_redist_region *rdreg; 1509ed24f4bSMarc Zyngier u8 index; 1519ed24f4bSMarc Zyngier 1529ed24f4bSMarc Zyngier r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3); 1539ed24f4bSMarc Zyngier if (r) 1549ed24f4bSMarc Zyngier break; 1559ed24f4bSMarc Zyngier 1564b85080fSMarc Zyngier index = addr & KVM_VGIC_V3_RDIST_INDEX_MASK; 1579ed24f4bSMarc Zyngier 1589ed24f4bSMarc Zyngier if (write) { 1594b85080fSMarc Zyngier gpa_t base = addr & KVM_VGIC_V3_RDIST_BASE_MASK; 1604b85080fSMarc Zyngier u32 count = FIELD_GET(KVM_VGIC_V3_RDIST_COUNT_MASK, addr); 1614b85080fSMarc Zyngier u8 flags = FIELD_GET(KVM_VGIC_V3_RDIST_FLAGS_MASK, addr); 1629ed24f4bSMarc Zyngier 1639ed24f4bSMarc Zyngier if (!count || flags) 1649ed24f4bSMarc Zyngier r = -EINVAL; 1659ed24f4bSMarc Zyngier else 1669ed24f4bSMarc Zyngier r = vgic_v3_set_redist_base(kvm, index, 1679ed24f4bSMarc Zyngier base, count); 1689ed24f4bSMarc Zyngier goto out; 1699ed24f4bSMarc Zyngier } 1709ed24f4bSMarc Zyngier 1719ed24f4bSMarc Zyngier rdreg = vgic_v3_rdist_region_from_index(kvm, index); 1729ed24f4bSMarc Zyngier if (!rdreg) { 1739ed24f4bSMarc Zyngier r = -ENOENT; 1749ed24f4bSMarc Zyngier goto out; 1759ed24f4bSMarc Zyngier } 1769ed24f4bSMarc Zyngier 1774b85080fSMarc Zyngier addr = index; 1784b85080fSMarc Zyngier addr |= rdreg->base; 1794b85080fSMarc Zyngier addr |= (u64)rdreg->count << KVM_VGIC_V3_RDIST_COUNT_SHIFT; 1809ed24f4bSMarc Zyngier goto out; 1819ed24f4bSMarc Zyngier } 1829ed24f4bSMarc Zyngier default: 1839ed24f4bSMarc Zyngier r = -ENODEV; 1849ed24f4bSMarc Zyngier } 1859ed24f4bSMarc Zyngier 1869ed24f4bSMarc Zyngier if (r) 1879ed24f4bSMarc Zyngier goto out; 1889ed24f4bSMarc Zyngier 189*59112e9cSJean-Philippe Brucker mutex_lock(&kvm->arch.config_lock); 1909ed24f4bSMarc Zyngier if (write) { 1914b85080fSMarc Zyngier r = vgic_check_iorange(kvm, *addr_ptr, addr, alignment, size); 1929ed24f4bSMarc Zyngier if (!r) 1934b85080fSMarc Zyngier *addr_ptr = addr; 1949ed24f4bSMarc Zyngier } else { 1954b85080fSMarc Zyngier addr = *addr_ptr; 1969ed24f4bSMarc Zyngier } 197*59112e9cSJean-Philippe Brucker mutex_unlock(&kvm->arch.config_lock); 1989ed24f4bSMarc Zyngier 1999ed24f4bSMarc Zyngier out: 200*59112e9cSJean-Philippe Brucker mutex_unlock(&kvm->slots_lock); 2014b85080fSMarc Zyngier 2024b85080fSMarc Zyngier if (!r && !write) 2034b85080fSMarc Zyngier r = put_user(addr, uaddr); 2044b85080fSMarc Zyngier 2059ed24f4bSMarc Zyngier return r; 2069ed24f4bSMarc Zyngier } 2079ed24f4bSMarc Zyngier 2089ed24f4bSMarc Zyngier static int vgic_set_common_attr(struct kvm_device *dev, 2099ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 2109ed24f4bSMarc Zyngier { 2119ed24f4bSMarc Zyngier int r; 2129ed24f4bSMarc Zyngier 2139ed24f4bSMarc Zyngier switch (attr->group) { 2144b85080fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR: 2154b85080fSMarc Zyngier r = kvm_vgic_addr(dev->kvm, attr, true); 2169ed24f4bSMarc Zyngier return (r == -ENODEV) ? -ENXIO : r; 2179ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { 2189ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 2199ed24f4bSMarc Zyngier u32 val; 2209ed24f4bSMarc Zyngier int ret = 0; 2219ed24f4bSMarc Zyngier 2229ed24f4bSMarc Zyngier if (get_user(val, uaddr)) 2239ed24f4bSMarc Zyngier return -EFAULT; 2249ed24f4bSMarc Zyngier 2259ed24f4bSMarc Zyngier /* 2269ed24f4bSMarc Zyngier * We require: 2279ed24f4bSMarc Zyngier * - at least 32 SPIs on top of the 16 SGIs and 16 PPIs 2289ed24f4bSMarc Zyngier * - at most 1024 interrupts 2299ed24f4bSMarc Zyngier * - a multiple of 32 interrupts 2309ed24f4bSMarc Zyngier */ 2319ed24f4bSMarc Zyngier if (val < (VGIC_NR_PRIVATE_IRQS + 32) || 2329ed24f4bSMarc Zyngier val > VGIC_MAX_RESERVED || 2339ed24f4bSMarc Zyngier (val & 31)) 2349ed24f4bSMarc Zyngier return -EINVAL; 2359ed24f4bSMarc Zyngier 236f0032773SOliver Upton mutex_lock(&dev->kvm->arch.config_lock); 2379ed24f4bSMarc Zyngier 2389ed24f4bSMarc Zyngier if (vgic_ready(dev->kvm) || dev->kvm->arch.vgic.nr_spis) 2399ed24f4bSMarc Zyngier ret = -EBUSY; 2409ed24f4bSMarc Zyngier else 2419ed24f4bSMarc Zyngier dev->kvm->arch.vgic.nr_spis = 2429ed24f4bSMarc Zyngier val - VGIC_NR_PRIVATE_IRQS; 2439ed24f4bSMarc Zyngier 244f0032773SOliver Upton mutex_unlock(&dev->kvm->arch.config_lock); 2459ed24f4bSMarc Zyngier 2469ed24f4bSMarc Zyngier return ret; 2479ed24f4bSMarc Zyngier } 2489ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL: { 2499ed24f4bSMarc Zyngier switch (attr->attr) { 2509ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_CTRL_INIT: 251f0032773SOliver Upton mutex_lock(&dev->kvm->arch.config_lock); 2529ed24f4bSMarc Zyngier r = vgic_init(dev->kvm); 253f0032773SOliver Upton mutex_unlock(&dev->kvm->arch.config_lock); 2549ed24f4bSMarc Zyngier return r; 255619064afSMarc Zyngier case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES: 256619064afSMarc Zyngier /* 257619064afSMarc Zyngier * OK, this one isn't common at all, but we 258619064afSMarc Zyngier * want to handle all control group attributes 259619064afSMarc Zyngier * in a single place. 260619064afSMarc Zyngier */ 261619064afSMarc Zyngier if (vgic_check_type(dev->kvm, KVM_DEV_TYPE_ARM_VGIC_V3)) 262619064afSMarc Zyngier return -ENXIO; 263619064afSMarc Zyngier mutex_lock(&dev->kvm->lock); 264619064afSMarc Zyngier 265619064afSMarc Zyngier if (!lock_all_vcpus(dev->kvm)) { 266619064afSMarc Zyngier mutex_unlock(&dev->kvm->lock); 267619064afSMarc Zyngier return -EBUSY; 268619064afSMarc Zyngier } 269f0032773SOliver Upton 270f0032773SOliver Upton mutex_lock(&dev->kvm->arch.config_lock); 271619064afSMarc Zyngier r = vgic_v3_save_pending_tables(dev->kvm); 272f0032773SOliver Upton mutex_unlock(&dev->kvm->arch.config_lock); 273619064afSMarc Zyngier unlock_all_vcpus(dev->kvm); 274619064afSMarc Zyngier mutex_unlock(&dev->kvm->lock); 275619064afSMarc Zyngier return r; 2769ed24f4bSMarc Zyngier } 2779ed24f4bSMarc Zyngier break; 2789ed24f4bSMarc Zyngier } 2799ed24f4bSMarc Zyngier } 2809ed24f4bSMarc Zyngier 2819ed24f4bSMarc Zyngier return -ENXIO; 2829ed24f4bSMarc Zyngier } 2839ed24f4bSMarc Zyngier 2849ed24f4bSMarc Zyngier static int vgic_get_common_attr(struct kvm_device *dev, 2859ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 2869ed24f4bSMarc Zyngier { 2879ed24f4bSMarc Zyngier int r = -ENXIO; 2889ed24f4bSMarc Zyngier 2899ed24f4bSMarc Zyngier switch (attr->group) { 2904b85080fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR: 2914b85080fSMarc Zyngier r = kvm_vgic_addr(dev->kvm, attr, false); 2929ed24f4bSMarc Zyngier return (r == -ENODEV) ? -ENXIO : r; 2939ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { 2949ed24f4bSMarc Zyngier u32 __user *uaddr = (u32 __user *)(long)attr->addr; 2959ed24f4bSMarc Zyngier 2969ed24f4bSMarc Zyngier r = put_user(dev->kvm->arch.vgic.nr_spis + 2979ed24f4bSMarc Zyngier VGIC_NR_PRIVATE_IRQS, uaddr); 2989ed24f4bSMarc Zyngier break; 2999ed24f4bSMarc Zyngier } 3009ed24f4bSMarc Zyngier } 3019ed24f4bSMarc Zyngier 3029ed24f4bSMarc Zyngier return r; 3039ed24f4bSMarc Zyngier } 3049ed24f4bSMarc Zyngier 3059ed24f4bSMarc Zyngier static int vgic_create(struct kvm_device *dev, u32 type) 3069ed24f4bSMarc Zyngier { 3079ed24f4bSMarc Zyngier return kvm_vgic_create(dev->kvm, type); 3089ed24f4bSMarc Zyngier } 3099ed24f4bSMarc Zyngier 3109ed24f4bSMarc Zyngier static void vgic_destroy(struct kvm_device *dev) 3119ed24f4bSMarc Zyngier { 3129ed24f4bSMarc Zyngier kfree(dev); 3139ed24f4bSMarc Zyngier } 3149ed24f4bSMarc Zyngier 3159ed24f4bSMarc Zyngier int kvm_register_vgic_device(unsigned long type) 3169ed24f4bSMarc Zyngier { 3179ed24f4bSMarc Zyngier int ret = -ENODEV; 3189ed24f4bSMarc Zyngier 3199ed24f4bSMarc Zyngier switch (type) { 3209ed24f4bSMarc Zyngier case KVM_DEV_TYPE_ARM_VGIC_V2: 3219ed24f4bSMarc Zyngier ret = kvm_register_device_ops(&kvm_arm_vgic_v2_ops, 3229ed24f4bSMarc Zyngier KVM_DEV_TYPE_ARM_VGIC_V2); 3239ed24f4bSMarc Zyngier break; 3249ed24f4bSMarc Zyngier case KVM_DEV_TYPE_ARM_VGIC_V3: 3259ed24f4bSMarc Zyngier ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops, 3269ed24f4bSMarc Zyngier KVM_DEV_TYPE_ARM_VGIC_V3); 3279ed24f4bSMarc Zyngier 3289ed24f4bSMarc Zyngier if (ret) 3299ed24f4bSMarc Zyngier break; 3309ed24f4bSMarc Zyngier ret = kvm_vgic_register_its_device(); 3319ed24f4bSMarc Zyngier break; 3329ed24f4bSMarc Zyngier } 3339ed24f4bSMarc Zyngier 3349ed24f4bSMarc Zyngier return ret; 3359ed24f4bSMarc Zyngier } 3369ed24f4bSMarc Zyngier 3379ed24f4bSMarc Zyngier int vgic_v2_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, 3389ed24f4bSMarc Zyngier struct vgic_reg_attr *reg_attr) 3399ed24f4bSMarc Zyngier { 3409ed24f4bSMarc Zyngier int cpuid; 3419ed24f4bSMarc Zyngier 3429ed24f4bSMarc Zyngier cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >> 3439ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_CPUID_SHIFT; 3449ed24f4bSMarc Zyngier 3459ed24f4bSMarc Zyngier if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) 3469ed24f4bSMarc Zyngier return -EINVAL; 3479ed24f4bSMarc Zyngier 3489ed24f4bSMarc Zyngier reg_attr->vcpu = kvm_get_vcpu(dev->kvm, cpuid); 3499ed24f4bSMarc Zyngier reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; 3509ed24f4bSMarc Zyngier 3519ed24f4bSMarc Zyngier return 0; 3529ed24f4bSMarc Zyngier } 3539ed24f4bSMarc Zyngier 3549ed24f4bSMarc Zyngier /** 3559ed24f4bSMarc Zyngier * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state 3569ed24f4bSMarc Zyngier * 3579ed24f4bSMarc Zyngier * @dev: kvm device handle 3589ed24f4bSMarc Zyngier * @attr: kvm device attribute 3599ed24f4bSMarc Zyngier * @is_write: true if userspace is writing a register 3609ed24f4bSMarc Zyngier */ 3619ed24f4bSMarc Zyngier static int vgic_v2_attr_regs_access(struct kvm_device *dev, 3629ed24f4bSMarc Zyngier struct kvm_device_attr *attr, 3637e9f723cSMarc Zyngier bool is_write) 3649ed24f4bSMarc Zyngier { 3657e9f723cSMarc Zyngier u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr; 3669ed24f4bSMarc Zyngier struct vgic_reg_attr reg_attr; 3679ed24f4bSMarc Zyngier gpa_t addr; 3689ed24f4bSMarc Zyngier struct kvm_vcpu *vcpu; 3699ed24f4bSMarc Zyngier int ret; 3707e9f723cSMarc Zyngier u32 val; 3719ed24f4bSMarc Zyngier 3729ed24f4bSMarc Zyngier ret = vgic_v2_parse_attr(dev, attr, ®_attr); 3739ed24f4bSMarc Zyngier if (ret) 3749ed24f4bSMarc Zyngier return ret; 3759ed24f4bSMarc Zyngier 3769ed24f4bSMarc Zyngier vcpu = reg_attr.vcpu; 3779ed24f4bSMarc Zyngier addr = reg_attr.addr; 3789ed24f4bSMarc Zyngier 3797e9f723cSMarc Zyngier if (is_write) 3807e9f723cSMarc Zyngier if (get_user(val, uaddr)) 3817e9f723cSMarc Zyngier return -EFAULT; 3827e9f723cSMarc Zyngier 3839ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock); 3849ed24f4bSMarc Zyngier 385f0032773SOliver Upton if (!lock_all_vcpus(dev->kvm)) { 386f0032773SOliver Upton mutex_unlock(&dev->kvm->lock); 387f0032773SOliver Upton return -EBUSY; 388f0032773SOliver Upton } 389f0032773SOliver Upton 390f0032773SOliver Upton mutex_lock(&dev->kvm->arch.config_lock); 391f0032773SOliver Upton 3929ed24f4bSMarc Zyngier ret = vgic_init(dev->kvm); 3939ed24f4bSMarc Zyngier if (ret) 3949ed24f4bSMarc Zyngier goto out; 3959ed24f4bSMarc Zyngier 3969ed24f4bSMarc Zyngier switch (attr->group) { 3979ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: 3987e9f723cSMarc Zyngier ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, &val); 3999ed24f4bSMarc Zyngier break; 4009ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 4017e9f723cSMarc Zyngier ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, &val); 4029ed24f4bSMarc Zyngier break; 4039ed24f4bSMarc Zyngier default: 4049ed24f4bSMarc Zyngier ret = -EINVAL; 4059ed24f4bSMarc Zyngier break; 4069ed24f4bSMarc Zyngier } 4079ed24f4bSMarc Zyngier 4089ed24f4bSMarc Zyngier out: 409f0032773SOliver Upton mutex_unlock(&dev->kvm->arch.config_lock); 410f0032773SOliver Upton unlock_all_vcpus(dev->kvm); 4119ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock); 4127e9f723cSMarc Zyngier 4137e9f723cSMarc Zyngier if (!ret && !is_write) 4147e9f723cSMarc Zyngier ret = put_user(val, uaddr); 4157e9f723cSMarc Zyngier 4169ed24f4bSMarc Zyngier return ret; 4179ed24f4bSMarc Zyngier } 4189ed24f4bSMarc Zyngier 4199ed24f4bSMarc Zyngier static int vgic_v2_set_attr(struct kvm_device *dev, 4209ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 4219ed24f4bSMarc Zyngier { 4229ed24f4bSMarc Zyngier switch (attr->group) { 4239ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 4247e9f723cSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: 4257e9f723cSMarc Zyngier return vgic_v2_attr_regs_access(dev, attr, true); 426619064afSMarc Zyngier default: 427619064afSMarc Zyngier return vgic_set_common_attr(dev, attr); 4289ed24f4bSMarc Zyngier } 4299ed24f4bSMarc Zyngier } 4309ed24f4bSMarc Zyngier 4319ed24f4bSMarc Zyngier static int vgic_v2_get_attr(struct kvm_device *dev, 4329ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 4339ed24f4bSMarc Zyngier { 4349ed24f4bSMarc Zyngier switch (attr->group) { 4359ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 4367e9f723cSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: 4377e9f723cSMarc Zyngier return vgic_v2_attr_regs_access(dev, attr, false); 438619064afSMarc Zyngier default: 439619064afSMarc Zyngier return vgic_get_common_attr(dev, attr); 4409ed24f4bSMarc Zyngier } 4419ed24f4bSMarc Zyngier } 4429ed24f4bSMarc Zyngier 4439ed24f4bSMarc Zyngier static int vgic_v2_has_attr(struct kvm_device *dev, 4449ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 4459ed24f4bSMarc Zyngier { 4469ed24f4bSMarc Zyngier switch (attr->group) { 4479ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR: 4489ed24f4bSMarc Zyngier switch (attr->attr) { 4499ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_DIST: 4509ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_CPU: 4519ed24f4bSMarc Zyngier return 0; 4529ed24f4bSMarc Zyngier } 4539ed24f4bSMarc Zyngier break; 4549ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 4559ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: 4569ed24f4bSMarc Zyngier return vgic_v2_has_attr_regs(dev, attr); 4579ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: 4589ed24f4bSMarc Zyngier return 0; 4599ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL: 4609ed24f4bSMarc Zyngier switch (attr->attr) { 4619ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_CTRL_INIT: 4629ed24f4bSMarc Zyngier return 0; 4639ed24f4bSMarc Zyngier } 4649ed24f4bSMarc Zyngier } 4659ed24f4bSMarc Zyngier return -ENXIO; 4669ed24f4bSMarc Zyngier } 4679ed24f4bSMarc Zyngier 4689ed24f4bSMarc Zyngier struct kvm_device_ops kvm_arm_vgic_v2_ops = { 4699ed24f4bSMarc Zyngier .name = "kvm-arm-vgic-v2", 4709ed24f4bSMarc Zyngier .create = vgic_create, 4719ed24f4bSMarc Zyngier .destroy = vgic_destroy, 4729ed24f4bSMarc Zyngier .set_attr = vgic_v2_set_attr, 4739ed24f4bSMarc Zyngier .get_attr = vgic_v2_get_attr, 4749ed24f4bSMarc Zyngier .has_attr = vgic_v2_has_attr, 4759ed24f4bSMarc Zyngier }; 4769ed24f4bSMarc Zyngier 4779ed24f4bSMarc Zyngier int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, 4789ed24f4bSMarc Zyngier struct vgic_reg_attr *reg_attr) 4799ed24f4bSMarc Zyngier { 4809ed24f4bSMarc Zyngier unsigned long vgic_mpidr, mpidr_reg; 4819ed24f4bSMarc Zyngier 4829ed24f4bSMarc Zyngier /* 4839ed24f4bSMarc Zyngier * For KVM_DEV_ARM_VGIC_GRP_DIST_REGS group, 4849ed24f4bSMarc Zyngier * attr might not hold MPIDR. Hence assume vcpu0. 4859ed24f4bSMarc Zyngier */ 4869ed24f4bSMarc Zyngier if (attr->group != KVM_DEV_ARM_VGIC_GRP_DIST_REGS) { 4879ed24f4bSMarc Zyngier vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >> 4889ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT; 4899ed24f4bSMarc Zyngier 4909ed24f4bSMarc Zyngier mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr); 4919ed24f4bSMarc Zyngier reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg); 4929ed24f4bSMarc Zyngier } else { 4939ed24f4bSMarc Zyngier reg_attr->vcpu = kvm_get_vcpu(dev->kvm, 0); 4949ed24f4bSMarc Zyngier } 4959ed24f4bSMarc Zyngier 4969ed24f4bSMarc Zyngier if (!reg_attr->vcpu) 4979ed24f4bSMarc Zyngier return -EINVAL; 4989ed24f4bSMarc Zyngier 4999ed24f4bSMarc Zyngier reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK; 5009ed24f4bSMarc Zyngier 5019ed24f4bSMarc Zyngier return 0; 5029ed24f4bSMarc Zyngier } 5039ed24f4bSMarc Zyngier 5049ed24f4bSMarc Zyngier /* 5059ed24f4bSMarc Zyngier * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state 5069ed24f4bSMarc Zyngier * 5079ed24f4bSMarc Zyngier * @dev: kvm device handle 5089ed24f4bSMarc Zyngier * @attr: kvm device attribute 5099ed24f4bSMarc Zyngier * @is_write: true if userspace is writing a register 5109ed24f4bSMarc Zyngier */ 5119ed24f4bSMarc Zyngier static int vgic_v3_attr_regs_access(struct kvm_device *dev, 5129ed24f4bSMarc Zyngier struct kvm_device_attr *attr, 513e1246f3fSMarc Zyngier bool is_write) 5149ed24f4bSMarc Zyngier { 5159ed24f4bSMarc Zyngier struct vgic_reg_attr reg_attr; 5169ed24f4bSMarc Zyngier gpa_t addr; 5179ed24f4bSMarc Zyngier struct kvm_vcpu *vcpu; 518e1246f3fSMarc Zyngier bool uaccess; 519e1246f3fSMarc Zyngier u32 val; 5209ed24f4bSMarc Zyngier int ret; 5219ed24f4bSMarc Zyngier 5229ed24f4bSMarc Zyngier ret = vgic_v3_parse_attr(dev, attr, ®_attr); 5239ed24f4bSMarc Zyngier if (ret) 5249ed24f4bSMarc Zyngier return ret; 5259ed24f4bSMarc Zyngier 5269ed24f4bSMarc Zyngier vcpu = reg_attr.vcpu; 5279ed24f4bSMarc Zyngier addr = reg_attr.addr; 5289ed24f4bSMarc Zyngier 529e1246f3fSMarc Zyngier switch (attr->group) { 530e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 531e1246f3fSMarc Zyngier /* Sysregs uaccess is performed by the sysreg handling code */ 532e1246f3fSMarc Zyngier uaccess = false; 533e1246f3fSMarc Zyngier break; 534e1246f3fSMarc Zyngier default: 535e1246f3fSMarc Zyngier uaccess = true; 536e1246f3fSMarc Zyngier } 537e1246f3fSMarc Zyngier 538e1246f3fSMarc Zyngier if (uaccess && is_write) { 539e1246f3fSMarc Zyngier u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr; 540e1246f3fSMarc Zyngier if (get_user(val, uaddr)) 541e1246f3fSMarc Zyngier return -EFAULT; 542e1246f3fSMarc Zyngier } 543e1246f3fSMarc Zyngier 5449ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock); 5459ed24f4bSMarc Zyngier 546f0032773SOliver Upton if (!lock_all_vcpus(dev->kvm)) { 547f0032773SOliver Upton mutex_unlock(&dev->kvm->lock); 548f0032773SOliver Upton return -EBUSY; 5499ed24f4bSMarc Zyngier } 5509ed24f4bSMarc Zyngier 551f0032773SOliver Upton mutex_lock(&dev->kvm->arch.config_lock); 552f0032773SOliver Upton 553f0032773SOliver Upton if (unlikely(!vgic_initialized(dev->kvm))) { 5549ed24f4bSMarc Zyngier ret = -EBUSY; 5559ed24f4bSMarc Zyngier goto out; 5569ed24f4bSMarc Zyngier } 5579ed24f4bSMarc Zyngier 5589ed24f4bSMarc Zyngier switch (attr->group) { 5599ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 560e1246f3fSMarc Zyngier ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &val); 5619ed24f4bSMarc Zyngier break; 5629ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: 563e1246f3fSMarc Zyngier ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &val); 5649ed24f4bSMarc Zyngier break; 565db25081eSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 566db25081eSMarc Zyngier ret = vgic_v3_cpu_sysregs_uaccess(vcpu, attr, is_write); 5679ed24f4bSMarc Zyngier break; 5689ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { 5699ed24f4bSMarc Zyngier unsigned int info, intid; 5709ed24f4bSMarc Zyngier 5719ed24f4bSMarc Zyngier info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >> 5729ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT; 5739ed24f4bSMarc Zyngier if (info == VGIC_LEVEL_INFO_LINE_LEVEL) { 5749ed24f4bSMarc Zyngier intid = attr->attr & 5759ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK; 5769ed24f4bSMarc Zyngier ret = vgic_v3_line_level_info_uaccess(vcpu, is_write, 577e1246f3fSMarc Zyngier intid, &val); 5789ed24f4bSMarc Zyngier } else { 5799ed24f4bSMarc Zyngier ret = -EINVAL; 5809ed24f4bSMarc Zyngier } 5819ed24f4bSMarc Zyngier break; 5829ed24f4bSMarc Zyngier } 5839ed24f4bSMarc Zyngier default: 5849ed24f4bSMarc Zyngier ret = -EINVAL; 5859ed24f4bSMarc Zyngier break; 5869ed24f4bSMarc Zyngier } 5879ed24f4bSMarc Zyngier 5889ed24f4bSMarc Zyngier out: 589f0032773SOliver Upton mutex_unlock(&dev->kvm->arch.config_lock); 590f0032773SOliver Upton unlock_all_vcpus(dev->kvm); 5919ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock); 592e1246f3fSMarc Zyngier 593e1246f3fSMarc Zyngier if (!ret && uaccess && !is_write) { 594e1246f3fSMarc Zyngier u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr; 595e1246f3fSMarc Zyngier ret = put_user(val, uaddr); 596e1246f3fSMarc Zyngier } 597e1246f3fSMarc Zyngier 5989ed24f4bSMarc Zyngier return ret; 5999ed24f4bSMarc Zyngier } 6009ed24f4bSMarc Zyngier 6019ed24f4bSMarc Zyngier static int vgic_v3_set_attr(struct kvm_device *dev, 6029ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 6039ed24f4bSMarc Zyngier { 6049ed24f4bSMarc Zyngier switch (attr->group) { 6059ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 606e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: 607db25081eSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 608e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: 609e1246f3fSMarc Zyngier return vgic_v3_attr_regs_access(dev, attr, true); 610619064afSMarc Zyngier default: 611619064afSMarc Zyngier return vgic_set_common_attr(dev, attr); 6129ed24f4bSMarc Zyngier } 6139ed24f4bSMarc Zyngier } 6149ed24f4bSMarc Zyngier 6159ed24f4bSMarc Zyngier static int vgic_v3_get_attr(struct kvm_device *dev, 6169ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 6179ed24f4bSMarc Zyngier { 6189ed24f4bSMarc Zyngier switch (attr->group) { 6199ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 620e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: 621db25081eSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 622e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: 623e1246f3fSMarc Zyngier return vgic_v3_attr_regs_access(dev, attr, false); 624619064afSMarc Zyngier default: 625619064afSMarc Zyngier return vgic_get_common_attr(dev, attr); 6269ed24f4bSMarc Zyngier } 6279ed24f4bSMarc Zyngier } 6289ed24f4bSMarc Zyngier 6299ed24f4bSMarc Zyngier static int vgic_v3_has_attr(struct kvm_device *dev, 6309ed24f4bSMarc Zyngier struct kvm_device_attr *attr) 6319ed24f4bSMarc Zyngier { 6329ed24f4bSMarc Zyngier switch (attr->group) { 6339ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR: 6349ed24f4bSMarc Zyngier switch (attr->attr) { 6359ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_DIST: 6369ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST: 6379ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION: 6389ed24f4bSMarc Zyngier return 0; 6399ed24f4bSMarc Zyngier } 6409ed24f4bSMarc Zyngier break; 6419ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: 6429ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: 6439ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: 6449ed24f4bSMarc Zyngier return vgic_v3_has_attr_regs(dev, attr); 6459ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: 6469ed24f4bSMarc Zyngier return 0; 6479ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { 6489ed24f4bSMarc Zyngier if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >> 6499ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) == 6509ed24f4bSMarc Zyngier VGIC_LEVEL_INFO_LINE_LEVEL) 6519ed24f4bSMarc Zyngier return 0; 6529ed24f4bSMarc Zyngier break; 6539ed24f4bSMarc Zyngier } 6549ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL: 6559ed24f4bSMarc Zyngier switch (attr->attr) { 6569ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_CTRL_INIT: 6579ed24f4bSMarc Zyngier return 0; 6589ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES: 6599ed24f4bSMarc Zyngier return 0; 6609ed24f4bSMarc Zyngier } 6619ed24f4bSMarc Zyngier } 6629ed24f4bSMarc Zyngier return -ENXIO; 6639ed24f4bSMarc Zyngier } 6649ed24f4bSMarc Zyngier 6659ed24f4bSMarc Zyngier struct kvm_device_ops kvm_arm_vgic_v3_ops = { 6669ed24f4bSMarc Zyngier .name = "kvm-arm-vgic-v3", 6679ed24f4bSMarc Zyngier .create = vgic_create, 6689ed24f4bSMarc Zyngier .destroy = vgic_destroy, 6699ed24f4bSMarc Zyngier .set_attr = vgic_v3_set_attr, 6709ed24f4bSMarc Zyngier .get_attr = vgic_v3_get_attr, 6719ed24f4bSMarc Zyngier .has_attr = vgic_v3_has_attr, 6729ed24f4bSMarc Zyngier }; 673