aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2016-07-15 07:43:31 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2016-07-18 13:14:35 -0400
commit1085fdc68c6097244627a02a56bd2d8fe58a1a9c (patch)
tree6a26676301cddc817aa4a4b0ba8eee7e841383f4
parent59c5ab40989afa5aba9c4a0918a5ed910a917422 (diff)
KVM: arm64: vgic-its: Introduce new KVM ITS device
Introduce a new KVM device that represents an ARM Interrupt Translation Service (ITS) controller. Since there can be multiple of this per guest, we can't piggy back on the existing GICv3 distributor device, but create a new type of KVM device. On the KVM_CREATE_DEVICE ioctl we allocate and initialize the ITS data structure and store the pointer in the kvm_device data. Upon an explicit init ioctl from userland (after having setup the MMIO address) we register the handlers with the kvm_io_bus framework. Any reference to an ITS thus has to go via this interface. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com> Tested-by: Eric Auger <eric.auger@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--Documentation/virtual/kvm/devices/arm-vgic.txt25
-rw-r--r--arch/arm/kvm/arm.c1
-rw-r--r--arch/arm64/include/uapi/asm/kvm.h2
-rw-r--r--include/kvm/arm_vgic.h3
-rw-r--r--include/uapi/linux/kvm.h2
-rw-r--r--virt/kvm/arm/vgic/vgic-its.c135
-rw-r--r--virt/kvm/arm/vgic/vgic-kvm-device.c4
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio-v3.c2
-rw-r--r--virt/kvm/arm/vgic/vgic.h3
9 files changed, 168 insertions, 9 deletions
diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
index 59541d49e15c..89182f80cc7f 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
@@ -4,16 +4,22 @@ ARM Virtual Generic Interrupt Controller (VGIC)
4Device types supported: 4Device types supported:
5 KVM_DEV_TYPE_ARM_VGIC_V2 ARM Generic Interrupt Controller v2.0 5 KVM_DEV_TYPE_ARM_VGIC_V2 ARM Generic Interrupt Controller v2.0
6 KVM_DEV_TYPE_ARM_VGIC_V3 ARM Generic Interrupt Controller v3.0 6 KVM_DEV_TYPE_ARM_VGIC_V3 ARM Generic Interrupt Controller v3.0
7 KVM_DEV_TYPE_ARM_VGIC_ITS ARM Interrupt Translation Service Controller
7 8
8Only one VGIC instance may be instantiated through either this API or the 9Only one VGIC instance of the V2/V3 types above may be instantiated through
9legacy KVM_CREATE_IRQCHIP api. The created VGIC will act as the VM interrupt 10either this API or the legacy KVM_CREATE_IRQCHIP api. The created VGIC will
10controller, requiring emulated user-space devices to inject interrupts to the 11act as the VM interrupt controller, requiring emulated user-space devices to
11VGIC instead of directly to CPUs. 12inject interrupts to the VGIC instead of directly to CPUs.
12 13
13Creating a guest GICv3 device requires a host GICv3 as well. 14Creating a guest GICv3 device requires a host GICv3 as well.
14GICv3 implementations with hardware compatibility support allow a guest GICv2 15GICv3 implementations with hardware compatibility support allow a guest GICv2
15as well. 16as well.
16 17
18Creating a virtual ITS controller requires a host GICv3 (but does not depend
19on having physical ITS controllers).
20There can be multiple ITS controllers per guest, each of them has to have
21a separate, non-overlapping MMIO region.
22
17Groups: 23Groups:
18 KVM_DEV_ARM_VGIC_GRP_ADDR 24 KVM_DEV_ARM_VGIC_GRP_ADDR
19 Attributes: 25 Attributes:
@@ -39,6 +45,13 @@ Groups:
39 Only valid for KVM_DEV_TYPE_ARM_VGIC_V3. 45 Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
40 This address needs to be 64K aligned. 46 This address needs to be 64K aligned.
41 47
48 KVM_VGIC_V3_ADDR_TYPE_ITS (rw, 64-bit)
49 Base address in the guest physical address space of the GICv3 ITS
50 control register frame. The ITS allows MSI(-X) interrupts to be
51 injected into guests. This extension is optional. If the kernel
52 does not support the ITS, the call returns -ENODEV.
53 Only valid for KVM_DEV_TYPE_ARM_VGIC_ITS.
54 This address needs to be 64K aligned and the region covers 128K.
42 55
43 KVM_DEV_ARM_VGIC_GRP_DIST_REGS 56 KVM_DEV_ARM_VGIC_GRP_DIST_REGS
44 Attributes: 57 Attributes:
@@ -109,8 +122,8 @@ Groups:
109 KVM_DEV_ARM_VGIC_GRP_CTRL 122 KVM_DEV_ARM_VGIC_GRP_CTRL
110 Attributes: 123 Attributes:
111 KVM_DEV_ARM_VGIC_CTRL_INIT 124 KVM_DEV_ARM_VGIC_CTRL_INIT
112 request the initialization of the VGIC, no additional parameter in 125 request the initialization of the VGIC or ITS, no additional parameter
113 kvm_device_attr.addr. 126 in kvm_device_attr.addr.
114 Errors: 127 Errors:
115 -ENXIO: VGIC not properly configured as required prior to calling 128 -ENXIO: VGIC not properly configured as required prior to calling
116 this attribute 129 this attribute
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 972075cc111c..fb4661cf896e 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -20,6 +20,7 @@
20#include <linux/errno.h> 20#include <linux/errno.h>
21#include <linux/err.h> 21#include <linux/err.h>
22#include <linux/kvm_host.h> 22#include <linux/kvm_host.h>
23#include <linux/list.h>
23#include <linux/module.h> 24#include <linux/module.h>
24#include <linux/vmalloc.h> 25#include <linux/vmalloc.h>
25#include <linux/fs.h> 26#include <linux/fs.h>
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index f209ea151dca..3051f86a9b5f 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -87,9 +87,11 @@ struct kvm_regs {
87/* Supported VGICv3 address types */ 87/* Supported VGICv3 address types */
88#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 88#define KVM_VGIC_V3_ADDR_TYPE_DIST 2
89#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 89#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3
90#define KVM_VGIC_ITS_ADDR_TYPE 4
90 91
91#define KVM_VGIC_V3_DIST_SIZE SZ_64K 92#define KVM_VGIC_V3_DIST_SIZE SZ_64K
92#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) 93#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K)
94#define KVM_VGIC_V3_ITS_SIZE (2 * SZ_64K)
93 95
94#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ 96#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
95#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ 97#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 685f33975ce4..8609faced83e 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -134,6 +134,7 @@ struct vgic_its {
134 gpa_t vgic_its_base; 134 gpa_t vgic_its_base;
135 135
136 bool enabled; 136 bool enabled;
137 bool initialized;
137 struct vgic_io_device iodev; 138 struct vgic_io_device iodev;
138}; 139};
139 140
@@ -167,6 +168,8 @@ struct vgic_dist {
167 168
168 struct vgic_io_device dist_iodev; 169 struct vgic_io_device dist_iodev;
169 170
171 bool has_its;
172
170 /* 173 /*
171 * Contains the attributes and gpa of the LPI configuration table. 174 * Contains the attributes and gpa of the LPI configuration table.
172 * Since we report GICR_TYPER.CommonLPIAff as 0b00, we can share 175 * Since we report GICR_TYPER.CommonLPIAff as 0b00, we can share
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 7de96f5bb92c..d8c4c324cfae 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1077,6 +1077,8 @@ enum kvm_device_type {
1077#define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC 1077#define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC
1078 KVM_DEV_TYPE_ARM_VGIC_V3, 1078 KVM_DEV_TYPE_ARM_VGIC_V3,
1079#define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3 1079#define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3
1080 KVM_DEV_TYPE_ARM_VGIC_ITS,
1081#define KVM_DEV_TYPE_ARM_VGIC_ITS KVM_DEV_TYPE_ARM_VGIC_ITS
1080 KVM_DEV_TYPE_MAX, 1082 KVM_DEV_TYPE_MAX,
1081}; 1083};
1082 1084
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 4654d6edf6a6..6b47b3674690 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -21,6 +21,7 @@
21#include <linux/kvm.h> 21#include <linux/kvm.h>
22#include <linux/kvm_host.h> 22#include <linux/kvm_host.h>
23#include <linux/interrupt.h> 23#include <linux/interrupt.h>
24#include <linux/uaccess.h>
24 25
25#include <linux/irqchip/arm-gic-v3.h> 26#include <linux/irqchip/arm-gic-v3.h>
26 27
@@ -84,6 +85,9 @@ static int vgic_its_init_its(struct kvm *kvm, struct vgic_its *its)
84 struct vgic_io_device *iodev = &its->iodev; 85 struct vgic_io_device *iodev = &its->iodev;
85 int ret; 86 int ret;
86 87
88 if (its->initialized)
89 return 0;
90
87 if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base)) 91 if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base))
88 return -ENXIO; 92 return -ENXIO;
89 93
@@ -99,5 +103,136 @@ static int vgic_its_init_its(struct kvm *kvm, struct vgic_its *its)
99 KVM_VGIC_V3_ITS_SIZE, &iodev->dev); 103 KVM_VGIC_V3_ITS_SIZE, &iodev->dev);
100 mutex_unlock(&kvm->slots_lock); 104 mutex_unlock(&kvm->slots_lock);
101 105
106 if (!ret)
107 its->initialized = true;
108
102 return ret; 109 return ret;
103} 110}
111
112static int vgic_its_create(struct kvm_device *dev, u32 type)
113{
114 struct vgic_its *its;
115
116 if (type != KVM_DEV_TYPE_ARM_VGIC_ITS)
117 return -ENODEV;
118
119 its = kzalloc(sizeof(struct vgic_its), GFP_KERNEL);
120 if (!its)
121 return -ENOMEM;
122
123 its->vgic_its_base = VGIC_ADDR_UNDEF;
124
125 dev->kvm->arch.vgic.has_its = true;
126 its->initialized = false;
127 its->enabled = false;
128
129 dev->private = its;
130
131 return 0;
132}
133
134static void vgic_its_destroy(struct kvm_device *kvm_dev)
135{
136 struct vgic_its *its = kvm_dev->private;
137
138 kfree(its);
139}
140
141static int vgic_its_has_attr(struct kvm_device *dev,
142 struct kvm_device_attr *attr)
143{
144 switch (attr->group) {
145 case KVM_DEV_ARM_VGIC_GRP_ADDR:
146 switch (attr->attr) {
147 case KVM_VGIC_ITS_ADDR_TYPE:
148 return 0;
149 }
150 break;
151 case KVM_DEV_ARM_VGIC_GRP_CTRL:
152 switch (attr->attr) {
153 case KVM_DEV_ARM_VGIC_CTRL_INIT:
154 return 0;
155 }
156 break;
157 }
158 return -ENXIO;
159}
160
161static int vgic_its_set_attr(struct kvm_device *dev,
162 struct kvm_device_attr *attr)
163{
164 struct vgic_its *its = dev->private;
165 int ret;
166
167 switch (attr->group) {
168 case KVM_DEV_ARM_VGIC_GRP_ADDR: {
169 u64 __user *uaddr = (u64 __user *)(long)attr->addr;
170 unsigned long type = (unsigned long)attr->attr;
171 u64 addr;
172
173 if (type != KVM_VGIC_ITS_ADDR_TYPE)
174 return -ENODEV;
175
176 if (its->initialized)
177 return -EBUSY;
178
179 if (copy_from_user(&addr, uaddr, sizeof(addr)))
180 return -EFAULT;
181
182 ret = vgic_check_ioaddr(dev->kvm, &its->vgic_its_base,
183 addr, SZ_64K);
184 if (ret)
185 return ret;
186
187 its->vgic_its_base = addr;
188
189 return 0;
190 }
191 case KVM_DEV_ARM_VGIC_GRP_CTRL:
192 switch (attr->attr) {
193 case KVM_DEV_ARM_VGIC_CTRL_INIT:
194 return vgic_its_init_its(dev->kvm, its);
195 }
196 break;
197 }
198 return -ENXIO;
199}
200
201static int vgic_its_get_attr(struct kvm_device *dev,
202 struct kvm_device_attr *attr)
203{
204 switch (attr->group) {
205 case KVM_DEV_ARM_VGIC_GRP_ADDR: {
206 struct vgic_its *its = dev->private;
207 u64 addr = its->vgic_its_base;
208 u64 __user *uaddr = (u64 __user *)(long)attr->addr;
209 unsigned long type = (unsigned long)attr->attr;
210
211 if (type != KVM_VGIC_ITS_ADDR_TYPE)
212 return -ENODEV;
213
214 if (copy_to_user(uaddr, &addr, sizeof(addr)))
215 return -EFAULT;
216 break;
217 default:
218 return -ENXIO;
219 }
220 }
221
222 return 0;
223}
224
225static struct kvm_device_ops kvm_arm_vgic_its_ops = {
226 .name = "kvm-arm-vgic-its",
227 .create = vgic_its_create,
228 .destroy = vgic_its_destroy,
229 .set_attr = vgic_its_set_attr,
230 .get_attr = vgic_its_get_attr,
231 .has_attr = vgic_its_has_attr,
232};
233
234int kvm_vgic_register_its_device(void)
235{
236 return kvm_register_device_ops(&kvm_arm_vgic_its_ops,
237 KVM_DEV_TYPE_ARM_VGIC_ITS);
238}
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 2f24f13c6c90..561d2ba96a4f 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -21,8 +21,8 @@
21 21
22/* common helpers */ 22/* common helpers */
23 23
24static int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr, 24int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
25 phys_addr_t addr, phys_addr_t alignment) 25 phys_addr_t addr, phys_addr_t alignment)
26{ 26{
27 if (addr & ~KVM_PHYS_MASK) 27 if (addr & ~KVM_PHYS_MASK)
28 return -E2BIG; 28 return -E2BIG;
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index b92b7d6cabe6..a5c35050c786 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -49,7 +49,7 @@ bool vgic_has_its(struct kvm *kvm)
49 if (dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3) 49 if (dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
50 return false; 50 return false;
51 51
52 return false; 52 return dist->has_its;
53} 53}
54 54
55static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu, 55static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 31807c166d2a..8192a293f119 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -42,6 +42,9 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
42bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq); 42bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
43void vgic_kick_vcpus(struct kvm *kvm); 43void vgic_kick_vcpus(struct kvm *kvm);
44 44
45int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
46 phys_addr_t addr, phys_addr_t alignment);
47
45void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu); 48void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
46void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu); 49void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
47void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr); 50void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);