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
vgic_check_iorange(struct kvm * kvm,phys_addr_t ioaddr,phys_addr_t addr,phys_addr_t alignment,phys_addr_t size)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
vgic_check_type(struct kvm * kvm,int type_needed)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
kvm_set_legacy_vgic_v2_addr(struct kvm * kvm,struct kvm_arm_device_addr * dev_addr)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 */
kvm_vgic_addr(struct kvm * kvm,struct kvm_device_attr * attr,bool write)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
10559112e9cSJean-Philippe Brucker /*
10659112e9cSJean-Philippe Brucker * Since we can't hold config_lock while registering the redistributor
10759112e9cSJean-Philippe Brucker * iodevs, take the slots_lock immediately.
10859112e9cSJean-Philippe Brucker */
10959112e9cSJean-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
18959112e9cSJean-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 }
19759112e9cSJean-Philippe Brucker mutex_unlock(&kvm->arch.config_lock);
1989ed24f4bSMarc Zyngier
1999ed24f4bSMarc Zyngier out:
20059112e9cSJean-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
vgic_set_common_attr(struct kvm_device * dev,struct kvm_device_attr * attr)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
vgic_get_common_attr(struct kvm_device * dev,struct kvm_device_attr * attr)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
vgic_create(struct kvm_device * dev,u32 type)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
vgic_destroy(struct kvm_device * dev)3109ed24f4bSMarc Zyngier static void vgic_destroy(struct kvm_device *dev)
3119ed24f4bSMarc Zyngier {
3129ed24f4bSMarc Zyngier kfree(dev);
3139ed24f4bSMarc Zyngier }
3149ed24f4bSMarc Zyngier
kvm_register_vgic_device(unsigned long type)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
vgic_v2_parse_attr(struct kvm_device * dev,struct kvm_device_attr * attr,struct vgic_reg_attr * reg_attr)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 {
3408d6a1c8eSOliver Upton int cpuid = FIELD_GET(KVM_DEV_ARM_VGIC_CPUID_MASK, attr->attr);
3419ed24f4bSMarc Zyngier
3429ed24f4bSMarc Zyngier reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
3438d6a1c8eSOliver Upton reg_attr->vcpu = kvm_get_vcpu_by_id(dev->kvm, cpuid);
3448d6a1c8eSOliver Upton if (!reg_attr->vcpu)
3458d6a1c8eSOliver Upton return -EINVAL;
3469ed24f4bSMarc Zyngier
3479ed24f4bSMarc Zyngier return 0;
3489ed24f4bSMarc Zyngier }
3499ed24f4bSMarc Zyngier
3509ed24f4bSMarc Zyngier /**
3519ed24f4bSMarc Zyngier * vgic_v2_attr_regs_access - allows user space to access VGIC v2 state
3529ed24f4bSMarc Zyngier *
3539ed24f4bSMarc Zyngier * @dev: kvm device handle
3549ed24f4bSMarc Zyngier * @attr: kvm device attribute
3559ed24f4bSMarc Zyngier * @is_write: true if userspace is writing a register
3569ed24f4bSMarc Zyngier */
vgic_v2_attr_regs_access(struct kvm_device * dev,struct kvm_device_attr * attr,bool is_write)3579ed24f4bSMarc Zyngier static int vgic_v2_attr_regs_access(struct kvm_device *dev,
3589ed24f4bSMarc Zyngier struct kvm_device_attr *attr,
3597e9f723cSMarc Zyngier bool is_write)
3609ed24f4bSMarc Zyngier {
3617e9f723cSMarc Zyngier u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr;
3629ed24f4bSMarc Zyngier struct vgic_reg_attr reg_attr;
3639ed24f4bSMarc Zyngier gpa_t addr;
3649ed24f4bSMarc Zyngier struct kvm_vcpu *vcpu;
3659ed24f4bSMarc Zyngier int ret;
3667e9f723cSMarc Zyngier u32 val;
3679ed24f4bSMarc Zyngier
3689ed24f4bSMarc Zyngier ret = vgic_v2_parse_attr(dev, attr, ®_attr);
3699ed24f4bSMarc Zyngier if (ret)
3709ed24f4bSMarc Zyngier return ret;
3719ed24f4bSMarc Zyngier
3729ed24f4bSMarc Zyngier vcpu = reg_attr.vcpu;
3739ed24f4bSMarc Zyngier addr = reg_attr.addr;
3749ed24f4bSMarc Zyngier
3757e9f723cSMarc Zyngier if (is_write)
3767e9f723cSMarc Zyngier if (get_user(val, uaddr))
3777e9f723cSMarc Zyngier return -EFAULT;
3787e9f723cSMarc Zyngier
3799ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock);
3809ed24f4bSMarc Zyngier
381f0032773SOliver Upton if (!lock_all_vcpus(dev->kvm)) {
382f0032773SOliver Upton mutex_unlock(&dev->kvm->lock);
383f0032773SOliver Upton return -EBUSY;
384f0032773SOliver Upton }
385f0032773SOliver Upton
386f0032773SOliver Upton mutex_lock(&dev->kvm->arch.config_lock);
387f0032773SOliver Upton
3889ed24f4bSMarc Zyngier ret = vgic_init(dev->kvm);
3899ed24f4bSMarc Zyngier if (ret)
3909ed24f4bSMarc Zyngier goto out;
3919ed24f4bSMarc Zyngier
3929ed24f4bSMarc Zyngier switch (attr->group) {
3939ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
3947e9f723cSMarc Zyngier ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, &val);
3959ed24f4bSMarc Zyngier break;
3969ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
3977e9f723cSMarc Zyngier ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, &val);
3989ed24f4bSMarc Zyngier break;
3999ed24f4bSMarc Zyngier default:
4009ed24f4bSMarc Zyngier ret = -EINVAL;
4019ed24f4bSMarc Zyngier break;
4029ed24f4bSMarc Zyngier }
4039ed24f4bSMarc Zyngier
4049ed24f4bSMarc Zyngier out:
405f0032773SOliver Upton mutex_unlock(&dev->kvm->arch.config_lock);
406f0032773SOliver Upton unlock_all_vcpus(dev->kvm);
4079ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock);
4087e9f723cSMarc Zyngier
4097e9f723cSMarc Zyngier if (!ret && !is_write)
4107e9f723cSMarc Zyngier ret = put_user(val, uaddr);
4117e9f723cSMarc Zyngier
4129ed24f4bSMarc Zyngier return ret;
4139ed24f4bSMarc Zyngier }
4149ed24f4bSMarc Zyngier
vgic_v2_set_attr(struct kvm_device * dev,struct kvm_device_attr * attr)4159ed24f4bSMarc Zyngier static int vgic_v2_set_attr(struct kvm_device *dev,
4169ed24f4bSMarc Zyngier struct kvm_device_attr *attr)
4179ed24f4bSMarc Zyngier {
4189ed24f4bSMarc Zyngier switch (attr->group) {
4199ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
4207e9f723cSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
4217e9f723cSMarc Zyngier return vgic_v2_attr_regs_access(dev, attr, true);
422619064afSMarc Zyngier default:
423619064afSMarc Zyngier return vgic_set_common_attr(dev, attr);
4249ed24f4bSMarc Zyngier }
4259ed24f4bSMarc Zyngier }
4269ed24f4bSMarc Zyngier
vgic_v2_get_attr(struct kvm_device * dev,struct kvm_device_attr * attr)4279ed24f4bSMarc Zyngier static int vgic_v2_get_attr(struct kvm_device *dev,
4289ed24f4bSMarc Zyngier struct kvm_device_attr *attr)
4299ed24f4bSMarc Zyngier {
4309ed24f4bSMarc Zyngier switch (attr->group) {
4319ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
4327e9f723cSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
4337e9f723cSMarc Zyngier return vgic_v2_attr_regs_access(dev, attr, false);
434619064afSMarc Zyngier default:
435619064afSMarc Zyngier return vgic_get_common_attr(dev, attr);
4369ed24f4bSMarc Zyngier }
4379ed24f4bSMarc Zyngier }
4389ed24f4bSMarc Zyngier
vgic_v2_has_attr(struct kvm_device * dev,struct kvm_device_attr * attr)4399ed24f4bSMarc Zyngier static int vgic_v2_has_attr(struct kvm_device *dev,
4409ed24f4bSMarc Zyngier struct kvm_device_attr *attr)
4419ed24f4bSMarc Zyngier {
4429ed24f4bSMarc Zyngier switch (attr->group) {
4439ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR:
4449ed24f4bSMarc Zyngier switch (attr->attr) {
4459ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_DIST:
4469ed24f4bSMarc Zyngier case KVM_VGIC_V2_ADDR_TYPE_CPU:
4479ed24f4bSMarc Zyngier return 0;
4489ed24f4bSMarc Zyngier }
4499ed24f4bSMarc Zyngier break;
4509ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
4519ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
4529ed24f4bSMarc Zyngier return vgic_v2_has_attr_regs(dev, attr);
4539ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
4549ed24f4bSMarc Zyngier return 0;
4559ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL:
4569ed24f4bSMarc Zyngier switch (attr->attr) {
4579ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_CTRL_INIT:
4589ed24f4bSMarc Zyngier return 0;
4599ed24f4bSMarc Zyngier }
4609ed24f4bSMarc Zyngier }
4619ed24f4bSMarc Zyngier return -ENXIO;
4629ed24f4bSMarc Zyngier }
4639ed24f4bSMarc Zyngier
4649ed24f4bSMarc Zyngier struct kvm_device_ops kvm_arm_vgic_v2_ops = {
4659ed24f4bSMarc Zyngier .name = "kvm-arm-vgic-v2",
4669ed24f4bSMarc Zyngier .create = vgic_create,
4679ed24f4bSMarc Zyngier .destroy = vgic_destroy,
4689ed24f4bSMarc Zyngier .set_attr = vgic_v2_set_attr,
4699ed24f4bSMarc Zyngier .get_attr = vgic_v2_get_attr,
4709ed24f4bSMarc Zyngier .has_attr = vgic_v2_has_attr,
4719ed24f4bSMarc Zyngier };
4729ed24f4bSMarc Zyngier
vgic_v3_parse_attr(struct kvm_device * dev,struct kvm_device_attr * attr,struct vgic_reg_attr * reg_attr)4739ed24f4bSMarc Zyngier int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr,
4749ed24f4bSMarc Zyngier struct vgic_reg_attr *reg_attr)
4759ed24f4bSMarc Zyngier {
4769ed24f4bSMarc Zyngier unsigned long vgic_mpidr, mpidr_reg;
4779ed24f4bSMarc Zyngier
4789ed24f4bSMarc Zyngier /*
4799ed24f4bSMarc Zyngier * For KVM_DEV_ARM_VGIC_GRP_DIST_REGS group,
4809ed24f4bSMarc Zyngier * attr might not hold MPIDR. Hence assume vcpu0.
4819ed24f4bSMarc Zyngier */
4829ed24f4bSMarc Zyngier if (attr->group != KVM_DEV_ARM_VGIC_GRP_DIST_REGS) {
4839ed24f4bSMarc Zyngier vgic_mpidr = (attr->attr & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) >>
4849ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_V3_MPIDR_SHIFT;
4859ed24f4bSMarc Zyngier
4869ed24f4bSMarc Zyngier mpidr_reg = VGIC_TO_MPIDR(vgic_mpidr);
4879ed24f4bSMarc Zyngier reg_attr->vcpu = kvm_mpidr_to_vcpu(dev->kvm, mpidr_reg);
4889ed24f4bSMarc Zyngier } else {
4899ed24f4bSMarc Zyngier reg_attr->vcpu = kvm_get_vcpu(dev->kvm, 0);
4909ed24f4bSMarc Zyngier }
4919ed24f4bSMarc Zyngier
4929ed24f4bSMarc Zyngier if (!reg_attr->vcpu)
4939ed24f4bSMarc Zyngier return -EINVAL;
4949ed24f4bSMarc Zyngier
4959ed24f4bSMarc Zyngier reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
4969ed24f4bSMarc Zyngier
4979ed24f4bSMarc Zyngier return 0;
4989ed24f4bSMarc Zyngier }
4999ed24f4bSMarc Zyngier
5009ed24f4bSMarc Zyngier /*
5019ed24f4bSMarc Zyngier * vgic_v3_attr_regs_access - allows user space to access VGIC v3 state
5029ed24f4bSMarc Zyngier *
5039ed24f4bSMarc Zyngier * @dev: kvm device handle
5049ed24f4bSMarc Zyngier * @attr: kvm device attribute
5059ed24f4bSMarc Zyngier * @is_write: true if userspace is writing a register
5069ed24f4bSMarc Zyngier */
vgic_v3_attr_regs_access(struct kvm_device * dev,struct kvm_device_attr * attr,bool is_write)5079ed24f4bSMarc Zyngier static int vgic_v3_attr_regs_access(struct kvm_device *dev,
5089ed24f4bSMarc Zyngier struct kvm_device_attr *attr,
509e1246f3fSMarc Zyngier bool is_write)
5109ed24f4bSMarc Zyngier {
5119ed24f4bSMarc Zyngier struct vgic_reg_attr reg_attr;
5129ed24f4bSMarc Zyngier gpa_t addr;
5139ed24f4bSMarc Zyngier struct kvm_vcpu *vcpu;
514e1246f3fSMarc Zyngier bool uaccess;
515e1246f3fSMarc Zyngier u32 val;
5169ed24f4bSMarc Zyngier int ret;
5179ed24f4bSMarc Zyngier
5189ed24f4bSMarc Zyngier ret = vgic_v3_parse_attr(dev, attr, ®_attr);
5199ed24f4bSMarc Zyngier if (ret)
5209ed24f4bSMarc Zyngier return ret;
5219ed24f4bSMarc Zyngier
5229ed24f4bSMarc Zyngier vcpu = reg_attr.vcpu;
5239ed24f4bSMarc Zyngier addr = reg_attr.addr;
5249ed24f4bSMarc Zyngier
525e1246f3fSMarc Zyngier switch (attr->group) {
526e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
527e1246f3fSMarc Zyngier /* Sysregs uaccess is performed by the sysreg handling code */
528e1246f3fSMarc Zyngier uaccess = false;
529e1246f3fSMarc Zyngier break;
530e1246f3fSMarc Zyngier default:
531e1246f3fSMarc Zyngier uaccess = true;
532e1246f3fSMarc Zyngier }
533e1246f3fSMarc Zyngier
534e1246f3fSMarc Zyngier if (uaccess && is_write) {
535e1246f3fSMarc Zyngier u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr;
536e1246f3fSMarc Zyngier if (get_user(val, uaddr))
537e1246f3fSMarc Zyngier return -EFAULT;
538e1246f3fSMarc Zyngier }
539e1246f3fSMarc Zyngier
5409ed24f4bSMarc Zyngier mutex_lock(&dev->kvm->lock);
5419ed24f4bSMarc Zyngier
542f0032773SOliver Upton if (!lock_all_vcpus(dev->kvm)) {
543f0032773SOliver Upton mutex_unlock(&dev->kvm->lock);
544f0032773SOliver Upton return -EBUSY;
5459ed24f4bSMarc Zyngier }
5469ed24f4bSMarc Zyngier
547f0032773SOliver Upton mutex_lock(&dev->kvm->arch.config_lock);
548f0032773SOliver Upton
549f0032773SOliver Upton if (unlikely(!vgic_initialized(dev->kvm))) {
5509ed24f4bSMarc Zyngier ret = -EBUSY;
5519ed24f4bSMarc Zyngier goto out;
5529ed24f4bSMarc Zyngier }
5539ed24f4bSMarc Zyngier
5549ed24f4bSMarc Zyngier switch (attr->group) {
5559ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
556e1246f3fSMarc Zyngier ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &val);
5579ed24f4bSMarc Zyngier break;
5589ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
559e1246f3fSMarc Zyngier ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &val);
5609ed24f4bSMarc Zyngier break;
561db25081eSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
562db25081eSMarc Zyngier ret = vgic_v3_cpu_sysregs_uaccess(vcpu, attr, is_write);
5639ed24f4bSMarc Zyngier break;
5649ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
5659ed24f4bSMarc Zyngier unsigned int info, intid;
5669ed24f4bSMarc Zyngier
5679ed24f4bSMarc Zyngier info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
5689ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT;
5699ed24f4bSMarc Zyngier if (info == VGIC_LEVEL_INFO_LINE_LEVEL) {
5709ed24f4bSMarc Zyngier intid = attr->attr &
5719ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK;
5729ed24f4bSMarc Zyngier ret = vgic_v3_line_level_info_uaccess(vcpu, is_write,
573e1246f3fSMarc Zyngier intid, &val);
5749ed24f4bSMarc Zyngier } else {
5759ed24f4bSMarc Zyngier ret = -EINVAL;
5769ed24f4bSMarc Zyngier }
5779ed24f4bSMarc Zyngier break;
5789ed24f4bSMarc Zyngier }
5799ed24f4bSMarc Zyngier default:
5809ed24f4bSMarc Zyngier ret = -EINVAL;
5819ed24f4bSMarc Zyngier break;
5829ed24f4bSMarc Zyngier }
5839ed24f4bSMarc Zyngier
5849ed24f4bSMarc Zyngier out:
585f0032773SOliver Upton mutex_unlock(&dev->kvm->arch.config_lock);
586f0032773SOliver Upton unlock_all_vcpus(dev->kvm);
5879ed24f4bSMarc Zyngier mutex_unlock(&dev->kvm->lock);
588e1246f3fSMarc Zyngier
589e1246f3fSMarc Zyngier if (!ret && uaccess && !is_write) {
590e1246f3fSMarc Zyngier u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr;
591e1246f3fSMarc Zyngier ret = put_user(val, uaddr);
592e1246f3fSMarc Zyngier }
593e1246f3fSMarc Zyngier
5949ed24f4bSMarc Zyngier return ret;
5959ed24f4bSMarc Zyngier }
5969ed24f4bSMarc Zyngier
vgic_v3_set_attr(struct kvm_device * dev,struct kvm_device_attr * attr)5979ed24f4bSMarc Zyngier static int vgic_v3_set_attr(struct kvm_device *dev,
5989ed24f4bSMarc Zyngier struct kvm_device_attr *attr)
5999ed24f4bSMarc Zyngier {
6009ed24f4bSMarc Zyngier switch (attr->group) {
6019ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
602e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
603db25081eSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
604e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO:
605e1246f3fSMarc Zyngier return vgic_v3_attr_regs_access(dev, attr, true);
606619064afSMarc Zyngier default:
607619064afSMarc Zyngier return vgic_set_common_attr(dev, attr);
6089ed24f4bSMarc Zyngier }
6099ed24f4bSMarc Zyngier }
6109ed24f4bSMarc Zyngier
vgic_v3_get_attr(struct kvm_device * dev,struct kvm_device_attr * attr)6119ed24f4bSMarc Zyngier static int vgic_v3_get_attr(struct kvm_device *dev,
6129ed24f4bSMarc Zyngier struct kvm_device_attr *attr)
6139ed24f4bSMarc Zyngier {
6149ed24f4bSMarc Zyngier switch (attr->group) {
6159ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
616e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
617db25081eSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
618e1246f3fSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO:
619e1246f3fSMarc Zyngier return vgic_v3_attr_regs_access(dev, attr, false);
620619064afSMarc Zyngier default:
621619064afSMarc Zyngier return vgic_get_common_attr(dev, attr);
6229ed24f4bSMarc Zyngier }
6239ed24f4bSMarc Zyngier }
6249ed24f4bSMarc Zyngier
vgic_v3_has_attr(struct kvm_device * dev,struct kvm_device_attr * attr)6259ed24f4bSMarc Zyngier static int vgic_v3_has_attr(struct kvm_device *dev,
6269ed24f4bSMarc Zyngier struct kvm_device_attr *attr)
6279ed24f4bSMarc Zyngier {
6289ed24f4bSMarc Zyngier switch (attr->group) {
6299ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_ADDR:
6309ed24f4bSMarc Zyngier switch (attr->attr) {
6319ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_DIST:
6329ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST:
6339ed24f4bSMarc Zyngier case KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION:
6349ed24f4bSMarc Zyngier return 0;
6359ed24f4bSMarc Zyngier }
6369ed24f4bSMarc Zyngier break;
6379ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_DIST_REGS:
6389ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
6399ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
6409ed24f4bSMarc Zyngier return vgic_v3_has_attr_regs(dev, attr);
6419ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_NR_IRQS:
6429ed24f4bSMarc Zyngier return 0;
6439ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: {
6449ed24f4bSMarc Zyngier if (((attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >>
6459ed24f4bSMarc Zyngier KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT) ==
6469ed24f4bSMarc Zyngier VGIC_LEVEL_INFO_LINE_LEVEL)
6479ed24f4bSMarc Zyngier return 0;
6489ed24f4bSMarc Zyngier break;
6499ed24f4bSMarc Zyngier }
6509ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_GRP_CTRL:
6519ed24f4bSMarc Zyngier switch (attr->attr) {
6529ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_CTRL_INIT:
6539ed24f4bSMarc Zyngier return 0;
6549ed24f4bSMarc Zyngier case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
6559ed24f4bSMarc Zyngier return 0;
6569ed24f4bSMarc Zyngier }
6579ed24f4bSMarc Zyngier }
6589ed24f4bSMarc Zyngier return -ENXIO;
6599ed24f4bSMarc Zyngier }
6609ed24f4bSMarc Zyngier
6619ed24f4bSMarc Zyngier struct kvm_device_ops kvm_arm_vgic_v3_ops = {
6629ed24f4bSMarc Zyngier .name = "kvm-arm-vgic-v3",
6639ed24f4bSMarc Zyngier .create = vgic_create,
6649ed24f4bSMarc Zyngier .destroy = vgic_destroy,
6659ed24f4bSMarc Zyngier .set_attr = vgic_v3_set_attr,
6669ed24f4bSMarc Zyngier .get_attr = vgic_v3_get_attr,
6679ed24f4bSMarc Zyngier .has_attr = vgic_v3_has_attr,
6689ed24f4bSMarc Zyngier };
669