Loading arch/powerpc/kvm/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ config KVM_BOOK3S_64 select KVM_BOOK3S_64_HANDLER select KVM select KVM_BOOK3S_PR_POSSIBLE if !KVM_BOOK3S_HV_POSSIBLE select SPAPR_TCE_IOMMU if IOMMU_SUPPORT select SPAPR_TCE_IOMMU if IOMMU_SUPPORT && (PPC_SERIES || PPC_POWERNV) ---help--- Support running unmodified book3s_64 and book3s_32 guest kernels in virtual machines on book3s_64 host processors. Loading arch/powerpc/kvm/Makefile +2 −2 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ kvm-e500mc-objs := \ e500_emulate.o kvm-objs-$(CONFIG_KVM_E500MC) := $(kvm-e500mc-objs) kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) := \ kvm-book3s_64-builtin-objs-$(CONFIG_SPAPR_TCE_IOMMU) := \ book3s_64_vio_hv.o kvm-pr-y := \ Loading Loading @@ -90,11 +90,11 @@ kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \ book3s_xics.o kvm-book3s_64-objs-$(CONFIG_KVM_XIVE) += book3s_xive.o kvm-book3s_64-objs-$(CONFIG_SPAPR_TCE_IOMMU) += book3s_64_vio.o kvm-book3s_64-module-objs := \ $(common-objs-y) \ book3s.o \ book3s_64_vio.o \ book3s_rtas.o \ $(kvm-book3s_64-objs-y) Loading arch/powerpc/kvm/book3s_64_vio_hv.c +13 −0 Original line number Diff line number Diff line Loading @@ -301,6 +301,10 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, /* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */ /* liobn, ioba, tce); */ /* For radix, we might be in virtual mode, so punt */ if (kvm_is_radix(vcpu->kvm)) return H_TOO_HARD; stt = kvmppc_find_table(vcpu->kvm, liobn); if (!stt) return H_TOO_HARD; Loading Loading @@ -381,6 +385,10 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, bool prereg = false; struct kvmppc_spapr_tce_iommu_table *stit; /* For radix, we might be in virtual mode, so punt */ if (kvm_is_radix(vcpu->kvm)) return H_TOO_HARD; stt = kvmppc_find_table(vcpu->kvm, liobn); if (!stt) return H_TOO_HARD; Loading Loading @@ -491,6 +499,10 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu, long i, ret; struct kvmppc_spapr_tce_iommu_table *stit; /* For radix, we might be in virtual mode, so punt */ if (kvm_is_radix(vcpu->kvm)) return H_TOO_HARD; stt = kvmppc_find_table(vcpu->kvm, liobn); if (!stt) return H_TOO_HARD; Loading Loading @@ -527,6 +539,7 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu, return H_SUCCESS; } /* This can be called in either virtual mode or real mode */ long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn, unsigned long ioba) { Loading arch/powerpc/kvm/book3s_hv_builtin.c +8 −1 Original line number Diff line number Diff line Loading @@ -207,7 +207,14 @@ EXPORT_SYMBOL_GPL(kvmppc_hwrng_present); long kvmppc_h_random(struct kvm_vcpu *vcpu) { if (powernv_get_random_real_mode(&vcpu->arch.gpr[4])) int r; /* Only need to do the expensive mfmsr() on radix */ if (kvm_is_radix(vcpu->kvm) && (mfmsr() & MSR_IR)) r = powernv_get_random_long(&vcpu->arch.gpr[4]); else r = powernv_get_random_real_mode(&vcpu->arch.gpr[4]); if (r) return H_SUCCESS; return H_HARDWARE; Loading arch/powerpc/kvm/book3s_pr_papr.c +53 −17 Original line number Diff line number Diff line Loading @@ -50,7 +50,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu) pteg_addr = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)); ret = H_FUNCTION; if (copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg))) goto done; hpte = pteg; ret = H_PTEG_FULL; Loading @@ -71,7 +73,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu) hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6)); hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7)); pteg_addr += i * HPTE_SIZE; copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE); ret = H_FUNCTION; if (copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE)) goto done; kvmppc_set_gpr(vcpu, 4, pte_index | i); ret = H_SUCCESS; Loading @@ -93,7 +97,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) pteg = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); copy_from_user(pte, (void __user *)pteg, sizeof(pte)); ret = H_FUNCTION; if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) goto done; pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); Loading @@ -103,7 +109,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) ((flags & H_ANDCOND) && (pte[0] & avpn) != 0)) goto done; copy_to_user((void __user *)pteg, &v, sizeof(v)); ret = H_FUNCTION; if (copy_to_user((void __user *)pteg, &v, sizeof(v))) goto done; rb = compute_tlbie_rb(pte[0], pte[1], pte_index); vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); Loading Loading @@ -171,7 +179,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) } pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX); copy_from_user(pte, (void __user *)pteg, sizeof(pte)); if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) { ret = H_FUNCTION; break; } pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); Loading @@ -184,7 +195,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) tsh |= H_BULK_REMOVE_NOT_FOUND; } else { /* Splat the pteg in (userland) hpt */ copy_to_user((void __user *)pteg, &v, sizeof(v)); if (copy_to_user((void __user *)pteg, &v, sizeof(v))) { ret = H_FUNCTION; break; } rb = compute_tlbie_rb(pte[0], pte[1], tsh & H_BULK_REMOVE_PTEX); Loading @@ -211,7 +225,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) pteg = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); copy_from_user(pte, (void __user *)pteg, sizeof(pte)); ret = H_FUNCTION; if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) goto done; pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); Loading @@ -234,7 +250,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); pte[0] = (__force u64)cpu_to_be64(pte[0]); pte[1] = (__force u64)cpu_to_be64(pte[1]); copy_to_user((void __user *)pteg, pte, sizeof(pte)); ret = H_FUNCTION; if (copy_to_user((void __user *)pteg, pte, sizeof(pte))) goto done; ret = H_SUCCESS; done: Loading @@ -244,36 +262,37 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) return EMULATE_DONE; } static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu) static int kvmppc_h_pr_logical_ci_load(struct kvm_vcpu *vcpu) { unsigned long liobn = kvmppc_get_gpr(vcpu, 4); unsigned long ioba = kvmppc_get_gpr(vcpu, 5); unsigned long tce = kvmppc_get_gpr(vcpu, 6); long rc; rc = kvmppc_h_put_tce(vcpu, liobn, ioba, tce); rc = kvmppc_h_logical_ci_load(vcpu); if (rc == H_TOO_HARD) return EMULATE_FAIL; kvmppc_set_gpr(vcpu, 3, rc); return EMULATE_DONE; } static int kvmppc_h_pr_logical_ci_load(struct kvm_vcpu *vcpu) static int kvmppc_h_pr_logical_ci_store(struct kvm_vcpu *vcpu) { long rc; rc = kvmppc_h_logical_ci_load(vcpu); rc = kvmppc_h_logical_ci_store(vcpu); if (rc == H_TOO_HARD) return EMULATE_FAIL; kvmppc_set_gpr(vcpu, 3, rc); return EMULATE_DONE; } static int kvmppc_h_pr_logical_ci_store(struct kvm_vcpu *vcpu) #ifdef CONFIG_SPAPR_TCE_IOMMU static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu) { unsigned long liobn = kvmppc_get_gpr(vcpu, 4); unsigned long ioba = kvmppc_get_gpr(vcpu, 5); unsigned long tce = kvmppc_get_gpr(vcpu, 6); long rc; rc = kvmppc_h_logical_ci_store(vcpu); rc = kvmppc_h_put_tce(vcpu, liobn, ioba, tce); if (rc == H_TOO_HARD) return EMULATE_FAIL; kvmppc_set_gpr(vcpu, 3, rc); Loading Loading @@ -311,6 +330,23 @@ static int kvmppc_h_pr_stuff_tce(struct kvm_vcpu *vcpu) return EMULATE_DONE; } #else /* CONFIG_SPAPR_TCE_IOMMU */ static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu) { return EMULATE_FAIL; } static int kvmppc_h_pr_put_tce_indirect(struct kvm_vcpu *vcpu) { return EMULATE_FAIL; } static int kvmppc_h_pr_stuff_tce(struct kvm_vcpu *vcpu) { return EMULATE_FAIL; } #endif /* CONFIG_SPAPR_TCE_IOMMU */ static int kvmppc_h_pr_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd) { long rc = kvmppc_xics_hcall(vcpu, cmd); Loading Loading
arch/powerpc/kvm/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -67,7 +67,7 @@ config KVM_BOOK3S_64 select KVM_BOOK3S_64_HANDLER select KVM select KVM_BOOK3S_PR_POSSIBLE if !KVM_BOOK3S_HV_POSSIBLE select SPAPR_TCE_IOMMU if IOMMU_SUPPORT select SPAPR_TCE_IOMMU if IOMMU_SUPPORT && (PPC_SERIES || PPC_POWERNV) ---help--- Support running unmodified book3s_64 and book3s_32 guest kernels in virtual machines on book3s_64 host processors. Loading
arch/powerpc/kvm/Makefile +2 −2 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ kvm-e500mc-objs := \ e500_emulate.o kvm-objs-$(CONFIG_KVM_E500MC) := $(kvm-e500mc-objs) kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) := \ kvm-book3s_64-builtin-objs-$(CONFIG_SPAPR_TCE_IOMMU) := \ book3s_64_vio_hv.o kvm-pr-y := \ Loading Loading @@ -90,11 +90,11 @@ kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \ book3s_xics.o kvm-book3s_64-objs-$(CONFIG_KVM_XIVE) += book3s_xive.o kvm-book3s_64-objs-$(CONFIG_SPAPR_TCE_IOMMU) += book3s_64_vio.o kvm-book3s_64-module-objs := \ $(common-objs-y) \ book3s.o \ book3s_64_vio.o \ book3s_rtas.o \ $(kvm-book3s_64-objs-y) Loading
arch/powerpc/kvm/book3s_64_vio_hv.c +13 −0 Original line number Diff line number Diff line Loading @@ -301,6 +301,10 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn, /* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */ /* liobn, ioba, tce); */ /* For radix, we might be in virtual mode, so punt */ if (kvm_is_radix(vcpu->kvm)) return H_TOO_HARD; stt = kvmppc_find_table(vcpu->kvm, liobn); if (!stt) return H_TOO_HARD; Loading Loading @@ -381,6 +385,10 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu, bool prereg = false; struct kvmppc_spapr_tce_iommu_table *stit; /* For radix, we might be in virtual mode, so punt */ if (kvm_is_radix(vcpu->kvm)) return H_TOO_HARD; stt = kvmppc_find_table(vcpu->kvm, liobn); if (!stt) return H_TOO_HARD; Loading Loading @@ -491,6 +499,10 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu, long i, ret; struct kvmppc_spapr_tce_iommu_table *stit; /* For radix, we might be in virtual mode, so punt */ if (kvm_is_radix(vcpu->kvm)) return H_TOO_HARD; stt = kvmppc_find_table(vcpu->kvm, liobn); if (!stt) return H_TOO_HARD; Loading Loading @@ -527,6 +539,7 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu, return H_SUCCESS; } /* This can be called in either virtual mode or real mode */ long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn, unsigned long ioba) { Loading
arch/powerpc/kvm/book3s_hv_builtin.c +8 −1 Original line number Diff line number Diff line Loading @@ -207,7 +207,14 @@ EXPORT_SYMBOL_GPL(kvmppc_hwrng_present); long kvmppc_h_random(struct kvm_vcpu *vcpu) { if (powernv_get_random_real_mode(&vcpu->arch.gpr[4])) int r; /* Only need to do the expensive mfmsr() on radix */ if (kvm_is_radix(vcpu->kvm) && (mfmsr() & MSR_IR)) r = powernv_get_random_long(&vcpu->arch.gpr[4]); else r = powernv_get_random_real_mode(&vcpu->arch.gpr[4]); if (r) return H_SUCCESS; return H_HARDWARE; Loading
arch/powerpc/kvm/book3s_pr_papr.c +53 −17 Original line number Diff line number Diff line Loading @@ -50,7 +50,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu) pteg_addr = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)); ret = H_FUNCTION; if (copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg))) goto done; hpte = pteg; ret = H_PTEG_FULL; Loading @@ -71,7 +73,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu) hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6)); hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7)); pteg_addr += i * HPTE_SIZE; copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE); ret = H_FUNCTION; if (copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE)) goto done; kvmppc_set_gpr(vcpu, 4, pte_index | i); ret = H_SUCCESS; Loading @@ -93,7 +97,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) pteg = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); copy_from_user(pte, (void __user *)pteg, sizeof(pte)); ret = H_FUNCTION; if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) goto done; pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); Loading @@ -103,7 +109,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) ((flags & H_ANDCOND) && (pte[0] & avpn) != 0)) goto done; copy_to_user((void __user *)pteg, &v, sizeof(v)); ret = H_FUNCTION; if (copy_to_user((void __user *)pteg, &v, sizeof(v))) goto done; rb = compute_tlbie_rb(pte[0], pte[1], pte_index); vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); Loading Loading @@ -171,7 +179,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) } pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX); copy_from_user(pte, (void __user *)pteg, sizeof(pte)); if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) { ret = H_FUNCTION; break; } pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); Loading @@ -184,7 +195,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) tsh |= H_BULK_REMOVE_NOT_FOUND; } else { /* Splat the pteg in (userland) hpt */ copy_to_user((void __user *)pteg, &v, sizeof(v)); if (copy_to_user((void __user *)pteg, &v, sizeof(v))) { ret = H_FUNCTION; break; } rb = compute_tlbie_rb(pte[0], pte[1], tsh & H_BULK_REMOVE_PTEX); Loading @@ -211,7 +225,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) pteg = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); copy_from_user(pte, (void __user *)pteg, sizeof(pte)); ret = H_FUNCTION; if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) goto done; pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); Loading @@ -234,7 +250,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); pte[0] = (__force u64)cpu_to_be64(pte[0]); pte[1] = (__force u64)cpu_to_be64(pte[1]); copy_to_user((void __user *)pteg, pte, sizeof(pte)); ret = H_FUNCTION; if (copy_to_user((void __user *)pteg, pte, sizeof(pte))) goto done; ret = H_SUCCESS; done: Loading @@ -244,36 +262,37 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) return EMULATE_DONE; } static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu) static int kvmppc_h_pr_logical_ci_load(struct kvm_vcpu *vcpu) { unsigned long liobn = kvmppc_get_gpr(vcpu, 4); unsigned long ioba = kvmppc_get_gpr(vcpu, 5); unsigned long tce = kvmppc_get_gpr(vcpu, 6); long rc; rc = kvmppc_h_put_tce(vcpu, liobn, ioba, tce); rc = kvmppc_h_logical_ci_load(vcpu); if (rc == H_TOO_HARD) return EMULATE_FAIL; kvmppc_set_gpr(vcpu, 3, rc); return EMULATE_DONE; } static int kvmppc_h_pr_logical_ci_load(struct kvm_vcpu *vcpu) static int kvmppc_h_pr_logical_ci_store(struct kvm_vcpu *vcpu) { long rc; rc = kvmppc_h_logical_ci_load(vcpu); rc = kvmppc_h_logical_ci_store(vcpu); if (rc == H_TOO_HARD) return EMULATE_FAIL; kvmppc_set_gpr(vcpu, 3, rc); return EMULATE_DONE; } static int kvmppc_h_pr_logical_ci_store(struct kvm_vcpu *vcpu) #ifdef CONFIG_SPAPR_TCE_IOMMU static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu) { unsigned long liobn = kvmppc_get_gpr(vcpu, 4); unsigned long ioba = kvmppc_get_gpr(vcpu, 5); unsigned long tce = kvmppc_get_gpr(vcpu, 6); long rc; rc = kvmppc_h_logical_ci_store(vcpu); rc = kvmppc_h_put_tce(vcpu, liobn, ioba, tce); if (rc == H_TOO_HARD) return EMULATE_FAIL; kvmppc_set_gpr(vcpu, 3, rc); Loading Loading @@ -311,6 +330,23 @@ static int kvmppc_h_pr_stuff_tce(struct kvm_vcpu *vcpu) return EMULATE_DONE; } #else /* CONFIG_SPAPR_TCE_IOMMU */ static int kvmppc_h_pr_put_tce(struct kvm_vcpu *vcpu) { return EMULATE_FAIL; } static int kvmppc_h_pr_put_tce_indirect(struct kvm_vcpu *vcpu) { return EMULATE_FAIL; } static int kvmppc_h_pr_stuff_tce(struct kvm_vcpu *vcpu) { return EMULATE_FAIL; } #endif /* CONFIG_SPAPR_TCE_IOMMU */ static int kvmppc_h_pr_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd) { long rc = kvmppc_xics_hcall(vcpu, cmd); Loading