diff options
| author | Marc Zyngier <marc.zyngier@arm.com> | 2016-09-06 04:28:47 -0400 |
|---|---|---|
| committer | Christoffer Dall <christoffer.dall@linaro.org> | 2016-09-08 06:53:00 -0400 |
| commit | a07d3b07a876d44827e62f3ef55837ebbf61c4e6 (patch) | |
| tree | 58d07ebae9e09ac06c056d5a002a3840f96d8b60 /virt | |
| parent | bf8feb39642b4c71c644e2d534ce53029bd2219b (diff) | |
arm64: KVM: vgic-v2: Enable GICV access from HYP if access from guest is unsafe
So far, we've been disabling KVM on systems where the GICV region couldn't
be safely given to a guest. Now that we're able to handle this access
safely by emulating it in HYP, we can enable this feature when we detect
an unsafe configuration.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'virt')
| -rw-r--r-- | virt/kvm/arm/vgic/vgic-v2.c | 69 |
1 files changed, 42 insertions, 27 deletions
diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c index b8da9011889d..0a063af40565 100644 --- a/virt/kvm/arm/vgic/vgic-v2.c +++ b/virt/kvm/arm/vgic/vgic-v2.c | |||
| @@ -278,12 +278,14 @@ int vgic_v2_map_resources(struct kvm *kvm) | |||
| 278 | goto out; | 278 | goto out; |
| 279 | } | 279 | } |
| 280 | 280 | ||
| 281 | ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base, | 281 | if (!static_branch_unlikely(&vgic_v2_cpuif_trap)) { |
| 282 | kvm_vgic_global_state.vcpu_base, | 282 | ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base, |
| 283 | KVM_VGIC_V2_CPU_SIZE, true); | 283 | kvm_vgic_global_state.vcpu_base, |
| 284 | if (ret) { | 284 | KVM_VGIC_V2_CPU_SIZE, true); |
| 285 | kvm_err("Unable to remap VGIC CPU to VCPU\n"); | 285 | if (ret) { |
| 286 | goto out; | 286 | kvm_err("Unable to remap VGIC CPU to VCPU\n"); |
| 287 | goto out; | ||
| 288 | } | ||
| 287 | } | 289 | } |
| 288 | 290 | ||
| 289 | dist->ready = true; | 291 | dist->ready = true; |
| @@ -312,45 +314,51 @@ int vgic_v2_probe(const struct gic_kvm_info *info) | |||
| 312 | return -ENXIO; | 314 | return -ENXIO; |
| 313 | } | 315 | } |
| 314 | 316 | ||
| 315 | if (!PAGE_ALIGNED(info->vcpu.start)) { | 317 | if (!PAGE_ALIGNED(info->vcpu.start) || |
| 316 | kvm_err("GICV physical address 0x%llx not page aligned\n", | 318 | !PAGE_ALIGNED(resource_size(&info->vcpu))) { |
| 317 | (unsigned long long)info->vcpu.start); | 319 | kvm_info("GICV region size/alignment is unsafe, using trapping (reduced performance)\n"); |
| 318 | return -ENXIO; | 320 | kvm_vgic_global_state.vcpu_base_va = ioremap(info->vcpu.start, |
| 319 | } | 321 | resource_size(&info->vcpu)); |
| 322 | if (!kvm_vgic_global_state.vcpu_base_va) { | ||
| 323 | kvm_err("Cannot ioremap GICV\n"); | ||
| 324 | return -ENOMEM; | ||
| 325 | } | ||
| 320 | 326 | ||
| 321 | if (!PAGE_ALIGNED(resource_size(&info->vcpu))) { | 327 | ret = create_hyp_io_mappings(kvm_vgic_global_state.vcpu_base_va, |
| 322 | kvm_err("GICV size 0x%llx not a multiple of page size 0x%lx\n", | 328 | kvm_vgic_global_state.vcpu_base_va + resource_size(&info->vcpu), |
| 323 | (unsigned long long)resource_size(&info->vcpu), | 329 | info->vcpu.start); |
| 324 | PAGE_SIZE); | 330 | if (ret) { |
| 325 | return -ENXIO; | 331 | kvm_err("Cannot map GICV into hyp\n"); |
| 332 | goto out; | ||
| 333 | } | ||
| 334 | |||
| 335 | static_branch_enable(&vgic_v2_cpuif_trap); | ||
| 326 | } | 336 | } |
| 327 | 337 | ||
| 328 | kvm_vgic_global_state.vctrl_base = ioremap(info->vctrl.start, | 338 | kvm_vgic_global_state.vctrl_base = ioremap(info->vctrl.start, |
| 329 | resource_size(&info->vctrl)); | 339 | resource_size(&info->vctrl)); |
| 330 | if (!kvm_vgic_global_state.vctrl_base) { | 340 | if (!kvm_vgic_global_state.vctrl_base) { |
| 331 | kvm_err("Cannot ioremap GICH\n"); | 341 | kvm_err("Cannot ioremap GICH\n"); |
| 332 | return -ENOMEM; | 342 | ret = -ENOMEM; |
| 343 | goto out; | ||
| 333 | } | 344 | } |
| 334 | 345 | ||
| 335 | vtr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR); | 346 | vtr = readl_relaxed(kvm_vgic_global_state.vctrl_base + GICH_VTR); |
| 336 | kvm_vgic_global_state.nr_lr = (vtr & 0x3f) + 1; | 347 | kvm_vgic_global_state.nr_lr = (vtr & 0x3f) + 1; |
| 337 | 348 | ||
| 338 | ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2); | ||
| 339 | if (ret) { | ||
| 340 | kvm_err("Cannot register GICv2 KVM device\n"); | ||
| 341 | iounmap(kvm_vgic_global_state.vctrl_base); | ||
| 342 | return ret; | ||
| 343 | } | ||
| 344 | |||
| 345 | ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base, | 349 | ret = create_hyp_io_mappings(kvm_vgic_global_state.vctrl_base, |
| 346 | kvm_vgic_global_state.vctrl_base + | 350 | kvm_vgic_global_state.vctrl_base + |
| 347 | resource_size(&info->vctrl), | 351 | resource_size(&info->vctrl), |
| 348 | info->vctrl.start); | 352 | info->vctrl.start); |
| 349 | if (ret) { | 353 | if (ret) { |
| 350 | kvm_err("Cannot map VCTRL into hyp\n"); | 354 | kvm_err("Cannot map VCTRL into hyp\n"); |
| 351 | kvm_unregister_device_ops(KVM_DEV_TYPE_ARM_VGIC_V2); | 355 | goto out; |
| 352 | iounmap(kvm_vgic_global_state.vctrl_base); | 356 | } |
| 353 | return ret; | 357 | |
| 358 | ret = kvm_register_vgic_device(KVM_DEV_TYPE_ARM_VGIC_V2); | ||
| 359 | if (ret) { | ||
| 360 | kvm_err("Cannot register GICv2 KVM device\n"); | ||
| 361 | goto out; | ||
| 354 | } | 362 | } |
| 355 | 363 | ||
| 356 | kvm_vgic_global_state.can_emulate_gicv2 = true; | 364 | kvm_vgic_global_state.can_emulate_gicv2 = true; |
| @@ -361,4 +369,11 @@ int vgic_v2_probe(const struct gic_kvm_info *info) | |||
| 361 | kvm_info("vgic-v2@%llx\n", info->vctrl.start); | 369 | kvm_info("vgic-v2@%llx\n", info->vctrl.start); |
| 362 | 370 | ||
| 363 | return 0; | 371 | return 0; |
| 372 | out: | ||
| 373 | if (kvm_vgic_global_state.vctrl_base) | ||
| 374 | iounmap(kvm_vgic_global_state.vctrl_base); | ||
| 375 | if (kvm_vgic_global_state.vcpu_base_va) | ||
| 376 | iounmap(kvm_vgic_global_state.vcpu_base_va); | ||
| 377 | |||
| 378 | return ret; | ||
| 364 | } | 379 | } |
