aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorChristoffer Dall <c.dall@virtualopensystems.com>2013-01-21 19:36:13 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2013-02-11 13:59:01 -0500
commit330690cdceba06b60afcfe50a65f72fab7f4f970 (patch)
tree3dc8a6a3e8324e4e9d724497dd45942b1d66a042 /arch/arm
parent1a89dd9113badd7487313410a5f2e09b2944f92b (diff)
ARM: KVM: VGIC accept vcpu and dist base addresses from user space
User space defines the model to emulate to a guest and should therefore decide which addresses are used for both the virtual CPU interface directly mapped in the guest physical address space and for the emulated distributor interface, which is mapped in software by the in-kernel VGIC support. Reviewed-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/include/asm/kvm_vgic.h9
-rw-r--r--arch/arm/include/uapi/asm/kvm.h3
-rw-r--r--arch/arm/kvm/arm.c16
-rw-r--r--arch/arm/kvm/vgic.c62
4 files changed, 89 insertions, 1 deletions
diff --git a/arch/arm/include/asm/kvm_vgic.h b/arch/arm/include/asm/kvm_vgic.h
index 8f44799b8db1..b56fcf3c3575 100644
--- a/arch/arm/include/asm/kvm_vgic.h
+++ b/arch/arm/include/asm/kvm_vgic.h
@@ -22,6 +22,9 @@
22#include <linux/irqchip/arm-gic.h> 22#include <linux/irqchip/arm-gic.h>
23 23
24struct vgic_dist { 24struct vgic_dist {
25 /* Distributor and vcpu interface mapping in the guest */
26 phys_addr_t vgic_dist_base;
27 phys_addr_t vgic_cpu_base;
25}; 28};
26 29
27struct vgic_cpu { 30struct vgic_cpu {
@@ -33,6 +36,7 @@ struct kvm_run;
33struct kvm_exit_mmio; 36struct kvm_exit_mmio;
34 37
35#ifdef CONFIG_KVM_ARM_VGIC 38#ifdef CONFIG_KVM_ARM_VGIC
39int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr);
36bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, 40bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
37 struct kvm_exit_mmio *mmio); 41 struct kvm_exit_mmio *mmio);
38 42
@@ -42,6 +46,11 @@ static inline int kvm_vgic_hyp_init(void)
42 return 0; 46 return 0;
43} 47}
44 48
49static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
50{
51 return 0;
52}
53
45static inline int kvm_vgic_init(struct kvm *kvm) 54static inline int kvm_vgic_init(struct kvm *kvm)
46{ 55{
47 return 0; 56 return 0;
diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
index 346ac3f4a2b8..023bfeb367bf 100644
--- a/arch/arm/include/uapi/asm/kvm.h
+++ b/arch/arm/include/uapi/asm/kvm.h
@@ -78,6 +78,9 @@ struct kvm_regs {
78#define KVM_VGIC_V2_ADDR_TYPE_DIST 0 78#define KVM_VGIC_V2_ADDR_TYPE_DIST 0
79#define KVM_VGIC_V2_ADDR_TYPE_CPU 1 79#define KVM_VGIC_V2_ADDR_TYPE_CPU 1
80 80
81#define KVM_VGIC_V2_DIST_SIZE 0x1000
82#define KVM_VGIC_V2_CPU_SIZE 0x2000
83
81#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ 84#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
82 85
83struct kvm_vcpu_init { 86struct kvm_vcpu_init {
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index 7305aef28d0e..c327fd9d8ec3 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -880,7 +880,21 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
880static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm, 880static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
881 struct kvm_arm_device_addr *dev_addr) 881 struct kvm_arm_device_addr *dev_addr)
882{ 882{
883 return -ENODEV; 883 unsigned long dev_id, type;
884
885 dev_id = (dev_addr->id & KVM_ARM_DEVICE_ID_MASK) >>
886 KVM_ARM_DEVICE_ID_SHIFT;
887 type = (dev_addr->id & KVM_ARM_DEVICE_TYPE_MASK) >>
888 KVM_ARM_DEVICE_TYPE_SHIFT;
889
890 switch (dev_id) {
891 case KVM_ARM_DEVICE_VGIC_V2:
892 if (!vgic_present)
893 return -ENXIO;
894 return kvm_vgic_set_addr(kvm, type, dev_addr->addr);
895 default:
896 return -ENODEV;
897 }
884} 898}
885 899
886long kvm_arch_vm_ioctl(struct file *filp, 900long kvm_arch_vm_ioctl(struct file *filp,
diff --git a/arch/arm/kvm/vgic.c b/arch/arm/kvm/vgic.c
index c400661409ab..b333b58de4cb 100644
--- a/arch/arm/kvm/vgic.c
+++ b/arch/arm/kvm/vgic.c
@@ -22,6 +22,9 @@
22#include <linux/io.h> 22#include <linux/io.h>
23#include <asm/kvm_emulate.h> 23#include <asm/kvm_emulate.h>
24 24
25#define VGIC_ADDR_UNDEF (-1)
26#define IS_VGIC_ADDR_UNDEF(_x) ((_x) == VGIC_ADDR_UNDEF)
27
25#define ACCESS_READ_VALUE (1 << 0) 28#define ACCESS_READ_VALUE (1 << 0)
26#define ACCESS_READ_RAZ (0 << 0) 29#define ACCESS_READ_RAZ (0 << 0)
27#define ACCESS_READ_MASK(x) ((x) & (1 << 0)) 30#define ACCESS_READ_MASK(x) ((x) & (1 << 0))
@@ -151,3 +154,62 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
151{ 154{
152 return KVM_EXIT_MMIO; 155 return KVM_EXIT_MMIO;
153} 156}
157
158static bool vgic_ioaddr_overlap(struct kvm *kvm)
159{
160 phys_addr_t dist = kvm->arch.vgic.vgic_dist_base;
161 phys_addr_t cpu = kvm->arch.vgic.vgic_cpu_base;
162
163 if (IS_VGIC_ADDR_UNDEF(dist) || IS_VGIC_ADDR_UNDEF(cpu))
164 return 0;
165 if ((dist <= cpu && dist + KVM_VGIC_V2_DIST_SIZE > cpu) ||
166 (cpu <= dist && cpu + KVM_VGIC_V2_CPU_SIZE > dist))
167 return -EBUSY;
168 return 0;
169}
170
171static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr,
172 phys_addr_t addr, phys_addr_t size)
173{
174 int ret;
175
176 if (!IS_VGIC_ADDR_UNDEF(*ioaddr))
177 return -EEXIST;
178 if (addr + size < addr)
179 return -EINVAL;
180
181 ret = vgic_ioaddr_overlap(kvm);
182 if (ret)
183 return ret;
184 *ioaddr = addr;
185 return ret;
186}
187
188int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr)
189{
190 int r = 0;
191 struct vgic_dist *vgic = &kvm->arch.vgic;
192
193 if (addr & ~KVM_PHYS_MASK)
194 return -E2BIG;
195
196 if (addr & ~PAGE_MASK)
197 return -EINVAL;
198
199 mutex_lock(&kvm->lock);
200 switch (type) {
201 case KVM_VGIC_V2_ADDR_TYPE_DIST:
202 r = vgic_ioaddr_assign(kvm, &vgic->vgic_dist_base,
203 addr, KVM_VGIC_V2_DIST_SIZE);
204 break;
205 case KVM_VGIC_V2_ADDR_TYPE_CPU:
206 r = vgic_ioaddr_assign(kvm, &vgic->vgic_cpu_base,
207 addr, KVM_VGIC_V2_CPU_SIZE);
208 break;
209 default:
210 r = -ENODEV;
211 }
212
213 mutex_unlock(&kvm->lock);
214 return r;
215}