diff options
-rw-r--r-- | Documentation/virtual/kvm/api.txt | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/kvm_vgic.h | 9 | ||||
-rw-r--r-- | arch/arm/include/uapi/asm/kvm.h | 3 | ||||
-rw-r--r-- | arch/arm/kvm/arm.c | 16 | ||||
-rw-r--r-- | arch/arm/kvm/vgic.c | 62 |
5 files changed, 90 insertions, 1 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 4505f869e450..e0fa0ea2b187 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt | |||
@@ -2222,6 +2222,7 @@ Errors: | |||
2222 | ENXIO: Device not supported on current system | 2222 | ENXIO: Device not supported on current system |
2223 | EEXIST: Address already set | 2223 | EEXIST: Address already set |
2224 | E2BIG: Address outside guest physical address space | 2224 | E2BIG: Address outside guest physical address space |
2225 | EBUSY: Address overlaps with other device range | ||
2225 | 2226 | ||
2226 | struct kvm_arm_device_addr { | 2227 | struct kvm_arm_device_addr { |
2227 | __u64 id; | 2228 | __u64 id; |
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 | ||
24 | struct vgic_dist { | 24 | struct 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 | ||
27 | struct vgic_cpu { | 30 | struct vgic_cpu { |
@@ -33,6 +36,7 @@ struct kvm_run; | |||
33 | struct kvm_exit_mmio; | 36 | struct kvm_exit_mmio; |
34 | 37 | ||
35 | #ifdef CONFIG_KVM_ARM_VGIC | 38 | #ifdef CONFIG_KVM_ARM_VGIC |
39 | int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr); | ||
36 | bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, | 40 | bool 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 | ||
49 | static inline int kvm_vgic_set_addr(struct kvm *kvm, unsigned long type, u64 addr) | ||
50 | { | ||
51 | return 0; | ||
52 | } | ||
53 | |||
45 | static inline int kvm_vgic_init(struct kvm *kvm) | 54 | static 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 | ||
83 | struct kvm_vcpu_init { | 86 | struct 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) | |||
880 | static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm, | 880 | static 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 | ||
886 | long kvm_arch_vm_ioctl(struct file *filp, | 900 | long 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 | |||
158 | static 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 | |||
171 | static 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 | |||
188 | int 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 | } | ||