aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2016-07-15 07:43:30 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2016-07-18 13:14:35 -0400
commit59c5ab40989afa5aba9c4a0918a5ed910a917422 (patch)
tree42cf5f34ab95494f0993bbcbb39c88e36f61fda5
parent0aa1de57319c4e023187aca0d59dd593a96459a8 (diff)
KVM: arm64: vgic-its: Introduce ITS emulation file with MMIO framework
The ARM GICv3 ITS emulation code goes into a separate file, but needs to be connected to the GICv3 emulation, of which it is an option. The ITS MMIO handlers require the respective ITS pointer to be passed in, so we amend the existing VGIC MMIO framework to let it cope with that. Also we introduce the basic ITS data structure and initialize it, but don't return any success yet, as we are not yet ready for the show. 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--include/kvm/arm_vgic.h22
-rw-r--r--virt/kvm/arm/vgic/vgic-its.c103
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio-v3.c40
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio.c37
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio.h17
-rw-r--r--virt/kvm/arm/vgic/vgic.h7
6 files changed, 213 insertions, 13 deletions
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index df2dec5ef620..685f33975ce4 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -108,15 +108,35 @@ struct vgic_irq {
108}; 108};
109 109
110struct vgic_register_region; 110struct vgic_register_region;
111struct vgic_its;
112
113enum iodev_type {
114 IODEV_CPUIF,
115 IODEV_DIST,
116 IODEV_REDIST,
117 IODEV_ITS
118};
111 119
112struct vgic_io_device { 120struct vgic_io_device {
113 gpa_t base_addr; 121 gpa_t base_addr;
114 struct kvm_vcpu *redist_vcpu; 122 union {
123 struct kvm_vcpu *redist_vcpu;
124 struct vgic_its *its;
125 };
115 const struct vgic_register_region *regions; 126 const struct vgic_register_region *regions;
127 enum iodev_type iodev_type;
116 int nr_regions; 128 int nr_regions;
117 struct kvm_io_device dev; 129 struct kvm_io_device dev;
118}; 130};
119 131
132struct vgic_its {
133 /* The base address of the ITS control register frame */
134 gpa_t vgic_its_base;
135
136 bool enabled;
137 struct vgic_io_device iodev;
138};
139
120struct vgic_dist { 140struct vgic_dist {
121 bool in_kernel; 141 bool in_kernel;
122 bool ready; 142 bool ready;
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
new file mode 100644
index 000000000000..4654d6edf6a6
--- /dev/null
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -0,0 +1,103 @@
1/*
2 * GICv3 ITS emulation
3 *
4 * Copyright (C) 2015,2016 ARM Ltd.
5 * Author: Andre Przywara <andre.przywara@arm.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/cpu.h>
21#include <linux/kvm.h>
22#include <linux/kvm_host.h>
23#include <linux/interrupt.h>
24
25#include <linux/irqchip/arm-gic-v3.h>
26
27#include <asm/kvm_emulate.h>
28#include <asm/kvm_arm.h>
29#include <asm/kvm_mmu.h>
30
31#include "vgic.h"
32#include "vgic-mmio.h"
33
34#define REGISTER_ITS_DESC(off, rd, wr, length, acc) \
35{ \
36 .reg_offset = off, \
37 .len = length, \
38 .access_flags = acc, \
39 .its_read = rd, \
40 .its_write = wr, \
41}
42
43static unsigned long its_mmio_read_raz(struct kvm *kvm, struct vgic_its *its,
44 gpa_t addr, unsigned int len)
45{
46 return 0;
47}
48
49static void its_mmio_write_wi(struct kvm *kvm, struct vgic_its *its,
50 gpa_t addr, unsigned int len, unsigned long val)
51{
52 /* Ignore */
53}
54
55static struct vgic_register_region its_registers[] = {
56 REGISTER_ITS_DESC(GITS_CTLR,
57 its_mmio_read_raz, its_mmio_write_wi, 4,
58 VGIC_ACCESS_32bit),
59 REGISTER_ITS_DESC(GITS_IIDR,
60 its_mmio_read_raz, its_mmio_write_wi, 4,
61 VGIC_ACCESS_32bit),
62 REGISTER_ITS_DESC(GITS_TYPER,
63 its_mmio_read_raz, its_mmio_write_wi, 8,
64 VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
65 REGISTER_ITS_DESC(GITS_CBASER,
66 its_mmio_read_raz, its_mmio_write_wi, 8,
67 VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
68 REGISTER_ITS_DESC(GITS_CWRITER,
69 its_mmio_read_raz, its_mmio_write_wi, 8,
70 VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
71 REGISTER_ITS_DESC(GITS_CREADR,
72 its_mmio_read_raz, its_mmio_write_wi, 8,
73 VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
74 REGISTER_ITS_DESC(GITS_BASER,
75 its_mmio_read_raz, its_mmio_write_wi, 0x40,
76 VGIC_ACCESS_64bit | VGIC_ACCESS_32bit),
77 REGISTER_ITS_DESC(GITS_IDREGS_BASE,
78 its_mmio_read_raz, its_mmio_write_wi, 0x30,
79 VGIC_ACCESS_32bit),
80};
81
82static int vgic_its_init_its(struct kvm *kvm, struct vgic_its *its)
83{
84 struct vgic_io_device *iodev = &its->iodev;
85 int ret;
86
87 if (IS_VGIC_ADDR_UNDEF(its->vgic_its_base))
88 return -ENXIO;
89
90 iodev->regions = its_registers;
91 iodev->nr_regions = ARRAY_SIZE(its_registers);
92 kvm_iodevice_init(&iodev->dev, &kvm_io_gic_ops);
93
94 iodev->base_addr = its->vgic_its_base;
95 iodev->iodev_type = IODEV_ITS;
96 iodev->its = its;
97 mutex_lock(&kvm->slots_lock);
98 ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, iodev->base_addr,
99 KVM_VGIC_V3_ITS_SIZE, &iodev->dev);
100 mutex_unlock(&kvm->slots_lock);
101
102 return ret;
103}
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 278bfbb36ef9..b92b7d6cabe6 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -42,6 +42,16 @@ static u64 update_64bit_reg(u64 reg, unsigned int offset, unsigned int len,
42 return reg | ((u64)val << lower); 42 return reg | ((u64)val << lower);
43} 43}
44 44
45bool vgic_has_its(struct kvm *kvm)
46{
47 struct vgic_dist *dist = &kvm->arch.vgic;
48
49 if (dist->vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
50 return false;
51
52 return false;
53}
54
45static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu, 55static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
46 gpa_t addr, unsigned int len) 56 gpa_t addr, unsigned int len)
47{ 57{
@@ -132,6 +142,32 @@ static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
132 vgic_put_irq(vcpu->kvm, irq); 142 vgic_put_irq(vcpu->kvm, irq);
133} 143}
134 144
145static unsigned long vgic_mmio_read_v3r_ctlr(struct kvm_vcpu *vcpu,
146 gpa_t addr, unsigned int len)
147{
148 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
149
150 return vgic_cpu->lpis_enabled ? GICR_CTLR_ENABLE_LPIS : 0;
151}
152
153
154static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,
155 gpa_t addr, unsigned int len,
156 unsigned long val)
157{
158 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
159 bool was_enabled = vgic_cpu->lpis_enabled;
160
161 if (!vgic_has_its(vcpu->kvm))
162 return;
163
164 vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS;
165
166 if (!was_enabled && vgic_cpu->lpis_enabled) {
167 /* Eventually do something */
168 }
169}
170
135static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu, 171static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
136 gpa_t addr, unsigned int len) 172 gpa_t addr, unsigned int len)
137{ 173{
@@ -372,7 +408,7 @@ static const struct vgic_register_region vgic_v3_dist_registers[] = {
372 408
373static const struct vgic_register_region vgic_v3_rdbase_registers[] = { 409static const struct vgic_register_region vgic_v3_rdbase_registers[] = {
374 REGISTER_DESC_WITH_LENGTH(GICR_CTLR, 410 REGISTER_DESC_WITH_LENGTH(GICR_CTLR,
375 vgic_mmio_read_raz, vgic_mmio_write_wi, 4, 411 vgic_mmio_read_v3r_ctlr, vgic_mmio_write_v3r_ctlr, 4,
376 VGIC_ACCESS_32bit), 412 VGIC_ACCESS_32bit),
377 REGISTER_DESC_WITH_LENGTH(GICR_IIDR, 413 REGISTER_DESC_WITH_LENGTH(GICR_IIDR,
378 vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4, 414 vgic_mmio_read_v3r_iidr, vgic_mmio_write_wi, 4,
@@ -450,6 +486,7 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
450 486
451 kvm_iodevice_init(&rd_dev->dev, &kvm_io_gic_ops); 487 kvm_iodevice_init(&rd_dev->dev, &kvm_io_gic_ops);
452 rd_dev->base_addr = rd_base; 488 rd_dev->base_addr = rd_base;
489 rd_dev->iodev_type = IODEV_REDIST;
453 rd_dev->regions = vgic_v3_rdbase_registers; 490 rd_dev->regions = vgic_v3_rdbase_registers;
454 rd_dev->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers); 491 rd_dev->nr_regions = ARRAY_SIZE(vgic_v3_rdbase_registers);
455 rd_dev->redist_vcpu = vcpu; 492 rd_dev->redist_vcpu = vcpu;
@@ -464,6 +501,7 @@ int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t redist_base_address)
464 501
465 kvm_iodevice_init(&sgi_dev->dev, &kvm_io_gic_ops); 502 kvm_iodevice_init(&sgi_dev->dev, &kvm_io_gic_ops);
466 sgi_dev->base_addr = sgi_base; 503 sgi_dev->base_addr = sgi_base;
504 sgi_dev->iodev_type = IODEV_REDIST;
467 sgi_dev->regions = vgic_v3_sgibase_registers; 505 sgi_dev->regions = vgic_v3_sgibase_registers;
468 sgi_dev->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers); 506 sgi_dev->nr_regions = ARRAY_SIZE(vgic_v3_sgibase_registers);
469 sgi_dev->redist_vcpu = vcpu; 507 sgi_dev->redist_vcpu = vcpu;
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 5e79e0137cb6..26be827bbfcc 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -473,8 +473,7 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
473{ 473{
474 struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev); 474 struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
475 const struct vgic_register_region *region; 475 const struct vgic_register_region *region;
476 struct kvm_vcpu *r_vcpu; 476 unsigned long data = 0;
477 unsigned long data;
478 477
479 region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions, 478 region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
480 addr - iodev->base_addr); 479 addr - iodev->base_addr);
@@ -483,8 +482,20 @@ static int dispatch_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
483 return 0; 482 return 0;
484 } 483 }
485 484
486 r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu; 485 switch (iodev->iodev_type) {
487 data = region->read(r_vcpu, addr, len); 486 case IODEV_CPUIF:
487 return 1;
488 case IODEV_DIST:
489 data = region->read(vcpu, addr, len);
490 break;
491 case IODEV_REDIST:
492 data = region->read(iodev->redist_vcpu, addr, len);
493 break;
494 case IODEV_ITS:
495 data = region->its_read(vcpu->kvm, iodev->its, addr, len);
496 break;
497 }
498
488 vgic_data_host_to_mmio_bus(val, len, data); 499 vgic_data_host_to_mmio_bus(val, len, data);
489 return 0; 500 return 0;
490} 501}
@@ -494,7 +505,6 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
494{ 505{
495 struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev); 506 struct vgic_io_device *iodev = kvm_to_vgic_iodev(dev);
496 const struct vgic_register_region *region; 507 const struct vgic_register_region *region;
497 struct kvm_vcpu *r_vcpu;
498 unsigned long data = vgic_data_mmio_bus_to_host(val, len); 508 unsigned long data = vgic_data_mmio_bus_to_host(val, len);
499 509
500 region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions, 510 region = vgic_find_mmio_region(iodev->regions, iodev->nr_regions,
@@ -505,8 +515,20 @@ static int dispatch_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
505 if (!check_region(region, addr, len)) 515 if (!check_region(region, addr, len))
506 return 0; 516 return 0;
507 517
508 r_vcpu = iodev->redist_vcpu ? iodev->redist_vcpu : vcpu; 518 switch (iodev->iodev_type) {
509 region->write(r_vcpu, addr, len, data); 519 case IODEV_CPUIF:
520 break;
521 case IODEV_DIST:
522 region->write(vcpu, addr, len, data);
523 break;
524 case IODEV_REDIST:
525 region->write(iodev->redist_vcpu, addr, len, data);
526 break;
527 case IODEV_ITS:
528 region->its_write(vcpu->kvm, iodev->its, addr, len, data);
529 break;
530 }
531
510 return 0; 532 return 0;
511} 533}
512 534
@@ -536,6 +558,7 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
536 } 558 }
537 559
538 io_device->base_addr = dist_base_address; 560 io_device->base_addr = dist_base_address;
561 io_device->iodev_type = IODEV_DIST;
539 io_device->redist_vcpu = NULL; 562 io_device->redist_vcpu = NULL;
540 563
541 mutex_lock(&kvm->slots_lock); 564 mutex_lock(&kvm->slots_lock);
diff --git a/virt/kvm/arm/vgic/vgic-mmio.h b/virt/kvm/arm/vgic/vgic-mmio.h
index 71aa39d4cfdf..366d66378732 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.h
+++ b/virt/kvm/arm/vgic/vgic-mmio.h
@@ -21,10 +21,19 @@ struct vgic_register_region {
21 unsigned int len; 21 unsigned int len;
22 unsigned int bits_per_irq; 22 unsigned int bits_per_irq;
23 unsigned int access_flags; 23 unsigned int access_flags;
24 unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr, 24 union {
25 unsigned int len); 25 unsigned long (*read)(struct kvm_vcpu *vcpu, gpa_t addr,
26 void (*write)(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len, 26 unsigned int len);
27 unsigned long val); 27 unsigned long (*its_read)(struct kvm *kvm, struct vgic_its *its,
28 gpa_t addr, unsigned int len);
29 };
30 union {
31 void (*write)(struct kvm_vcpu *vcpu, gpa_t addr,
32 unsigned int len, unsigned long val);
33 void (*its_write)(struct kvm *kvm, struct vgic_its *its,
34 gpa_t addr, unsigned int len,
35 unsigned long val);
36 };
28}; 37};
29 38
30extern struct kvm_io_device_ops kvm_io_gic_ops; 39extern struct kvm_io_device_ops kvm_io_gic_ops;
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index 5b79c340f17e..31807c166d2a 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -72,6 +72,7 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu);
72int vgic_v3_probe(const struct gic_kvm_info *info); 72int vgic_v3_probe(const struct gic_kvm_info *info);
73int vgic_v3_map_resources(struct kvm *kvm); 73int vgic_v3_map_resources(struct kvm *kvm);
74int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address); 74int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
75bool vgic_has_its(struct kvm *kvm);
75#else 76#else
76static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu) 77static inline void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
77{ 78{
@@ -123,6 +124,12 @@ static inline int vgic_register_redist_iodevs(struct kvm *kvm,
123{ 124{
124 return -ENODEV; 125 return -ENODEV;
125} 126}
127
128static inline bool vgic_has_its(struct kvm *kvm)
129{
130 return false;
131}
132
126#endif 133#endif
127 134
128int kvm_register_vgic_device(unsigned long type); 135int kvm_register_vgic_device(unsigned long type);