aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@ozlabs.org>2017-05-10 02:39:41 -0400
committerPaul Mackerras <paulus@ozlabs.org>2017-05-12 01:08:09 -0400
commitacde25726bc6034b628febb8a4c6c0838736ccbf (patch)
treeaf3b2cd2deb9ceb36046f440e1116ddc6882aa88
parent36c344f3f1ffc0b1b20abd237b7401dc6687ee8f (diff)
KVM: PPC: Book3S HV: Add radix checks in real-mode hypercall handlers
POWER9 running a radix guest will take some hypervisor interrupts without going to real mode (turning off the MMU). This means that early hypercall handlers may now be called in virtual mode. Most of the handlers work just fine in both modes, but there are some that can crash the host if called in virtual mode, notably the TCE (IOMMU) hypercalls H_PUT_TCE, H_STUFF_TCE and H_PUT_TCE_INDIRECT. These already have both a real-mode and a virtual-mode version, so we arrange for the real-mode version to return H_TOO_HARD for radix guests, which will result in the virtual-mode version being called. The other hypercall which is sensitive to the MMU mode is H_RANDOM. It doesn't have a virtual-mode version, so this adds code to enable it to be called in either mode. An alternative solution was considered which would refuse to call any of the early hypercall handlers when doing a virtual-mode exit from a radix guest. However, the XICS-on-XIVE code depends on the XICS hypercalls being handled early even for virtual-mode exits, because the handlers need to be called before the XIVE vCPU state has been pulled off the hardware. Therefore that solution would have become quite invasive and complicated, and was rejected in favour of the simpler, though less elegant, solution presented here. Reviewed-by: David Gibson <david@gibson.dropbear.id.au> Tested-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
-rw-r--r--arch/powerpc/kvm/book3s_64_vio_hv.c13
-rw-r--r--arch/powerpc/kvm/book3s_hv_builtin.c9
2 files changed, 21 insertions, 1 deletions
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
index eda0a8f6fae8..3adfd2f5301c 100644
--- a/arch/powerpc/kvm/book3s_64_vio_hv.c
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -301,6 +301,10 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
301 /* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */ 301 /* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */
302 /* liobn, ioba, tce); */ 302 /* liobn, ioba, tce); */
303 303
304 /* For radix, we might be in virtual mode, so punt */
305 if (kvm_is_radix(vcpu->kvm))
306 return H_TOO_HARD;
307
304 stt = kvmppc_find_table(vcpu->kvm, liobn); 308 stt = kvmppc_find_table(vcpu->kvm, liobn);
305 if (!stt) 309 if (!stt)
306 return H_TOO_HARD; 310 return H_TOO_HARD;
@@ -381,6 +385,10 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
381 bool prereg = false; 385 bool prereg = false;
382 struct kvmppc_spapr_tce_iommu_table *stit; 386 struct kvmppc_spapr_tce_iommu_table *stit;
383 387
388 /* For radix, we might be in virtual mode, so punt */
389 if (kvm_is_radix(vcpu->kvm))
390 return H_TOO_HARD;
391
384 stt = kvmppc_find_table(vcpu->kvm, liobn); 392 stt = kvmppc_find_table(vcpu->kvm, liobn);
385 if (!stt) 393 if (!stt)
386 return H_TOO_HARD; 394 return H_TOO_HARD;
@@ -491,6 +499,10 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
491 long i, ret; 499 long i, ret;
492 struct kvmppc_spapr_tce_iommu_table *stit; 500 struct kvmppc_spapr_tce_iommu_table *stit;
493 501
502 /* For radix, we might be in virtual mode, so punt */
503 if (kvm_is_radix(vcpu->kvm))
504 return H_TOO_HARD;
505
494 stt = kvmppc_find_table(vcpu->kvm, liobn); 506 stt = kvmppc_find_table(vcpu->kvm, liobn);
495 if (!stt) 507 if (!stt)
496 return H_TOO_HARD; 508 return H_TOO_HARD;
@@ -527,6 +539,7 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
527 return H_SUCCESS; 539 return H_SUCCESS;
528} 540}
529 541
542/* This can be called in either virtual mode or real mode */
530long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn, 543long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
531 unsigned long ioba) 544 unsigned long ioba)
532{ 545{
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index 88a65923c649..ee4c2558c305 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -207,7 +207,14 @@ EXPORT_SYMBOL_GPL(kvmppc_hwrng_present);
207 207
208long kvmppc_h_random(struct kvm_vcpu *vcpu) 208long kvmppc_h_random(struct kvm_vcpu *vcpu)
209{ 209{
210 if (powernv_get_random_real_mode(&vcpu->arch.gpr[4])) 210 int r;
211
212 /* Only need to do the expensive mfmsr() on radix */
213 if (kvm_is_radix(vcpu->kvm) && (mfmsr() & MSR_IR))
214 r = powernv_get_random_long(&vcpu->arch.gpr[4]);
215 else
216 r = powernv_get_random_real_mode(&vcpu->arch.gpr[4]);
217 if (r)
211 return H_SUCCESS; 218 return H_SUCCESS;
212 219
213 return H_HARDWARE; 220 return H_HARDWARE;