diff options
Diffstat (limited to 'arch/powerpc/kvm')
44 files changed, 3538 insertions, 810 deletions
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index a9f57dad6d91..c9a2d50ff1b0 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -19,14 +19,9 @@ if VIRTUALIZATION config KVM bool - select PREEMPT_NOTIFIERS - select HAVE_KVM_EVENTFD - select HAVE_KVM_VCPU_ASYNC_IOCTL - select SRCU + select KVM_COMMON select KVM_VFIO - select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS - select INTERVAL_TREE config KVM_BOOK3S_HANDLER bool @@ -43,7 +38,7 @@ config KVM_BOOK3S_64_HANDLER config KVM_BOOK3S_PR_POSSIBLE bool select KVM_MMIO - select MMU_NOTIFIER + select KVM_GENERIC_MMU_NOTIFIER config KVM_BOOK3S_HV_POSSIBLE bool @@ -86,7 +81,8 @@ config KVM_BOOK3S_64_HV tristate "KVM for POWER7 and later using hypervisor mode in host" depends on KVM_BOOK3S_64 && PPC_POWERNV select KVM_BOOK3S_HV_POSSIBLE - select MMU_NOTIFIER + select KVM_GENERIC_MMU_NOTIFIER + select KVM_BOOK3S_HV_PMU select CMA help Support running unmodified book3s_64 guest kernels in @@ -175,6 +171,18 @@ config KVM_BOOK3S_HV_NESTED_PMU_WORKAROUND those buggy L1s which saves the L2 state, at the cost of performance in all nested-capable guest entry/exit. +config KVM_BOOK3S_HV_PMU + tristate "Hypervisor Perf events for KVM Book3s-HV" + depends on KVM_BOOK3S_64_HV + help + Enable Book3s-HV Hypervisor Perf events PMU named 'kvm-hv'. These + Perf events give an overview of hypervisor performance overall + instead of a specific guests. Currently the PMU reports + L0-Hypervisor stats on a kvm-hv enabled PSeries LPAR like: + * Total/Used Guest-Heap + * Total/Used Guest Page-table Memory + * Total amount of Guest Page-table Memory reclaimed + config KVM_BOOKE_HV bool @@ -195,7 +203,7 @@ config KVM_E500V2 depends on !CONTEXT_TRACKING_USER select KVM select KVM_MMIO - select MMU_NOTIFIER + select KVM_GENERIC_MMU_NOTIFIER help Support running unmodified E500 guest kernels in virtual machines on E500v2 host processors. @@ -212,7 +220,7 @@ config KVM_E500MC select KVM select KVM_MMIO select KVM_BOOKE_HV - select MMU_NOTIFIER + select KVM_GENERIC_MMU_NOTIFIER help Support running unmodified E500MC/E5500/E6500 guest kernels in virtual machines on E500MC/E5500/E6500 host processors. @@ -226,7 +234,6 @@ config KVM_MPIC bool "KVM in-kernel MPIC emulation" depends on KVM && PPC_E500 select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQFD select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_MSI help @@ -239,7 +246,6 @@ config KVM_XICS bool "KVM in-kernel XICS emulation" depends on KVM_BOOK3S_64 && !KVM_MPIC select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQFD default y help Include support for the XICS (eXternal Interrupt Controller diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index 5319d889b184..4bd9d1230869 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile @@ -87,8 +87,12 @@ kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HANDLER) += \ book3s_hv_ras.o \ book3s_hv_builtin.o \ book3s_hv_p9_perf.o \ + book3s_hv_nestedv2.o \ + guest-state-buffer.o \ $(kvm-book3s_64-builtin-tm-objs-y) \ $(kvm-book3s_64-builtin-xics-objs-y) + +obj-$(CONFIG_GUEST_STATE_BUFFER_TEST) += test-guest-state-buffer.o endif kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \ diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 6d525285dbe8..d79c5d1098c0 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -188,10 +188,10 @@ void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) } EXPORT_SYMBOL_GPL(kvmppc_book3s_queue_irqprio); -void kvmppc_core_queue_machine_check(struct kvm_vcpu *vcpu, ulong flags) +void kvmppc_core_queue_machine_check(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_MACHINE_CHECK, flags); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_MACHINE_CHECK, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_machine_check); @@ -201,29 +201,29 @@ void kvmppc_core_queue_syscall(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL(kvmppc_core_queue_syscall); -void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags) +void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_PROGRAM, flags); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_PROGRAM, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_program); -void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, 0); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, srr1_flags); } -void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_ALTIVEC, 0); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_ALTIVEC, srr1_flags); } -void kvmppc_core_queue_vsx_unavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_vsx_unavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { /* might as well deliver this straight away */ - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_VSX, 0); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_VSX, srr1_flags); } void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) @@ -278,18 +278,18 @@ void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu) kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); } -void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong dar, - ulong flags) +void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong srr1_flags, + ulong dar, ulong dsisr) { kvmppc_set_dar(vcpu, dar); - kvmppc_set_dsisr(vcpu, flags); - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE, 0); + kvmppc_set_dsisr(vcpu, dsisr); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_DATA_STORAGE, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_data_storage); -void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu, ulong flags) +void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu, ulong srr1_flags) { - kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE, flags); + kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_inst_storage); @@ -302,11 +302,11 @@ static int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, switch (priority) { case BOOK3S_IRQPRIO_DECREMENTER: - deliver = (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; + deliver = !kvmhv_is_nestedv2() && (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; vec = BOOK3S_INTERRUPT_DECREMENTER; break; case BOOK3S_IRQPRIO_EXTERNAL: - deliver = (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; + deliver = !kvmhv_is_nestedv2() && (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; vec = BOOK3S_INTERRUPT_EXTERNAL; break; case BOOK3S_IRQPRIO_SYSTEM_RESET: @@ -360,10 +360,6 @@ static int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, break; } -#if 0 - printk(KERN_INFO "Deliver interrupt 0x%x? %x\n", vec, deliver); -#endif - if (deliver) kvmppc_inject_interrupt(vcpu, vec, 0); @@ -426,7 +422,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu) EXPORT_SYMBOL_GPL(kvmppc_core_prepare_to_enter); kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing, - bool *writable) + bool *writable, struct page **page) { ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM; gfn_t gfn = gpa >> PAGE_SHIFT; @@ -441,13 +437,14 @@ kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing, kvm_pfn_t pfn; pfn = (kvm_pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT; - get_page(pfn_to_page(pfn)); + *page = pfn_to_page(pfn); + get_page(*page); if (writable) *writable = true; return pfn; } - return gfn_to_pfn_prot(vcpu->kvm, gfn, writing, writable); + return kvm_faultin_pfn(vcpu, gfn, writing, writable, page); } EXPORT_SYMBOL_GPL(kvmppc_gpa_to_pfn); @@ -481,20 +478,42 @@ int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, enum xlate_instdata xlid, return r; } +/* + * Returns prefixed instructions with the prefix in the high 32 bits + * of *inst and suffix in the low 32 bits. This is the same convention + * as used in HEIR, vcpu->arch.last_inst and vcpu->arch.emul_inst. + * Like vcpu->arch.last_inst but unlike vcpu->arch.emul_inst, each + * half of the value needs byte-swapping if the guest endianness is + * different from the host endianness. + */ int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, - enum instruction_fetch_type type, u32 *inst) + enum instruction_fetch_type type, unsigned long *inst) { ulong pc = kvmppc_get_pc(vcpu); int r; + u32 iw; if (type == INST_SC) pc -= 4; - r = kvmppc_ld(vcpu, &pc, sizeof(u32), inst, false); - if (r == EMULATE_DONE) - return r; - else + r = kvmppc_ld(vcpu, &pc, sizeof(u32), &iw, false); + if (r != EMULATE_DONE) return EMULATE_AGAIN; + /* + * If [H]SRR1 indicates that the instruction that caused the + * current interrupt is a prefixed instruction, get the suffix. + */ + if (kvmppc_get_msr(vcpu) & SRR1_PREFIXED) { + u32 suffix; + pc += 4; + r = kvmppc_ld(vcpu, &pc, sizeof(u32), &suffix, false); + if (r != EMULATE_DONE) + return EMULATE_AGAIN; + *inst = ((u64)iw << 32) | suffix; + } else { + *inst = iw; + } + return r; } EXPORT_SYMBOL_GPL(kvmppc_load_last_inst); @@ -543,7 +562,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) regs->msr = kvmppc_get_msr(vcpu); regs->srr0 = kvmppc_get_srr0(vcpu); regs->srr1 = kvmppc_get_srr1(vcpu); - regs->pid = vcpu->arch.pid; + regs->pid = kvmppc_get_pid(vcpu); regs->sprg0 = kvmppc_get_sprg0(vcpu); regs->sprg1 = kvmppc_get_sprg1(vcpu); regs->sprg2 = kvmppc_get_sprg2(vcpu); @@ -614,17 +633,17 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, break; case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: i = id - KVM_REG_PPC_FPR0; - *val = get_reg_val(id, VCPU_FPR(vcpu, i)); + *val = get_reg_val(id, kvmppc_get_fpr(vcpu, i)); break; case KVM_REG_PPC_FPSCR: - *val = get_reg_val(id, vcpu->arch.fp.fpscr); + *val = get_reg_val(id, kvmppc_get_fpscr(vcpu)); break; #ifdef CONFIG_VSX case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: if (cpu_has_feature(CPU_FTR_VSX)) { i = id - KVM_REG_PPC_VSR0; - val->vsxval[0] = vcpu->arch.fp.fpr[i][0]; - val->vsxval[1] = vcpu->arch.fp.fpr[i][1]; + val->vsxval[0] = kvmppc_get_vsx_fpr(vcpu, i, 0); + val->vsxval[1] = kvmppc_get_vsx_fpr(vcpu, i, 1); } else { r = -ENXIO; } @@ -661,19 +680,19 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, *val = get_reg_val(id, vcpu->arch.fscr); break; case KVM_REG_PPC_TAR: - *val = get_reg_val(id, vcpu->arch.tar); + *val = get_reg_val(id, kvmppc_get_tar(vcpu)); break; case KVM_REG_PPC_EBBHR: - *val = get_reg_val(id, vcpu->arch.ebbhr); + *val = get_reg_val(id, kvmppc_get_ebbhr(vcpu)); break; case KVM_REG_PPC_EBBRR: - *val = get_reg_val(id, vcpu->arch.ebbrr); + *val = get_reg_val(id, kvmppc_get_ebbrr(vcpu)); break; case KVM_REG_PPC_BESCR: - *val = get_reg_val(id, vcpu->arch.bescr); + *val = get_reg_val(id, kvmppc_get_bescr(vcpu)); break; case KVM_REG_PPC_IC: - *val = get_reg_val(id, vcpu->arch.ic); + *val = get_reg_val(id, kvmppc_get_ic(vcpu)); break; default: r = -EINVAL; @@ -702,7 +721,7 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, break; case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: i = id - KVM_REG_PPC_FPR0; - VCPU_FPR(vcpu, i) = set_reg_val(id, *val); + kvmppc_set_fpr(vcpu, i, set_reg_val(id, *val)); break; case KVM_REG_PPC_FPSCR: vcpu->arch.fp.fpscr = set_reg_val(id, *val); @@ -711,8 +730,8 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: if (cpu_has_feature(CPU_FTR_VSX)) { i = id - KVM_REG_PPC_VSR0; - vcpu->arch.fp.fpr[i][0] = val->vsxval[0]; - vcpu->arch.fp.fpr[i][1] = val->vsxval[1]; + kvmppc_set_vsx_fpr(vcpu, i, 0, val->vsxval[0]); + kvmppc_set_vsx_fpr(vcpu, i, 1, val->vsxval[1]); } else { r = -ENXIO; } @@ -743,22 +762,22 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, break; #endif /* CONFIG_KVM_XIVE */ case KVM_REG_PPC_FSCR: - vcpu->arch.fscr = set_reg_val(id, *val); + kvmppc_set_fpscr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_TAR: - vcpu->arch.tar = set_reg_val(id, *val); + kvmppc_set_tar(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_EBBHR: - vcpu->arch.ebbhr = set_reg_val(id, *val); + kvmppc_set_ebbhr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_EBBRR: - vcpu->arch.ebbrr = set_reg_val(id, *val); + kvmppc_set_ebbrr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_BESCR: - vcpu->arch.bescr = set_reg_val(id, *val); + kvmppc_set_bescr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_IC: - vcpu->arch.ic = set_reg_val(id, *val); + kvmppc_set_ic(vcpu, set_reg_val(id, *val)); break; default: r = -EINVAL; @@ -877,11 +896,6 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) return kvm->arch.kvm_ops->test_age_gfn(kvm, range); } -bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) -{ - return kvm->arch.kvm_ops->set_spte_gfn(kvm, range); -} - int kvmppc_core_init_vm(struct kvm *kvm) { @@ -999,16 +1013,6 @@ int kvmppc_h_logical_ci_store(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvmppc_h_logical_ci_store); -int kvmppc_core_check_processor_compat(void) -{ - /* - * We always return 0 for book3s. We check - * for compatibility while loading the HV - * or PR module - */ - return 0; -} - int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hcall) { return kvm->arch.kvm_ops->hcall_implemented(hcall); @@ -1062,7 +1066,7 @@ static int kvmppc_book3s_init(void) { int r; - r = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); + r = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (r) return r; #ifdef CONFIG_KVM_BOOK3S_32_HANDLER diff --git a/arch/powerpc/kvm/book3s.h b/arch/powerpc/kvm/book3s.h index 58391b4b32ed..4aa2ab89afbc 100644 --- a/arch/powerpc/kvm/book3s.h +++ b/arch/powerpc/kvm/book3s.h @@ -12,7 +12,6 @@ extern void kvmppc_core_flush_memslot_hv(struct kvm *kvm, extern bool kvm_unmap_gfn_range_hv(struct kvm *kvm, struct kvm_gfn_range *range); extern bool kvm_age_gfn_hv(struct kvm *kvm, struct kvm_gfn_range *range); extern bool kvm_test_age_gfn_hv(struct kvm *kvm, struct kvm_gfn_range *range); -extern bool kvm_set_spte_gfn_hv(struct kvm *kvm, struct kvm_gfn_range *range); extern int kvmppc_mmu_init_pr(struct kvm_vcpu *vcpu); extern void kvmppc_mmu_destroy_pr(struct kvm_vcpu *vcpu); diff --git a/arch/powerpc/kvm/book3s_32_mmu_host.c b/arch/powerpc/kvm/book3s_32_mmu_host.c index 4b3a8d80cfa3..c7e4b62642ea 100644 --- a/arch/powerpc/kvm/book3s_32_mmu_host.c +++ b/arch/powerpc/kvm/book3s_32_mmu_host.c @@ -125,11 +125,10 @@ static u32 *kvmppc_mmu_get_pteg(struct kvm_vcpu *vcpu, u32 vsid, u32 eaddr, return (u32*)pteg; } -extern char etext[]; - int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, bool iswrite) { + struct page *page; kvm_pfn_t hpaddr; u64 vpn; u64 vsid; @@ -145,7 +144,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, bool writable; /* Get host physical address for gpa */ - hpaddr = kvmppc_gpa_to_pfn(vcpu, orig_pte->raddr, iswrite, &writable); + hpaddr = kvmppc_gpa_to_pfn(vcpu, orig_pte->raddr, iswrite, &writable, &page); if (is_error_noslot_pfn(hpaddr)) { printk(KERN_INFO "Couldn't get guest page for gpa %lx!\n", orig_pte->raddr); @@ -232,7 +231,7 @@ next_pteg: pte = kvmppc_mmu_hpte_cache_next(vcpu); if (!pte) { - kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT); + kvm_release_page_unused(page); r = -EAGAIN; goto out; } @@ -250,7 +249,7 @@ next_pteg: kvmppc_mmu_hpte_cache_map(vcpu, pte); - kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT); + kvm_release_page_clean(page); out: return r; } diff --git a/arch/powerpc/kvm/book3s_64_entry.S b/arch/powerpc/kvm/book3s_64_entry.S index 6c2b1d17cb63..a9ab92abffe8 100644 --- a/arch/powerpc/kvm/book3s_64_entry.S +++ b/arch/powerpc/kvm/book3s_64_entry.S @@ -1,9 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include <linux/export.h> #include <asm/asm-offsets.h> #include <asm/cache.h> #include <asm/code-patching-asm.h> #include <asm/exception-64s.h> -#include <asm/export.h> #include <asm/kvm_asm.h> #include <asm/kvm_book3s_asm.h> #include <asm/mmu.h> @@ -19,7 +19,7 @@ /* * This is a hcall, so register convention is as - * Documentation/powerpc/papr_hcalls.rst. + * Documentation/arch/powerpc/papr_hcalls.rst. * * This may also be a syscall from PR-KVM userspace that is to be * reflected to the PR guest kernel, so registers may be set up for diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c index bc6a381b5346..be20aee6fd7d 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_host.c +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c @@ -88,13 +88,14 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, struct hpte_cache *cpte; unsigned long gfn = orig_pte->raddr >> PAGE_SHIFT; unsigned long pfn; + struct page *page; /* used to check for invalidations in progress */ mmu_seq = kvm->mmu_invalidate_seq; smp_rmb(); /* Get host physical address for gpa */ - pfn = kvmppc_gpa_to_pfn(vcpu, orig_pte->raddr, iswrite, &writable); + pfn = kvmppc_gpa_to_pfn(vcpu, orig_pte->raddr, iswrite, &writable, &page); if (is_error_noslot_pfn(pfn)) { printk(KERN_INFO "Couldn't get guest page for gpa %lx!\n", orig_pte->raddr); @@ -121,13 +122,10 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, vpn = hpt_vpn(orig_pte->eaddr, map->host_vsid, MMU_SEGSIZE_256M); - kvm_set_pfn_accessed(pfn); if (!orig_pte->may_write || !writable) rflags |= PP_RXRX; - else { + else mark_page_dirty(vcpu->kvm, gfn); - kvm_set_pfn_dirty(pfn); - } if (!orig_pte->may_execute) rflags |= HPTE_R_N; @@ -202,8 +200,10 @@ map_again: } out_unlock: + /* FIXME: Don't unconditionally pass unused=false. */ + kvm_release_faultin_page(kvm, page, false, + orig_pte->may_write && writable); spin_unlock(&kvm->mmu_lock); - kvm_release_pfn_clean(pfn); if (cpte) kvmppc_mmu_hpte_cache_free(cpte); diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c index 7006bcbc2e37..f305395cf26e 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_hv.c +++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c @@ -28,6 +28,7 @@ #include <asm/pte-walk.h> #include "book3s.h" +#include "book3s_hv.h" #include "trace_hv.h" //#define DEBUG_RESIZE_HPT 1 @@ -120,13 +121,13 @@ void kvmppc_set_hpt(struct kvm *kvm, struct kvm_hpt_info *info) kvm->arch.hpt = *info; kvm->arch.sdr1 = __pa(info->virt) | (info->order - 18); - pr_debug("KVM guest htab at %lx (order %ld), LPID %x\n", + pr_debug("KVM guest htab at %lx (order %ld), LPID %llx\n", info->virt, (long)info->order, kvm->arch.lpid); } -long kvmppc_alloc_reset_hpt(struct kvm *kvm, int order) +int kvmppc_alloc_reset_hpt(struct kvm *kvm, int order) { - long err = -EBUSY; + int err = -EBUSY; struct kvm_hpt_info info; mutex_lock(&kvm->arch.mmu_setup_lock); @@ -182,7 +183,7 @@ void kvmppc_free_hpt(struct kvm_hpt_info *info) vfree(info->rev); info->rev = NULL; if (info->cma) - kvm_free_hpt_cma(virt_to_page(info->virt), + kvm_free_hpt_cma(virt_to_page((void *)info->virt), 1 << (info->order - PAGE_SHIFT)); else if (info->virt) free_pages(info->virt, info->order - PAGE_SHIFT); @@ -347,7 +348,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, unsigned long v, orig_v, gr; __be64 *hptep; long int index; - int virtmode = vcpu->arch.shregs.msr & (data ? MSR_DR : MSR_IR); + int virtmode = __kvmppc_get_msr_hv(vcpu) & (data ? MSR_DR : MSR_IR); if (kvm_is_radix(vcpu->kvm)) return kvmppc_mmu_radix_xlate(vcpu, eaddr, gpte, data, iswrite); @@ -385,7 +386,7 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, /* Get PP bits and key for permission check */ pp = gr & (HPTE_R_PP0 | HPTE_R_PP); - key = (vcpu->arch.shregs.msr & MSR_PR) ? SLB_VSID_KP : SLB_VSID_KS; + key = (__kvmppc_get_msr_hv(vcpu) & MSR_PR) ? SLB_VSID_KP : SLB_VSID_KS; key &= slb_v; /* Calculate permissions */ @@ -415,20 +416,25 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, * embodied here.) If the instruction isn't a load or store, then * this doesn't return anything useful. */ -static int instruction_is_store(unsigned int instr) +static int instruction_is_store(ppc_inst_t instr) { unsigned int mask; + unsigned int suffix; mask = 0x10000000; - if ((instr & 0xfc000000) == 0x7c000000) + suffix = ppc_inst_val(instr); + if (ppc_inst_prefixed(instr)) + suffix = ppc_inst_suffix(instr); + else if ((suffix & 0xfc000000) == 0x7c000000) mask = 0x100; /* major opcode 31 */ - return (instr & mask) != 0; + return (suffix & mask) != 0; } int kvmppc_hv_emulate_mmio(struct kvm_vcpu *vcpu, unsigned long gpa, gva_t ea, int is_store) { - u32 last_inst; + ppc_inst_t last_inst; + bool is_prefixed = !!(kvmppc_get_msr(vcpu) & SRR1_PREFIXED); /* * Fast path - check if the guest physical address corresponds to a @@ -443,7 +449,7 @@ int kvmppc_hv_emulate_mmio(struct kvm_vcpu *vcpu, NULL); srcu_read_unlock(&vcpu->kvm->srcu, idx); if (!ret) { - kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); + kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + (is_prefixed ? 8 : 4)); return RESUME_GUEST; } } @@ -458,7 +464,16 @@ int kvmppc_hv_emulate_mmio(struct kvm_vcpu *vcpu, /* * WARNING: We do not know for sure whether the instruction we just * read from memory is the same that caused the fault in the first - * place. If the instruction we read is neither an load or a store, + * place. + * + * If the fault is prefixed but the instruction is not or vice + * versa, try again so that we don't advance pc the wrong amount. + */ + if (ppc_inst_prefixed(last_inst) != is_prefixed) + return RESUME_GUEST; + + /* + * If the instruction we read is neither an load or a store, * then it can't access memory, so we don't need to worry about * enforcing access permissions. So, assuming it is a load or * store, we just check that its direction (load or store) is @@ -588,27 +603,10 @@ int kvmppc_book3s_hv_page_fault(struct kvm_vcpu *vcpu, write_ok = writing; hva = gfn_to_hva_memslot(memslot, gfn); - /* - * Do a fast check first, since __gfn_to_pfn_memslot doesn't - * do it with !atomic && !async, which is how we call it. - * We always ask for write permission since the common case - * is that the page is writable. - */ - if (get_user_page_fast_only(hva, FOLL_WRITE, &page)) { - write_ok = true; - } else { - /* Call KVM generic code to do the slow-path check */ - pfn = __gfn_to_pfn_memslot(memslot, gfn, false, false, NULL, - writing, &write_ok, NULL); - if (is_error_noslot_pfn(pfn)) - return -EFAULT; - page = NULL; - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (PageReserved(page)) - page = NULL; - } - } + pfn = __kvm_faultin_pfn(memslot, gfn, writing ? FOLL_WRITE : 0, + &write_ok, &page); + if (is_error_noslot_pfn(pfn)) + return -EFAULT; /* * Read the PTE from the process' radix tree and use that @@ -995,18 +993,6 @@ bool kvm_test_age_gfn_hv(struct kvm *kvm, struct kvm_gfn_range *range) return kvm_test_age_rmapp(kvm, range->slot, range->start); } -bool kvm_set_spte_gfn_hv(struct kvm *kvm, struct kvm_gfn_range *range) -{ - WARN_ON(range->start + 1 != range->end); - - if (kvm_is_radix(kvm)) - kvm_unmap_radix(kvm, range->slot, range->start); - else - kvm_unmap_rmapp(kvm, range->slot, range->start); - - return false; -} - static int vcpus_running(struct kvm *kvm) { return atomic_read(&kvm->arch.vcpus_running) != 0; @@ -1468,8 +1454,8 @@ static void resize_hpt_prepare_work(struct work_struct *work) mutex_unlock(&kvm->arch.mmu_setup_lock); } -long kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm, - struct kvm_ppc_resize_hpt *rhpt) +int kvm_vm_ioctl_resize_hpt_prepare(struct kvm *kvm, + struct kvm_ppc_resize_hpt *rhpt) { unsigned long flags = rhpt->flags; unsigned long shift = rhpt->shift; @@ -1534,13 +1520,13 @@ static void resize_hpt_boot_vcpu(void *opaque) /* Nothing to do, just force a KVM exit */ } -long kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm, - struct kvm_ppc_resize_hpt *rhpt) +int kvm_vm_ioctl_resize_hpt_commit(struct kvm *kvm, + struct kvm_ppc_resize_hpt *rhpt) { unsigned long flags = rhpt->flags; unsigned long shift = rhpt->shift; struct kvm_resize_hpt *resize; - long ret; + int ret; if (flags != 0 || kvm_is_radix(kvm)) return -EINVAL; diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 9d3743ca16d5..b3e6e73d6a08 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -15,6 +15,7 @@ #include <asm/kvm_ppc.h> #include <asm/kvm_book3s.h> +#include "book3s_hv.h" #include <asm/page.h> #include <asm/mmu.h> #include <asm/pgalloc.h> @@ -39,6 +40,9 @@ unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid, unsigned long quadrant, ret = n; bool is_load = !!to; + if (kvmhv_is_nestedv2()) + return H_UNSUPPORTED; + /* Can't access quadrants 1 or 2 in non-HV mode, call the HV to do it */ if (kvmhv_on_pseries()) return plpar_hcall_norets(H_COPY_TOFROM_GUEST, lpid, pid, eaddr, @@ -96,7 +100,7 @@ static long kvmhv_copy_tofrom_guest_radix(struct kvm_vcpu *vcpu, gva_t eaddr, void *to, void *from, unsigned long n) { int lpid = vcpu->kvm->arch.lpid; - int pid = vcpu->arch.pid; + int pid; /* This would cause a data segment intr so don't allow the access */ if (eaddr & (0x3FFUL << 52)) @@ -109,6 +113,8 @@ static long kvmhv_copy_tofrom_guest_radix(struct kvm_vcpu *vcpu, gva_t eaddr, /* If accessing quadrant 3 then pid is expected to be 0 */ if (((eaddr >> 62) & 0x3) == 0x3) pid = 0; + else + pid = kvmppc_get_pid(vcpu); eaddr &= ~(0xFFFUL << 52); @@ -270,7 +276,7 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, /* Work out effective PID */ switch (eaddr >> 62) { case 0: - pid = vcpu->arch.pid; + pid = kvmppc_get_pid(vcpu); break; case 3: pid = 0; @@ -294,9 +300,9 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, } else { if (!(pte & _PAGE_PRIVILEGED)) { /* Check AMR/IAMR to see if strict mode is in force */ - if (vcpu->arch.amr & (1ul << 62)) + if (kvmppc_get_amr_hv(vcpu) & (1ul << 62)) gpte->may_read = 0; - if (vcpu->arch.amr & (1ul << 63)) + if (kvmppc_get_amr_hv(vcpu) & (1ul << 63)) gpte->may_write = 0; if (vcpu->arch.iamr & (1ul << 62)) gpte->may_execute = 0; @@ -307,7 +313,7 @@ int kvmppc_mmu_radix_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, } void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr, - unsigned int pshift, unsigned int lpid) + unsigned int pshift, u64 lpid) { unsigned long psize = PAGE_SIZE; int psi; @@ -344,7 +350,7 @@ void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr, pr_err("KVM: TLB page invalidation hcall failed, rc=%ld\n", rc); } -static void kvmppc_radix_flush_pwc(struct kvm *kvm, unsigned int lpid) +static void kvmppc_radix_flush_pwc(struct kvm *kvm, u64 lpid) { long rc; @@ -417,7 +423,7 @@ static void kvmppc_pmd_free(pmd_t *pmdp) void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, unsigned long gpa, unsigned int shift, const struct kvm_memory_slot *memslot, - unsigned int lpid) + u64 lpid) { unsigned long old; @@ -468,7 +474,7 @@ void kvmppc_unmap_pte(struct kvm *kvm, pte_t *pte, unsigned long gpa, * (or 4kB) mappings (of sub-pages of the same 2MB page). */ static void kvmppc_unmap_free_pte(struct kvm *kvm, pte_t *pte, bool full, - unsigned int lpid) + u64 lpid) { if (full) { memset(pte, 0, sizeof(long) << RADIX_PTE_INDEX_SIZE); @@ -489,7 +495,7 @@ static void kvmppc_unmap_free_pte(struct kvm *kvm, pte_t *pte, bool full, } static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full, - unsigned int lpid) + u64 lpid) { unsigned long im; pmd_t *p = pmd; @@ -497,7 +503,7 @@ static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full, for (im = 0; im < PTRS_PER_PMD; ++im, ++p) { if (!pmd_present(*p)) continue; - if (pmd_is_leaf(*p)) { + if (pmd_leaf(*p)) { if (full) { pmd_clear(p); } else { @@ -509,7 +515,7 @@ static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full, } else { pte_t *pte; - pte = pte_offset_map(p, 0); + pte = pte_offset_kernel(p, 0); kvmppc_unmap_free_pte(kvm, pte, full, lpid); pmd_clear(p); } @@ -518,7 +524,7 @@ static void kvmppc_unmap_free_pmd(struct kvm *kvm, pmd_t *pmd, bool full, } static void kvmppc_unmap_free_pud(struct kvm *kvm, pud_t *pud, - unsigned int lpid) + u64 lpid) { unsigned long iu; pud_t *p = pud; @@ -526,7 +532,7 @@ static void kvmppc_unmap_free_pud(struct kvm *kvm, pud_t *pud, for (iu = 0; iu < PTRS_PER_PUD; ++iu, ++p) { if (!pud_present(*p)) continue; - if (pud_is_leaf(*p)) { + if (pud_leaf(*p)) { pud_clear(p); } else { pmd_t *pmd; @@ -539,7 +545,7 @@ static void kvmppc_unmap_free_pud(struct kvm *kvm, pud_t *pud, pud_free(kvm->mm, pud); } -void kvmppc_free_pgtable_radix(struct kvm *kvm, pgd_t *pgd, unsigned int lpid) +void kvmppc_free_pgtable_radix(struct kvm *kvm, pgd_t *pgd, u64 lpid) { unsigned long ig; @@ -566,7 +572,7 @@ void kvmppc_free_radix(struct kvm *kvm) } static void kvmppc_unmap_free_pmd_entry_table(struct kvm *kvm, pmd_t *pmd, - unsigned long gpa, unsigned int lpid) + unsigned long gpa, u64 lpid) { pte_t *pte = pte_offset_kernel(pmd, 0); @@ -582,7 +588,7 @@ static void kvmppc_unmap_free_pmd_entry_table(struct kvm *kvm, pmd_t *pmd, } static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud, - unsigned long gpa, unsigned int lpid) + unsigned long gpa, u64 lpid) { pmd_t *pmd = pmd_offset(pud, 0); @@ -608,7 +614,7 @@ static void kvmppc_unmap_free_pud_entry_table(struct kvm *kvm, pud_t *pud, int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, unsigned long gpa, unsigned int level, - unsigned long mmu_seq, unsigned int lpid, + unsigned long mmu_seq, u64 lpid, unsigned long *rmapp, struct rmap_nested **n_rmap) { pgd_t *pgd; @@ -629,12 +635,12 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, new_pud = pud_alloc_one(kvm->mm, gpa); pmd = NULL; - if (pud && pud_present(*pud) && !pud_is_leaf(*pud)) + if (pud && pud_present(*pud) && !pud_leaf(*pud)) pmd = pmd_offset(pud, gpa); else if (level <= 1) new_pmd = kvmppc_pmd_alloc(); - if (level == 0 && !(pmd && pmd_present(*pmd) && !pmd_is_leaf(*pmd))) + if (level == 0 && !(pmd && pmd_present(*pmd) && !pmd_leaf(*pmd))) new_ptep = kvmppc_pte_alloc(); /* Check if we might have been invalidated; let the guest retry if so */ @@ -652,7 +658,7 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, new_pud = NULL; } pud = pud_offset(p4d, gpa); - if (pud_is_leaf(*pud)) { + if (pud_leaf(*pud)) { unsigned long hgpa = gpa & PUD_MASK; /* Check if we raced and someone else has set the same thing */ @@ -703,7 +709,7 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, new_pmd = NULL; } pmd = pmd_offset(pud, gpa); - if (pmd_is_leaf(*pmd)) { + if (pmd_leaf(*pmd)) { unsigned long lgpa = gpa & PMD_MASK; /* Check if we raced and someone else has set the same thing */ @@ -785,7 +791,7 @@ int kvmppc_create_pte(struct kvm *kvm, pgd_t *pgtable, pte_t pte, } bool kvmppc_hv_handle_set_rc(struct kvm *kvm, bool nested, bool writing, - unsigned long gpa, unsigned int lpid) + unsigned long gpa, u64 lpid) { unsigned long pgflags; unsigned int shift; @@ -815,7 +821,7 @@ bool kvmppc_hv_handle_set_rc(struct kvm *kvm, bool nested, bool writing, int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, unsigned long gpa, struct kvm_memory_slot *memslot, - bool writing, bool kvm_ro, + bool writing, pte_t *inserted_pte, unsigned int *levelp) { struct kvm *kvm = vcpu->kvm; @@ -823,40 +829,21 @@ int kvmppc_book3s_instantiate_page(struct kvm_vcpu *vcpu, unsigned long mmu_seq; unsigned long hva, gfn = gpa >> PAGE_SHIFT; bool upgrade_write = false; - bool *upgrade_p = &upgrade_write; pte_t pte, *ptep; unsigned int shift, level; int ret; bool large_enable; + kvm_pfn_t pfn; /* used to check for invalidations in progress */ mmu_seq = kvm->mmu_invalidate_seq; smp_rmb(); - /* - * Do a fast check first, since __gfn_to_pfn_memslot doesn't - * do it with !atomic && !async, which is how we call it. - * We always ask for write permission since the common case - * is that the page is writable. - */ hva = gfn_to_hva_memslot(memslot, gfn); - if (!kvm_ro && get_user_page_fast_only(hva, FOLL_WRITE, &page)) { - upgrade_write = true; - } else { - unsigned long pfn; - - /* Call KVM generic code to do the slow-path check */ - pfn = __gfn_to_pfn_memslot(memslot, gfn, false, false, NULL, - writing, upgrade_p, NULL); - if (is_error_noslot_pfn(pfn)) - return -EFAULT; - page = NULL; - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (PageReserved(page)) - page = NULL; - } - } + pfn = __kvm_faultin_pfn(memslot, gfn, writing ? FOLL_WRITE : 0, + &upgrade_write, &page); + if (is_error_noslot_pfn(pfn)) + return -EFAULT; /* * Read the PTE from the process' radix tree and use that @@ -944,7 +931,6 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot; long ret; bool writing = !!(dsisr & DSISR_ISSTORE); - bool kvm_ro = false; /* Check for unusual errors */ if (dsisr & DSISR_UNSUPP_MMU) { @@ -954,7 +940,9 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, if (dsisr & DSISR_BADACCESS) { /* Reflect to the guest as DSI */ pr_err("KVM: Got radix HV page fault with DSISR=%lx\n", dsisr); - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, dsisr); return RESUME_GUEST; } @@ -979,7 +967,9 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, * Bad address in guest page table tree, or other * unusual error - reflect it to the guest as DSI. */ - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, dsisr); return RESUME_GUEST; } return kvmppc_hv_emulate_mmio(vcpu, gpa, ea, writing); @@ -988,11 +978,11 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, if (memslot->flags & KVM_MEM_READONLY) { if (writing) { /* give the guest a DSI */ - kvmppc_core_queue_data_storage(vcpu, ea, DSISR_ISSTORE | - DSISR_PROTFAULT); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, DSISR_ISSTORE | DSISR_PROTFAULT); return RESUME_GUEST; } - kvm_ro = true; } /* Failed to set the reference/change bits */ @@ -1010,7 +1000,7 @@ int kvmppc_book3s_radix_page_fault(struct kvm_vcpu *vcpu, /* Try to insert a pte */ ret = kvmppc_book3s_instantiate_page(vcpu, gpa, memslot, writing, - kvm_ro, NULL, NULL); + NULL, NULL); if (ret == 0 || ret == -EAGAIN) ret = RESUME_GUEST; diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 95e738ef9062..742aa58a7c7e 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -20,6 +20,7 @@ #include <linux/iommu.h> #include <linux/file.h> #include <linux/mm.h> +#include <linux/rcupdate_wait.h> #include <asm/kvm_ppc.h> #include <asm/kvm_book3s.h> @@ -77,8 +78,8 @@ static void kvm_spapr_tce_liobn_put(struct kref *kref) call_rcu(&stit->rcu, kvm_spapr_tce_iommu_table_free); } -extern void kvm_spapr_tce_release_iommu_group(struct kvm *kvm, - struct iommu_group *grp) +void kvm_spapr_tce_release_iommu_group(struct kvm *kvm, + struct iommu_group *grp) { int i; struct kvmppc_spapr_tce_table *stt; @@ -105,8 +106,8 @@ extern void kvm_spapr_tce_release_iommu_group(struct kvm *kvm, rcu_read_unlock(); } -extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, - struct iommu_group *grp) +long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, + struct iommu_group *grp) { struct kvmppc_spapr_tce_table *stt = NULL; bool found = false; @@ -114,23 +115,20 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm *kvm, int tablefd, struct iommu_table_group *table_group; long i; struct kvmppc_spapr_tce_iommu_table *stit; - struct fd f; + CLASS(fd, f)(tablefd); - f = fdget(tablefd); - if (!f.file) + if (fd_empty(f)) return -EBADF; rcu_read_lock(); list_for_each_entry_rcu(stt, &kvm->arch.spapr_tce_tables, list) { - if (stt == f.file->private_data) { + if (stt == fd_file(f)->private_data) { found = true; break; } } rcu_read_unlock(); - fdput(f); - if (!found) return -EINVAL; @@ -288,8 +286,8 @@ static const struct file_operations kvm_spapr_tce_fops = { .release = kvm_spapr_tce_release, }; -long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, - struct kvm_create_spapr_tce_64 *args) +int kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm, + struct kvm_create_spapr_tce_64 *args) { struct kvmppc_spapr_tce_table *stt = NULL; struct kvmppc_spapr_tce_table *siter; @@ -786,12 +784,12 @@ long kvmppc_h_get_tce(struct kvm_vcpu *vcpu, unsigned long liobn, idx = (ioba >> stt->page_shift) - stt->offset; page = stt->pages[idx / TCES_PER_PAGE]; if (!page) { - vcpu->arch.regs.gpr[4] = 0; + kvmppc_set_gpr(vcpu, 4, 0); return H_SUCCESS; } tbl = (u64 *)page_address(page); - vcpu->arch.regs.gpr[4] = tbl[idx % TCES_PER_PAGE]; + kvmppc_set_gpr(vcpu, 4, tbl[idx % TCES_PER_PAGE]); return H_SUCCESS; } diff --git a/arch/powerpc/kvm/book3s_emulate.c b/arch/powerpc/kvm/book3s_emulate.c index 5bbfb2eed127..de126d153328 100644 --- a/arch/powerpc/kvm/book3s_emulate.c +++ b/arch/powerpc/kvm/book3s_emulate.c @@ -714,7 +714,7 @@ int kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val) case SPRN_HID1: to_book3s(vcpu)->hid[1] = spr_val; break; - case SPRN_HID2: + case SPRN_HID2_750FX: to_book3s(vcpu)->hid[2] = spr_val; break; case SPRN_HID2_GEKKO: @@ -900,7 +900,7 @@ int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val case SPRN_HID1: *spr_val = to_book3s(vcpu)->hid[1]; break; - case SPRN_HID2: + case SPRN_HID2_750FX: case SPRN_HID2_GEKKO: *spr_val = to_book3s(vcpu)->hid[2]; break; diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 6ba68dd6190b..7667563fb9ff 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -43,6 +43,7 @@ #include <linux/compiler.h> #include <linux/of.h> #include <linux/irqdomain.h> +#include <linux/smp.h> #include <asm/ftrace.h> #include <asm/reg.h> @@ -80,6 +81,8 @@ #include <asm/dtl.h> #include <asm/plpar_wrappers.h> +#include <trace/events/ipi.h> + #include "book3s.h" #include "book3s_hv.h" @@ -388,13 +391,34 @@ static void kvmppc_set_pvr_hv(struct kvm_vcpu *vcpu, u32 pvr) /* Dummy value used in computing PCR value below */ #define PCR_ARCH_31 (PCR_ARCH_300 << 1) +static inline unsigned long map_pcr_to_cap(unsigned long pcr) +{ + unsigned long cap = 0; + + switch (pcr) { + case PCR_ARCH_300: + cap = H_GUEST_CAP_POWER9; + break; + case PCR_ARCH_31: + if (cpu_has_feature(CPU_FTR_P11_PVR)) + cap = H_GUEST_CAP_POWER11; + else + cap = H_GUEST_CAP_POWER10; + break; + default: + break; + } + + return cap; +} + static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) { - unsigned long host_pcr_bit = 0, guest_pcr_bit = 0; + unsigned long host_pcr_bit = 0, guest_pcr_bit = 0, cap = 0; struct kvmppc_vcore *vc = vcpu->arch.vcore; /* We can (emulate) our own architecture version and anything older */ - if (cpu_has_feature(CPU_FTR_ARCH_31)) + if (cpu_has_feature(CPU_FTR_P11_PVR) || cpu_has_feature(CPU_FTR_ARCH_31)) host_pcr_bit = PCR_ARCH_31; else if (cpu_has_feature(CPU_FTR_ARCH_300)) host_pcr_bit = PCR_ARCH_300; @@ -423,6 +447,7 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) guest_pcr_bit = PCR_ARCH_300; break; case PVR_ARCH_31: + case PVR_ARCH_31_P11: guest_pcr_bit = PCR_ARCH_31; break; default: @@ -434,8 +459,20 @@ static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) if (guest_pcr_bit > host_pcr_bit) return -EINVAL; + if (kvmhv_on_pseries() && kvmhv_is_nestedv2()) { + /* + * 'arch_compat == 0' would mean the guest should default to + * L1's compatibility. In this case, the guest would pick + * host's PCR and evaluate the corresponding capabilities. + */ + cap = map_pcr_to_cap(guest_pcr_bit); + if (!(cap & nested_capabilities)) + return -EINVAL; + } + spin_lock(&vc->lock); vc->arch_compat = arch_compat; + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_LOGICAL_PVR); /* * Set all PCR bits for which guest_pcr_bit <= bit < host_pcr_bit * Also set all reserved PCR bits @@ -474,7 +511,7 @@ static void kvmppc_dump_regs(struct kvm_vcpu *vcpu) for (r = 0; r < vcpu->arch.slb_max; ++r) pr_err(" ESID = %.16llx VSID = %.16llx\n", vcpu->arch.slb[r].orige, vcpu->arch.slb[r].origv); - pr_err("lpcr = %.16lx sdr1 = %.16lx last_inst = %.8x\n", + pr_err("lpcr = %.16lx sdr1 = %.16lx last_inst = %.16lx\n", vcpu->arch.vcore->lpcr, vcpu->kvm->arch.sdr1, vcpu->arch.last_inst); } @@ -639,7 +676,8 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu, return err; } -static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) +static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap, + struct kvmppc_vpa *old_vpap) { struct kvm *kvm = vcpu->kvm; void *va; @@ -679,9 +717,8 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) kvmppc_unpin_guest_page(kvm, va, gpa, false); va = NULL; } - if (vpap->pinned_addr) - kvmppc_unpin_guest_page(kvm, vpap->pinned_addr, vpap->gpa, - vpap->dirty); + *old_vpap = *vpap; + vpap->gpa = gpa; vpap->pinned_addr = va; vpap->dirty = false; @@ -691,6 +728,9 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) static void kvmppc_update_vpas(struct kvm_vcpu *vcpu) { + struct kvm *kvm = vcpu->kvm; + struct kvmppc_vpa old_vpa = { 0 }; + if (!(vcpu->arch.vpa.update_pending || vcpu->arch.slb_shadow.update_pending || vcpu->arch.dtl.update_pending)) @@ -698,17 +738,34 @@ static void kvmppc_update_vpas(struct kvm_vcpu *vcpu) spin_lock(&vcpu->arch.vpa_update_lock); if (vcpu->arch.vpa.update_pending) { - kvmppc_update_vpa(vcpu, &vcpu->arch.vpa); - if (vcpu->arch.vpa.pinned_addr) + kvmppc_update_vpa(vcpu, &vcpu->arch.vpa, &old_vpa); + if (old_vpa.pinned_addr) { + if (kvmhv_is_nestedv2()) + kvmhv_nestedv2_set_vpa(vcpu, ~0ull); + kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa, + old_vpa.dirty); + } + if (vcpu->arch.vpa.pinned_addr) { init_vpa(vcpu, vcpu->arch.vpa.pinned_addr); + if (kvmhv_is_nestedv2()) + kvmhv_nestedv2_set_vpa(vcpu, __pa(vcpu->arch.vpa.pinned_addr)); + } } if (vcpu->arch.dtl.update_pending) { - kvmppc_update_vpa(vcpu, &vcpu->arch.dtl); + kvmppc_update_vpa(vcpu, &vcpu->arch.dtl, &old_vpa); + if (old_vpa.pinned_addr) + kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa, + old_vpa.dirty); vcpu->arch.dtl_ptr = vcpu->arch.dtl.pinned_addr; vcpu->arch.dtl_index = 0; } - if (vcpu->arch.slb_shadow.update_pending) - kvmppc_update_vpa(vcpu, &vcpu->arch.slb_shadow); + if (vcpu->arch.slb_shadow.update_pending) { + kvmppc_update_vpa(vcpu, &vcpu->arch.slb_shadow, &old_vpa); + if (old_vpa.pinned_addr) + kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa, + old_vpa.dirty); + } + spin_unlock(&vcpu->arch.vpa_update_lock); } @@ -791,7 +848,7 @@ static void kvmppc_update_vpa_dispatch(struct kvm_vcpu *vcpu, vpa->enqueue_dispatch_tb = cpu_to_be64(be64_to_cpu(vpa->enqueue_dispatch_tb) + stolen); - __kvmppc_create_dtl_entry(vcpu, vpa, vc->pcpu, now + vc->tb_offset, stolen); + __kvmppc_create_dtl_entry(vcpu, vpa, vc->pcpu, now + kvmppc_get_tb_offset(vcpu), stolen); vcpu->arch.vpa.dirty = true; } @@ -842,9 +899,9 @@ static bool kvmppc_doorbell_pending(struct kvm_vcpu *vcpu) static bool kvmppc_power8_compatible(struct kvm_vcpu *vcpu) { - if (vcpu->arch.vcore->arch_compat >= PVR_ARCH_207) + if (kvmppc_get_arch_compat(vcpu) >= PVR_ARCH_207) return true; - if ((!vcpu->arch.vcore->arch_compat) && + if ((!kvmppc_get_arch_compat(vcpu)) && cpu_has_feature(CPU_FTR_ARCH_207S)) return true; return false; @@ -865,7 +922,7 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, /* Guests can't breakpoint the hypervisor */ if ((value1 & CIABR_PRIV) == CIABR_PRIV_HYPER) return H_P3; - vcpu->arch.ciabr = value1; + kvmppc_set_ciabr_hv(vcpu, value1); return H_SUCCESS; case H_SET_MODE_RESOURCE_SET_DAWR0: if (!kvmppc_power8_compatible(vcpu)) @@ -876,8 +933,8 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, return H_UNSUPPORTED_FLAG_START; if (value2 & DABRX_HYP) return H_P4; - vcpu->arch.dawr0 = value1; - vcpu->arch.dawrx0 = value2; + kvmppc_set_dawr0_hv(vcpu, value1); + kvmppc_set_dawrx0_hv(vcpu, value2); return H_SUCCESS; case H_SET_MODE_RESOURCE_SET_DAWR1: if (!kvmppc_power8_compatible(vcpu)) @@ -892,8 +949,8 @@ static int kvmppc_h_set_mode(struct kvm_vcpu *vcpu, unsigned long mflags, return H_UNSUPPORTED_FLAG_START; if (value2 & DABRX_HYP) return H_P4; - vcpu->arch.dawr1 = value1; - vcpu->arch.dawrx1 = value2; + kvmppc_set_dawr1_hv(vcpu, value1); + kvmppc_set_dawrx1_hv(vcpu, value2); return H_SUCCESS; case H_SET_MODE_RESOURCE_ADDR_TRANS_MODE: /* @@ -1264,10 +1321,14 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) return RESUME_HOST; break; #endif - case H_RANDOM: - if (!arch_get_random_seed_longs(&vcpu->arch.regs.gpr[4], 1)) + case H_RANDOM: { + unsigned long rand; + + if (!arch_get_random_seed_longs(&rand, 1)) ret = H_HARDWARE; + kvmppc_set_gpr(vcpu, 4, rand); break; + } case H_RPT_INVALIDATE: ret = kvmppc_h_rpt_invalidate(vcpu, kvmppc_get_gpr(vcpu, 4), kvmppc_get_gpr(vcpu, 5), @@ -1367,7 +1428,7 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) */ static void kvmppc_cede(struct kvm_vcpu *vcpu) { - vcpu->arch.shregs.msr |= MSR_EE; + __kvmppc_set_msr_hv(vcpu, __kvmppc_get_msr_hv(vcpu) | MSR_EE); vcpu->arch.ceded = 1; smp_mb(); if (vcpu->arch.prodded) { @@ -1412,7 +1473,7 @@ static int kvmppc_hcall_impl_hv(unsigned long cmd) static int kvmppc_emulate_debug_inst(struct kvm_vcpu *vcpu) { - u32 last_inst; + ppc_inst_t last_inst; if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst) != EMULATE_DONE) { @@ -1423,12 +1484,13 @@ static int kvmppc_emulate_debug_inst(struct kvm_vcpu *vcpu) return RESUME_GUEST; } - if (last_inst == KVMPPC_INST_SW_BREAKPOINT) { + if (ppc_inst_val(last_inst) == KVMPPC_INST_SW_BREAKPOINT) { vcpu->run->exit_reason = KVM_EXIT_DEBUG; vcpu->run->debug.arch.address = kvmppc_get_pc(vcpu); return RESUME_HOST; } else { - kvmppc_core_queue_program(vcpu, SRR1_PROGILL); + kvmppc_core_queue_program(vcpu, SRR1_PROGILL | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); return RESUME_GUEST; } } @@ -1476,9 +1538,11 @@ static int kvmppc_emulate_doorbell_instr(struct kvm_vcpu *vcpu) unsigned long arg; struct kvm *kvm = vcpu->kvm; struct kvm_vcpu *tvcpu; + ppc_inst_t pinst; - if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst) != EMULATE_DONE) + if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst) != EMULATE_DONE) return RESUME_GUEST; + inst = ppc_inst_val(pinst); if (get_op(inst) != 31) return EMULATE_FAIL; rb = get_rb(inst); @@ -1538,7 +1602,7 @@ static int kvmppc_pmu_unavailable(struct kvm_vcpu *vcpu) if (!(vcpu->arch.hfscr_permitted & HFSCR_PM)) return EMULATE_FAIL; - vcpu->arch.hfscr |= HFSCR_PM; + kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_PM); return RESUME_GUEST; } @@ -1548,7 +1612,7 @@ static int kvmppc_ebb_unavailable(struct kvm_vcpu *vcpu) if (!(vcpu->arch.hfscr_permitted & HFSCR_EBB)) return EMULATE_FAIL; - vcpu->arch.hfscr |= HFSCR_EBB; + kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_EBB); return RESUME_GUEST; } @@ -1558,7 +1622,7 @@ static int kvmppc_tm_unavailable(struct kvm_vcpu *vcpu) if (!(vcpu->arch.hfscr_permitted & HFSCR_TM)) return EMULATE_FAIL; - vcpu->arch.hfscr |= HFSCR_TM; + kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_TM); return RESUME_GUEST; } @@ -1579,7 +1643,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, * That can happen due to a bug, or due to a machine check * occurring at just the wrong time. */ - if (vcpu->arch.shregs.msr & MSR_HV) { + if (!kvmhv_is_nestedv2() && (__kvmppc_get_msr_hv(vcpu) & MSR_HV)) { printk(KERN_EMERG "KVM trap in HV mode!\n"); printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n", vcpu->arch.trap, kvmppc_get_pc(vcpu), @@ -1630,7 +1694,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, * so that it knows that the machine check occurred. */ if (!vcpu->kvm->arch.fwnmi_enabled) { - ulong flags = vcpu->arch.shregs.msr & 0x083c0000; + ulong flags = (__kvmppc_get_msr_hv(vcpu) & 0x083c0000) | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED); kvmppc_core_queue_machine_check(vcpu, flags); r = RESUME_GUEST; break; @@ -1659,7 +1724,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, * as a result of a hypervisor emulation interrupt * (e40) getting turned into a 700 by BML RTAS. */ - flags = vcpu->arch.shregs.msr & 0x1f0000ull; + flags = (__kvmppc_get_msr_hv(vcpu) & 0x1f0000ull) | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED); kvmppc_core_queue_program(vcpu, flags); r = RESUME_GUEST; break; @@ -1668,7 +1734,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, { int i; - if (unlikely(vcpu->arch.shregs.msr & MSR_PR)) { + if (!kvmhv_is_nestedv2() && unlikely(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { /* * Guest userspace executed sc 1. This can only be * reached by the P9 path because the old path @@ -1740,12 +1806,13 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, if (!(vcpu->arch.fault_dsisr & (DSISR_NOHPTE | DSISR_PROTFAULT))) { kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, vcpu->arch.fault_dar, vcpu->arch.fault_dsisr); r = RESUME_GUEST; break; } - if (!(vcpu->arch.shregs.msr & MSR_DR)) + if (!(__kvmppc_get_msr_hv(vcpu) & MSR_DR)) vsid = vcpu->kvm->arch.vrma_slb_v; else vsid = vcpu->arch.fault_gpa; @@ -1758,6 +1825,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, r = RESUME_PAGE_FAULT; } else { kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, vcpu->arch.fault_dar, err); r = RESUME_GUEST; } @@ -1768,7 +1836,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, long err; vcpu->arch.fault_dar = kvmppc_get_pc(vcpu); - vcpu->arch.fault_dsisr = vcpu->arch.shregs.msr & + vcpu->arch.fault_dsisr = __kvmppc_get_msr_hv(vcpu) & DSISR_SRR1_MATCH_64S; if (kvm_is_radix(vcpu->kvm) || !cpu_has_feature(CPU_FTR_ARCH_300)) { /* @@ -1777,7 +1845,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, * hash fault handling below is v3 only (it uses ASDR * via fault_gpa). */ - if (vcpu->arch.shregs.msr & HSRR1_HISI_WRITE) + if (__kvmppc_get_msr_hv(vcpu) & HSRR1_HISI_WRITE) vcpu->arch.fault_dsisr |= DSISR_ISSTORE; r = RESUME_PAGE_FAULT; break; @@ -1785,12 +1853,13 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, if (!(vcpu->arch.fault_dsisr & SRR1_ISI_NOPT)) { kvmppc_core_queue_inst_storage(vcpu, - vcpu->arch.fault_dsisr); + vcpu->arch.fault_dsisr | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); r = RESUME_GUEST; break; } - if (!(vcpu->arch.shregs.msr & MSR_IR)) + if (!(__kvmppc_get_msr_hv(vcpu) & MSR_IR)) vsid = vcpu->kvm->arch.vrma_slb_v; else vsid = vcpu->arch.fault_gpa; @@ -1802,7 +1871,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, } else if (err == -1) { r = RESUME_PAGE_FAULT; } else { - kvmppc_core_queue_inst_storage(vcpu, err); + kvmppc_core_queue_inst_storage(vcpu, + err | (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); r = RESUME_GUEST; } break; @@ -1823,7 +1893,8 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) { r = kvmppc_emulate_debug_inst(vcpu); } else { - kvmppc_core_queue_program(vcpu, SRR1_PROGILL); + kvmppc_core_queue_program(vcpu, SRR1_PROGILL | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); r = RESUME_GUEST; } break; @@ -1850,21 +1921,30 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, * Otherwise, we just generate a program interrupt to the guest. */ case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: { - u64 cause = vcpu->arch.hfscr >> 56; + u64 cause = kvmppc_get_hfscr_hv(vcpu) >> 56; r = EMULATE_FAIL; if (cpu_has_feature(CPU_FTR_ARCH_300)) { - if (cause == FSCR_MSGP_LG) + switch (cause) { + case FSCR_MSGP_LG: r = kvmppc_emulate_doorbell_instr(vcpu); - if (cause == FSCR_PM_LG) + break; + case FSCR_PM_LG: r = kvmppc_pmu_unavailable(vcpu); - if (cause == FSCR_EBB_LG) + break; + case FSCR_EBB_LG: r = kvmppc_ebb_unavailable(vcpu); - if (cause == FSCR_TM_LG) + break; + case FSCR_TM_LG: r = kvmppc_tm_unavailable(vcpu); + break; + default: + break; + } } if (r == EMULATE_FAIL) { - kvmppc_core_queue_program(vcpu, SRR1_PROGILL); + kvmppc_core_queue_program(vcpu, SRR1_PROGILL | + (kvmppc_get_msr(vcpu) & SRR1_PREFIXED)); r = RESUME_GUEST; } break; @@ -1877,7 +1957,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, kvmppc_dump_regs(vcpu); printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n", vcpu->arch.trap, kvmppc_get_pc(vcpu), - vcpu->arch.shregs.msr); + __kvmppc_get_msr_hv(vcpu)); run->hw.hardware_exit_reason = vcpu->arch.trap; r = RESUME_HOST; break; @@ -1901,11 +1981,11 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) * That can happen due to a bug, or due to a machine check * occurring at just the wrong time. */ - if (vcpu->arch.shregs.msr & MSR_HV) { + if (__kvmppc_get_msr_hv(vcpu) & MSR_HV) { pr_emerg("KVM trap in HV mode while nested!\n"); pr_emerg("trap=0x%x | pc=0x%lx | msr=0x%llx\n", vcpu->arch.trap, kvmppc_get_pc(vcpu), - vcpu->arch.shregs.msr); + __kvmppc_get_msr_hv(vcpu)); kvmppc_dump_regs(vcpu); return RESUME_HOST; } @@ -1962,7 +2042,7 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) vcpu->arch.fault_dar = kvmppc_get_pc(vcpu); vcpu->arch.fault_dsisr = kvmppc_get_msr(vcpu) & DSISR_SRR1_MATCH_64S; - if (vcpu->arch.shregs.msr & HSRR1_HISI_WRITE) + if (__kvmppc_get_msr_hv(vcpu) & HSRR1_HISI_WRITE) vcpu->arch.fault_dsisr |= DSISR_ISSTORE; srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); r = kvmhv_nested_page_fault(vcpu); @@ -1983,35 +2063,9 @@ static int kvmppc_handle_nested_exit(struct kvm_vcpu *vcpu) fallthrough; /* go to facility unavailable handler */ #endif - case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: { - u64 cause = vcpu->arch.hfscr >> 56; - - /* - * Only pass HFU interrupts to the L1 if the facility is - * permitted but disabled by the L1's HFSCR, otherwise - * the interrupt does not make sense to the L1 so turn - * it into a HEAI. - */ - if (!(vcpu->arch.hfscr_permitted & (1UL << cause)) || - (vcpu->arch.nested_hfscr & (1UL << cause))) { - vcpu->arch.trap = BOOK3S_INTERRUPT_H_EMUL_ASSIST; - - /* - * If the fetch failed, return to guest and - * try executing it again. - */ - r = kvmppc_get_last_inst(vcpu, INST_GENERIC, - &vcpu->arch.emul_inst); - if (r != EMULATE_DONE) - r = RESUME_GUEST; - else - r = RESUME_HOST; - } else { - r = RESUME_HOST; - } - + case BOOK3S_INTERRUPT_H_FAC_UNAVAIL: + r = RESUME_HOST; break; - } case BOOK3S_INTERRUPT_HV_RM_HARD: vcpu->arch.trap = 0; @@ -2168,6 +2222,7 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr, } vc->lpcr = new_lpcr; + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_LPCR); spin_unlock(&vc->lock); } @@ -2192,64 +2247,64 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, *val = get_reg_val(id, vcpu->arch.dabrx); break; case KVM_REG_PPC_DSCR: - *val = get_reg_val(id, vcpu->arch.dscr); + *val = get_reg_val(id, kvmppc_get_dscr_hv(vcpu)); break; case KVM_REG_PPC_PURR: - *val = get_reg_val(id, vcpu->arch.purr); + *val = get_reg_val(id, kvmppc_get_purr_hv(vcpu)); break; case KVM_REG_PPC_SPURR: - *val = get_reg_val(id, vcpu->arch.spurr); + *val = get_reg_val(id, kvmppc_get_spurr_hv(vcpu)); break; case KVM_REG_PPC_AMR: - *val = get_reg_val(id, vcpu->arch.amr); + *val = get_reg_val(id, kvmppc_get_amr_hv(vcpu)); break; case KVM_REG_PPC_UAMOR: - *val = get_reg_val(id, vcpu->arch.uamor); + *val = get_reg_val(id, kvmppc_get_uamor_hv(vcpu)); break; case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCR1: i = id - KVM_REG_PPC_MMCR0; - *val = get_reg_val(id, vcpu->arch.mmcr[i]); + *val = get_reg_val(id, kvmppc_get_mmcr_hv(vcpu, i)); break; case KVM_REG_PPC_MMCR2: - *val = get_reg_val(id, vcpu->arch.mmcr[2]); + *val = get_reg_val(id, kvmppc_get_mmcr_hv(vcpu, 2)); break; case KVM_REG_PPC_MMCRA: - *val = get_reg_val(id, vcpu->arch.mmcra); + *val = get_reg_val(id, kvmppc_get_mmcra_hv(vcpu)); break; case KVM_REG_PPC_MMCRS: *val = get_reg_val(id, vcpu->arch.mmcrs); break; case KVM_REG_PPC_MMCR3: - *val = get_reg_val(id, vcpu->arch.mmcr[3]); + *val = get_reg_val(id, kvmppc_get_mmcr_hv(vcpu, 3)); break; case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8: i = id - KVM_REG_PPC_PMC1; - *val = get_reg_val(id, vcpu->arch.pmc[i]); + *val = get_reg_val(id, kvmppc_get_pmc_hv(vcpu, i)); break; case KVM_REG_PPC_SPMC1 ... KVM_REG_PPC_SPMC2: i = id - KVM_REG_PPC_SPMC1; *val = get_reg_val(id, vcpu->arch.spmc[i]); break; case KVM_REG_PPC_SIAR: - *val = get_reg_val(id, vcpu->arch.siar); + *val = get_reg_val(id, kvmppc_get_siar_hv(vcpu)); break; case KVM_REG_PPC_SDAR: - *val = get_reg_val(id, vcpu->arch.sdar); + *val = get_reg_val(id, kvmppc_get_sdar_hv(vcpu)); break; case KVM_REG_PPC_SIER: - *val = get_reg_val(id, vcpu->arch.sier[0]); + *val = get_reg_val(id, kvmppc_get_sier_hv(vcpu, 0)); break; case KVM_REG_PPC_SIER2: - *val = get_reg_val(id, vcpu->arch.sier[1]); + *val = get_reg_val(id, kvmppc_get_sier_hv(vcpu, 1)); break; case KVM_REG_PPC_SIER3: - *val = get_reg_val(id, vcpu->arch.sier[2]); + *val = get_reg_val(id, kvmppc_get_sier_hv(vcpu, 2)); break; case KVM_REG_PPC_IAMR: - *val = get_reg_val(id, vcpu->arch.iamr); + *val = get_reg_val(id, kvmppc_get_iamr_hv(vcpu)); break; case KVM_REG_PPC_PSPB: - *val = get_reg_val(id, vcpu->arch.pspb); + *val = get_reg_val(id, kvmppc_get_pspb_hv(vcpu)); break; case KVM_REG_PPC_DPDES: /* @@ -2264,22 +2319,31 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, *val = get_reg_val(id, vcpu->arch.vcore->dpdes); break; case KVM_REG_PPC_VTB: - *val = get_reg_val(id, vcpu->arch.vcore->vtb); + *val = get_reg_val(id, kvmppc_get_vtb(vcpu)); break; case KVM_REG_PPC_DAWR: - *val = get_reg_val(id, vcpu->arch.dawr0); + *val = get_reg_val(id, kvmppc_get_dawr0_hv(vcpu)); break; case KVM_REG_PPC_DAWRX: - *val = get_reg_val(id, vcpu->arch.dawrx0); + *val = get_reg_val(id, kvmppc_get_dawrx0_hv(vcpu)); break; case KVM_REG_PPC_DAWR1: - *val = get_reg_val(id, vcpu->arch.dawr1); + *val = get_reg_val(id, kvmppc_get_dawr1_hv(vcpu)); break; case KVM_REG_PPC_DAWRX1: - *val = get_reg_val(id, vcpu->arch.dawrx1); + *val = get_reg_val(id, kvmppc_get_dawrx1_hv(vcpu)); + break; + case KVM_REG_PPC_DEXCR: + *val = get_reg_val(id, kvmppc_get_dexcr_hv(vcpu)); + break; + case KVM_REG_PPC_HASHKEYR: + *val = get_reg_val(id, kvmppc_get_hashkeyr_hv(vcpu)); + break; + case KVM_REG_PPC_HASHPKEYR: + *val = get_reg_val(id, kvmppc_get_hashpkeyr_hv(vcpu)); break; case KVM_REG_PPC_CIABR: - *val = get_reg_val(id, vcpu->arch.ciabr); + *val = get_reg_val(id, kvmppc_get_ciabr_hv(vcpu)); break; case KVM_REG_PPC_CSIGR: *val = get_reg_val(id, vcpu->arch.csigr); @@ -2291,13 +2355,13 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, *val = get_reg_val(id, vcpu->arch.tcscr); break; case KVM_REG_PPC_PID: - *val = get_reg_val(id, vcpu->arch.pid); + *val = get_reg_val(id, kvmppc_get_pid(vcpu)); break; case KVM_REG_PPC_ACOP: *val = get_reg_val(id, vcpu->arch.acop); break; case KVM_REG_PPC_WORT: - *val = get_reg_val(id, vcpu->arch.wort); + *val = get_reg_val(id, kvmppc_get_wort_hv(vcpu)); break; case KVM_REG_PPC_TIDR: *val = get_reg_val(id, vcpu->arch.tid); @@ -2323,14 +2387,14 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, spin_unlock(&vcpu->arch.vpa_update_lock); break; case KVM_REG_PPC_TB_OFFSET: - *val = get_reg_val(id, vcpu->arch.vcore->tb_offset); + *val = get_reg_val(id, kvmppc_get_tb_offset(vcpu)); break; case KVM_REG_PPC_LPCR: case KVM_REG_PPC_LPCR_64: - *val = get_reg_val(id, vcpu->arch.vcore->lpcr); + *val = get_reg_val(id, kvmppc_get_lpcr(vcpu)); break; case KVM_REG_PPC_PPR: - *val = get_reg_val(id, vcpu->arch.ppr); + *val = get_reg_val(id, kvmppc_get_ppr_hv(vcpu)); break; #ifdef CONFIG_PPC_TRANSACTIONAL_MEM case KVM_REG_PPC_TFHAR: @@ -2399,10 +2463,10 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, break; #endif case KVM_REG_PPC_ARCH_COMPAT: - *val = get_reg_val(id, vcpu->arch.vcore->arch_compat); + *val = get_reg_val(id, kvmppc_get_arch_compat(vcpu)); break; case KVM_REG_PPC_DEC_EXPIRY: - *val = get_reg_val(id, vcpu->arch.dec_expires); + *val = get_reg_val(id, kvmppc_get_dec_expires(vcpu)); break; case KVM_REG_PPC_ONLINE: *val = get_reg_val(id, vcpu->arch.online); @@ -2410,6 +2474,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_PTCR: *val = get_reg_val(id, vcpu->kvm->arch.l1_ptcr); break; + case KVM_REG_PPC_FSCR: + *val = get_reg_val(id, kvmppc_get_fscr_hv(vcpu)); + break; default: r = -EINVAL; break; @@ -2438,64 +2505,64 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, vcpu->arch.dabrx = set_reg_val(id, *val) & ~DABRX_HYP; break; case KVM_REG_PPC_DSCR: - vcpu->arch.dscr = set_reg_val(id, *val); + kvmppc_set_dscr_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_PURR: - vcpu->arch.purr = set_reg_val(id, *val); + kvmppc_set_purr_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_SPURR: - vcpu->arch.spurr = set_reg_val(id, *val); + kvmppc_set_spurr_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_AMR: - vcpu->arch.amr = set_reg_val(id, *val); + kvmppc_set_amr_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_UAMOR: - vcpu->arch.uamor = set_reg_val(id, *val); + kvmppc_set_uamor_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCR1: i = id - KVM_REG_PPC_MMCR0; - vcpu->arch.mmcr[i] = set_reg_val(id, *val); + kvmppc_set_mmcr_hv(vcpu, i, set_reg_val(id, *val)); break; case KVM_REG_PPC_MMCR2: - vcpu->arch.mmcr[2] = set_reg_val(id, *val); + kvmppc_set_mmcr_hv(vcpu, 2, set_reg_val(id, *val)); break; case KVM_REG_PPC_MMCRA: - vcpu->arch.mmcra = set_reg_val(id, *val); + kvmppc_set_mmcra_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_MMCRS: vcpu->arch.mmcrs = set_reg_val(id, *val); break; case KVM_REG_PPC_MMCR3: - *val = get_reg_val(id, vcpu->arch.mmcr[3]); + kvmppc_set_mmcr_hv(vcpu, 3, set_reg_val(id, *val)); break; case KVM_REG_PPC_PMC1 ... KVM_REG_PPC_PMC8: i = id - KVM_REG_PPC_PMC1; - vcpu->arch.pmc[i] = set_reg_val(id, *val); + kvmppc_set_pmc_hv(vcpu, i, set_reg_val(id, *val)); break; case KVM_REG_PPC_SPMC1 ... KVM_REG_PPC_SPMC2: i = id - KVM_REG_PPC_SPMC1; vcpu->arch.spmc[i] = set_reg_val(id, *val); break; case KVM_REG_PPC_SIAR: - vcpu->arch.siar = set_reg_val(id, *val); + kvmppc_set_siar_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_SDAR: - vcpu->arch.sdar = set_reg_val(id, *val); + kvmppc_set_sdar_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_SIER: - vcpu->arch.sier[0] = set_reg_val(id, *val); + kvmppc_set_sier_hv(vcpu, 0, set_reg_val(id, *val)); break; case KVM_REG_PPC_SIER2: - vcpu->arch.sier[1] = set_reg_val(id, *val); + kvmppc_set_sier_hv(vcpu, 1, set_reg_val(id, *val)); break; case KVM_REG_PPC_SIER3: - vcpu->arch.sier[2] = set_reg_val(id, *val); + kvmppc_set_sier_hv(vcpu, 2, set_reg_val(id, *val)); break; case KVM_REG_PPC_IAMR: - vcpu->arch.iamr = set_reg_val(id, *val); + kvmppc_set_iamr_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_PSPB: - vcpu->arch.pspb = set_reg_val(id, *val); + kvmppc_set_pspb_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_DPDES: if (cpu_has_feature(CPU_FTR_ARCH_300)) @@ -2504,25 +2571,34 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, vcpu->arch.vcore->dpdes = set_reg_val(id, *val); break; case KVM_REG_PPC_VTB: - vcpu->arch.vcore->vtb = set_reg_val(id, *val); + kvmppc_set_vtb(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_DAWR: - vcpu->arch.dawr0 = set_reg_val(id, *val); + kvmppc_set_dawr0_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_DAWRX: - vcpu->arch.dawrx0 = set_reg_val(id, *val) & ~DAWRX_HYP; + kvmppc_set_dawrx0_hv(vcpu, set_reg_val(id, *val) & ~DAWRX_HYP); break; case KVM_REG_PPC_DAWR1: - vcpu->arch.dawr1 = set_reg_val(id, *val); + kvmppc_set_dawr1_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_DAWRX1: - vcpu->arch.dawrx1 = set_reg_val(id, *val) & ~DAWRX_HYP; + kvmppc_set_dawrx1_hv(vcpu, set_reg_val(id, *val) & ~DAWRX_HYP); + break; + case KVM_REG_PPC_DEXCR: + kvmppc_set_dexcr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_HASHKEYR: + kvmppc_set_hashkeyr_hv(vcpu, set_reg_val(id, *val)); + break; + case KVM_REG_PPC_HASHPKEYR: + kvmppc_set_hashpkeyr_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_CIABR: - vcpu->arch.ciabr = set_reg_val(id, *val); + kvmppc_set_ciabr_hv(vcpu, set_reg_val(id, *val)); /* Don't allow setting breakpoints in hypervisor code */ - if ((vcpu->arch.ciabr & CIABR_PRIV) == CIABR_PRIV_HYPER) - vcpu->arch.ciabr &= ~CIABR_PRIV; /* disable */ + if ((kvmppc_get_ciabr_hv(vcpu) & CIABR_PRIV) == CIABR_PRIV_HYPER) + kvmppc_set_ciabr_hv(vcpu, kvmppc_get_ciabr_hv(vcpu) & ~CIABR_PRIV); break; case KVM_REG_PPC_CSIGR: vcpu->arch.csigr = set_reg_val(id, *val); @@ -2534,13 +2610,13 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, vcpu->arch.tcscr = set_reg_val(id, *val); break; case KVM_REG_PPC_PID: - vcpu->arch.pid = set_reg_val(id, *val); + kvmppc_set_pid(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_ACOP: vcpu->arch.acop = set_reg_val(id, *val); break; case KVM_REG_PPC_WORT: - vcpu->arch.wort = set_reg_val(id, *val); + kvmppc_set_wort_hv(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_TIDR: vcpu->arch.tid = set_reg_val(id, *val); @@ -2587,10 +2663,11 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, * decrementer, which is better than a large one that * causes a hang. */ - if (!vcpu->arch.dec_expires && tb_offset) - vcpu->arch.dec_expires = get_tb() + tb_offset; + kvmppc_set_tb_offset(vcpu, tb_offset); + if (!kvmppc_get_dec_expires(vcpu) && tb_offset) + kvmppc_set_dec_expires(vcpu, get_tb() + tb_offset); - vcpu->arch.vcore->tb_offset = tb_offset; + kvmppc_set_tb_offset(vcpu, tb_offset); break; } case KVM_REG_PPC_LPCR: @@ -2600,7 +2677,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, kvmppc_set_lpcr(vcpu, set_reg_val(id, *val), false); break; case KVM_REG_PPC_PPR: - vcpu->arch.ppr = set_reg_val(id, *val); + kvmppc_set_ppr_hv(vcpu, set_reg_val(id, *val)); break; #ifdef CONFIG_PPC_TRANSACTIONAL_MEM case KVM_REG_PPC_TFHAR: @@ -2671,7 +2748,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_DEC_EXPIRY: - vcpu->arch.dec_expires = set_reg_val(id, *val); + kvmppc_set_dec_expires(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_ONLINE: i = set_reg_val(id, *val); @@ -2684,6 +2761,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id, case KVM_REG_PPC_PTCR: vcpu->kvm->arch.l1_ptcr = set_reg_val(id, *val); break; + case KVM_REG_PPC_FSCR: + kvmppc_set_fscr_hv(vcpu, set_reg_val(id, *val)); + break; default: r = -EINVAL; break; @@ -2901,46 +2981,59 @@ static int kvmppc_core_vcpu_create_hv(struct kvm_vcpu *vcpu) vcpu->arch.shared_big_endian = false; #endif #endif - vcpu->arch.mmcr[0] = MMCR0_FC; + + if (kvmhv_is_nestedv2()) { + err = kvmhv_nestedv2_vcpu_create(vcpu, &vcpu->arch.nestedv2_io); + if (err < 0) + return err; + } + + kvmppc_set_mmcr_hv(vcpu, 0, MMCR0_FC); if (cpu_has_feature(CPU_FTR_ARCH_31)) { - vcpu->arch.mmcr[0] |= MMCR0_PMCCEXT; - vcpu->arch.mmcra = MMCRA_BHRB_DISABLE; + kvmppc_set_mmcr_hv(vcpu, 0, kvmppc_get_mmcr_hv(vcpu, 0) | MMCR0_PMCCEXT); + kvmppc_set_mmcra_hv(vcpu, MMCRA_BHRB_DISABLE); } - vcpu->arch.ctrl = CTRL_RUNLATCH; + kvmppc_set_ctrl_hv(vcpu, CTRL_RUNLATCH); /* default to host PVR, since we can't spoof it */ kvmppc_set_pvr_hv(vcpu, mfspr(SPRN_PVR)); spin_lock_init(&vcpu->arch.vpa_update_lock); spin_lock_init(&vcpu->arch.tbacct_lock); vcpu->arch.busy_preempt = TB_NIL; - vcpu->arch.shregs.msr = MSR_ME; + __kvmppc_set_msr_hv(vcpu, MSR_ME); vcpu->arch.intr_msr = MSR_SF | MSR_ME; /* * Set the default HFSCR for the guest from the host value. - * This value is only used on POWER9. - * On POWER9, we want to virtualize the doorbell facility, so we + * This value is only used on POWER9 and later. + * On >= POWER9, we want to virtualize the doorbell facility, so we * don't set the HFSCR_MSGP bit, and that causes those instructions * to trap and then we emulate them. */ - vcpu->arch.hfscr = HFSCR_TAR | HFSCR_EBB | HFSCR_PM | HFSCR_BHRB | - HFSCR_DSCR | HFSCR_VECVSX | HFSCR_FP; + kvmppc_set_hfscr_hv(vcpu, HFSCR_TAR | HFSCR_EBB | HFSCR_PM | HFSCR_BHRB | + HFSCR_DSCR | HFSCR_VECVSX | HFSCR_FP); + + /* On POWER10 and later, allow prefixed instructions */ + if (cpu_has_feature(CPU_FTR_ARCH_31)) + kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_PREFIX); + if (cpu_has_feature(CPU_FTR_HVMODE)) { - vcpu->arch.hfscr &= mfspr(SPRN_HFSCR); + kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) & mfspr(SPRN_HFSCR)); + #ifdef CONFIG_PPC_TRANSACTIONAL_MEM if (cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) - vcpu->arch.hfscr |= HFSCR_TM; + kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) | HFSCR_TM); #endif } if (cpu_has_feature(CPU_FTR_TM_COMP)) vcpu->arch.hfscr |= HFSCR_TM; - vcpu->arch.hfscr_permitted = vcpu->arch.hfscr; + vcpu->arch.hfscr_permitted = kvmppc_get_hfscr_hv(vcpu); /* * PM, EBB, TM are demand-faulted so start with it clear. */ - vcpu->arch.hfscr &= ~(HFSCR_PM | HFSCR_EBB | HFSCR_TM); + kvmppc_set_hfscr_hv(vcpu, kvmppc_get_hfscr_hv(vcpu) & ~(HFSCR_PM | HFSCR_EBB | HFSCR_TM)); kvmppc_mmu_book3s_hv_init(vcpu); @@ -3051,6 +3144,8 @@ static void kvmppc_core_vcpu_free_hv(struct kvm_vcpu *vcpu) unpin_vpa(vcpu->kvm, &vcpu->arch.slb_shadow); unpin_vpa(vcpu->kvm, &vcpu->arch.vpa); spin_unlock(&vcpu->arch.vpa_update_lock); + if (kvmhv_is_nestedv2()) + kvmhv_nestedv2_vcpu_free(vcpu, &vcpu->arch.nestedv2_io); } static int kvmppc_core_check_requests_hv(struct kvm_vcpu *vcpu) @@ -3938,7 +4033,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) /* Return to whole-core mode if we split the core earlier */ if (cmd_bit) { unsigned long hid0 = mfspr(SPRN_HID0); - unsigned long loops = 0; hid0 &= ~HID0_POWER8_DYNLPARDIS; stat_bit = HID0_POWER8_2LPARMODE | HID0_POWER8_4LPARMODE; @@ -3950,7 +4044,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) if (!(hid0 & stat_bit)) break; cpu_relax(); - ++loops; } split_info.do_nap = 0; } @@ -4015,10 +4108,207 @@ static void vcpu_vpa_increment_dispatch(struct kvm_vcpu *vcpu) } } +/* Helper functions for reading L2's stats from L1's VPA */ +#ifdef CONFIG_PPC_PSERIES +static DEFINE_PER_CPU(u64, l1_to_l2_cs); +static DEFINE_PER_CPU(u64, l2_to_l1_cs); +static DEFINE_PER_CPU(u64, l2_runtime_agg); + +int kvmhv_get_l2_counters_status(void) +{ + return firmware_has_feature(FW_FEATURE_LPAR) && + get_lppaca()->l2_counters_enable; +} + +void kvmhv_set_l2_counters_status(int cpu, bool status) +{ + if (!firmware_has_feature(FW_FEATURE_LPAR)) + return; + if (status) + lppaca_of(cpu).l2_counters_enable = 1; + else + lppaca_of(cpu).l2_counters_enable = 0; +} +EXPORT_SYMBOL(kvmhv_set_l2_counters_status); + +int kvmhv_counters_tracepoint_regfunc(void) +{ + int cpu; + + for_each_present_cpu(cpu) { + kvmhv_set_l2_counters_status(cpu, true); + } + return 0; +} + +void kvmhv_counters_tracepoint_unregfunc(void) +{ + int cpu; + + for_each_present_cpu(cpu) { + kvmhv_set_l2_counters_status(cpu, false); + } +} + +static void do_trace_nested_cs_time(struct kvm_vcpu *vcpu) +{ + struct lppaca *lp = get_lppaca(); + u64 l1_to_l2_ns, l2_to_l1_ns, l2_runtime_ns; + u64 *l1_to_l2_cs_ptr = this_cpu_ptr(&l1_to_l2_cs); + u64 *l2_to_l1_cs_ptr = this_cpu_ptr(&l2_to_l1_cs); + u64 *l2_runtime_agg_ptr = this_cpu_ptr(&l2_runtime_agg); + + l1_to_l2_ns = tb_to_ns(be64_to_cpu(lp->l1_to_l2_cs_tb)); + l2_to_l1_ns = tb_to_ns(be64_to_cpu(lp->l2_to_l1_cs_tb)); + l2_runtime_ns = tb_to_ns(be64_to_cpu(lp->l2_runtime_tb)); + trace_kvmppc_vcpu_stats(vcpu, l1_to_l2_ns - *l1_to_l2_cs_ptr, + l2_to_l1_ns - *l2_to_l1_cs_ptr, + l2_runtime_ns - *l2_runtime_agg_ptr); + *l1_to_l2_cs_ptr = l1_to_l2_ns; + *l2_to_l1_cs_ptr = l2_to_l1_ns; + *l2_runtime_agg_ptr = l2_runtime_ns; + vcpu->arch.l1_to_l2_cs = l1_to_l2_ns; + vcpu->arch.l2_to_l1_cs = l2_to_l1_ns; + vcpu->arch.l2_runtime_agg = l2_runtime_ns; +} + +u64 kvmhv_get_l1_to_l2_cs_time(void) +{ + return tb_to_ns(be64_to_cpu(get_lppaca()->l1_to_l2_cs_tb)); +} +EXPORT_SYMBOL(kvmhv_get_l1_to_l2_cs_time); + +u64 kvmhv_get_l2_to_l1_cs_time(void) +{ + return tb_to_ns(be64_to_cpu(get_lppaca()->l2_to_l1_cs_tb)); +} +EXPORT_SYMBOL(kvmhv_get_l2_to_l1_cs_time); + +u64 kvmhv_get_l2_runtime_agg(void) +{ + return tb_to_ns(be64_to_cpu(get_lppaca()->l2_runtime_tb)); +} +EXPORT_SYMBOL(kvmhv_get_l2_runtime_agg); + +u64 kvmhv_get_l1_to_l2_cs_time_vcpu(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vcpu_arch *arch; + + vcpu = local_paca->kvm_hstate.kvm_vcpu; + if (vcpu) { + arch = &vcpu->arch; + return arch->l1_to_l2_cs; + } else { + return 0; + } +} +EXPORT_SYMBOL(kvmhv_get_l1_to_l2_cs_time_vcpu); + +u64 kvmhv_get_l2_to_l1_cs_time_vcpu(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vcpu_arch *arch; + + vcpu = local_paca->kvm_hstate.kvm_vcpu; + if (vcpu) { + arch = &vcpu->arch; + return arch->l2_to_l1_cs; + } else { + return 0; + } +} +EXPORT_SYMBOL(kvmhv_get_l2_to_l1_cs_time_vcpu); + +u64 kvmhv_get_l2_runtime_agg_vcpu(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vcpu_arch *arch; + + vcpu = local_paca->kvm_hstate.kvm_vcpu; + if (vcpu) { + arch = &vcpu->arch; + return arch->l2_runtime_agg; + } else { + return 0; + } +} +EXPORT_SYMBOL(kvmhv_get_l2_runtime_agg_vcpu); + +#else +int kvmhv_get_l2_counters_status(void) +{ + return 0; +} + +static void do_trace_nested_cs_time(struct kvm_vcpu *vcpu) +{ +} +#endif + +static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu *vcpu, u64 time_limit, + unsigned long lpcr, u64 *tb) +{ + struct kvmhv_nestedv2_io *io; + unsigned long msr, i; + int trap; + long rc; + + if (vcpu->arch.doorbell_request) { + vcpu->arch.doorbell_request = 0; + kvmppc_set_dpdes(vcpu, 1); + } + + io = &vcpu->arch.nestedv2_io; + + msr = mfmsr(); + kvmppc_msr_hard_disable_set_facilities(vcpu, msr); + if (lazy_irq_pending()) + return 0; + + rc = kvmhv_nestedv2_flush_vcpu(vcpu, time_limit); + if (rc < 0) + return -EINVAL; + + kvmppc_gse_put_u64(io->vcpu_run_input, KVMPPC_GSID_LPCR, lpcr); + + accumulate_time(vcpu, &vcpu->arch.in_guest); + rc = plpar_guest_run_vcpu(0, vcpu->kvm->arch.lpid, vcpu->vcpu_id, + &trap, &i); + + if (rc != H_SUCCESS) { + pr_err("KVM Guest Run VCPU hcall failed\n"); + if (rc == H_INVALID_ELEMENT_ID) + pr_err("KVM: Guest Run VCPU invalid element id at %ld\n", i); + else if (rc == H_INVALID_ELEMENT_SIZE) + pr_err("KVM: Guest Run VCPU invalid element size at %ld\n", i); + else if (rc == H_INVALID_ELEMENT_VALUE) + pr_err("KVM: Guest Run VCPU invalid element value at %ld\n", i); + return -EINVAL; + } + accumulate_time(vcpu, &vcpu->arch.guest_exit); + + *tb = mftb(); + kvmppc_gsm_reset(io->vcpu_message); + kvmppc_gsm_reset(io->vcore_message); + kvmppc_gsbm_zero(&io->valids); + + rc = kvmhv_nestedv2_parse_output(vcpu); + if (rc < 0) + return -EINVAL; + + timer_rearm_host_dec(*tb); + + /* Record context switch and guest_run_time data */ + if (kvmhv_get_l2_counters_status()) + do_trace_nested_cs_time(vcpu); + + return trap; +} + /* call our hypervisor to load up HV regs and go */ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, unsigned long lpcr, u64 *tb) { - struct kvmppc_vcore *vc = vcpu->arch.vcore; unsigned long host_psscr; unsigned long msr; struct hv_guest_state hvregs; @@ -4063,6 +4353,15 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns hvregs.hdec_expiry = time_limit; /* + * hvregs has the doorbell status, so zero it here which + * enables us to receive doorbells when H_ENTER_NESTED is + * in progress for this vCPU + */ + + if (vcpu->arch.doorbell_request) + vcpu->arch.doorbell_request = 0; + + /* * When setting DEC, we must always deal with irq_work_raise * via NMI vs setting DEC. The problem occurs right as we * switch into guest mode if a NMI hits and sets pending work @@ -4098,7 +4397,7 @@ static int kvmhv_vcpu_entry_p9_nested(struct kvm_vcpu *vcpu, u64 time_limit, uns if (!(lpcr & LPCR_LD)) /* Sign extend if not using large decrementer */ dec = (s32) dec; *tb = mftb(); - vcpu->arch.dec_expires = dec + (*tb + vc->tb_offset); + vcpu->arch.dec_expires = dec + (*tb + kvmppc_get_tb_offset(vcpu)); timer_rearm_host_dec(*tb); @@ -4133,7 +4432,10 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, vcpu_vpa_increment_dispatch(vcpu); if (kvmhv_on_pseries()) { - trap = kvmhv_vcpu_entry_p9_nested(vcpu, time_limit, lpcr, tb); + if (kvmhv_is_nestedv1()) + trap = kvmhv_vcpu_entry_p9_nested(vcpu, time_limit, lpcr, tb); + else + trap = kvmhv_vcpu_entry_nestedv2(vcpu, time_limit, lpcr, tb); /* H_CEDE has to be handled now, not later */ if (trap == BOOK3S_INTERRUPT_SYSCALL && !nested && @@ -4156,7 +4458,7 @@ static int kvmhv_p9_guest_entry(struct kvm_vcpu *vcpu, u64 time_limit, __this_cpu_write(cpu_in_guest, NULL); if (trap == BOOK3S_INTERRUPT_SYSCALL && - !(vcpu->arch.shregs.msr & MSR_PR)) { + !(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { unsigned long req = kvmppc_get_gpr(vcpu, 3); /* @@ -4635,16 +4937,33 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, if (!nested) { kvmppc_core_prepare_to_enter(vcpu); - if (vcpu->arch.shregs.msr & MSR_EE) { - if (xive_interrupt_pending(vcpu)) + if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, + &vcpu->arch.pending_exceptions) || + xive_interrupt_pending(vcpu)) { + /* + * For nested HV, don't synthesize but always pass MER, + * the L0 will be able to optimise that more + * effectively than manipulating registers directly. + */ + if (!kvmhv_on_pseries() && (__kvmppc_get_msr_hv(vcpu) & MSR_EE)) kvmppc_inject_interrupt_hv(vcpu, - BOOK3S_INTERRUPT_EXTERNAL, 0); - } else if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, - &vcpu->arch.pending_exceptions)) { - lpcr |= LPCR_MER; + BOOK3S_INTERRUPT_EXTERNAL, 0); + else + lpcr |= LPCR_MER; + } else { + /* + * L1's copy of L2's LPCR (vcpu->arch.vcore->lpcr) can get its MER bit + * unexpectedly set - for e.g. during NMI handling when all register + * states are synchronized from L0 to L1. L1 needs to inform L0 about + * MER=1 only when there are pending external interrupts. + * In the above if check, MER bit is set if there are pending + * external interrupts. Hence, explicitly mask off MER bit + * here as otherwise it may generate spurious interrupts in L2 KVM + * causing an endless loop, which results in L2 guest getting hung. + */ + lpcr &= ~LPCR_MER; } } else if (vcpu->arch.pending_exceptions || - vcpu->arch.doorbell_request || xive_interrupt_pending(vcpu)) { vcpu->arch.ret = RESUME_HOST; goto out; @@ -4657,7 +4976,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, tb = mftb(); - kvmppc_update_vpa_dispatch_p9(vcpu, vc, tb + vc->tb_offset); + kvmppc_update_vpa_dispatch_p9(vcpu, vc, tb + kvmppc_get_tb_offset(vcpu)); trace_kvm_guest_enter(vcpu); @@ -4824,7 +5143,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu) msr |= MSR_VSX; if ((cpu_has_feature(CPU_FTR_TM) || cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)) && - (vcpu->arch.hfscr & HFSCR_TM)) + (kvmppc_get_hfscr_hv(vcpu) & HFSCR_TM)) msr |= MSR_TM; msr = msr_check_and_set(msr); @@ -4848,7 +5167,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu) if (run->exit_reason == KVM_EXIT_PAPR_HCALL) { accumulate_time(vcpu, &vcpu->arch.hcall); - if (WARN_ON_ONCE(vcpu->arch.shregs.msr & MSR_PR)) { + if (!kvmhv_is_nestedv2() && WARN_ON_ONCE(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { /* * These should have been caught reflected * into the guest by now. Final sanity check: @@ -5113,6 +5432,14 @@ void kvmppc_update_lpcr(struct kvm *kvm, unsigned long lpcr, unsigned long mask) if (++cores_done >= kvm->arch.online_vcores) break; } + + if (kvmhv_is_nestedv2()) { + struct kvm_vcpu *vcpu; + + kvm_for_each_vcpu(i, vcpu, kvm) { + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_LPCR); + } + } } void kvmppc_setup_partition_table(struct kvm *kvm) @@ -5379,15 +5706,43 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) /* Allocate the guest's logical partition ID */ - lpid = kvmppc_alloc_lpid(); - if ((long)lpid < 0) - return -ENOMEM; - kvm->arch.lpid = lpid; + if (!kvmhv_is_nestedv2()) { + lpid = kvmppc_alloc_lpid(); + if ((long)lpid < 0) + return -ENOMEM; + kvm->arch.lpid = lpid; + } kvmppc_alloc_host_rm_ops(); kvmhv_vm_nested_init(kvm); + if (kvmhv_is_nestedv2()) { + long rc; + unsigned long guest_id; + + rc = plpar_guest_create(0, &guest_id); + + if (rc != H_SUCCESS) + pr_err("KVM: Create Guest hcall failed, rc=%ld\n", rc); + + switch (rc) { + case H_PARAMETER: + case H_FUNCTION: + case H_STATE: + return -EINVAL; + case H_NOT_ENOUGH_RESOURCES: + case H_ABORTED: + return -ENOMEM; + case H_AUTHORITY: + return -EPERM; + case H_NOT_AVAILABLE: + return -EBUSY; + } + kvm->arch.lpid = guest_id; + } + + /* * Since we don't flush the TLB when tearing down a VM, * and this lpid might have previously been used, @@ -5457,7 +5812,10 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm) lpcr |= LPCR_HAIL; ret = kvmppc_init_vm_radix(kvm); if (ret) { - kvmppc_free_lpid(kvm->arch.lpid); + if (kvmhv_is_nestedv2()) + plpar_guest_delete(0, kvm->arch.lpid); + else + kvmppc_free_lpid(kvm->arch.lpid); return ret; } kvmppc_setup_partition_table(kvm); @@ -5547,10 +5905,16 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm) kvm->arch.process_table = 0; if (kvm->arch.secure_guest) uv_svm_terminate(kvm->arch.lpid); - kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0); + if (!kvmhv_is_nestedv2()) + kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0); } - kvmppc_free_lpid(kvm->arch.lpid); + if (kvmhv_is_nestedv2()) { + kvmhv_flush_lpid(kvm->arch.lpid); + plpar_guest_delete(0, kvm->arch.lpid); + } else { + kvmppc_free_lpid(kvm->arch.lpid); + } kvmppc_free_pimap(kvm); } @@ -5677,7 +6041,7 @@ static int kvmppc_set_passthru_irq(struct kvm *kvm, int host_irq, int guest_gsi) * the underlying calls, which will EOI the interrupt in real * mode, need an HW IRQ number mapped in the XICS IRQ domain. */ - host_data = irq_domain_get_irq_data(irq_get_default_host(), host_irq); + host_data = irq_domain_get_irq_data(irq_get_default_domain(), host_irq); irq_map->r_hwirq = (unsigned int)irqd_to_hwirq(host_data); if (i == pimap->n_mapped) @@ -5779,12 +6143,12 @@ static void kvmppc_irq_bypass_del_producer_hv(struct irq_bypass_consumer *cons, } #endif -static long kvm_arch_vm_ioctl_hv(struct file *filp, - unsigned int ioctl, unsigned long arg) +static int kvm_arch_vm_ioctl_hv(struct file *filp, + unsigned int ioctl, unsigned long arg) { struct kvm *kvm __maybe_unused = filp->private_data; void __user *argp = (void __user *)arg; - long r; + int r; switch (ioctl) { @@ -5962,6 +6326,8 @@ static int kvmhv_enable_nested(struct kvm *kvm) return -ENODEV; if (!radix_enabled()) return -ENODEV; + if (kvmhv_is_nestedv2()) + return -ENODEV; /* kvm == NULL means the caller is testing if the capability exists */ if (kvm) @@ -6064,7 +6430,7 @@ static int kvmhv_svm_off(struct kvm *kvm) } srcu_idx = srcu_read_lock(&kvm->srcu); - for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) { + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { struct kvm_memory_slot *memslot; struct kvm_memslots *slots = __kvm_memslots(kvm, i); int bkt; @@ -6165,7 +6531,6 @@ static struct kvmppc_ops kvm_ops_hv = { .unmap_gfn_range = kvm_unmap_gfn_range_hv, .age_gfn = kvm_age_gfn_hv, .test_age_gfn = kvm_test_age_gfn_hv, - .set_spte_gfn = kvm_set_spte_gfn_hv, .free_memslot = kvmppc_core_free_memslot_hv, .init_vm = kvmppc_core_init_vm_hv, .destroy_vm = kvmppc_core_destroy_vm_hv, @@ -6176,10 +6541,6 @@ static struct kvmppc_ops kvm_ops_hv = { .fast_vcpu_kick = kvmppc_fast_vcpu_kick_hv, .arch_vm_ioctl = kvm_arch_vm_ioctl_hv, .hcall_implemented = kvmppc_hcall_impl_hv, -#ifdef CONFIG_KVM_XICS - .irq_bypass_add_producer = kvmppc_irq_bypass_add_producer_hv, - .irq_bypass_del_producer = kvmppc_irq_bypass_del_producer_hv, -#endif .configure_mmu = kvmhv_configure_mmu, .get_rmmu_info = kvmhv_get_rmmu_info, .set_smt_mode = kvmhv_set_smt_mode, @@ -6297,6 +6658,22 @@ static int kvmppc_book3s_init_hv(void) return r; } +#if defined(CONFIG_KVM_XICS) + /* + * IRQ bypass is supported only for interrupts whose EOI operations are + * handled via OPAL calls. Therefore, register IRQ bypass handlers + * exclusively for PowerNV KVM when booted with 'xive=off', indicating + * the use of the emulated XICS interrupt controller. + */ + if (!kvmhv_on_pseries()) { + pr_info("KVM-HV: Enabling IRQ bypass\n"); + kvm_ops_hv.irq_bypass_add_producer = + kvmppc_irq_bypass_add_producer_hv; + kvm_ops_hv.irq_bypass_del_producer = + kvmppc_irq_bypass_del_producer_hv; + } +#endif + kvm_ops_hv.owner = THIS_MODULE; kvmppc_hv_ops = &kvm_ops_hv; @@ -6321,6 +6698,7 @@ static void kvmppc_book3s_exit_hv(void) module_init(kvmppc_book3s_init_hv); module_exit(kvmppc_book3s_exit_hv); +MODULE_DESCRIPTION("KVM on Book3S (POWER8 and later) in hypervisor mode"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(KVM_MINOR); MODULE_ALIAS("devname:kvm"); diff --git a/arch/powerpc/kvm/book3s_hv.h b/arch/powerpc/kvm/book3s_hv.h index 2f2e59d7d433..a404c9b221c1 100644 --- a/arch/powerpc/kvm/book3s_hv.h +++ b/arch/powerpc/kvm/book3s_hv.h @@ -3,6 +3,8 @@ /* * Privileged (non-hypervisor) host registers to save. */ +#include "asm/guest-state-buffer.h" + struct p9_host_os_sprs { unsigned long iamr; unsigned long amr; @@ -50,3 +52,80 @@ void accumulate_time(struct kvm_vcpu *vcpu, struct kvmhv_tb_accumulator *next); #define start_timing(vcpu, next) do {} while (0) #define end_timing(vcpu) do {} while (0) #endif + +static inline void __kvmppc_set_msr_hv(struct kvm_vcpu *vcpu, u64 val) +{ + vcpu->arch.shregs.msr = val; + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_MSR); +} + +static inline u64 __kvmppc_get_msr_hv(struct kvm_vcpu *vcpu) +{ + WARN_ON(kvmhv_nestedv2_cached_reload(vcpu, KVMPPC_GSID_MSR) < 0); + return vcpu->arch.shregs.msr; +} + +#define KVMPPC_BOOK3S_HV_VCPU_ACCESSOR_SET(reg, size, iden) \ +static inline void kvmppc_set_##reg ##_hv(struct kvm_vcpu *vcpu, u##size val) \ +{ \ + vcpu->arch.reg = val; \ + kvmhv_nestedv2_mark_dirty(vcpu, iden); \ +} + +#define KVMPPC_BOOK3S_HV_VCPU_ACCESSOR_GET(reg, size, iden) \ +static inline u##size kvmppc_get_##reg ##_hv(struct kvm_vcpu *vcpu) \ +{ \ + kvmhv_nestedv2_cached_reload(vcpu, iden); \ + return vcpu->arch.reg; \ +} + +#define KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(reg, size, iden) \ + KVMPPC_BOOK3S_HV_VCPU_ACCESSOR_SET(reg, size, iden) \ + KVMPPC_BOOK3S_HV_VCPU_ACCESSOR_GET(reg, size, iden) \ + +#define KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR_SET(reg, size, iden) \ +static inline void kvmppc_set_##reg ##_hv(struct kvm_vcpu *vcpu, int i, u##size val) \ +{ \ + vcpu->arch.reg[i] = val; \ + kvmhv_nestedv2_mark_dirty(vcpu, iden(i)); \ +} + +#define KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR_GET(reg, size, iden) \ +static inline u##size kvmppc_get_##reg ##_hv(struct kvm_vcpu *vcpu, int i) \ +{ \ + WARN_ON(kvmhv_nestedv2_cached_reload(vcpu, iden(i)) < 0); \ + return vcpu->arch.reg[i]; \ +} + +#define KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR(reg, size, iden) \ + KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR_SET(reg, size, iden) \ + KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR_GET(reg, size, iden) \ + +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(mmcra, 64, KVMPPC_GSID_MMCRA) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(hfscr, 64, KVMPPC_GSID_HFSCR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(fscr, 64, KVMPPC_GSID_FSCR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dscr, 64, KVMPPC_GSID_DSCR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(purr, 64, KVMPPC_GSID_PURR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(spurr, 64, KVMPPC_GSID_SPURR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(amr, 64, KVMPPC_GSID_AMR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(uamor, 64, KVMPPC_GSID_UAMOR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(siar, 64, KVMPPC_GSID_SIAR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(sdar, 64, KVMPPC_GSID_SDAR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(iamr, 64, KVMPPC_GSID_IAMR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr0, 64, KVMPPC_GSID_DAWR0) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawr1, 64, KVMPPC_GSID_DAWR1) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawrx0, 64, KVMPPC_GSID_DAWRX0) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dawrx1, 64, KVMPPC_GSID_DAWRX1) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(dexcr, 64, KVMPPC_GSID_DEXCR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(hashkeyr, 64, KVMPPC_GSID_HASHKEYR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(hashpkeyr, 64, KVMPPC_GSID_HASHPKEYR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ciabr, 64, KVMPPC_GSID_CIABR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(wort, 64, KVMPPC_GSID_WORT) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ppr, 64, KVMPPC_GSID_PPR) +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(ctrl, 64, KVMPPC_GSID_CTRL); + +KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR(mmcr, 64, KVMPPC_GSID_MMCR) +KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR(sier, 64, KVMPPC_GSID_SIER) +KVMPPC_BOOK3S_HV_VCPU_ARRAY_ACCESSOR(pmc, 32, KVMPPC_GSID_PMC) + +KVMPPC_BOOK3S_HV_VCPU_ACCESSOR(pspb, 32, KVMPPC_GSID_PSPB) diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index da85f046377a..fa0e3a22cac0 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c @@ -32,6 +32,7 @@ #include "book3s_xics.h" #include "book3s_xive.h" +#include "book3s_hv.h" /* * Hash page table alignment on newer cpus(CPU_FTR_ARCH_206) @@ -182,9 +183,13 @@ EXPORT_SYMBOL_GPL(kvmppc_hwrng_present); long kvmppc_rm_h_random(struct kvm_vcpu *vcpu) { + unsigned long rand; + if (ppc_md.get_random_seed && - ppc_md.get_random_seed(&vcpu->arch.regs.gpr[4])) + ppc_md.get_random_seed(&rand)) { + kvmppc_set_gpr(vcpu, 4, rand); return H_SUCCESS; + } return H_HARDWARE; } @@ -406,7 +411,7 @@ static long kvmppc_read_one_intr(bool *again) return 1; /* see if a host IPI is pending */ - host_ipi = local_paca->kvm_hstate.host_ipi; + host_ipi = READ_ONCE(local_paca->kvm_hstate.host_ipi); if (host_ipi) return 1; @@ -466,7 +471,7 @@ static long kvmppc_read_one_intr(bool *again) * meantime. If it's clear, we bounce the interrupt to the * guest */ - host_ipi = local_paca->kvm_hstate.host_ipi; + host_ipi = READ_ONCE(local_paca->kvm_hstate.host_ipi); if (unlikely(host_ipi != 0)) { /* We raced with the host, * we need to resend that IPI, bummer @@ -510,7 +515,7 @@ void kvmppc_set_msr_hv(struct kvm_vcpu *vcpu, u64 msr) */ if ((msr & MSR_TS_MASK) == MSR_TS_MASK) msr &= ~MSR_TS_MASK; - vcpu->arch.shregs.msr = msr; + __kvmppc_set_msr_hv(vcpu, msr); kvmppc_end_cede(vcpu); } EXPORT_SYMBOL_GPL(kvmppc_set_msr_hv); @@ -548,7 +553,7 @@ static void inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 srr1_flags) kvmppc_set_srr0(vcpu, pc); kvmppc_set_srr1(vcpu, (msr & SRR1_MSR_BITS) | srr1_flags); kvmppc_set_pc(vcpu, new_pc); - vcpu->arch.shregs.msr = new_msr; + __kvmppc_set_msr_hv(vcpu, new_msr); } void kvmppc_inject_interrupt_hv(struct kvm_vcpu *vcpu, int vec, u64 srr1_flags) diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 5a64a1341e6f..5f8c2321cfb5 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -32,7 +32,7 @@ void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) struct kvmppc_vcore *vc = vcpu->arch.vcore; hr->pcr = vc->pcr | PCR_MASK; - hr->dpdes = vc->dpdes; + hr->dpdes = vcpu->arch.doorbell_request; hr->hfscr = vcpu->arch.hfscr; hr->tb_offset = vc->tb_offset; hr->dawr0 = vcpu->arch.dawr0; @@ -55,7 +55,7 @@ void kvmhv_save_hv_regs(struct kvm_vcpu *vcpu, struct hv_guest_state *hr) hr->dawrx1 = vcpu->arch.dawrx1; } -/* Use noinline_for_stack due to https://bugs.llvm.org/show_bug.cgi?id=49610 */ +/* Use noinline_for_stack due to https://llvm.org/pr49610 */ static noinline_for_stack void byteswap_pt_regs(struct pt_regs *regs) { unsigned long *addr = (unsigned long *) regs; @@ -105,7 +105,7 @@ static void save_hv_return_state(struct kvm_vcpu *vcpu, { struct kvmppc_vcore *vc = vcpu->arch.vcore; - hr->dpdes = vc->dpdes; + hr->dpdes = vcpu->arch.doorbell_request; hr->purr = vcpu->arch.purr; hr->spurr = vcpu->arch.spurr; hr->ic = vcpu->arch.ic; @@ -143,7 +143,7 @@ static void restore_hv_regs(struct kvm_vcpu *vcpu, const struct hv_guest_state * struct kvmppc_vcore *vc = vcpu->arch.vcore; vc->pcr = hr->pcr | PCR_MASK; - vc->dpdes = hr->dpdes; + vcpu->arch.doorbell_request = hr->dpdes; vcpu->arch.hfscr = hr->hfscr; vcpu->arch.dawr0 = hr->dawr0; vcpu->arch.dawrx0 = hr->dawrx0; @@ -170,7 +170,13 @@ void kvmhv_restore_hv_return_state(struct kvm_vcpu *vcpu, { struct kvmppc_vcore *vc = vcpu->arch.vcore; - vc->dpdes = hr->dpdes; + /* + * This L2 vCPU might have received a doorbell while H_ENTER_NESTED was being handled. + * Make sure we preserve the doorbell if it was either: + * a) Sent after H_ENTER_NESTED was called on this vCPU (arch.doorbell_request would be 1) + * b) Doorbell was not handled and L2 exited for some other reason (hr->dpdes would be 1) + */ + vcpu->arch.doorbell_request = vcpu->arch.doorbell_request | hr->dpdes; vcpu->arch.hfscr = hr->hfscr; vcpu->arch.purr = hr->purr; vcpu->arch.spurr = hr->spurr; @@ -428,10 +434,12 @@ long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu) return vcpu->arch.trap; } +unsigned long nested_capabilities; + long kvmhv_nested_init(void) { long int ptb_order; - unsigned long ptcr; + unsigned long ptcr, host_capabilities; long rc; if (!kvmhv_on_pseries()) @@ -439,6 +447,31 @@ long kvmhv_nested_init(void) if (!radix_enabled()) return -ENODEV; + rc = plpar_guest_get_capabilities(0, &host_capabilities); + if (rc == H_SUCCESS) { + unsigned long capabilities = 0; + + if (cpu_has_feature(CPU_FTR_P11_PVR)) + capabilities |= H_GUEST_CAP_POWER11; + if (cpu_has_feature(CPU_FTR_ARCH_31)) + capabilities |= H_GUEST_CAP_POWER10; + if (cpu_has_feature(CPU_FTR_ARCH_300)) + capabilities |= H_GUEST_CAP_POWER9; + + nested_capabilities = capabilities & host_capabilities; + rc = plpar_guest_set_capabilities(0, nested_capabilities); + if (rc != H_SUCCESS) { + pr_err("kvm-hv: Could not configure parent hypervisor capabilities (rc=%ld)", + rc); + return -ENODEV; + } + + static_branch_enable(&__kvmhv_is_nestedv2); + return 0; + } + + pr_info("kvm-hv: nestedv2 get capabilities hcall failed, falling back to nestedv1 (rc=%ld)\n", + rc); /* Partition table entry is 1<<4 bytes in size, hence the 4. */ ptb_order = KVM_MAX_NESTED_GUESTS_SHIFT + 4; /* Minimum partition table size is 1<<12 bytes */ @@ -478,7 +511,7 @@ void kvmhv_nested_exit(void) } } -static void kvmhv_flush_lpid(unsigned int lpid) +void kvmhv_flush_lpid(u64 lpid) { long rc; @@ -500,17 +533,22 @@ static void kvmhv_flush_lpid(unsigned int lpid) pr_err("KVM: TLB LPID invalidation hcall failed, rc=%ld\n", rc); } -void kvmhv_set_ptbl_entry(unsigned int lpid, u64 dw0, u64 dw1) +void kvmhv_set_ptbl_entry(u64 lpid, u64 dw0, u64 dw1) { if (!kvmhv_on_pseries()) { mmu_partition_table_set_entry(lpid, dw0, dw1, true); return; } - pseries_partition_tb[lpid].patb0 = cpu_to_be64(dw0); - pseries_partition_tb[lpid].patb1 = cpu_to_be64(dw1); - /* L0 will do the necessary barriers */ - kvmhv_flush_lpid(lpid); + if (kvmhv_is_nestedv1()) { + pseries_partition_tb[lpid].patb0 = cpu_to_be64(dw0); + pseries_partition_tb[lpid].patb1 = cpu_to_be64(dw1); + /* L0 will do the necessary barriers */ + kvmhv_flush_lpid(lpid); + } + + if (kvmhv_is_nestedv2()) + kvmhv_nestedv2_set_ptbl_entry(lpid, dw0, dw1); } static void kvmhv_set_nested_ptbl(struct kvm_nested_guest *gp) @@ -1497,7 +1535,6 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, unsigned long n_gpa, gpa, gfn, perm = 0UL; unsigned int shift, l1_shift, level; bool writing = !!(dsisr & DSISR_ISSTORE); - bool kvm_ro = false; long int ret; if (!gp->l1_gr_to_hr) { @@ -1560,7 +1597,9 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) { if (dsisr & (DSISR_PRTABLE_FAULT | DSISR_BADACCESS)) { /* unusual error -> reflect to the guest as a DSI */ - kvmppc_core_queue_data_storage(vcpu, ea, dsisr); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, dsisr); return RESUME_GUEST; } @@ -1570,11 +1609,11 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, if (memslot->flags & KVM_MEM_READONLY) { if (writing) { /* Give the guest a DSI */ - kvmppc_core_queue_data_storage(vcpu, ea, - DSISR_ISSTORE | DSISR_PROTFAULT); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + ea, DSISR_ISSTORE | DSISR_PROTFAULT); return RESUME_GUEST; } - kvm_ro = true; } /* 2. Find the host pte for this L1 guest real address */ @@ -1596,7 +1635,7 @@ static long int __kvmhv_nested_page_fault(struct kvm_vcpu *vcpu, if (!pte_present(pte) || (writing && !(pte_val(pte) & _PAGE_WRITE))) { /* No suitable pte found -> try to insert a mapping */ ret = kvmppc_book3s_instantiate_page(vcpu, gpa, memslot, - writing, kvm_ro, &pte, &level); + writing, &pte, &level); if (ret == -EAGAIN) return RESUME_GUEST; else if (ret) diff --git a/arch/powerpc/kvm/book3s_hv_nestedv2.c b/arch/powerpc/kvm/book3s_hv_nestedv2.c new file mode 100644 index 000000000000..87691cf86cae --- /dev/null +++ b/arch/powerpc/kvm/book3s_hv_nestedv2.c @@ -0,0 +1,1072 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2023 Jordan Niethe, IBM Corp. <jniethe5@gmail.com> + * + * Authors: + * Jordan Niethe <jniethe5@gmail.com> + * + * Description: KVM functions specific to running on Book 3S + * processors as a NESTEDv2 guest. + * + */ + +#include "linux/blk-mq.h" +#include "linux/console.h" +#include "linux/gfp_types.h" +#include "linux/signal.h" +#include <linux/kernel.h> +#include <linux/kvm_host.h> +#include <linux/pgtable.h> + +#include <asm/kvm_ppc.h> +#include <asm/kvm_book3s.h> +#include <asm/hvcall.h> +#include <asm/pgalloc.h> +#include <asm/reg.h> +#include <asm/plpar_wrappers.h> +#include <asm/guest-state-buffer.h> +#include "trace_hv.h" + +struct static_key_false __kvmhv_is_nestedv2 __read_mostly; +EXPORT_SYMBOL_GPL(__kvmhv_is_nestedv2); + + +static size_t +gs_msg_ops_kvmhv_nestedv2_config_get_size(struct kvmppc_gs_msg *gsm) +{ + u16 ids[] = { + KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE, + KVMPPC_GSID_RUN_INPUT, + KVMPPC_GSID_RUN_OUTPUT, + + }; + size_t size = 0; + + for (int i = 0; i < ARRAY_SIZE(ids); i++) + size += kvmppc_gse_total_size(kvmppc_gsid_size(ids[i])); + return size; +} + +static int +gs_msg_ops_kvmhv_nestedv2_config_fill_info(struct kvmppc_gs_buff *gsb, + struct kvmppc_gs_msg *gsm) +{ + struct kvmhv_nestedv2_config *cfg; + int rc; + + cfg = gsm->data; + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE)) { + rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE, + cfg->vcpu_run_output_size); + if (rc < 0) + return rc; + } + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_RUN_INPUT)) { + rc = kvmppc_gse_put_buff_info(gsb, KVMPPC_GSID_RUN_INPUT, + cfg->vcpu_run_input_cfg); + if (rc < 0) + return rc; + } + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_RUN_OUTPUT)) { + rc = kvmppc_gse_put_buff_info(gsb, KVMPPC_GSID_RUN_OUTPUT, + cfg->vcpu_run_output_cfg); + if (rc < 0) + return rc; + } + + return 0; +} + +static int +gs_msg_ops_kvmhv_nestedv2_config_refresh_info(struct kvmppc_gs_msg *gsm, + struct kvmppc_gs_buff *gsb) +{ + struct kvmhv_nestedv2_config *cfg; + struct kvmppc_gs_parser gsp = { 0 }; + struct kvmppc_gs_elem *gse; + int rc; + + cfg = gsm->data; + + rc = kvmppc_gse_parse(&gsp, gsb); + if (rc < 0) + return rc; + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE); + if (gse) + cfg->vcpu_run_output_size = kvmppc_gse_get_u64(gse); + return 0; +} + +static struct kvmppc_gs_msg_ops config_msg_ops = { + .get_size = gs_msg_ops_kvmhv_nestedv2_config_get_size, + .fill_info = gs_msg_ops_kvmhv_nestedv2_config_fill_info, + .refresh_info = gs_msg_ops_kvmhv_nestedv2_config_refresh_info, +}; + +static size_t gs_msg_ops_vcpu_get_size(struct kvmppc_gs_msg *gsm) +{ + struct kvmppc_gs_bitmap gsbm = { 0 }; + size_t size = 0; + u16 iden; + + kvmppc_gsbm_fill(&gsbm); + kvmppc_gsbm_for_each(&gsbm, iden) + { + switch (iden) { + case KVMPPC_GSID_HOST_STATE_SIZE: + case KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE: + case KVMPPC_GSID_PARTITION_TABLE: + case KVMPPC_GSID_PROCESS_TABLE: + case KVMPPC_GSID_RUN_INPUT: + case KVMPPC_GSID_RUN_OUTPUT: + /* Host wide counters */ + case KVMPPC_GSID_L0_GUEST_HEAP: + case KVMPPC_GSID_L0_GUEST_HEAP_MAX: + case KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE: + case KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX: + case KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM: + break; + default: + size += kvmppc_gse_total_size(kvmppc_gsid_size(iden)); + } + } + return size; +} + +static int gs_msg_ops_vcpu_fill_info(struct kvmppc_gs_buff *gsb, + struct kvmppc_gs_msg *gsm) +{ + struct kvm_vcpu *vcpu; + vector128 v; + int rc, i; + u16 iden; + u32 arch_compat = 0; + + vcpu = gsm->data; + + kvmppc_gsm_for_each(gsm, iden) + { + rc = 0; + + if ((gsm->flags & KVMPPC_GS_FLAGS_WIDE) != + (kvmppc_gsid_flags(iden) & KVMPPC_GS_FLAGS_WIDE)) + continue; + + switch (iden) { + case KVMPPC_GSID_DSCR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dscr); + break; + case KVMPPC_GSID_MMCRA: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.mmcra); + break; + case KVMPPC_GSID_HFSCR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hfscr); + break; + case KVMPPC_GSID_PURR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.purr); + break; + case KVMPPC_GSID_SPURR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.spurr); + break; + case KVMPPC_GSID_AMR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.amr); + break; + case KVMPPC_GSID_UAMOR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.uamor); + break; + case KVMPPC_GSID_SIAR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.siar); + break; + case KVMPPC_GSID_SDAR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.sdar); + break; + case KVMPPC_GSID_IAMR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.iamr); + break; + case KVMPPC_GSID_DAWR0: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dawr0); + break; + case KVMPPC_GSID_DAWR1: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dawr1); + break; + case KVMPPC_GSID_DAWRX0: + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.dawrx0); + break; + case KVMPPC_GSID_DAWRX1: + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.dawrx1); + break; + case KVMPPC_GSID_DEXCR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.dexcr); + break; + case KVMPPC_GSID_HASHKEYR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hashkeyr); + break; + case KVMPPC_GSID_HASHPKEYR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.hashpkeyr); + break; + case KVMPPC_GSID_CIABR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ciabr); + break; + case KVMPPC_GSID_WORT: + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.wort); + break; + case KVMPPC_GSID_PPR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ppr); + break; + case KVMPPC_GSID_PSPB: + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.pspb); + break; + case KVMPPC_GSID_TAR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.tar); + break; + case KVMPPC_GSID_FSCR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.fscr); + break; + case KVMPPC_GSID_EBBHR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ebbhr); + break; + case KVMPPC_GSID_EBBRR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ebbrr); + break; + case KVMPPC_GSID_BESCR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.bescr); + break; + case KVMPPC_GSID_IC: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ic); + break; + case KVMPPC_GSID_CTRL: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.ctrl); + break; + case KVMPPC_GSID_PIDR: + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.pid); + break; + case KVMPPC_GSID_AMOR: { + u64 amor = ~0; + + rc = kvmppc_gse_put_u64(gsb, iden, amor); + break; + } + case KVMPPC_GSID_VRSAVE: + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.vrsave); + break; + case KVMPPC_GSID_MMCR(0)... KVMPPC_GSID_MMCR(3): + i = iden - KVMPPC_GSID_MMCR(0); + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.mmcr[i]); + break; + case KVMPPC_GSID_SIER(0)... KVMPPC_GSID_SIER(2): + i = iden - KVMPPC_GSID_SIER(0); + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.sier[i]); + break; + case KVMPPC_GSID_PMC(0)... KVMPPC_GSID_PMC(5): + i = iden - KVMPPC_GSID_PMC(0); + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.pmc[i]); + break; + case KVMPPC_GSID_GPR(0)... KVMPPC_GSID_GPR(31): + i = iden - KVMPPC_GSID_GPR(0); + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.regs.gpr[i]); + break; + case KVMPPC_GSID_CR: + rc = kvmppc_gse_put_u32(gsb, iden, vcpu->arch.regs.ccr); + break; + case KVMPPC_GSID_XER: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.regs.xer); + break; + case KVMPPC_GSID_CTR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.regs.ctr); + break; + case KVMPPC_GSID_LR: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.regs.link); + break; + case KVMPPC_GSID_NIA: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.regs.nip); + break; + case KVMPPC_GSID_SRR0: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.shregs.srr0); + break; + case KVMPPC_GSID_SRR1: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.shregs.srr1); + break; + case KVMPPC_GSID_SPRG0: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.shregs.sprg0); + break; + case KVMPPC_GSID_SPRG1: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.shregs.sprg1); + break; + case KVMPPC_GSID_SPRG2: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.shregs.sprg2); + break; + case KVMPPC_GSID_SPRG3: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.shregs.sprg3); + break; + case KVMPPC_GSID_DAR: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.shregs.dar); + break; + case KVMPPC_GSID_DSISR: + rc = kvmppc_gse_put_u32(gsb, iden, + vcpu->arch.shregs.dsisr); + break; + case KVMPPC_GSID_MSR: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.shregs.msr); + break; + case KVMPPC_GSID_VTB: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.vcore->vtb); + break; + case KVMPPC_GSID_DPDES: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.vcore->dpdes); + break; + case KVMPPC_GSID_LPCR: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.vcore->lpcr); + break; + case KVMPPC_GSID_TB_OFFSET: + rc = kvmppc_gse_put_u64(gsb, iden, + vcpu->arch.vcore->tb_offset); + break; + case KVMPPC_GSID_FPSCR: + rc = kvmppc_gse_put_u64(gsb, iden, vcpu->arch.fp.fpscr); + break; + case KVMPPC_GSID_VSRS(0)... KVMPPC_GSID_VSRS(31): + i = iden - KVMPPC_GSID_VSRS(0); + memcpy(&v, &vcpu->arch.fp.fpr[i], + sizeof(vcpu->arch.fp.fpr[i])); + rc = kvmppc_gse_put_vector128(gsb, iden, &v); + break; +#ifdef CONFIG_VSX + case KVMPPC_GSID_VSCR: + rc = kvmppc_gse_put_u32(gsb, iden, + vcpu->arch.vr.vscr.u[3]); + break; + case KVMPPC_GSID_VSRS(32)... KVMPPC_GSID_VSRS(63): + i = iden - KVMPPC_GSID_VSRS(32); + rc = kvmppc_gse_put_vector128(gsb, iden, + &vcpu->arch.vr.vr[i]); + break; +#endif + case KVMPPC_GSID_DEC_EXPIRY_TB: { + u64 dw; + + dw = vcpu->arch.dec_expires - + vcpu->arch.vcore->tb_offset; + rc = kvmppc_gse_put_u64(gsb, iden, dw); + break; + } + case KVMPPC_GSID_LOGICAL_PVR: + /* + * Though 'arch_compat == 0' would mean the default + * compatibility, arch_compat, being a Guest Wide + * Element, cannot be filled with a value of 0 in GSB + * as this would result into a kernel trap. + * Hence, when `arch_compat == 0`, arch_compat should + * default to L1's PVR. + */ + if (!vcpu->arch.vcore->arch_compat) { + if (cpu_has_feature(CPU_FTR_P11_PVR)) + arch_compat = PVR_ARCH_31_P11; + else if (cpu_has_feature(CPU_FTR_ARCH_31)) + arch_compat = PVR_ARCH_31; + else if (cpu_has_feature(CPU_FTR_ARCH_300)) + arch_compat = PVR_ARCH_300; + } else { + arch_compat = vcpu->arch.vcore->arch_compat; + } + rc = kvmppc_gse_put_u32(gsb, iden, arch_compat); + break; + } + + if (rc < 0) + return rc; + } + + return 0; +} + +static int gs_msg_ops_vcpu_refresh_info(struct kvmppc_gs_msg *gsm, + struct kvmppc_gs_buff *gsb) +{ + struct kvmppc_gs_parser gsp = { 0 }; + struct kvmhv_nestedv2_io *io; + struct kvmppc_gs_bitmap *valids; + struct kvm_vcpu *vcpu; + struct kvmppc_gs_elem *gse; + vector128 v; + int rc, i; + u16 iden; + + vcpu = gsm->data; + + rc = kvmppc_gse_parse(&gsp, gsb); + if (rc < 0) + return rc; + + io = &vcpu->arch.nestedv2_io; + valids = &io->valids; + + kvmppc_gsp_for_each(&gsp, iden, gse) + { + switch (iden) { + case KVMPPC_GSID_DSCR: + vcpu->arch.dscr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_MMCRA: + vcpu->arch.mmcra = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_HFSCR: + vcpu->arch.hfscr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_PURR: + vcpu->arch.purr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SPURR: + vcpu->arch.spurr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_AMR: + vcpu->arch.amr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_UAMOR: + vcpu->arch.uamor = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SIAR: + vcpu->arch.siar = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SDAR: + vcpu->arch.sdar = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_IAMR: + vcpu->arch.iamr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_DAWR0: + vcpu->arch.dawr0 = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_DAWR1: + vcpu->arch.dawr1 = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_DAWRX0: + vcpu->arch.dawrx0 = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_DAWRX1: + vcpu->arch.dawrx1 = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_DEXCR: + vcpu->arch.dexcr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_HASHKEYR: + vcpu->arch.hashkeyr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_HASHPKEYR: + vcpu->arch.hashpkeyr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_CIABR: + vcpu->arch.ciabr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_WORT: + vcpu->arch.wort = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_PPR: + vcpu->arch.ppr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_PSPB: + vcpu->arch.pspb = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_TAR: + vcpu->arch.tar = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_FSCR: + vcpu->arch.fscr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_EBBHR: + vcpu->arch.ebbhr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_EBBRR: + vcpu->arch.ebbrr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_BESCR: + vcpu->arch.bescr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_IC: + vcpu->arch.ic = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_CTRL: + vcpu->arch.ctrl = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_PIDR: + vcpu->arch.pid = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_AMOR: + break; + case KVMPPC_GSID_VRSAVE: + vcpu->arch.vrsave = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_MMCR(0)... KVMPPC_GSID_MMCR(3): + i = iden - KVMPPC_GSID_MMCR(0); + vcpu->arch.mmcr[i] = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SIER(0)... KVMPPC_GSID_SIER(2): + i = iden - KVMPPC_GSID_SIER(0); + vcpu->arch.sier[i] = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_PMC(0)... KVMPPC_GSID_PMC(5): + i = iden - KVMPPC_GSID_PMC(0); + vcpu->arch.pmc[i] = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_GPR(0)... KVMPPC_GSID_GPR(31): + i = iden - KVMPPC_GSID_GPR(0); + vcpu->arch.regs.gpr[i] = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_CR: + vcpu->arch.regs.ccr = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_XER: + vcpu->arch.regs.xer = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_CTR: + vcpu->arch.regs.ctr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_LR: + vcpu->arch.regs.link = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_NIA: + vcpu->arch.regs.nip = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SRR0: + vcpu->arch.shregs.srr0 = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SRR1: + vcpu->arch.shregs.srr1 = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SPRG0: + vcpu->arch.shregs.sprg0 = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SPRG1: + vcpu->arch.shregs.sprg1 = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SPRG2: + vcpu->arch.shregs.sprg2 = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_SPRG3: + vcpu->arch.shregs.sprg3 = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_DAR: + vcpu->arch.shregs.dar = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_DSISR: + vcpu->arch.shregs.dsisr = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_MSR: + vcpu->arch.shregs.msr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_VTB: + vcpu->arch.vcore->vtb = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_DPDES: + vcpu->arch.vcore->dpdes = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_LPCR: + vcpu->arch.vcore->lpcr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_TB_OFFSET: + vcpu->arch.vcore->tb_offset = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_FPSCR: + vcpu->arch.fp.fpscr = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_VSRS(0)... KVMPPC_GSID_VSRS(31): + kvmppc_gse_get_vector128(gse, &v); + i = iden - KVMPPC_GSID_VSRS(0); + memcpy(&vcpu->arch.fp.fpr[i], &v, + sizeof(vcpu->arch.fp.fpr[i])); + break; +#ifdef CONFIG_VSX + case KVMPPC_GSID_VSCR: + vcpu->arch.vr.vscr.u[3] = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_VSRS(32)... KVMPPC_GSID_VSRS(63): + i = iden - KVMPPC_GSID_VSRS(32); + kvmppc_gse_get_vector128(gse, &vcpu->arch.vr.vr[i]); + break; +#endif + case KVMPPC_GSID_HDAR: + vcpu->arch.fault_dar = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_HDSISR: + vcpu->arch.fault_dsisr = kvmppc_gse_get_u32(gse); + break; + case KVMPPC_GSID_ASDR: + vcpu->arch.fault_gpa = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_HEIR: + vcpu->arch.emul_inst = kvmppc_gse_get_u64(gse); + break; + case KVMPPC_GSID_DEC_EXPIRY_TB: { + u64 dw; + + dw = kvmppc_gse_get_u64(gse); + vcpu->arch.dec_expires = + dw + vcpu->arch.vcore->tb_offset; + break; + } + case KVMPPC_GSID_LOGICAL_PVR: + vcpu->arch.vcore->arch_compat = kvmppc_gse_get_u32(gse); + break; + default: + continue; + } + kvmppc_gsbm_set(valids, iden); + } + + return 0; +} + +static struct kvmppc_gs_msg_ops vcpu_message_ops = { + .get_size = gs_msg_ops_vcpu_get_size, + .fill_info = gs_msg_ops_vcpu_fill_info, + .refresh_info = gs_msg_ops_vcpu_refresh_info, +}; + +static int kvmhv_nestedv2_host_create(struct kvm_vcpu *vcpu, + struct kvmhv_nestedv2_io *io) +{ + struct kvmhv_nestedv2_config *cfg; + struct kvmppc_gs_buff *gsb, *vcpu_run_output, *vcpu_run_input; + unsigned long guest_id, vcpu_id; + struct kvmppc_gs_msg *gsm, *vcpu_message, *vcore_message; + int rc; + + cfg = &io->cfg; + guest_id = vcpu->kvm->arch.lpid; + vcpu_id = vcpu->vcpu_id; + + gsm = kvmppc_gsm_new(&config_msg_ops, cfg, KVMPPC_GS_FLAGS_WIDE, + GFP_KERNEL); + if (!gsm) { + rc = -ENOMEM; + goto err; + } + + gsb = kvmppc_gsb_new(kvmppc_gsm_size(gsm), guest_id, vcpu_id, + GFP_KERNEL); + if (!gsb) { + rc = -ENOMEM; + goto free_gsm; + } + + rc = kvmppc_gsb_receive_datum(gsb, gsm, + KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE); + if (rc < 0) { + pr_err("KVM-NESTEDv2: couldn't get vcpu run output buffer minimum size\n"); + goto free_gsb; + } + + vcpu_run_output = kvmppc_gsb_new(cfg->vcpu_run_output_size, guest_id, + vcpu_id, GFP_KERNEL); + if (!vcpu_run_output) { + rc = -ENOMEM; + goto free_gsb; + } + + cfg->vcpu_run_output_cfg.address = kvmppc_gsb_paddress(vcpu_run_output); + cfg->vcpu_run_output_cfg.size = kvmppc_gsb_capacity(vcpu_run_output); + io->vcpu_run_output = vcpu_run_output; + + gsm->flags = 0; + rc = kvmppc_gsb_send_datum(gsb, gsm, KVMPPC_GSID_RUN_OUTPUT); + if (rc < 0) { + pr_err("KVM-NESTEDv2: couldn't set vcpu run output buffer\n"); + goto free_gs_out; + } + + vcpu_message = kvmppc_gsm_new(&vcpu_message_ops, vcpu, 0, GFP_KERNEL); + if (!vcpu_message) { + rc = -ENOMEM; + goto free_gs_out; + } + kvmppc_gsm_include_all(vcpu_message); + + io->vcpu_message = vcpu_message; + + vcpu_run_input = kvmppc_gsb_new(kvmppc_gsm_size(vcpu_message), guest_id, + vcpu_id, GFP_KERNEL); + if (!vcpu_run_input) { + rc = -ENOMEM; + goto free_vcpu_message; + } + + io->vcpu_run_input = vcpu_run_input; + cfg->vcpu_run_input_cfg.address = kvmppc_gsb_paddress(vcpu_run_input); + cfg->vcpu_run_input_cfg.size = kvmppc_gsb_capacity(vcpu_run_input); + rc = kvmppc_gsb_send_datum(gsb, gsm, KVMPPC_GSID_RUN_INPUT); + if (rc < 0) { + pr_err("KVM-NESTEDv2: couldn't set vcpu run input buffer\n"); + goto free_vcpu_run_input; + } + + vcore_message = kvmppc_gsm_new(&vcpu_message_ops, vcpu, + KVMPPC_GS_FLAGS_WIDE, GFP_KERNEL); + if (!vcore_message) { + rc = -ENOMEM; + goto free_vcpu_run_input; + } + + kvmppc_gsm_include_all(vcore_message); + kvmppc_gsbm_clear(&vcore_message->bitmap, KVMPPC_GSID_LOGICAL_PVR); + io->vcore_message = vcore_message; + + kvmppc_gsbm_fill(&io->valids); + kvmppc_gsm_free(gsm); + kvmppc_gsb_free(gsb); + return 0; + +free_vcpu_run_input: + kvmppc_gsb_free(vcpu_run_input); +free_vcpu_message: + kvmppc_gsm_free(vcpu_message); +free_gs_out: + kvmppc_gsb_free(vcpu_run_output); +free_gsb: + kvmppc_gsb_free(gsb); +free_gsm: + kvmppc_gsm_free(gsm); +err: + return rc; +} + +/** + * __kvmhv_nestedv2_mark_dirty() - mark a Guest State ID to be sent to the host + * @vcpu: vcpu + * @iden: guest state ID + * + * Mark a guest state ID as having been changed by the L1 host and thus + * the new value must be sent to the L0 hypervisor. See kvmhv_nestedv2_flush_vcpu() + */ +int __kvmhv_nestedv2_mark_dirty(struct kvm_vcpu *vcpu, u16 iden) +{ + struct kvmhv_nestedv2_io *io; + struct kvmppc_gs_bitmap *valids; + struct kvmppc_gs_msg *gsm; + + if (!iden) + return 0; + + io = &vcpu->arch.nestedv2_io; + valids = &io->valids; + gsm = io->vcpu_message; + kvmppc_gsm_include(gsm, iden); + gsm = io->vcore_message; + kvmppc_gsm_include(gsm, iden); + kvmppc_gsbm_set(valids, iden); + return 0; +} +EXPORT_SYMBOL_GPL(__kvmhv_nestedv2_mark_dirty); + +/** + * __kvmhv_nestedv2_cached_reload() - reload a Guest State ID from the host + * @vcpu: vcpu + * @iden: guest state ID + * + * Reload the value for the guest state ID from the L0 host into the L1 host. + * This is cached so that going out to the L0 host only happens if necessary. + */ +int __kvmhv_nestedv2_cached_reload(struct kvm_vcpu *vcpu, u16 iden) +{ + struct kvmhv_nestedv2_io *io; + struct kvmppc_gs_bitmap *valids; + struct kvmppc_gs_buff *gsb; + struct kvmppc_gs_msg gsm; + int rc; + + if (!iden) + return 0; + + io = &vcpu->arch.nestedv2_io; + valids = &io->valids; + if (kvmppc_gsbm_test(valids, iden)) + return 0; + + gsb = io->vcpu_run_input; + kvmppc_gsm_init(&gsm, &vcpu_message_ops, vcpu, kvmppc_gsid_flags(iden)); + rc = kvmppc_gsb_receive_datum(gsb, &gsm, iden); + if (rc < 0) { + pr_err("KVM-NESTEDv2: couldn't get GSID: 0x%x\n", iden); + return rc; + } + return 0; +} +EXPORT_SYMBOL_GPL(__kvmhv_nestedv2_cached_reload); + +/** + * kvmhv_nestedv2_flush_vcpu() - send modified Guest State IDs to the host + * @vcpu: vcpu + * @time_limit: hdec expiry tb + * + * Send the values marked by __kvmhv_nestedv2_mark_dirty() to the L0 host. + * Thread wide values are copied to the H_GUEST_RUN_VCPU input buffer. Guest + * wide values need to be sent with H_GUEST_SET first. + * + * The hdec tb offset is always sent to L0 host. + */ +int kvmhv_nestedv2_flush_vcpu(struct kvm_vcpu *vcpu, u64 time_limit) +{ + struct kvmhv_nestedv2_io *io; + struct kvmppc_gs_buff *gsb; + struct kvmppc_gs_msg *gsm; + int rc; + + io = &vcpu->arch.nestedv2_io; + gsb = io->vcpu_run_input; + gsm = io->vcore_message; + rc = kvmppc_gsb_send_data(gsb, gsm); + if (rc < 0) { + pr_err("KVM-NESTEDv2: couldn't set guest wide elements\n"); + return rc; + } + + gsm = io->vcpu_message; + kvmppc_gsb_reset(gsb); + rc = kvmppc_gsm_fill_info(gsm, gsb); + if (rc < 0) { + pr_err("KVM-NESTEDv2: couldn't fill vcpu run input buffer\n"); + return rc; + } + + rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_HDEC_EXPIRY_TB, time_limit); + if (rc < 0) + return rc; + return 0; +} +EXPORT_SYMBOL_GPL(kvmhv_nestedv2_flush_vcpu); + +/** + * kvmhv_nestedv2_set_ptbl_entry() - send partition and process table state to + * L0 host + * @lpid: guest id + * @dw0: partition table double word + * @dw1: process table double word + */ +int kvmhv_nestedv2_set_ptbl_entry(unsigned long lpid, u64 dw0, u64 dw1) +{ + struct kvmppc_gs_part_table patbl; + struct kvmppc_gs_proc_table prtbl; + struct kvmppc_gs_buff *gsb; + size_t size; + int rc; + + size = kvmppc_gse_total_size( + kvmppc_gsid_size(KVMPPC_GSID_PARTITION_TABLE)) + + kvmppc_gse_total_size( + kvmppc_gsid_size(KVMPPC_GSID_PROCESS_TABLE)) + + sizeof(struct kvmppc_gs_header); + gsb = kvmppc_gsb_new(size, lpid, 0, GFP_KERNEL); + if (!gsb) + return -ENOMEM; + + patbl.address = dw0 & RPDB_MASK; + patbl.ea_bits = ((((dw0 & RTS1_MASK) >> (RTS1_SHIFT - 3)) | + ((dw0 & RTS2_MASK) >> RTS2_SHIFT)) + + 31); + patbl.gpd_size = 1ul << ((dw0 & RPDS_MASK) + 3); + rc = kvmppc_gse_put_part_table(gsb, KVMPPC_GSID_PARTITION_TABLE, patbl); + if (rc < 0) + goto free_gsb; + + prtbl.address = dw1 & PRTB_MASK; + prtbl.gpd_size = 1ul << ((dw1 & PRTS_MASK) + 12); + rc = kvmppc_gse_put_proc_table(gsb, KVMPPC_GSID_PROCESS_TABLE, prtbl); + if (rc < 0) + goto free_gsb; + + rc = kvmppc_gsb_send(gsb, KVMPPC_GS_FLAGS_WIDE); + if (rc < 0) { + pr_err("KVM-NESTEDv2: couldn't set the PATE\n"); + goto free_gsb; + } + + kvmppc_gsb_free(gsb); + return 0; + +free_gsb: + kvmppc_gsb_free(gsb); + return rc; +} +EXPORT_SYMBOL_GPL(kvmhv_nestedv2_set_ptbl_entry); + +/** + * kvmhv_nestedv2_set_vpa() - register L2 VPA with L0 + * @vcpu: vcpu + * @vpa: L1 logical real address + */ +int kvmhv_nestedv2_set_vpa(struct kvm_vcpu *vcpu, unsigned long vpa) +{ + struct kvmhv_nestedv2_io *io; + struct kvmppc_gs_buff *gsb; + int rc = 0; + + io = &vcpu->arch.nestedv2_io; + gsb = io->vcpu_run_input; + + kvmppc_gsb_reset(gsb); + rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_VPA, vpa); + if (rc < 0) + goto out; + + rc = kvmppc_gsb_send(gsb, 0); + if (rc < 0) + pr_err("KVM-NESTEDv2: couldn't register the L2 VPA (rc=%d)\n", rc); + +out: + kvmppc_gsb_reset(gsb); + return rc; +} +EXPORT_SYMBOL_GPL(kvmhv_nestedv2_set_vpa); + +/** + * kvmhv_nestedv2_parse_output() - receive values from H_GUEST_RUN_VCPU output + * @vcpu: vcpu + * + * Parse the output buffer from H_GUEST_RUN_VCPU to update vcpu. + */ +int kvmhv_nestedv2_parse_output(struct kvm_vcpu *vcpu) +{ + struct kvmhv_nestedv2_io *io; + struct kvmppc_gs_buff *gsb; + struct kvmppc_gs_msg gsm; + + io = &vcpu->arch.nestedv2_io; + gsb = io->vcpu_run_output; + + vcpu->arch.fault_dar = 0; + vcpu->arch.fault_dsisr = 0; + vcpu->arch.fault_gpa = 0; + vcpu->arch.emul_inst = KVM_INST_FETCH_FAILED; + + kvmppc_gsm_init(&gsm, &vcpu_message_ops, vcpu, 0); + return kvmppc_gsm_refresh_info(&gsm, gsb); +} +EXPORT_SYMBOL_GPL(kvmhv_nestedv2_parse_output); + +static void kvmhv_nestedv2_host_free(struct kvm_vcpu *vcpu, + struct kvmhv_nestedv2_io *io) +{ + kvmppc_gsm_free(io->vcpu_message); + kvmppc_gsm_free(io->vcore_message); + kvmppc_gsb_free(io->vcpu_run_input); + kvmppc_gsb_free(io->vcpu_run_output); +} + +int __kvmhv_nestedv2_reload_ptregs(struct kvm_vcpu *vcpu, struct pt_regs *regs) +{ + struct kvmhv_nestedv2_io *io; + struct kvmppc_gs_bitmap *valids; + struct kvmppc_gs_buff *gsb; + struct kvmppc_gs_msg gsm; + int rc = 0; + + + io = &vcpu->arch.nestedv2_io; + valids = &io->valids; + + gsb = io->vcpu_run_input; + kvmppc_gsm_init(&gsm, &vcpu_message_ops, vcpu, 0); + + for (int i = 0; i < 32; i++) { + if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_GPR(i))) + kvmppc_gsm_include(&gsm, KVMPPC_GSID_GPR(i)); + } + + if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_CR)) + kvmppc_gsm_include(&gsm, KVMPPC_GSID_CR); + + if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_XER)) + kvmppc_gsm_include(&gsm, KVMPPC_GSID_XER); + + if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_CTR)) + kvmppc_gsm_include(&gsm, KVMPPC_GSID_CTR); + + if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_LR)) + kvmppc_gsm_include(&gsm, KVMPPC_GSID_LR); + + if (!kvmppc_gsbm_test(valids, KVMPPC_GSID_NIA)) + kvmppc_gsm_include(&gsm, KVMPPC_GSID_NIA); + + rc = kvmppc_gsb_receive_data(gsb, &gsm); + if (rc < 0) + pr_err("KVM-NESTEDv2: couldn't reload ptregs\n"); + + return rc; +} +EXPORT_SYMBOL_GPL(__kvmhv_nestedv2_reload_ptregs); + +int __kvmhv_nestedv2_mark_dirty_ptregs(struct kvm_vcpu *vcpu, + struct pt_regs *regs) +{ + for (int i = 0; i < 32; i++) + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_GPR(i)); + + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_CR); + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_XER); + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_CTR); + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_LR); + kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_NIA); + + return 0; +} +EXPORT_SYMBOL_GPL(__kvmhv_nestedv2_mark_dirty_ptregs); + +/** + * kvmhv_nestedv2_vcpu_create() - create nested vcpu for the NESTEDv2 API + * @vcpu: vcpu + * @io: NESTEDv2 nested io state + * + * Parse the output buffer from H_GUEST_RUN_VCPU to update vcpu. + */ +int kvmhv_nestedv2_vcpu_create(struct kvm_vcpu *vcpu, + struct kvmhv_nestedv2_io *io) +{ + long rc; + + rc = plpar_guest_create_vcpu(0, vcpu->kvm->arch.lpid, vcpu->vcpu_id); + + if (rc != H_SUCCESS) { + pr_err("KVM: Create Guest vcpu hcall failed, rc=%ld\n", rc); + switch (rc) { + case H_NOT_ENOUGH_RESOURCES: + case H_ABORTED: + return -ENOMEM; + case H_AUTHORITY: + return -EPERM; + default: + return -EINVAL; + } + } + + rc = kvmhv_nestedv2_host_create(vcpu, io); + + return rc; +} +EXPORT_SYMBOL_GPL(kvmhv_nestedv2_vcpu_create); + +/** + * kvmhv_nestedv2_vcpu_free() - free the NESTEDv2 state + * @vcpu: vcpu + * @io: NESTEDv2 nested io state + */ +void kvmhv_nestedv2_vcpu_free(struct kvm_vcpu *vcpu, + struct kvmhv_nestedv2_io *io) +{ + kvmhv_nestedv2_host_free(vcpu, io); +} +EXPORT_SYMBOL_GPL(kvmhv_nestedv2_vcpu_free); diff --git a/arch/powerpc/kvm/book3s_hv_p9_entry.c b/arch/powerpc/kvm/book3s_hv_p9_entry.c index 34f1db212824..34bc0a8a1288 100644 --- a/arch/powerpc/kvm/book3s_hv_p9_entry.c +++ b/arch/powerpc/kvm/book3s_hv_p9_entry.c @@ -305,7 +305,7 @@ static void switch_mmu_to_guest_radix(struct kvm *kvm, struct kvm_vcpu *vcpu, u6 u32 pid; lpid = nested ? nested->shadow_lpid : kvm->arch.lpid; - pid = vcpu->arch.pid; + pid = kvmppc_get_pid(vcpu); /* * Prior memory accesses to host PID Q3 must be completed before we @@ -330,7 +330,7 @@ static void switch_mmu_to_guest_hpt(struct kvm *kvm, struct kvm_vcpu *vcpu, u64 int i; lpid = kvm->arch.lpid; - pid = vcpu->arch.pid; + pid = kvmppc_get_pid(vcpu); /* * See switch_mmu_to_guest_radix. ptesync should not be required here diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index ccfd96965630..9012acadbca8 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c @@ -9,6 +9,7 @@ #include <linux/kvm.h> #include <linux/kvm_host.h> #include <linux/kernel.h> +#include <asm/lppaca.h> #include <asm/opal.h> #include <asm/mce.h> #include <asm/machdep.h> @@ -173,14 +174,14 @@ long kvmppc_p9_realmode_hmi_handler(struct kvm_vcpu *vcpu) ppc_md.hmi_exception_early(NULL); out: - if (vc->tb_offset) { + if (kvmppc_get_tb_offset(vcpu)) { u64 new_tb = mftb() + vc->tb_offset; mtspr(SPRN_TBU40, new_tb); if ((mftb() & 0xffffff) < (new_tb & 0xffffff)) { new_tb += 0x1000000; mtspr(SPRN_TBU40, new_tb); } - vc->tb_offset_applied = vc->tb_offset; + vc->tb_offset_applied = kvmppc_get_tb_offset(vcpu); } return ret; diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c index 9182324dbef9..17cb75a127b0 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c @@ -776,8 +776,8 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags, r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C)); r &= ~HPTE_GR_RESERVED; } - vcpu->arch.regs.gpr[4 + i * 2] = v; - vcpu->arch.regs.gpr[5 + i * 2] = r; + kvmppc_set_gpr(vcpu, 4 + i * 2, v); + kvmppc_set_gpr(vcpu, 5 + i * 2, r); } return H_SUCCESS; } @@ -824,7 +824,7 @@ long kvmppc_h_clear_ref(struct kvm_vcpu *vcpu, unsigned long flags, } } } - vcpu->arch.regs.gpr[4] = gr; + kvmppc_set_gpr(vcpu, 4, gr); ret = H_SUCCESS; out: unlock_hpte(hpte, v & ~HPTE_V_HVLOCK); @@ -872,7 +872,7 @@ long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags, kvmppc_set_dirty_from_hpte(kvm, v, gr); } } - vcpu->arch.regs.gpr[4] = gr; + kvmppc_set_gpr(vcpu, 4, gr); ret = H_SUCCESS; out: unlock_hpte(hpte, v & ~HPTE_V_HVLOCK); diff --git a/arch/powerpc/kvm/book3s_hv_rm_xics.c b/arch/powerpc/kvm/book3s_hv_rm_xics.c index e165bfa842bf..f2636414d82a 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_xics.c +++ b/arch/powerpc/kvm/book3s_hv_rm_xics.c @@ -481,7 +481,7 @@ static void icp_rm_down_cppr(struct kvmppc_xics *xics, struct kvmppc_icp *icp, unsigned long xics_rm_h_xirr_x(struct kvm_vcpu *vcpu) { - vcpu->arch.regs.gpr[5] = get_tb(); + kvmppc_set_gpr(vcpu, 5, get_tb()); return xics_rm_h_xirr(vcpu); } @@ -518,7 +518,7 @@ unsigned long xics_rm_h_xirr(struct kvm_vcpu *vcpu) } while (!icp_rm_try_update(icp, old_state, new_state)); /* Return the result in GPR4 */ - vcpu->arch.regs.gpr[4] = xirr; + kvmppc_set_gpr(vcpu, 4, xirr); return check_too_hard(xics, icp); } @@ -837,7 +837,7 @@ static inline void this_cpu_inc_rm(unsigned int __percpu *addr) */ static void kvmppc_rm_handle_irq_desc(struct irq_desc *desc) { - this_cpu_inc_rm(desc->kstat_irqs); + this_cpu_inc_rm(&desc->kstat_irqs->cnt); __this_cpu_inc(kstat.irqs_sum); } diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index acf80915f406..83f7504349d2 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -10,6 +10,7 @@ * Authors: Alexander Graf <agraf@suse.de> */ +#include <linux/export.h> #include <linux/linkage.h> #include <linux/objtool.h> #include <asm/ppc_asm.h> @@ -24,7 +25,6 @@ #include <asm/exception-64s.h> #include <asm/kvm_book3s_asm.h> #include <asm/book3s/64/mmu-hash.h> -#include <asm/export.h> #include <asm/tm.h> #include <asm/opal.h> #include <asm/thread_info.h> @@ -381,7 +381,7 @@ kvm_secondary_got_guest: bne kvm_no_guest li r3,0 /* NULL argument */ - bl hmi_exception_realmode + bl CFUNC(hmi_exception_realmode) /* * At this point we have finished executing in the guest. * We need to wait for hwthread_req to become zero, since @@ -458,7 +458,7 @@ kvm_unsplit_nap: cmpwi r12, BOOK3S_INTERRUPT_HMI bne 55f li r3, 0 /* NULL argument */ - bl hmi_exception_realmode + bl CFUNC(hmi_exception_realmode) 55: /* * Ensure that secondary doesn't nap when it has @@ -502,8 +502,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) * * *****************************************************************************/ -.global kvmppc_hv_entry -kvmppc_hv_entry: +SYM_CODE_START_LOCAL(kvmppc_hv_entry) /* Required state: * @@ -859,7 +858,7 @@ deliver_guest_interrupt: /* r4 = vcpu, r13 = paca */ cmpdi r0, 0 beq 71f mr r3, r4 - bl kvmppc_guest_entry_inject_int + bl CFUNC(kvmppc_guest_entry_inject_int) ld r4, HSTATE_KVM_VCPU(r13) 71: ld r6, VCPU_SRR0(r4) @@ -940,6 +939,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) ld r4, VCPU_GPR(R4)(r4) HRFI_TO_GUEST b . +SYM_CODE_END(kvmppc_hv_entry) secondary_too_late: li r12, 0 @@ -1071,11 +1071,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) /* Save HEIR (HV emulation assist reg) in emul_inst if this is an HEI (HV emulation interrupt, e40) */ li r3,KVM_INST_FETCH_FAILED - stw r3,VCPU_LAST_INST(r9) + std r3,VCPU_LAST_INST(r9) cmpwi r12,BOOK3S_INTERRUPT_H_EMUL_ASSIST bne 11f mfspr r3,SPRN_HEIR -11: stw r3,VCPU_HEIR(r9) +11: std r3,VCPU_HEIR(r9) /* these are volatile across C function calls */ mfctr r3 @@ -1524,14 +1524,12 @@ kvm_flush_link_stack: /* Flush the link stack. On Power8 it's up to 32 entries in size. */ .rept 32 - ANNOTATE_INTRA_FUNCTION_CALL bl .+4 .endr /* And on Power9 it's up to 64. */ BEGIN_FTR_SECTION .rept 32 - ANNOTATE_INTRA_FUNCTION_CALL bl .+4 .endr END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300) @@ -1544,7 +1542,7 @@ kvmppc_guest_external: /* External interrupt, first check for host_ipi. If this is * set, we know the host wants us out so let's do it now */ - bl kvmppc_read_intr + bl CFUNC(kvmppc_read_intr) /* * Restore the active volatile registers after returning from @@ -1626,7 +1624,7 @@ kvmppc_hdsi: /* Search the hash table. */ mr r3, r9 /* vcpu pointer */ li r7, 1 /* data fault */ - bl kvmppc_hpte_hv_fault + bl CFUNC(kvmppc_hpte_hv_fault) ld r9, HSTATE_KVM_VCPU(r13) ld r10, VCPU_PC(r9) ld r11, VCPU_MSR(r9) @@ -1676,7 +1674,7 @@ fast_interrupt_c_return: mtmsrd r3 /* Store the result */ - stw r8, VCPU_LAST_INST(r9) + std r8, VCPU_LAST_INST(r9) /* Unset guest mode. */ li r0, KVM_GUEST_MODE_HOST_HV @@ -1702,7 +1700,7 @@ kvmppc_hisi: mr r4, r10 mr r6, r11 li r7, 0 /* instruction fault */ - bl kvmppc_hpte_hv_fault + bl CFUNC(kvmppc_hpte_hv_fault) ld r9, HSTATE_KVM_VCPU(r13) ld r10, VCPU_PC(r9) ld r11, VCPU_MSR(r9) @@ -2342,7 +2340,7 @@ hmi_realmode: lbz r0, HSTATE_PTID(r13) cmpwi r0, 0 bne guest_exit_cont - bl kvmppc_realmode_hmi_handler + bl CFUNC(kvmppc_realmode_hmi_handler) ld r9, HSTATE_KVM_VCPU(r13) li r12, BOOK3S_INTERRUPT_HMI b guest_exit_cont @@ -2413,7 +2411,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) 7: mflr r0 std r0, PPC_LR_STKOFF(r1) stdu r1, -PPC_MIN_STKFRM(r1) - bl kvmppc_read_intr + bl CFUNC(kvmppc_read_intr) nop li r12, BOOK3S_INTERRUPT_EXTERNAL cmpdi r3, 1 diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c b/arch/powerpc/kvm/book3s_hv_uvmem.c index 1d67baa5557a..e5000bef90f2 100644 --- a/arch/powerpc/kvm/book3s_hv_uvmem.c +++ b/arch/powerpc/kvm/book3s_hv_uvmem.c @@ -393,6 +393,7 @@ static int kvmppc_memslot_page_merge(struct kvm *kvm, { unsigned long gfn = memslot->base_gfn; unsigned long end, start = gfn_to_hva(kvm, gfn); + vm_flags_t vm_flags; int ret = 0; struct vm_area_struct *vma; int merge_flag = (merge) ? MADV_MERGEABLE : MADV_UNMERGEABLE; @@ -409,12 +410,16 @@ static int kvmppc_memslot_page_merge(struct kvm *kvm, ret = H_STATE; break; } + vma_start_write(vma); + /* Copy vm_flags to avoid partial modifications in ksm_madvise */ + vm_flags = vma->vm_flags; ret = ksm_madvise(vma, vma->vm_start, vma->vm_end, - merge_flag, &vma->vm_flags); + merge_flag, &vm_flags); if (ret) { ret = H_STATE; break; } + vm_flags_reset(vma, vm_flags); start = vma->vm_end; } while (end > vma->vm_end); @@ -718,7 +723,7 @@ static struct page *kvmppc_uvmem_get_page(unsigned long gpa, struct kvm *kvm) dpage = pfn_to_page(uvmem_pfn); dpage->zone_device_data = pvt; - zone_device_page_init(dpage); + zone_device_page_init(dpage, 0); return dpage; out_clear: spin_lock(&kvmppc_uvmem_bitmap_lock); @@ -853,7 +858,7 @@ unsigned long kvmppc_h_svm_init_done(struct kvm *kvm) } kvm->arch.secure_guest |= KVMPPC_SECURE_INIT_DONE; - pr_info("LPID %d went secure\n", kvm->arch.lpid); + pr_info("LPID %lld went secure\n", kvm->arch.lpid); out: srcu_read_unlock(&kvm->srcu, srcu_idx); @@ -874,9 +879,8 @@ static unsigned long kvmppc_share_page(struct kvm *kvm, unsigned long gpa, { int ret = H_PARAMETER; - struct page *uvmem_page; + struct page *page, *uvmem_page; struct kvmppc_uvmem_page_pvt *pvt; - unsigned long pfn; unsigned long gfn = gpa >> page_shift; int srcu_idx; unsigned long uvmem_pfn; @@ -896,8 +900,8 @@ static unsigned long kvmppc_share_page(struct kvm *kvm, unsigned long gpa, retry: mutex_unlock(&kvm->arch.uvmem_lock); - pfn = gfn_to_pfn(kvm, gfn); - if (is_error_noslot_pfn(pfn)) + page = gfn_to_page(kvm, gfn); + if (!page) goto out; mutex_lock(&kvm->arch.uvmem_lock); @@ -906,16 +910,16 @@ retry: pvt = uvmem_page->zone_device_data; pvt->skip_page_out = true; pvt->remove_gfn = false; /* it continues to be a valid GFN */ - kvm_release_pfn_clean(pfn); + kvm_release_page_unused(page); goto retry; } - if (!uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0, + if (!uv_page_in(kvm->arch.lpid, page_to_pfn(page) << page_shift, gpa, 0, page_shift)) { kvmppc_gfn_shared(gfn, kvm); ret = H_SUCCESS; } - kvm_release_pfn_clean(pfn); + kvm_release_page_clean(page); mutex_unlock(&kvm->arch.uvmem_lock); out: srcu_read_unlock(&kvm->srcu, srcu_idx); @@ -1010,8 +1014,9 @@ static vm_fault_t kvmppc_uvmem_migrate_to_ram(struct vm_fault *vmf) * to a normal PFN during H_SVM_PAGE_OUT. * Gets called with kvm->arch.uvmem_lock held. */ -static void kvmppc_uvmem_page_free(struct page *page) +static void kvmppc_uvmem_folio_free(struct folio *folio) { + struct page *page = &folio->page; unsigned long pfn = page_to_pfn(page) - (kvmppc_uvmem_pgmap.range.start >> PAGE_SHIFT); struct kvmppc_uvmem_page_pvt *pvt; @@ -1030,7 +1035,7 @@ static void kvmppc_uvmem_page_free(struct page *page) } static const struct dev_pagemap_ops kvmppc_uvmem_ops = { - .page_free = kvmppc_uvmem_page_free, + .folio_free = kvmppc_uvmem_folio_free, .migrate_to_ram = kvmppc_uvmem_migrate_to_ram, }; @@ -1078,21 +1083,21 @@ out: int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn) { - unsigned long pfn; + struct page *page; int ret = U_SUCCESS; - pfn = gfn_to_pfn(kvm, gfn); - if (is_error_noslot_pfn(pfn)) + page = gfn_to_page(kvm, gfn); + if (!page) return -EFAULT; mutex_lock(&kvm->arch.uvmem_lock); if (kvmppc_gfn_is_uvmem_pfn(gfn, kvm, NULL)) goto out; - ret = uv_page_in(kvm->arch.lpid, pfn << PAGE_SHIFT, gfn << PAGE_SHIFT, - 0, PAGE_SHIFT); + ret = uv_page_in(kvm->arch.lpid, page_to_pfn(page) << PAGE_SHIFT, + gfn << PAGE_SHIFT, 0, PAGE_SHIFT); out: - kvm_release_pfn_clean(pfn); + kvm_release_page_clean(page); mutex_unlock(&kvm->arch.uvmem_lock); return (ret == U_SUCCESS) ? RESUME_GUEST : -EFAULT; } diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c index ce79ac33e8d3..d904e13e069b 100644 --- a/arch/powerpc/kvm/book3s_mmu_hpte.c +++ b/arch/powerpc/kvm/book3s_mmu_hpte.c @@ -92,12 +92,6 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte) spin_unlock(&vcpu3s->mmu_lock); } -static void free_pte_rcu(struct rcu_head *head) -{ - struct hpte_cache *pte = container_of(head, struct hpte_cache, rcu_head); - kmem_cache_free(hpte_cache, pte); -} - static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) { struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); @@ -126,7 +120,7 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) spin_unlock(&vcpu3s->mmu_lock); - call_rcu(&pte->rcu_head, free_pte_rcu); + kfree_rcu(pte, rcu_head); } static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu) diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c index a11436720a8c..bc39c76c9d9f 100644 --- a/arch/powerpc/kvm/book3s_paired_singles.c +++ b/arch/powerpc/kvm/book3s_paired_singles.c @@ -621,6 +621,7 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc, int kvmppc_emulate_paired_single(struct kvm_vcpu *vcpu) { u32 inst; + ppc_inst_t pinst; enum emulation_result emulated = EMULATE_DONE; int ax_rd, ax_ra, ax_rb, ax_rc; short full_d; @@ -632,7 +633,8 @@ int kvmppc_emulate_paired_single(struct kvm_vcpu *vcpu) int i; #endif - emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst); + emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + inst = ppc_inst_val(pinst); if (emulated != EMULATE_DONE) return emulated; diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 9fc4dd8f66eb..83bcdc80ce51 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -461,12 +461,6 @@ static bool kvm_test_age_gfn_pr(struct kvm *kvm, struct kvm_gfn_range *range) return false; } -static bool kvm_set_spte_gfn_pr(struct kvm *kvm, struct kvm_gfn_range *range) -{ - /* The page will get remapped properly on its next fault */ - return do_kvm_unmap_gfn(kvm, range); -} - /*****************************************/ static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr) @@ -604,6 +598,7 @@ static void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr) case PVR_POWER8: case PVR_POWER8E: case PVR_POWER8NVL: + case PVR_HX_C2000: case PVR_POWER9: vcpu->arch.hflags |= BOOK3S_HFLAG_MULTI_PGSIZE | BOOK3S_HFLAG_NEW_TLBIE; @@ -644,29 +639,27 @@ static void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr) */ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) { - struct page *hpage; + struct kvm_host_map map; u64 hpage_offset; u32 *page; - int i; + int i, r; - hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT); - if (is_error_page(hpage)) + r = kvm_vcpu_map(vcpu, pte->raddr >> PAGE_SHIFT, &map); + if (r) return; hpage_offset = pte->raddr & ~PAGE_MASK; hpage_offset &= ~0xFFFULL; hpage_offset /= 4; - get_page(hpage); - page = kmap_atomic(hpage); + page = map.hva; /* patch dcbz into reserved instruction, so we trap */ for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++) if ((be32_to_cpu(page[i]) & 0xff0007ff) == INS_DCBZ) page[i] &= cpu_to_be32(0xfffffff7); - kunmap_atomic(page); - put_page(hpage); + kvm_vcpu_unmap(vcpu, &map); } static bool kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa) @@ -759,7 +752,7 @@ static int kvmppc_handle_pagefault(struct kvm_vcpu *vcpu, flags = DSISR_NOHPTE; if (data) { flags |= vcpu->arch.fault_dsisr & DSISR_ISSTORE; - kvmppc_core_queue_data_storage(vcpu, eaddr, flags); + kvmppc_core_queue_data_storage(vcpu, 0, eaddr, flags); } else { kvmppc_core_queue_inst_storage(vcpu, flags); } @@ -1044,6 +1037,8 @@ void kvmppc_set_fscr(struct kvm_vcpu *vcpu, u64 fscr) { if (fscr & FSCR_SCV) fscr &= ~FSCR_SCV; /* SCV must not be enabled */ + /* Prohibit prefixed instructions for now */ + fscr &= ~FSCR_PREFIX; if ((vcpu->arch.fscr & FSCR_TAR) && !(fscr & FSCR_TAR)) { /* TAR got dropped, drop it in shadow too */ kvmppc_giveup_fac(vcpu, FSCR_TAR_LG); @@ -1079,7 +1074,7 @@ static int kvmppc_exit_pr_progint(struct kvm_vcpu *vcpu, unsigned int exit_nr) { enum emulation_result er; ulong flags; - u32 last_inst; + ppc_inst_t last_inst; int emul, r; /* @@ -1100,9 +1095,9 @@ static int kvmppc_exit_pr_progint(struct kvm_vcpu *vcpu, unsigned int exit_nr) if (kvmppc_get_msr(vcpu) & MSR_PR) { #ifdef EXIT_DEBUG pr_info("Userspace triggered 0x700 exception at\n 0x%lx (0x%x)\n", - kvmppc_get_pc(vcpu), last_inst); + kvmppc_get_pc(vcpu), ppc_inst_val(last_inst)); #endif - if ((last_inst & 0xff0007ff) != (INS_DCBZ & 0xfffffff7)) { + if ((ppc_inst_val(last_inst) & 0xff0007ff) != (INS_DCBZ & 0xfffffff7)) { kvmppc_core_queue_program(vcpu, flags); return RESUME_GUEST; } @@ -1119,7 +1114,7 @@ static int kvmppc_exit_pr_progint(struct kvm_vcpu *vcpu, unsigned int exit_nr) break; case EMULATE_FAIL: pr_crit("%s: emulation at %lx failed (%08x)\n", - __func__, kvmppc_get_pc(vcpu), last_inst); + __func__, kvmppc_get_pc(vcpu), ppc_inst_val(last_inst)); kvmppc_core_queue_program(vcpu, flags); r = RESUME_GUEST; break; @@ -1236,7 +1231,7 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) r = kvmppc_handle_pagefault(vcpu, dar, exit_nr); srcu_read_unlock(&vcpu->kvm->srcu, idx); } else { - kvmppc_core_queue_data_storage(vcpu, dar, fault_dsisr); + kvmppc_core_queue_data_storage(vcpu, 0, dar, fault_dsisr); r = RESUME_GUEST; } break; @@ -1281,7 +1276,7 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) break; case BOOK3S_INTERRUPT_SYSCALL: { - u32 last_sc; + ppc_inst_t last_sc; int emul; /* Get last sc for papr */ @@ -1296,7 +1291,7 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) } if (vcpu->arch.papr_enabled && - (last_sc == 0x44000022) && + (ppc_inst_val(last_sc) == 0x44000022) && !(kvmppc_get_msr(vcpu) & MSR_PR)) { /* SC 1 papr hypercalls */ ulong cmd = kvmppc_get_gpr(vcpu, 3); @@ -1348,7 +1343,7 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) { int ext_msr = 0; int emul; - u32 last_inst; + ppc_inst_t last_inst; if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE) { /* Do paired single instruction emulation */ @@ -1382,15 +1377,15 @@ int kvmppc_handle_exit_pr(struct kvm_vcpu *vcpu, unsigned int exit_nr) } case BOOK3S_INTERRUPT_ALIGNMENT: { - u32 last_inst; + ppc_inst_t last_inst; int emul = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); if (emul == EMULATE_DONE) { u32 dsisr; u64 dar; - dsisr = kvmppc_alignment_dsisr(vcpu, last_inst); - dar = kvmppc_alignment_dar(vcpu, last_inst); + dsisr = kvmppc_alignment_dsisr(vcpu, ppc_inst_val(last_inst)); + dar = kvmppc_alignment_dar(vcpu, ppc_inst_val(last_inst)); kvmppc_set_dsisr(vcpu, dsisr); kvmppc_set_dar(vcpu, dar); @@ -2042,8 +2037,8 @@ static int kvmppc_core_check_processor_compat_pr(void) return 0; } -static long kvm_arch_vm_ioctl_pr(struct file *filp, - unsigned int ioctl, unsigned long arg) +static int kvm_arch_vm_ioctl_pr(struct file *filp, + unsigned int ioctl, unsigned long arg) { return -ENOTTY; } @@ -2068,7 +2063,6 @@ static struct kvmppc_ops kvm_ops_pr = { .unmap_gfn_range = kvm_unmap_gfn_range_pr, .age_gfn = kvm_age_gfn_pr, .test_age_gfn = kvm_test_age_gfn_pr, - .set_spte_gfn = kvm_set_spte_gfn_pr, .free_memslot = kvmppc_core_free_memslot_pr, .init_vm = kvmppc_core_init_vm_pr, .destroy_vm = kvmppc_core_destroy_vm_pr, @@ -2115,6 +2109,7 @@ void kvmppc_book3s_exit_pr(void) module_init(kvmppc_book3s_init_pr); module_exit(kvmppc_book3s_exit_pr); +MODULE_DESCRIPTION("KVM on Book3S without using hypervisor mode"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(KVM_MINOR); MODULE_ALIAS("devname:kvm"); diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S index 03886ca24498..0a557ffca9fe 100644 --- a/arch/powerpc/kvm/book3s_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_rmhandlers.S @@ -123,6 +123,7 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC kvmppc_handler_skip_ins: /* Patch the IP to the next instruction */ + /* Note that prefixed instructions are disabled in PR KVM for now */ mfsrr0 r12 addi r12, r12, 4 mtsrr0 r12 diff --git a/arch/powerpc/kvm/book3s_xive.c b/arch/powerpc/kvm/book3s_xive.c index f4115819e738..89a1b8c21ab4 100644 --- a/arch/powerpc/kvm/book3s_xive.c +++ b/arch/powerpc/kvm/book3s_xive.c @@ -328,7 +328,7 @@ static unsigned long xive_vm_h_xirr(struct kvm_vcpu *vcpu) */ /* Return interrupt and old CPPR in GPR4 */ - vcpu->arch.regs.gpr[4] = hirq | (old_cppr << 24); + kvmppc_set_gpr(vcpu, 4, hirq | (old_cppr << 24)); return H_SUCCESS; } @@ -364,7 +364,7 @@ static unsigned long xive_vm_h_ipoll(struct kvm_vcpu *vcpu, unsigned long server hirq = xive_vm_scan_interrupts(xc, pending, scan_poll); /* Return interrupt and old CPPR in GPR4 */ - vcpu->arch.regs.gpr[4] = hirq | (xc->cppr << 24); + kvmppc_set_gpr(vcpu, 4, hirq | (xc->cppr << 24)); return H_SUCCESS; } @@ -531,7 +531,7 @@ static int xive_vm_h_eoi(struct kvm_vcpu *vcpu, unsigned long xirr) xc->cppr = xive_prio_from_guest(new_cppr); /* - * IPIs are synthetized from MFRR and thus don't need + * IPIs are synthesized from MFRR and thus don't need * any special EOI handling. The underlying interrupt * used to signal MFRR changes is EOId when fetched from * the queue. @@ -884,10 +884,10 @@ int kvmppc_xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio, } if (single_escalation) - name = kasprintf(GFP_KERNEL, "kvm-%d-%d", + name = kasprintf(GFP_KERNEL, "kvm-%lld-%d", vcpu->kvm->arch.lpid, xc->server_num); else - name = kasprintf(GFP_KERNEL, "kvm-%d-%d-%d", + name = kasprintf(GFP_KERNEL, "kvm-%lld-%d-%d", vcpu->kvm->arch.lpid, xc->server_num, prio); if (!name) { pr_err("Failed to allocate escalation irq name for queue %d of VCPU %d\n", @@ -916,8 +916,7 @@ int kvmppc_xive_attach_escalation(struct kvm_vcpu *vcpu, u8 prio, * it fires once. */ if (single_escalation) { - struct irq_data *d = irq_get_irq_data(xc->esc_virq[prio]); - struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); + struct xive_irq_data *xd = irq_get_chip_data(xc->esc_virq[prio]); xive_vm_esb_load(xd, XIVE_ESB_SET_PQ_01); vcpu->arch.xive_esc_raddr = xd->eoi_page; @@ -1555,7 +1554,7 @@ int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq, struct kvmppc_xive_src_block *sb; struct kvmppc_xive_irq_state *state; struct irq_data *host_data = - irq_domain_get_irq_data(irq_get_default_host(), host_irq); + irq_domain_get_irq_data(irq_get_default_domain(), host_irq); unsigned int hw_irq = (unsigned int)irqd_to_hwirq(host_data); u16 idx; u8 prio; @@ -1612,7 +1611,7 @@ int kvmppc_xive_set_mapped(struct kvm *kvm, unsigned long guest_irq, /* Grab info about irq */ state->pt_number = hw_irq; - state->pt_data = irq_data_get_irq_handler_data(host_data); + state->pt_data = irq_data_get_irq_chip_data(host_data); /* * Configure the IRQ to match the existing configuration of @@ -1787,8 +1786,7 @@ void kvmppc_xive_disable_vcpu_interrupts(struct kvm_vcpu *vcpu) */ void xive_cleanup_single_escalation(struct kvm_vcpu *vcpu, int irq) { - struct irq_data *d = irq_get_irq_data(irq); - struct xive_irq_data *xd = irq_data_get_irq_handler_data(d); + struct xive_irq_data *xd = irq_get_chip_data(irq); /* * This slightly odd sequence gives the right result @@ -2779,8 +2777,6 @@ static int kvmppc_xive_create(struct kvm_device *dev, u32 type) int kvmppc_xive_xics_hcall(struct kvm_vcpu *vcpu, u32 req) { - struct kvmppc_vcore *vc = vcpu->arch.vcore; - /* The VM should have configured XICS mode before doing XICS hcalls. */ if (!kvmppc_xics_enabled(vcpu)) return H_TOO_HARD; @@ -2799,7 +2795,7 @@ int kvmppc_xive_xics_hcall(struct kvm_vcpu *vcpu, u32 req) return xive_vm_h_ipoll(vcpu, kvmppc_get_gpr(vcpu, 4)); case H_XIRR_X: xive_vm_h_xirr(vcpu); - kvmppc_set_gpr(vcpu, 5, get_tb() + vc->tb_offset); + kvmppc_set_gpr(vcpu, 5, get_tb() + kvmppc_get_tb_offset(vcpu)); return H_SUCCESS; } @@ -2829,9 +2825,7 @@ int kvmppc_xive_debug_show_queues(struct seq_file *m, struct kvm_vcpu *vcpu) i0, i1); } if (xc->esc_virq[i]) { - struct irq_data *d = irq_get_irq_data(xc->esc_virq[i]); - struct xive_irq_data *xd = - irq_data_get_irq_handler_data(d); + struct xive_irq_data *xd = irq_get_chip_data(xc->esc_virq[i]); u64 pq = xive_vm_esb_load(xd, XIVE_ESB_GET); seq_printf(m, " ESC %d %c%c EOI @%llx", diff --git a/arch/powerpc/kvm/book3s_xive_native.c b/arch/powerpc/kvm/book3s_xive_native.c index 4f566bea5e10..d9bf1bc3ff61 100644 --- a/arch/powerpc/kvm/book3s_xive_native.c +++ b/arch/powerpc/kvm/book3s_xive_native.c @@ -324,7 +324,7 @@ static int kvmppc_xive_native_mmap(struct kvm_device *dev, return -EINVAL; } - vma->vm_flags |= VM_IO | VM_PFNMAP; + vm_flags_set(vma, VM_IO | VM_PFNMAP); vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); /* @@ -567,7 +567,7 @@ static int kvmppc_xive_native_set_queue_config(struct kvmppc_xive *xive, u8 priority; struct kvm_ppc_xive_eq kvm_eq; int rc; - __be32 *qaddr = 0; + __be32 *qaddr = NULL; struct page *page; struct xive_q *q; gfn_t gfn; @@ -654,7 +654,7 @@ static int kvmppc_xive_native_set_queue_config(struct kvmppc_xive *xive, } page = gfn_to_page(kvm, gfn); - if (is_error_page(page)) { + if (!page) { srcu_read_unlock(&kvm->srcu, srcu_idx); pr_err("Couldn't get queue page %llx!\n", kvm_eq.qaddr); return -EINVAL; diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index 0dce93ccaadf..3401b96be475 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -283,9 +283,10 @@ void kvmppc_core_queue_dtlb_miss(struct kvm_vcpu *vcpu, kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS); } -void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, +void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu, ulong srr1_flags, ulong dear_flags, ulong esr_flags) { + WARN_ON_ONCE(srr1_flags); vcpu->arch.queued_dear = dear_flags; vcpu->arch.queued_esr = esr_flags; kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DATA_STORAGE); @@ -316,14 +317,16 @@ void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong esr_flags) kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_PROGRAM); } -void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_fpunavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { + WARN_ON_ONCE(srr1_flags); kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_FP_UNAVAIL); } #ifdef CONFIG_ALTIVEC -void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu) +void kvmppc_core_queue_vec_unavail(struct kvm_vcpu *vcpu, ulong srr1_flags) { + WARN_ON_ONCE(srr1_flags); kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ALTIVEC_UNAVAIL); } #endif @@ -569,7 +572,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, /* * Return the number of jiffies until the next timeout. If the timeout is - * longer than the NEXT_TIMER_MAX_DELTA, then return NEXT_TIMER_MAX_DELTA + * longer than the TIMER_NEXT_MAX_DELTA, then return TIMER_NEXT_MAX_DELTA * because the larger value can break the timer APIs. */ static unsigned long watchdog_next_timeout(struct kvm_vcpu *vcpu) @@ -595,7 +598,7 @@ static unsigned long watchdog_next_timeout(struct kvm_vcpu *vcpu) if (do_div(nr_jiffies, tb_ticks_per_jiffy)) nr_jiffies++; - return min_t(unsigned long long, nr_jiffies, NEXT_TIMER_MAX_DELTA); + return min_t(unsigned long long, nr_jiffies, TIMER_NEXT_MAX_DELTA); } static void arm_next_watchdog(struct kvm_vcpu *vcpu) @@ -613,19 +616,19 @@ static void arm_next_watchdog(struct kvm_vcpu *vcpu) spin_lock_irqsave(&vcpu->arch.wdt_lock, flags); nr_jiffies = watchdog_next_timeout(vcpu); /* - * If the number of jiffies of watchdog timer >= NEXT_TIMER_MAX_DELTA + * If the number of jiffies of watchdog timer >= TIMER_NEXT_MAX_DELTA * then do not run the watchdog timer as this can break timer APIs. */ - if (nr_jiffies < NEXT_TIMER_MAX_DELTA) + if (nr_jiffies < TIMER_NEXT_MAX_DELTA) mod_timer(&vcpu->arch.wdt_timer, jiffies + nr_jiffies); else - del_timer(&vcpu->arch.wdt_timer); + timer_delete(&vcpu->arch.wdt_timer); spin_unlock_irqrestore(&vcpu->arch.wdt_lock, flags); } -void kvmppc_watchdog_func(struct timer_list *t) +static void kvmppc_watchdog_func(struct timer_list *t) { - struct kvm_vcpu *vcpu = from_timer(vcpu, t, arch.wdt_timer); + struct kvm_vcpu *vcpu = timer_container_of(vcpu, t, arch.wdt_timer); u32 tsr, new_tsr; int final; @@ -841,7 +844,7 @@ static int emulation_exit(struct kvm_vcpu *vcpu) return RESUME_GUEST; case EMULATE_FAIL: - printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", + printk(KERN_CRIT "%s: emulation at %lx failed (%08lx)\n", __func__, vcpu->arch.regs.nip, vcpu->arch.last_inst); /* For debugging, encode the failing instruction and * report it to userspace. */ @@ -912,16 +915,15 @@ static int kvmppc_handle_debug(struct kvm_vcpu *vcpu) static void kvmppc_fill_pt_regs(struct pt_regs *regs) { - ulong r1, ip, msr, lr; + ulong r1, msr, lr; asm("mr %0, 1" : "=r"(r1)); asm("mflr %0" : "=r"(lr)); asm("mfmsr %0" : "=r"(msr)); - asm("bl 1f; 1: mflr %0" : "=r"(ip)); memset(regs, 0, sizeof(*regs)); regs->gpr[1] = r1; - regs->nip = ip; + regs->nip = _THIS_IP_; regs->msr = msr; regs->link = lr; } @@ -1001,7 +1003,7 @@ static int kvmppc_resume_inst_load(struct kvm_vcpu *vcpu, } } -/** +/* * kvmppc_handle_exit * * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV) @@ -1013,6 +1015,7 @@ int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr) int s; int idx; u32 last_inst = KVM_INST_FETCH_FAILED; + ppc_inst_t pinst; enum emulation_result emulated = EMULATE_DONE; /* Fix irq state (pairs with kvmppc_fix_ee_before_entry()) */ @@ -1032,12 +1035,15 @@ int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr) case BOOKE_INTERRUPT_DATA_STORAGE: case BOOKE_INTERRUPT_DTLB_MISS: case BOOKE_INTERRUPT_HV_PRIV: - emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); + emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + last_inst = ppc_inst_val(pinst); break; case BOOKE_INTERRUPT_PROGRAM: /* SW breakpoints arrive as illegal instructions on HV */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) - emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); + if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) { + emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + last_inst = ppc_inst_val(pinst); + } break; default: break; @@ -1211,7 +1217,7 @@ int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr) /* * On cores with Vector category, KVM is loaded only if CONFIG_ALTIVEC, - * see kvmppc_core_check_processor_compat(). + * see kvmppc_e500mc_check_processor_compat(). */ #ifdef CONFIG_ALTIVEC case BOOKE_INTERRUPT_ALTIVEC_UNAVAIL: @@ -1226,7 +1232,7 @@ int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr) #endif case BOOKE_INTERRUPT_DATA_STORAGE: - kvmppc_core_queue_data_storage(vcpu, vcpu->arch.fault_dear, + kvmppc_core_queue_data_storage(vcpu, 0, vcpu->arch.fault_dear, vcpu->arch.fault_esr); kvmppc_account_exit(vcpu, DSI_EXITS); r = RESUME_GUEST; @@ -1435,7 +1441,7 @@ int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu) void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu) { - del_timer_sync(&vcpu->arch.wdt_timer); + timer_delete_sync(&vcpu->arch.wdt_timer); } int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) @@ -1947,7 +1953,8 @@ static int kvmppc_booke_add_watchpoint(struct debug_reg *dbg_reg, uint64_t addr, dbg_reg->dbcr0 |= DBCR0_IDM; return 0; } -void kvm_guest_protect_msr(struct kvm_vcpu *vcpu, ulong prot_bitmap, bool set) +static void kvm_guest_protect_msr(struct kvm_vcpu *vcpu, ulong prot_bitmap, + bool set) { /* XXX: Add similar MSR protection for BookE-PR */ #ifdef CONFIG_KVM_BOOKE_HV diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index be9da96d9f06..9c5b8e76014f 100644 --- a/arch/powerpc/kvm/booke.h +++ b/arch/powerpc/kvm/booke.h @@ -109,4 +109,7 @@ static inline void kvmppc_clear_dbsr(void) { mtspr(SPRN_DBSR, mfspr(SPRN_DBSR)); } + +int kvmppc_handle_exit(struct kvm_vcpu *vcpu, unsigned int exit_nr); + #endif /* __KVM_BOOKE_H__ */ diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S index b5fe6fb53c66..8b4a402217ba 100644 --- a/arch/powerpc/kvm/bookehv_interrupts.S +++ b/arch/powerpc/kvm/bookehv_interrupts.S @@ -139,7 +139,7 @@ END_BTB_FLUSH_SECTION * kvmppc_get_last_inst(). */ li r9, KVM_INST_FETCH_FAILED - stw r9, VCPU_LAST_INST(r4) + PPC_STL r9, VCPU_LAST_INST(r4) .endif .if \flags & NEED_ESR diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index c8b2b4478545..b0f695428733 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c @@ -314,7 +314,7 @@ static void kvmppc_core_vcpu_put_e500(struct kvm_vcpu *vcpu) kvmppc_booke_vcpu_put(vcpu); } -int kvmppc_core_check_processor_compat(void) +static int kvmppc_e500_check_processor_compat(void) { int r; @@ -507,7 +507,7 @@ static int __init kvmppc_e500_init(void) unsigned long handler_len; unsigned long max_ivor = 0; - r = kvmppc_core_check_processor_compat(); + r = kvmppc_e500_check_processor_compat(); if (r) goto err_out; @@ -531,7 +531,7 @@ static int __init kvmppc_e500_init(void) flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers + ivor[max_ivor] + handler_len); - r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); + r = kvm_init(sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); if (r) goto err_out; kvm_ops_e500.owner = THIS_MODULE; diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h index 6d0d329cbb35..f9acf866c709 100644 --- a/arch/powerpc/kvm/e500.h +++ b/arch/powerpc/kvm/e500.h @@ -34,6 +34,8 @@ enum vcpu_ftr { #define E500_TLB_BITMAP (1 << 30) /* TLB1 entry is mapped by host TLB0 */ #define E500_TLB_TLB0 (1 << 29) +/* entry is writable on the host */ +#define E500_TLB_WRITABLE (1 << 28) /* bits [6-5] MAS2_X1 and MAS2_X0 and [4-0] bits for WIMGE */ #define E500_TLB_MAS2_ATTR (0x7f) diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c index 05668e964140..06caf8bbbe2b 100644 --- a/arch/powerpc/kvm/e500_mmu_host.c +++ b/arch/powerpc/kvm/e500_mmu_host.c @@ -45,11 +45,14 @@ static inline unsigned int tlb1_max_shadow_size(void) return host_tlb_params[1].entries - tlbcam_index - 1; } -static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode) +static inline u32 e500_shadow_mas3_attrib(u32 mas3, bool writable, int usermode) { /* Mask off reserved bits. */ mas3 &= MAS3_ATTRIB_MASK; + if (!writable) + mas3 &= ~(MAS3_UW|MAS3_SW); + #ifndef CONFIG_KVM_BOOKE_HV if (!usermode) { /* Guest is in supervisor mode, @@ -244,19 +247,16 @@ static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe) static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref, struct kvm_book3e_206_tlb_entry *gtlbe, - kvm_pfn_t pfn, unsigned int wimg) + kvm_pfn_t pfn, unsigned int wimg, + bool writable) { ref->pfn = pfn; ref->flags = E500_TLB_VALID; + if (writable) + ref->flags |= E500_TLB_WRITABLE; /* Use guest supplied MAS2_G and MAS2_E */ ref->flags |= (gtlbe->mas2 & MAS2_ATTRIB_MASK) | wimg; - - /* Mark the page accessed */ - kvm_set_pfn_accessed(pfn); - - if (tlbe_is_writable(gtlbe)) - kvm_set_pfn_dirty(pfn); } static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref) @@ -309,6 +309,7 @@ static void kvmppc_e500_setup_stlbe( { kvm_pfn_t pfn = ref->pfn; u32 pr = vcpu->arch.shared->msr & MSR_PR; + bool writable = !!(ref->flags & E500_TLB_WRITABLE); BUG_ON(!(ref->flags & E500_TLB_VALID)); @@ -316,7 +317,7 @@ static void kvmppc_e500_setup_stlbe( stlbe->mas1 = MAS1_TSIZE(tsize) | get_tlb_sts(gtlbe) | MAS1_VALID; stlbe->mas2 = (gvaddr & MAS2_EPN) | (ref->flags & E500_TLB_MAS2_ATTR); stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT) | - e500_shadow_mas3_attrib(gtlbe->mas7_3, pr); + e500_shadow_mas3_attrib(gtlbe->mas7_3, writable, pr); } static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, @@ -325,18 +326,19 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, struct tlbe_ref *ref) { struct kvm_memory_slot *slot; - unsigned long pfn = 0; /* silence GCC warning */ + unsigned int psize; + unsigned long pfn; + struct page *page = NULL; unsigned long hva; - int pfnmap = 0; int tsize = BOOK3E_PAGESZ_4K; int ret = 0; unsigned long mmu_seq; struct kvm *kvm = vcpu_e500->vcpu.kvm; - unsigned long tsize_pages = 0; pte_t *ptep; unsigned int wimg = 0; pgd_t *pgdir; unsigned long flags; + bool writable = false; /* used to check for invalidations in progress */ mmu_seq = kvm->mmu_invalidate_seq; @@ -353,110 +355,12 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, slot = gfn_to_memslot(vcpu_e500->vcpu.kvm, gfn); hva = gfn_to_hva_memslot(slot, gfn); - if (tlbsel == 1) { - struct vm_area_struct *vma; - mmap_read_lock(kvm->mm); - - vma = find_vma(kvm->mm, hva); - if (vma && hva >= vma->vm_start && - (vma->vm_flags & VM_PFNMAP)) { - /* - * This VMA is a physically contiguous region (e.g. - * /dev/mem) that bypasses normal Linux page - * management. Find the overlap between the - * vma and the memslot. - */ - - unsigned long start, end; - unsigned long slot_start, slot_end; - - pfnmap = 1; - - start = vma->vm_pgoff; - end = start + - vma_pages(vma); - - pfn = start + ((hva - vma->vm_start) >> PAGE_SHIFT); - - slot_start = pfn - (gfn - slot->base_gfn); - slot_end = slot_start + slot->npages; - - if (start < slot_start) - start = slot_start; - if (end > slot_end) - end = slot_end; - - tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >> - MAS1_TSIZE_SHIFT; - - /* - * e500 doesn't implement the lowest tsize bit, - * or 1K pages. - */ - tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1); - - /* - * Now find the largest tsize (up to what the guest - * requested) that will cover gfn, stay within the - * range, and for which gfn and pfn are mutually - * aligned. - */ - - for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) { - unsigned long gfn_start, gfn_end; - tsize_pages = 1UL << (tsize - 2); - - gfn_start = gfn & ~(tsize_pages - 1); - gfn_end = gfn_start + tsize_pages; - - if (gfn_start + pfn - gfn < start) - continue; - if (gfn_end + pfn - gfn > end) - continue; - if ((gfn & (tsize_pages - 1)) != - (pfn & (tsize_pages - 1))) - continue; - - gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1); - pfn &= ~(tsize_pages - 1); - break; - } - } else if (vma && hva >= vma->vm_start && - is_vm_hugetlb_page(vma)) { - unsigned long psize = vma_kernel_pagesize(vma); - - tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >> - MAS1_TSIZE_SHIFT; - - /* - * Take the largest page size that satisfies both host - * and guest mapping - */ - tsize = min(__ilog2(psize) - 10, tsize); - - /* - * e500 doesn't implement the lowest tsize bit, - * or 1K pages. - */ - tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1); - } - - mmap_read_unlock(kvm->mm); - } - - if (likely(!pfnmap)) { - tsize_pages = 1UL << (tsize + 10 - PAGE_SHIFT); - pfn = gfn_to_pfn_memslot(slot, gfn); - if (is_error_noslot_pfn(pfn)) { - if (printk_ratelimit()) - pr_err("%s: real page not found for gfn %lx\n", - __func__, (long)gfn); - return -EINVAL; - } - - /* Align guest and physical address to page map boundaries */ - pfn &= ~(tsize_pages - 1); - gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1); + pfn = __kvm_faultin_pfn(slot, gfn, FOLL_WRITE, &writable, &page); + if (is_error_noslot_pfn(pfn)) { + if (printk_ratelimit()) + pr_err("%s: real page not found for gfn %lx\n", + __func__, (long)gfn); + return -EINVAL; } spin_lock(&kvm->mmu_lock); @@ -474,14 +378,13 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, * can't run hence pfn won't change. */ local_irq_save(flags); - ptep = find_linux_pte(pgdir, hva, NULL, NULL); + ptep = find_linux_pte(pgdir, hva, NULL, &psize); if (ptep) { pte_t pte = READ_ONCE(*ptep); if (pte_present(pte)) { wimg = (pte_val(pte) >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK; - local_irq_restore(flags); } else { local_irq_restore(flags); pr_err_ratelimited("%s: pte not present: gfn %lx,pfn %lx\n", @@ -490,20 +393,79 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, goto out; } } - kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg); + local_irq_restore(flags); + + if (psize && tlbsel == 1) { + unsigned long psize_pages, tsize_pages; + unsigned long start, end; + unsigned long slot_start, slot_end; + + psize_pages = 1UL << (psize - PAGE_SHIFT); + start = pfn & ~(psize_pages - 1); + end = start + psize_pages; + + slot_start = pfn - (gfn - slot->base_gfn); + slot_end = slot_start + slot->npages; + + if (start < slot_start) + start = slot_start; + if (end > slot_end) + end = slot_end; + + tsize = (gtlbe->mas1 & MAS1_TSIZE_MASK) >> + MAS1_TSIZE_SHIFT; + + /* + * Any page size that doesn't satisfy the host mapping + * will fail the start and end tests. + */ + tsize = min(psize - PAGE_SHIFT + BOOK3E_PAGESZ_4K, tsize); + + /* + * e500 doesn't implement the lowest tsize bit, + * or 1K pages. + */ + tsize = max(BOOK3E_PAGESZ_4K, tsize & ~1); + + /* + * Now find the largest tsize (up to what the guest + * requested) that will cover gfn, stay within the + * range, and for which gfn and pfn are mutually + * aligned. + */ + + for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) { + unsigned long gfn_start, gfn_end; + tsize_pages = 1UL << (tsize - 2); + + gfn_start = gfn & ~(tsize_pages - 1); + gfn_end = gfn_start + tsize_pages; + + if (gfn_start + pfn - gfn < start) + continue; + if (gfn_end + pfn - gfn > end) + continue; + if ((gfn & (tsize_pages - 1)) != + (pfn & (tsize_pages - 1))) + continue; + + gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1); + pfn &= ~(tsize_pages - 1); + break; + } + } + kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg, writable); kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize, ref, gvaddr, stlbe); + writable = tlbe_is_writable(stlbe); /* Clear i-cache for new pages */ kvmppc_mmu_flush_icache(pfn); out: + kvm_release_faultin_page(kvm, page, !!ret, writable); spin_unlock(&kvm->mmu_lock); - - /* Drop refcount on page, so that mmu notifiers can clear it */ - kvm_release_pfn_clean(pfn); - return ret; } @@ -623,7 +585,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, #ifdef CONFIG_KVM_BOOKE_HV int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, - enum instruction_fetch_type type, u32 *instr) + enum instruction_fetch_type type, unsigned long *instr) { gva_t geaddr; hpa_t addr; @@ -713,7 +675,7 @@ int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, } #else int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, - enum instruction_fetch_type type, u32 *instr) + enum instruction_fetch_type type, unsigned long *instr) { return EMULATE_AGAIN; } @@ -747,12 +709,6 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) return false; } -bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) -{ - /* The page will get remapped properly on its next fault */ - return kvm_e500_mmu_unmap_gfn(kvm, range); -} - /*****************************************/ int e500_mmu_host_init(struct kvmppc_vcpu_e500 *vcpu_e500) diff --git a/arch/powerpc/kvm/e500mc.c b/arch/powerpc/kvm/e500mc.c index 57e0ad6a2ca3..e476e107a932 100644 --- a/arch/powerpc/kvm/e500mc.c +++ b/arch/powerpc/kvm/e500mc.c @@ -20,6 +20,7 @@ #include <asm/cputable.h> #include <asm/kvm_ppc.h> #include <asm/dbell.h> +#include <asm/ppc-opcode.h> #include "booke.h" #include "e500.h" @@ -92,7 +93,11 @@ void kvmppc_e500_tlbil_all(struct kvmppc_vcpu_e500 *vcpu_e500) local_irq_save(flags); mtspr(SPRN_MAS5, MAS5_SGS | get_lpid(&vcpu_e500->vcpu)); - asm volatile("tlbilxlpid"); + /* + * clang-17 and older could not assemble tlbilxlpid. + * https://github.com/ClangBuiltLinux/linux/issues/1891 + */ + asm volatile (PPC_TLBILX_LPID); mtspr(SPRN_MAS5, 0); local_irq_restore(flags); } @@ -168,7 +173,7 @@ static void kvmppc_core_vcpu_put_e500mc(struct kvm_vcpu *vcpu) kvmppc_booke_vcpu_put(vcpu); } -int kvmppc_core_check_processor_compat(void) +static int kvmppc_e500mc_check_processor_compat(void) { int r; @@ -388,6 +393,10 @@ static int __init kvmppc_e500mc_init(void) { int r; + r = kvmppc_e500mc_check_processor_compat(); + if (r) + goto err_out; + r = kvmppc_booke_init(); if (r) goto err_out; @@ -400,7 +409,7 @@ static int __init kvmppc_e500mc_init(void) */ kvmppc_init_lpid(KVMPPC_NR_LPIDS/threads_per_core); - r = kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); + r = kvm_init(sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); if (r) goto err_out; kvm_ops_e500mc.owner = THIS_MODULE; diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index ee1147c98cd8..355d5206e8aa 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c @@ -194,6 +194,7 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) int kvmppc_emulate_instruction(struct kvm_vcpu *vcpu) { u32 inst; + ppc_inst_t pinst; int rs, rt, sprn; enum emulation_result emulated; int advance = 1; @@ -201,7 +202,8 @@ int kvmppc_emulate_instruction(struct kvm_vcpu *vcpu) /* this default type might be overwritten by subcategories */ kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); - emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &inst); + emulated = kvmppc_get_last_inst(vcpu, INST_GENERIC, &pinst); + inst = ppc_inst_val(pinst); if (emulated != EMULATE_DONE) return emulated; @@ -299,6 +301,10 @@ int kvmppc_emulate_instruction(struct kvm_vcpu *vcpu) trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated); /* Advance past emulated instruction. */ + /* + * If this ever handles prefixed instructions, the 4 + * will need to become ppc_inst_len(pinst) instead. + */ if (advance) kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); diff --git a/arch/powerpc/kvm/emulate_loadstore.c b/arch/powerpc/kvm/emulate_loadstore.c index cfc9114b87d0..ec60c7979718 100644 --- a/arch/powerpc/kvm/emulate_loadstore.c +++ b/arch/powerpc/kvm/emulate_loadstore.c @@ -28,7 +28,7 @@ static bool kvmppc_check_fp_disabled(struct kvm_vcpu *vcpu) { if (!(kvmppc_get_msr(vcpu) & MSR_FP)) { - kvmppc_core_queue_fpunavail(vcpu); + kvmppc_core_queue_fpunavail(vcpu, kvmppc_get_msr(vcpu) & SRR1_PREFIXED); return true; } @@ -40,7 +40,7 @@ static bool kvmppc_check_fp_disabled(struct kvm_vcpu *vcpu) static bool kvmppc_check_vsx_disabled(struct kvm_vcpu *vcpu) { if (!(kvmppc_get_msr(vcpu) & MSR_VSX)) { - kvmppc_core_queue_vsx_unavail(vcpu); + kvmppc_core_queue_vsx_unavail(vcpu, kvmppc_get_msr(vcpu) & SRR1_PREFIXED); return true; } @@ -52,7 +52,7 @@ static bool kvmppc_check_vsx_disabled(struct kvm_vcpu *vcpu) static bool kvmppc_check_altivec_disabled(struct kvm_vcpu *vcpu) { if (!(kvmppc_get_msr(vcpu) & MSR_VEC)) { - kvmppc_core_queue_vec_unavail(vcpu); + kvmppc_core_queue_vec_unavail(vcpu, kvmppc_get_msr(vcpu) & SRR1_PREFIXED); return true; } @@ -71,7 +71,7 @@ static bool kvmppc_check_altivec_disabled(struct kvm_vcpu *vcpu) */ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) { - u32 inst; + ppc_inst_t inst; enum emulation_result emulated = EMULATE_FAIL; struct instruction_op op; @@ -92,8 +92,8 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) vcpu->arch.mmio_host_swabbed = 0; emulated = EMULATE_FAIL; - vcpu->arch.regs.msr = vcpu->arch.shared->msr; - if (analyse_instr(&op, &vcpu->arch.regs, ppc_inst(inst)) == 0) { + vcpu->arch.regs.msr = kvmppc_get_msr(vcpu); + if (analyse_instr(&op, &vcpu->arch.regs, inst) == 0) { int type = op.type & INSTR_TYPE_MASK; int size = GETSIZE(op.type); @@ -111,7 +111,7 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) op.reg, size, !instr_byte_swap); if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) - kvmppc_set_gpr(vcpu, op.update_reg, op.ea); + kvmppc_set_gpr(vcpu, op.update_reg, vcpu->arch.vaddr_accessed); break; } @@ -131,7 +131,7 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) KVM_MMIO_REG_FPR|op.reg, size, 1); if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) - kvmppc_set_gpr(vcpu, op.update_reg, op.ea); + kvmppc_set_gpr(vcpu, op.update_reg, vcpu->arch.vaddr_accessed); break; #endif @@ -223,16 +223,17 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) break; } #endif - case STORE: - /* if need byte reverse, op.val has been reversed by - * analyse_instr(). - */ - emulated = kvmppc_handle_store(vcpu, op.val, size, 1); + case STORE: { + int instr_byte_swap = op.type & BYTEREV; + + emulated = kvmppc_handle_store(vcpu, kvmppc_get_gpr(vcpu, op.reg), + size, !instr_byte_swap); if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) - kvmppc_set_gpr(vcpu, op.update_reg, op.ea); + kvmppc_set_gpr(vcpu, op.update_reg, vcpu->arch.vaddr_accessed); break; + } #ifdef CONFIG_PPC_FPU case STORE_FP: if (kvmppc_check_fp_disabled(vcpu)) @@ -250,10 +251,10 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) vcpu->arch.mmio_sp64_extend = 1; emulated = kvmppc_handle_store(vcpu, - VCPU_FPR(vcpu, op.reg), size, 1); + kvmppc_get_fpr(vcpu, op.reg), size, 1); if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) - kvmppc_set_gpr(vcpu, op.update_reg, op.ea); + kvmppc_set_gpr(vcpu, op.update_reg, vcpu->arch.vaddr_accessed); break; #endif @@ -356,11 +357,11 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) } } - trace_kvm_ppc_instr(inst, kvmppc_get_pc(vcpu), emulated); + trace_kvm_ppc_instr(ppc_inst_val(inst), kvmppc_get_pc(vcpu), emulated); /* Advance past emulated instruction. */ if (emulated != EMULATE_FAIL) - kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); + kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + ppc_inst_len(inst)); return emulated; } diff --git a/arch/powerpc/kvm/guest-state-buffer.c b/arch/powerpc/kvm/guest-state-buffer.c new file mode 100644 index 000000000000..871cf60ddeb6 --- /dev/null +++ b/arch/powerpc/kvm/guest-state-buffer.c @@ -0,0 +1,660 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "asm/hvcall.h" +#include <linux/log2.h> +#include <asm/pgalloc.h> +#include <asm/guest-state-buffer.h> + +static const u16 kvmppc_gse_iden_len[__KVMPPC_GSE_TYPE_MAX] = { + [KVMPPC_GSE_BE32] = sizeof(__be32), + [KVMPPC_GSE_BE64] = sizeof(__be64), + [KVMPPC_GSE_VEC128] = sizeof(vector128), + [KVMPPC_GSE_PARTITION_TABLE] = sizeof(struct kvmppc_gs_part_table), + [KVMPPC_GSE_PROCESS_TABLE] = sizeof(struct kvmppc_gs_proc_table), + [KVMPPC_GSE_BUFFER] = sizeof(struct kvmppc_gs_buff_info), +}; + +/** + * kvmppc_gsb_new() - create a new guest state buffer + * @size: total size of the guest state buffer (includes header) + * @guest_id: guest_id + * @vcpu_id: vcpu_id + * @flags: GFP flags + * + * Returns a guest state buffer. + */ +struct kvmppc_gs_buff *kvmppc_gsb_new(size_t size, unsigned long guest_id, + unsigned long vcpu_id, gfp_t flags) +{ + struct kvmppc_gs_buff *gsb; + + gsb = kzalloc(sizeof(*gsb), flags); + if (!gsb) + return NULL; + + size = roundup_pow_of_two(size); + gsb->hdr = kzalloc(size, GFP_KERNEL); + if (!gsb->hdr) + goto free; + + gsb->capacity = size; + gsb->len = sizeof(struct kvmppc_gs_header); + gsb->vcpu_id = vcpu_id; + gsb->guest_id = guest_id; + + gsb->hdr->nelems = cpu_to_be32(0); + + return gsb; + +free: + kfree(gsb); + return NULL; +} +EXPORT_SYMBOL_GPL(kvmppc_gsb_new); + +/** + * kvmppc_gsb_free() - free a guest state buffer + * @gsb: guest state buffer + */ +void kvmppc_gsb_free(struct kvmppc_gs_buff *gsb) +{ + kfree(gsb->hdr); + kfree(gsb); +} +EXPORT_SYMBOL_GPL(kvmppc_gsb_free); + +/** + * kvmppc_gsb_put() - allocate space in a guest state buffer + * @gsb: buffer to allocate in + * @size: amount of space to allocate + * + * Returns a pointer to the amount of space requested within the buffer and + * increments the count of elements in the buffer. + * + * Does not check if there is enough space in the buffer. + */ +void *kvmppc_gsb_put(struct kvmppc_gs_buff *gsb, size_t size) +{ + u32 nelems = kvmppc_gsb_nelems(gsb); + void *p; + + p = (void *)kvmppc_gsb_header(gsb) + kvmppc_gsb_len(gsb); + gsb->len += size; + + kvmppc_gsb_header(gsb)->nelems = cpu_to_be32(nelems + 1); + return p; +} +EXPORT_SYMBOL_GPL(kvmppc_gsb_put); + +static int kvmppc_gsid_class(u16 iden) +{ + if ((iden >= KVMPPC_GSE_GUESTWIDE_START) && + (iden <= KVMPPC_GSE_GUESTWIDE_END)) + return KVMPPC_GS_CLASS_GUESTWIDE; + + if ((iden >= KVMPPC_GSE_HOSTWIDE_START) && + (iden <= KVMPPC_GSE_HOSTWIDE_END)) + return KVMPPC_GS_CLASS_HOSTWIDE; + + if ((iden >= KVMPPC_GSE_META_START) && (iden <= KVMPPC_GSE_META_END)) + return KVMPPC_GS_CLASS_META; + + if ((iden >= KVMPPC_GSE_DW_REGS_START) && + (iden <= KVMPPC_GSE_DW_REGS_END)) + return KVMPPC_GS_CLASS_DWORD_REG; + + if ((iden >= KVMPPC_GSE_W_REGS_START) && + (iden <= KVMPPC_GSE_W_REGS_END)) + return KVMPPC_GS_CLASS_WORD_REG; + + if ((iden >= KVMPPC_GSE_VSRS_START) && (iden <= KVMPPC_GSE_VSRS_END)) + return KVMPPC_GS_CLASS_VECTOR; + + if ((iden >= KVMPPC_GSE_INTR_REGS_START) && + (iden <= KVMPPC_GSE_INTR_REGS_END)) + return KVMPPC_GS_CLASS_INTR; + + return -1; +} + +static int kvmppc_gsid_type(u16 iden) +{ + int type = -1; + + switch (kvmppc_gsid_class(iden)) { + case KVMPPC_GS_CLASS_HOSTWIDE: + switch (iden) { + case KVMPPC_GSID_L0_GUEST_HEAP: + fallthrough; + case KVMPPC_GSID_L0_GUEST_HEAP_MAX: + fallthrough; + case KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE: + fallthrough; + case KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX: + fallthrough; + case KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM: + type = KVMPPC_GSE_BE64; + break; + } + break; + case KVMPPC_GS_CLASS_GUESTWIDE: + switch (iden) { + case KVMPPC_GSID_HOST_STATE_SIZE: + case KVMPPC_GSID_RUN_OUTPUT_MIN_SIZE: + case KVMPPC_GSID_TB_OFFSET: + type = KVMPPC_GSE_BE64; + break; + case KVMPPC_GSID_PARTITION_TABLE: + type = KVMPPC_GSE_PARTITION_TABLE; + break; + case KVMPPC_GSID_PROCESS_TABLE: + type = KVMPPC_GSE_PROCESS_TABLE; + break; + case KVMPPC_GSID_LOGICAL_PVR: + type = KVMPPC_GSE_BE32; + break; + } + break; + case KVMPPC_GS_CLASS_META: + switch (iden) { + case KVMPPC_GSID_RUN_INPUT: + case KVMPPC_GSID_RUN_OUTPUT: + type = KVMPPC_GSE_BUFFER; + break; + case KVMPPC_GSID_VPA: + type = KVMPPC_GSE_BE64; + break; + } + break; + case KVMPPC_GS_CLASS_DWORD_REG: + type = KVMPPC_GSE_BE64; + break; + case KVMPPC_GS_CLASS_WORD_REG: + type = KVMPPC_GSE_BE32; + break; + case KVMPPC_GS_CLASS_VECTOR: + type = KVMPPC_GSE_VEC128; + break; + case KVMPPC_GS_CLASS_INTR: + switch (iden) { + case KVMPPC_GSID_HDAR: + case KVMPPC_GSID_ASDR: + case KVMPPC_GSID_HEIR: + type = KVMPPC_GSE_BE64; + break; + case KVMPPC_GSID_HDSISR: + type = KVMPPC_GSE_BE32; + break; + } + break; + } + + return type; +} + +/** + * kvmppc_gsid_flags() - the flags for a guest state ID + * @iden: guest state ID + * + * Returns any flags for the guest state ID. + */ +unsigned long kvmppc_gsid_flags(u16 iden) +{ + unsigned long flags = 0; + + switch (kvmppc_gsid_class(iden)) { + case KVMPPC_GS_CLASS_GUESTWIDE: + flags = KVMPPC_GS_FLAGS_WIDE; + break; + case KVMPPC_GS_CLASS_HOSTWIDE: + flags = KVMPPC_GS_FLAGS_HOST_WIDE; + break; + case KVMPPC_GS_CLASS_META: + case KVMPPC_GS_CLASS_DWORD_REG: + case KVMPPC_GS_CLASS_WORD_REG: + case KVMPPC_GS_CLASS_VECTOR: + case KVMPPC_GS_CLASS_INTR: + break; + } + + return flags; +} +EXPORT_SYMBOL_GPL(kvmppc_gsid_flags); + +/** + * kvmppc_gsid_size() - the size of a guest state ID + * @iden: guest state ID + * + * Returns the size of guest state ID. + */ +u16 kvmppc_gsid_size(u16 iden) +{ + int type; + + type = kvmppc_gsid_type(iden); + if (type == -1) + return 0; + + if (type >= __KVMPPC_GSE_TYPE_MAX) + return 0; + + return kvmppc_gse_iden_len[type]; +} +EXPORT_SYMBOL_GPL(kvmppc_gsid_size); + +/** + * kvmppc_gsid_mask() - the settable bits of a guest state ID + * @iden: guest state ID + * + * Returns a mask of settable bits for a guest state ID. + */ +u64 kvmppc_gsid_mask(u16 iden) +{ + u64 mask = ~0ull; + + switch (iden) { + case KVMPPC_GSID_LPCR: + mask = LPCR_DPFD | LPCR_ILE | LPCR_AIL | LPCR_LD | LPCR_MER | + LPCR_GTSE; + break; + case KVMPPC_GSID_MSR: + mask = ~(MSR_HV | MSR_S | MSR_ME); + break; + } + + return mask; +} +EXPORT_SYMBOL_GPL(kvmppc_gsid_mask); + +/** + * __kvmppc_gse_put() - add a guest state element to a buffer + * @gsb: buffer to the element to + * @iden: guest state ID + * @size: length of data + * @data: pointer to data + */ +int __kvmppc_gse_put(struct kvmppc_gs_buff *gsb, u16 iden, u16 size, + const void *data) +{ + struct kvmppc_gs_elem *gse; + u16 total_size; + + total_size = sizeof(*gse) + size; + if (total_size + kvmppc_gsb_len(gsb) > kvmppc_gsb_capacity(gsb)) + return -ENOMEM; + + if (kvmppc_gsid_size(iden) != size) + return -EINVAL; + + gse = kvmppc_gsb_put(gsb, total_size); + gse->iden = cpu_to_be16(iden); + gse->len = cpu_to_be16(size); + memcpy(gse->data, data, size); + + return 0; +} +EXPORT_SYMBOL_GPL(__kvmppc_gse_put); + +/** + * kvmppc_gse_parse() - create a parse map from a guest state buffer + * @gsp: guest state parser + * @gsb: guest state buffer + */ +int kvmppc_gse_parse(struct kvmppc_gs_parser *gsp, struct kvmppc_gs_buff *gsb) +{ + struct kvmppc_gs_elem *curr; + int rem, i; + + kvmppc_gsb_for_each_elem(i, curr, gsb, rem) { + if (kvmppc_gse_len(curr) != + kvmppc_gsid_size(kvmppc_gse_iden(curr))) + return -EINVAL; + kvmppc_gsp_insert(gsp, kvmppc_gse_iden(curr), curr); + } + + if (kvmppc_gsb_nelems(gsb) != i) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(kvmppc_gse_parse); + +static inline int kvmppc_gse_flatten_iden(u16 iden) +{ + int bit = 0; + int class; + + class = kvmppc_gsid_class(iden); + + if (class == KVMPPC_GS_CLASS_GUESTWIDE) { + bit += iden - KVMPPC_GSE_GUESTWIDE_START; + return bit; + } + + bit += KVMPPC_GSE_GUESTWIDE_COUNT; + + if (class == KVMPPC_GS_CLASS_HOSTWIDE) { + bit += iden - KVMPPC_GSE_HOSTWIDE_START; + return bit; + } + + bit += KVMPPC_GSE_HOSTWIDE_COUNT; + + if (class == KVMPPC_GS_CLASS_META) { + bit += iden - KVMPPC_GSE_META_START; + return bit; + } + + bit += KVMPPC_GSE_META_COUNT; + + if (class == KVMPPC_GS_CLASS_DWORD_REG) { + bit += iden - KVMPPC_GSE_DW_REGS_START; + return bit; + } + + bit += KVMPPC_GSE_DW_REGS_COUNT; + + if (class == KVMPPC_GS_CLASS_WORD_REG) { + bit += iden - KVMPPC_GSE_W_REGS_START; + return bit; + } + + bit += KVMPPC_GSE_W_REGS_COUNT; + + if (class == KVMPPC_GS_CLASS_VECTOR) { + bit += iden - KVMPPC_GSE_VSRS_START; + return bit; + } + + bit += KVMPPC_GSE_VSRS_COUNT; + + if (class == KVMPPC_GS_CLASS_INTR) { + bit += iden - KVMPPC_GSE_INTR_REGS_START; + return bit; + } + + return 0; +} + +static inline u16 kvmppc_gse_unflatten_iden(int bit) +{ + u16 iden; + + if (bit < KVMPPC_GSE_GUESTWIDE_COUNT) { + iden = KVMPPC_GSE_GUESTWIDE_START + bit; + return iden; + } + bit -= KVMPPC_GSE_GUESTWIDE_COUNT; + + if (bit < KVMPPC_GSE_HOSTWIDE_COUNT) { + iden = KVMPPC_GSE_HOSTWIDE_START + bit; + return iden; + } + bit -= KVMPPC_GSE_HOSTWIDE_COUNT; + + if (bit < KVMPPC_GSE_META_COUNT) { + iden = KVMPPC_GSE_META_START + bit; + return iden; + } + bit -= KVMPPC_GSE_META_COUNT; + + if (bit < KVMPPC_GSE_DW_REGS_COUNT) { + iden = KVMPPC_GSE_DW_REGS_START + bit; + return iden; + } + bit -= KVMPPC_GSE_DW_REGS_COUNT; + + if (bit < KVMPPC_GSE_W_REGS_COUNT) { + iden = KVMPPC_GSE_W_REGS_START + bit; + return iden; + } + bit -= KVMPPC_GSE_W_REGS_COUNT; + + if (bit < KVMPPC_GSE_VSRS_COUNT) { + iden = KVMPPC_GSE_VSRS_START + bit; + return iden; + } + bit -= KVMPPC_GSE_VSRS_COUNT; + + if (bit < KVMPPC_GSE_IDEN_COUNT) { + iden = KVMPPC_GSE_INTR_REGS_START + bit; + return iden; + } + + return 0; +} + +/** + * kvmppc_gsp_insert() - add a mapping from an guest state ID to an element + * @gsp: guest state parser + * @iden: guest state id (key) + * @gse: guest state element (value) + */ +void kvmppc_gsp_insert(struct kvmppc_gs_parser *gsp, u16 iden, + struct kvmppc_gs_elem *gse) +{ + int i; + + i = kvmppc_gse_flatten_iden(iden); + kvmppc_gsbm_set(&gsp->iterator, iden); + gsp->gses[i] = gse; +} +EXPORT_SYMBOL_GPL(kvmppc_gsp_insert); + +/** + * kvmppc_gsp_lookup() - lookup an element from a guest state ID + * @gsp: guest state parser + * @iden: guest state ID (key) + * + * Returns the guest state element if present. + */ +struct kvmppc_gs_elem *kvmppc_gsp_lookup(struct kvmppc_gs_parser *gsp, u16 iden) +{ + int i; + + i = kvmppc_gse_flatten_iden(iden); + return gsp->gses[i]; +} +EXPORT_SYMBOL_GPL(kvmppc_gsp_lookup); + +/** + * kvmppc_gsbm_set() - set the guest state ID + * @gsbm: guest state bitmap + * @iden: guest state ID + */ +void kvmppc_gsbm_set(struct kvmppc_gs_bitmap *gsbm, u16 iden) +{ + set_bit(kvmppc_gse_flatten_iden(iden), gsbm->bitmap); +} +EXPORT_SYMBOL_GPL(kvmppc_gsbm_set); + +/** + * kvmppc_gsbm_clear() - clear the guest state ID + * @gsbm: guest state bitmap + * @iden: guest state ID + */ +void kvmppc_gsbm_clear(struct kvmppc_gs_bitmap *gsbm, u16 iden) +{ + clear_bit(kvmppc_gse_flatten_iden(iden), gsbm->bitmap); +} +EXPORT_SYMBOL_GPL(kvmppc_gsbm_clear); + +/** + * kvmppc_gsbm_test() - test the guest state ID + * @gsbm: guest state bitmap + * @iden: guest state ID + */ +bool kvmppc_gsbm_test(struct kvmppc_gs_bitmap *gsbm, u16 iden) +{ + return test_bit(kvmppc_gse_flatten_iden(iden), gsbm->bitmap); +} +EXPORT_SYMBOL_GPL(kvmppc_gsbm_test); + +/** + * kvmppc_gsbm_next() - return the next set guest state ID + * @gsbm: guest state bitmap + * @prev: last guest state ID + */ +u16 kvmppc_gsbm_next(struct kvmppc_gs_bitmap *gsbm, u16 prev) +{ + int bit, pbit; + + pbit = prev ? kvmppc_gse_flatten_iden(prev) + 1 : 0; + bit = find_next_bit(gsbm->bitmap, KVMPPC_GSE_IDEN_COUNT, pbit); + + if (bit < KVMPPC_GSE_IDEN_COUNT) + return kvmppc_gse_unflatten_iden(bit); + return 0; +} +EXPORT_SYMBOL_GPL(kvmppc_gsbm_next); + +/** + * kvmppc_gsm_init() - initialize a guest state message + * @gsm: guest state message + * @ops: callbacks + * @data: private data + * @flags: guest wide or thread wide + */ +int kvmppc_gsm_init(struct kvmppc_gs_msg *gsm, struct kvmppc_gs_msg_ops *ops, + void *data, unsigned long flags) +{ + memset(gsm, 0, sizeof(*gsm)); + gsm->ops = ops; + gsm->data = data; + gsm->flags = flags; + + return 0; +} +EXPORT_SYMBOL_GPL(kvmppc_gsm_init); + +/** + * kvmppc_gsm_new() - creates a new guest state message + * @ops: callbacks + * @data: private data + * @flags: guest wide or thread wide + * @gfp_flags: GFP allocation flags + * + * Returns an initialized guest state message. + */ +struct kvmppc_gs_msg *kvmppc_gsm_new(struct kvmppc_gs_msg_ops *ops, void *data, + unsigned long flags, gfp_t gfp_flags) +{ + struct kvmppc_gs_msg *gsm; + + gsm = kzalloc(sizeof(*gsm), gfp_flags); + if (!gsm) + return NULL; + + kvmppc_gsm_init(gsm, ops, data, flags); + + return gsm; +} +EXPORT_SYMBOL_GPL(kvmppc_gsm_new); + +/** + * kvmppc_gsm_size() - creates a new guest state message + * @gsm: self + * + * Returns the size required for the message. + */ +size_t kvmppc_gsm_size(struct kvmppc_gs_msg *gsm) +{ + if (gsm->ops->get_size) + return gsm->ops->get_size(gsm); + return 0; +} +EXPORT_SYMBOL_GPL(kvmppc_gsm_size); + +/** + * kvmppc_gsm_free() - free guest state message + * @gsm: guest state message + * + * Returns the size required for the message. + */ +void kvmppc_gsm_free(struct kvmppc_gs_msg *gsm) +{ + kfree(gsm); +} +EXPORT_SYMBOL_GPL(kvmppc_gsm_free); + +/** + * kvmppc_gsm_fill_info() - serialises message to guest state buffer format + * @gsm: self + * @gsb: buffer to serialise into + */ +int kvmppc_gsm_fill_info(struct kvmppc_gs_msg *gsm, struct kvmppc_gs_buff *gsb) +{ + if (!gsm->ops->fill_info) + return -EINVAL; + + return gsm->ops->fill_info(gsb, gsm); +} +EXPORT_SYMBOL_GPL(kvmppc_gsm_fill_info); + +/** + * kvmppc_gsm_refresh_info() - deserialises from guest state buffer + * @gsm: self + * @gsb: buffer to serialise from + */ +int kvmppc_gsm_refresh_info(struct kvmppc_gs_msg *gsm, + struct kvmppc_gs_buff *gsb) +{ + if (!gsm->ops->fill_info) + return -EINVAL; + + return gsm->ops->refresh_info(gsm, gsb); +} +EXPORT_SYMBOL_GPL(kvmppc_gsm_refresh_info); + +/** + * kvmppc_gsb_send - send all elements in the buffer to the hypervisor. + * @gsb: guest state buffer + * @flags: guest wide or thread wide + * + * Performs the H_GUEST_SET_STATE hcall for the guest state buffer. + */ +int kvmppc_gsb_send(struct kvmppc_gs_buff *gsb, unsigned long flags) +{ + unsigned long hflags = 0; + unsigned long i; + int rc; + + if (kvmppc_gsb_nelems(gsb) == 0) + return 0; + + if (flags & KVMPPC_GS_FLAGS_WIDE) + hflags |= H_GUEST_FLAGS_WIDE; + if (flags & KVMPPC_GS_FLAGS_HOST_WIDE) + hflags |= H_GUEST_FLAGS_HOST_WIDE; + + rc = plpar_guest_set_state(hflags, gsb->guest_id, gsb->vcpu_id, + __pa(gsb->hdr), gsb->capacity, &i); + return rc; +} +EXPORT_SYMBOL_GPL(kvmppc_gsb_send); + +/** + * kvmppc_gsb_recv - request all elements in the buffer have their value + * updated. + * @gsb: guest state buffer + * @flags: guest wide or thread wide + * + * Performs the H_GUEST_GET_STATE hcall for the guest state buffer. + * After returning from the hcall the guest state elements that were + * present in the buffer will have updated values from the hypervisor. + */ +int kvmppc_gsb_recv(struct kvmppc_gs_buff *gsb, unsigned long flags) +{ + unsigned long hflags = 0; + unsigned long i; + int rc; + + if (flags & KVMPPC_GS_FLAGS_WIDE) + hflags |= H_GUEST_FLAGS_WIDE; + if (flags & KVMPPC_GS_FLAGS_HOST_WIDE) + hflags |= H_GUEST_FLAGS_HOST_WIDE; + + rc = plpar_guest_get_state(hflags, gsb->guest_id, gsb->vcpu_id, + __pa(gsb->hdr), gsb->capacity, &i); + return rc; +} +EXPORT_SYMBOL_GPL(kvmppc_gsb_recv); diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 04494a4fb37a..9a89a6d98f97 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -69,7 +69,7 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) /* * Common checks before entering the guest world. Call with interrupts - * disabled. + * enabled. * * returns: * @@ -304,11 +304,11 @@ int kvmppc_emulate_mmio(struct kvm_vcpu *vcpu) break; case EMULATE_FAIL: { - u32 last_inst; + ppc_inst_t last_inst; kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); kvm_debug_ratelimited("Guest access to device memory using unsupported instruction (opcode: %#08x)\n", - last_inst); + ppc_inst_val(last_inst)); /* * Injecting a Data Storage here is a bit more @@ -321,7 +321,9 @@ int kvmppc_emulate_mmio(struct kvm_vcpu *vcpu) if (vcpu->mmio_is_write) dsisr |= DSISR_ISSTORE; - kvmppc_core_queue_data_storage(vcpu, vcpu->arch.vaddr_accessed, dsisr); + kvmppc_core_queue_data_storage(vcpu, + kvmppc_get_msr(vcpu) & SRR1_PREFIXED, + vcpu->arch.vaddr_accessed, dsisr); } else { /* * BookE does not send a SIGBUS on a bad @@ -435,21 +437,6 @@ int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, } EXPORT_SYMBOL_GPL(kvmppc_ld); -int kvm_arch_hardware_enable(void) -{ - return 0; -} - -int kvm_arch_hardware_setup(void *opaque) -{ - return 0; -} - -int kvm_arch_check_processor_compat(void *opaque) -{ - return kvmppc_core_check_processor_compat(); -} - int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { struct kvmppc_ops *kvm_ops = NULL; @@ -541,7 +528,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ENABLE_CAP: case KVM_CAP_ONE_REG: case KVM_CAP_IOEVENTFD: - case KVM_CAP_DEVICE_CTRL: case KVM_CAP_IMMEDIATE_EXIT: case KVM_CAP_SET_GUEST_DEBUG: r = 1; @@ -564,12 +550,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) #ifdef CONFIG_PPC_BOOK3S_64 case KVM_CAP_SPAPR_TCE: + fallthrough; case KVM_CAP_SPAPR_TCE_64: - r = 1; - break; case KVM_CAP_SPAPR_TCE_VFIO: - r = !!cpu_has_feature(CPU_FTR_HVMODE); - break; case KVM_CAP_PPC_RTAS: case KVM_CAP_PPC_FIXUP_HCALL: case KVM_CAP_PPC_ENABLE_HCALL: @@ -591,6 +574,12 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; #endif +#ifdef CONFIG_HAVE_KVM_IRQCHIP + case KVM_CAP_IRQFD_RESAMPLE: + r = !xive_enabled(); + break; +#endif + case KVM_CAP_PPC_ALLOC_HTAB: r = hv_enabled; break; @@ -620,9 +609,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = 8 | 4 | 2 | 1; } break; - case KVM_CAP_PPC_RMA: - r = 0; - break; case KVM_CAP_PPC_HWRNG: r = kvmppc_hwrng_present(); break; @@ -639,13 +625,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; #endif case KVM_CAP_SYNC_MMU: -#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE - r = hv_enabled; -#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER) + BUILD_BUG_ON(!IS_ENABLED(CONFIG_KVM_GENERIC_MMU_NOTIFIER)); r = 1; -#else - r = 0; -#endif break; #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE case KVM_CAP_PPC_HTAB_FD: @@ -782,8 +763,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) { int err; - hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); - vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup; + hrtimer_setup(&vcpu->arch.dec_timer, kvmppc_decrementer_wakeup, CLOCK_REALTIME, + HRTIMER_MODE_ABS); #ifdef CONFIG_KVM_EXIT_TIMING mutex_init(&vcpu->arch.exit_timing_lock); @@ -941,11 +922,11 @@ static inline void kvmppc_set_vsr_dword(struct kvm_vcpu *vcpu, return; if (index >= 32) { - val.vval = VCPU_VSX_VR(vcpu, index - 32); + kvmppc_get_vsx_vr(vcpu, index - 32, &val.vval); val.vsxval[offset] = gpr; - VCPU_VSX_VR(vcpu, index - 32) = val.vval; + kvmppc_set_vsx_vr(vcpu, index - 32, &val.vval); } else { - VCPU_VSX_FPR(vcpu, index, offset) = gpr; + kvmppc_set_vsx_fpr(vcpu, index, offset, gpr); } } @@ -956,13 +937,13 @@ static inline void kvmppc_set_vsr_dword_dump(struct kvm_vcpu *vcpu, int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; if (index >= 32) { - val.vval = VCPU_VSX_VR(vcpu, index - 32); + kvmppc_get_vsx_vr(vcpu, index - 32, &val.vval); val.vsxval[0] = gpr; val.vsxval[1] = gpr; - VCPU_VSX_VR(vcpu, index - 32) = val.vval; + kvmppc_set_vsx_vr(vcpu, index - 32, &val.vval); } else { - VCPU_VSX_FPR(vcpu, index, 0) = gpr; - VCPU_VSX_FPR(vcpu, index, 1) = gpr; + kvmppc_set_vsx_fpr(vcpu, index, 0, gpr); + kvmppc_set_vsx_fpr(vcpu, index, 1, gpr); } } @@ -977,12 +958,12 @@ static inline void kvmppc_set_vsr_word_dump(struct kvm_vcpu *vcpu, val.vsx32val[1] = gpr; val.vsx32val[2] = gpr; val.vsx32val[3] = gpr; - VCPU_VSX_VR(vcpu, index - 32) = val.vval; + kvmppc_set_vsx_vr(vcpu, index - 32, &val.vval); } else { val.vsx32val[0] = gpr; val.vsx32val[1] = gpr; - VCPU_VSX_FPR(vcpu, index, 0) = val.vsxval[0]; - VCPU_VSX_FPR(vcpu, index, 1) = val.vsxval[0]; + kvmppc_set_vsx_fpr(vcpu, index, 0, val.vsxval[0]); + kvmppc_set_vsx_fpr(vcpu, index, 1, val.vsxval[0]); } } @@ -998,15 +979,15 @@ static inline void kvmppc_set_vsr_word(struct kvm_vcpu *vcpu, return; if (index >= 32) { - val.vval = VCPU_VSX_VR(vcpu, index - 32); + kvmppc_get_vsx_vr(vcpu, index - 32, &val.vval); val.vsx32val[offset] = gpr32; - VCPU_VSX_VR(vcpu, index - 32) = val.vval; + kvmppc_set_vsx_vr(vcpu, index - 32, &val.vval); } else { dword_offset = offset / 2; word_offset = offset % 2; - val.vsxval[0] = VCPU_VSX_FPR(vcpu, index, dword_offset); + val.vsxval[0] = kvmppc_get_vsx_fpr(vcpu, index, dword_offset); val.vsx32val[word_offset] = gpr32; - VCPU_VSX_FPR(vcpu, index, dword_offset) = val.vsxval[0]; + kvmppc_set_vsx_fpr(vcpu, index, dword_offset, val.vsxval[0]); } } #endif /* CONFIG_VSX */ @@ -1065,9 +1046,9 @@ static inline void kvmppc_set_vmx_dword(struct kvm_vcpu *vcpu, if (offset == -1) return; - val.vval = VCPU_VSX_VR(vcpu, index); + kvmppc_get_vsx_vr(vcpu, index, &val.vval); val.vsxval[offset] = gpr; - VCPU_VSX_VR(vcpu, index) = val.vval; + kvmppc_set_vsx_vr(vcpu, index, &val.vval); } static inline void kvmppc_set_vmx_word(struct kvm_vcpu *vcpu, @@ -1081,9 +1062,9 @@ static inline void kvmppc_set_vmx_word(struct kvm_vcpu *vcpu, if (offset == -1) return; - val.vval = VCPU_VSX_VR(vcpu, index); + kvmppc_get_vsx_vr(vcpu, index, &val.vval); val.vsx32val[offset] = gpr32; - VCPU_VSX_VR(vcpu, index) = val.vval; + kvmppc_set_vsx_vr(vcpu, index, &val.vval); } static inline void kvmppc_set_vmx_hword(struct kvm_vcpu *vcpu, @@ -1097,9 +1078,9 @@ static inline void kvmppc_set_vmx_hword(struct kvm_vcpu *vcpu, if (offset == -1) return; - val.vval = VCPU_VSX_VR(vcpu, index); + kvmppc_get_vsx_vr(vcpu, index, &val.vval); val.vsx16val[offset] = gpr16; - VCPU_VSX_VR(vcpu, index) = val.vval; + kvmppc_set_vsx_vr(vcpu, index, &val.vval); } static inline void kvmppc_set_vmx_byte(struct kvm_vcpu *vcpu, @@ -1113,9 +1094,9 @@ static inline void kvmppc_set_vmx_byte(struct kvm_vcpu *vcpu, if (offset == -1) return; - val.vval = VCPU_VSX_VR(vcpu, index); + kvmppc_get_vsx_vr(vcpu, index, &val.vval); val.vsx8val[offset] = gpr8; - VCPU_VSX_VR(vcpu, index) = val.vval; + kvmppc_set_vsx_vr(vcpu, index, &val.vval); } #endif /* CONFIG_ALTIVEC */ @@ -1201,14 +1182,14 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu) if (vcpu->kvm->arch.kvm_ops->giveup_ext) vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_FP); - VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; + kvmppc_set_fpr(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK, gpr); break; #ifdef CONFIG_PPC_BOOK3S case KVM_MMIO_REG_QPR: vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; break; case KVM_MMIO_REG_FQPR: - VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; + kvmppc_set_fpr(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK, gpr); vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; break; #endif @@ -1426,9 +1407,9 @@ static inline int kvmppc_get_vsr_data(struct kvm_vcpu *vcpu, int rs, u64 *val) } if (rs < 32) { - *val = VCPU_VSX_FPR(vcpu, rs, vsx_offset); + *val = kvmppc_get_vsx_fpr(vcpu, rs, vsx_offset); } else { - reg.vval = VCPU_VSX_VR(vcpu, rs - 32); + kvmppc_get_vsx_vr(vcpu, rs - 32, ®.vval); *val = reg.vsxval[vsx_offset]; } break; @@ -1445,10 +1426,10 @@ static inline int kvmppc_get_vsr_data(struct kvm_vcpu *vcpu, int rs, u64 *val) if (rs < 32) { dword_offset = vsx_offset / 2; word_offset = vsx_offset % 2; - reg.vsxval[0] = VCPU_VSX_FPR(vcpu, rs, dword_offset); + reg.vsxval[0] = kvmppc_get_vsx_fpr(vcpu, rs, dword_offset); *val = reg.vsx32val[word_offset]; } else { - reg.vval = VCPU_VSX_VR(vcpu, rs - 32); + kvmppc_get_vsx_vr(vcpu, rs - 32, ®.vval); *val = reg.vsx32val[vsx_offset]; } break; @@ -1563,7 +1544,7 @@ static int kvmppc_get_vmx_dword(struct kvm_vcpu *vcpu, int index, u64 *val) if (vmx_offset == -1) return -1; - reg.vval = VCPU_VSX_VR(vcpu, index); + kvmppc_get_vsx_vr(vcpu, index, ®.vval); *val = reg.vsxval[vmx_offset]; return result; @@ -1581,7 +1562,7 @@ static int kvmppc_get_vmx_word(struct kvm_vcpu *vcpu, int index, u64 *val) if (vmx_offset == -1) return -1; - reg.vval = VCPU_VSX_VR(vcpu, index); + kvmppc_get_vsx_vr(vcpu, index, ®.vval); *val = reg.vsx32val[vmx_offset]; return result; @@ -1599,7 +1580,7 @@ static int kvmppc_get_vmx_hword(struct kvm_vcpu *vcpu, int index, u64 *val) if (vmx_offset == -1) return -1; - reg.vval = VCPU_VSX_VR(vcpu, index); + kvmppc_get_vsx_vr(vcpu, index, ®.vval); *val = reg.vsx16val[vmx_offset]; return result; @@ -1617,7 +1598,7 @@ static int kvmppc_get_vmx_byte(struct kvm_vcpu *vcpu, int index, u64 *val) if (vmx_offset == -1) return -1; - reg.vval = VCPU_VSX_VR(vcpu, index); + kvmppc_get_vsx_vr(vcpu, index, ®.vval); *val = reg.vsx8val[vmx_offset]; return result; @@ -1726,17 +1707,17 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) r = -ENXIO; break; } - val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0]; + kvmppc_get_vsx_vr(vcpu, reg->id - KVM_REG_PPC_VR0, &val.vval); break; case KVM_REG_PPC_VSCR: if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { r = -ENXIO; break; } - val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]); + val = get_reg_val(reg->id, kvmppc_get_vscr(vcpu)); break; case KVM_REG_PPC_VRSAVE: - val = get_reg_val(reg->id, vcpu->arch.vrsave); + val = get_reg_val(reg->id, kvmppc_get_vrsave(vcpu)); break; #endif /* CONFIG_ALTIVEC */ default: @@ -1777,21 +1758,21 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) r = -ENXIO; break; } - vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval; + kvmppc_set_vsx_vr(vcpu, reg->id - KVM_REG_PPC_VR0, &val.vval); break; case KVM_REG_PPC_VSCR: if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { r = -ENXIO; break; } - vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val); + kvmppc_set_vscr(vcpu, set_reg_val(reg->id, val)); break; case KVM_REG_PPC_VRSAVE: if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { r = -ENXIO; break; } - vcpu->arch.vrsave = set_reg_val(reg->id, val); + kvmppc_set_vrsave(vcpu, set_reg_val(reg->id, val)); break; #endif /* CONFIG_ALTIVEC */ default: @@ -1865,7 +1846,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_sigset_activate(vcpu); - if (run->immediate_exit) + if (!vcpu->wants_to_run) r = -EINTR; else r = kvmppc_vcpu_run(vcpu); @@ -1946,54 +1927,48 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, #endif #ifdef CONFIG_KVM_MPIC case KVM_CAP_IRQ_MPIC: { - struct fd f; + CLASS(fd, f)(cap->args[0]); struct kvm_device *dev; r = -EBADF; - f = fdget(cap->args[0]); - if (!f.file) + if (fd_empty(f)) break; r = -EPERM; - dev = kvm_device_from_filp(f.file); + dev = kvm_device_from_filp(fd_file(f)); if (dev) r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); - fdput(f); break; } #endif #ifdef CONFIG_KVM_XICS case KVM_CAP_IRQ_XICS: { - struct fd f; + CLASS(fd, f)(cap->args[0]); struct kvm_device *dev; r = -EBADF; - f = fdget(cap->args[0]); - if (!f.file) + if (fd_empty(f)) break; r = -EPERM; - dev = kvm_device_from_filp(f.file); + dev = kvm_device_from_filp(fd_file(f)); if (dev) { if (xics_on_xive()) r = kvmppc_xive_connect_vcpu(dev, vcpu, cap->args[1]); else r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]); } - - fdput(f); break; } #endif /* CONFIG_KVM_XICS */ #ifdef CONFIG_KVM_XIVE case KVM_CAP_PPC_IRQ_XIVE: { - struct fd f; + CLASS(fd, f)(cap->args[0]); struct kvm_device *dev; r = -EBADF; - f = fdget(cap->args[0]); - if (!f.file) + if (fd_empty(f)) break; r = -ENXIO; @@ -2001,12 +1976,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, break; r = -EPERM; - dev = kvm_device_from_filp(f.file); + dev = kvm_device_from_filp(fd_file(f)); if (dev) r = kvmppc_xive_native_connect_vcpu(dev, vcpu, cap->args[1]); - - fdput(f); break; } #endif /* CONFIG_KVM_XIVE */ @@ -2055,8 +2028,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, return -EINVAL; } -long kvm_arch_vcpu_async_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) +long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl, + unsigned long arg) { struct kvm_vcpu *vcpu = filp->private_data; void __user *argp = (void __user *)arg; @@ -2386,12 +2359,11 @@ static int kvmppc_get_cpu_char(struct kvm_ppc_cpu_char *cp) } #endif -long kvm_arch_vm_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) +int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { struct kvm *kvm __maybe_unused = filp->private_data; void __user *argp = (void __user *)arg; - long r; + int r; switch (ioctl) { case KVM_PPC_GET_PVINFO: { @@ -2544,11 +2516,6 @@ void kvmppc_init_lpid(unsigned long nr_lpids_param) } EXPORT_SYMBOL_GPL(kvmppc_init_lpid); -int kvm_arch_init(void *opaque) -{ - return 0; -} - EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ppc_instr); void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry) @@ -2557,9 +2524,8 @@ void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_ vcpu->kvm->arch.kvm_ops->create_vcpu_debugfs(vcpu, debugfs_dentry); } -int kvm_arch_create_vm_debugfs(struct kvm *kvm) +void kvm_arch_create_vm_debugfs(struct kvm *kvm) { if (kvm->arch.kvm_ops->create_vm_debugfs) kvm->arch.kvm_ops->create_vm_debugfs(kvm); - return 0; } diff --git a/arch/powerpc/kvm/test-guest-state-buffer.c b/arch/powerpc/kvm/test-guest-state-buffer.c new file mode 100644 index 000000000000..5ccca306997a --- /dev/null +++ b/arch/powerpc/kvm/test-guest-state-buffer.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <linux/init.h> +#include <linux/log2.h> +#include <kunit/test.h> + +#include <asm/guest-state-buffer.h> +#include <asm/kvm_ppc.h> + +static void test_creating_buffer(struct kunit *test) +{ + struct kvmppc_gs_buff *gsb; + size_t size = 0x100; + + gsb = kvmppc_gsb_new(size, 0, 0, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsb); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsb->hdr); + + KUNIT_EXPECT_EQ(test, gsb->capacity, roundup_pow_of_two(size)); + KUNIT_EXPECT_EQ(test, gsb->len, sizeof(__be32)); + + kvmppc_gsb_free(gsb); +} + +static void test_adding_element(struct kunit *test) +{ + const struct kvmppc_gs_elem *head, *curr; + union { + __vector128 v; + u64 dw[2]; + } u; + int rem; + struct kvmppc_gs_buff *gsb; + size_t size = 0x1000; + int i, rc; + u64 data; + + gsb = kvmppc_gsb_new(size, 0, 0, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsb); + + /* Single elements, direct use of __kvmppc_gse_put() */ + data = 0xdeadbeef; + rc = __kvmppc_gse_put(gsb, KVMPPC_GSID_GPR(0), 8, &data); + KUNIT_EXPECT_GE(test, rc, 0); + + head = kvmppc_gsb_data(gsb); + KUNIT_EXPECT_EQ(test, kvmppc_gse_iden(head), KVMPPC_GSID_GPR(0)); + KUNIT_EXPECT_EQ(test, kvmppc_gse_len(head), 8); + data = 0; + memcpy(&data, kvmppc_gse_data(head), 8); + KUNIT_EXPECT_EQ(test, data, 0xdeadbeef); + + /* Multiple elements, simple wrapper */ + rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_GPR(1), 0xcafef00d); + KUNIT_EXPECT_GE(test, rc, 0); + + u.dw[0] = 0x1; + u.dw[1] = 0x2; + rc = kvmppc_gse_put_vector128(gsb, KVMPPC_GSID_VSRS(0), &u.v); + KUNIT_EXPECT_GE(test, rc, 0); + u.dw[0] = 0x0; + u.dw[1] = 0x0; + + kvmppc_gsb_for_each_elem(i, curr, gsb, rem) { + switch (i) { + case 0: + KUNIT_EXPECT_EQ(test, kvmppc_gse_iden(curr), + KVMPPC_GSID_GPR(0)); + KUNIT_EXPECT_EQ(test, kvmppc_gse_len(curr), 8); + KUNIT_EXPECT_EQ(test, kvmppc_gse_get_be64(curr), + 0xdeadbeef); + break; + case 1: + KUNIT_EXPECT_EQ(test, kvmppc_gse_iden(curr), + KVMPPC_GSID_GPR(1)); + KUNIT_EXPECT_EQ(test, kvmppc_gse_len(curr), 8); + KUNIT_EXPECT_EQ(test, kvmppc_gse_get_u64(curr), + 0xcafef00d); + break; + case 2: + KUNIT_EXPECT_EQ(test, kvmppc_gse_iden(curr), + KVMPPC_GSID_VSRS(0)); + KUNIT_EXPECT_EQ(test, kvmppc_gse_len(curr), 16); + kvmppc_gse_get_vector128(curr, &u.v); + KUNIT_EXPECT_EQ(test, u.dw[0], 0x1); + KUNIT_EXPECT_EQ(test, u.dw[1], 0x2); + break; + } + } + KUNIT_EXPECT_EQ(test, i, 3); + + kvmppc_gsb_reset(gsb); + KUNIT_EXPECT_EQ(test, kvmppc_gsb_nelems(gsb), 0); + KUNIT_EXPECT_EQ(test, kvmppc_gsb_len(gsb), + sizeof(struct kvmppc_gs_header)); + + kvmppc_gsb_free(gsb); +} + +static void test_gs_parsing(struct kunit *test) +{ + struct kvmppc_gs_elem *gse; + struct kvmppc_gs_parser gsp = { 0 }; + struct kvmppc_gs_buff *gsb; + size_t size = 0x1000; + u64 tmp1, tmp2; + + gsb = kvmppc_gsb_new(size, 0, 0, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsb); + + tmp1 = 0xdeadbeefull; + kvmppc_gse_put_u64(gsb, KVMPPC_GSID_GPR(0), tmp1); + + KUNIT_EXPECT_GE(test, kvmppc_gse_parse(&gsp, gsb), 0); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_GPR(0)); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gse); + + tmp2 = kvmppc_gse_get_u64(gse); + KUNIT_EXPECT_EQ(test, tmp2, 0xdeadbeefull); + + kvmppc_gsb_free(gsb); +} + +static void test_gs_bitmap(struct kunit *test) +{ + struct kvmppc_gs_bitmap gsbm = { 0 }; + struct kvmppc_gs_bitmap gsbm1 = { 0 }; + struct kvmppc_gs_bitmap gsbm2 = { 0 }; + u16 iden; + int i, j; + + i = 0; + for (u16 iden = KVMPPC_GSID_HOST_STATE_SIZE; + iden <= KVMPPC_GSID_PROCESS_TABLE; iden++) { + kvmppc_gsbm_set(&gsbm, iden); + kvmppc_gsbm_set(&gsbm1, iden); + KUNIT_EXPECT_TRUE(test, kvmppc_gsbm_test(&gsbm, iden)); + kvmppc_gsbm_clear(&gsbm, iden); + KUNIT_EXPECT_FALSE(test, kvmppc_gsbm_test(&gsbm, iden)); + i++; + } + + for (u16 iden = KVMPPC_GSID_L0_GUEST_HEAP; + iden <= KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM; iden++) { + kvmppc_gsbm_set(&gsbm, iden); + kvmppc_gsbm_set(&gsbm1, iden); + KUNIT_EXPECT_TRUE(test, kvmppc_gsbm_test(&gsbm, iden)); + kvmppc_gsbm_clear(&gsbm, iden); + KUNIT_EXPECT_FALSE(test, kvmppc_gsbm_test(&gsbm, iden)); + i++; + } + + for (u16 iden = KVMPPC_GSID_RUN_INPUT; iden <= KVMPPC_GSID_VPA; + iden++) { + kvmppc_gsbm_set(&gsbm, iden); + kvmppc_gsbm_set(&gsbm1, iden); + KUNIT_EXPECT_TRUE(test, kvmppc_gsbm_test(&gsbm, iden)); + kvmppc_gsbm_clear(&gsbm, iden); + KUNIT_EXPECT_FALSE(test, kvmppc_gsbm_test(&gsbm, iden)); + i++; + } + + for (u16 iden = KVMPPC_GSID_GPR(0); iden <= KVMPPC_GSE_DW_REGS_END; iden++) { + kvmppc_gsbm_set(&gsbm, iden); + kvmppc_gsbm_set(&gsbm1, iden); + KUNIT_EXPECT_TRUE(test, kvmppc_gsbm_test(&gsbm, iden)); + kvmppc_gsbm_clear(&gsbm, iden); + KUNIT_EXPECT_FALSE(test, kvmppc_gsbm_test(&gsbm, iden)); + i++; + } + + for (u16 iden = KVMPPC_GSID_CR; iden <= KVMPPC_GSID_PSPB; iden++) { + kvmppc_gsbm_set(&gsbm, iden); + kvmppc_gsbm_set(&gsbm1, iden); + KUNIT_EXPECT_TRUE(test, kvmppc_gsbm_test(&gsbm, iden)); + kvmppc_gsbm_clear(&gsbm, iden); + KUNIT_EXPECT_FALSE(test, kvmppc_gsbm_test(&gsbm, iden)); + i++; + } + + for (u16 iden = KVMPPC_GSID_VSRS(0); iden <= KVMPPC_GSID_VSRS(63); + iden++) { + kvmppc_gsbm_set(&gsbm, iden); + kvmppc_gsbm_set(&gsbm1, iden); + KUNIT_EXPECT_TRUE(test, kvmppc_gsbm_test(&gsbm, iden)); + kvmppc_gsbm_clear(&gsbm, iden); + KUNIT_EXPECT_FALSE(test, kvmppc_gsbm_test(&gsbm, iden)); + i++; + } + + for (u16 iden = KVMPPC_GSID_HDAR; iden <= KVMPPC_GSID_ASDR; iden++) { + kvmppc_gsbm_set(&gsbm, iden); + kvmppc_gsbm_set(&gsbm1, iden); + KUNIT_EXPECT_TRUE(test, kvmppc_gsbm_test(&gsbm, iden)); + kvmppc_gsbm_clear(&gsbm, iden); + KUNIT_EXPECT_FALSE(test, kvmppc_gsbm_test(&gsbm, iden)); + i++; + } + + j = 0; + kvmppc_gsbm_for_each(&gsbm1, iden) + { + kvmppc_gsbm_set(&gsbm2, iden); + j++; + } + KUNIT_EXPECT_EQ(test, i, j); + KUNIT_EXPECT_MEMEQ(test, &gsbm1, &gsbm2, sizeof(gsbm1)); +} + +struct kvmppc_gs_msg_test1_data { + u64 a; + u32 b; + struct kvmppc_gs_part_table c; + struct kvmppc_gs_proc_table d; + struct kvmppc_gs_buff_info e; +}; + +static size_t test1_get_size(struct kvmppc_gs_msg *gsm) +{ + size_t size = 0; + u16 ids[] = { + KVMPPC_GSID_PARTITION_TABLE, + KVMPPC_GSID_PROCESS_TABLE, + KVMPPC_GSID_RUN_INPUT, + KVMPPC_GSID_GPR(0), + KVMPPC_GSID_CR, + }; + + for (int i = 0; i < ARRAY_SIZE(ids); i++) + size += kvmppc_gse_total_size(kvmppc_gsid_size(ids[i])); + return size; +} + +static int test1_fill_info(struct kvmppc_gs_buff *gsb, + struct kvmppc_gs_msg *gsm) +{ + struct kvmppc_gs_msg_test1_data *data = gsm->data; + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_GPR(0))) + kvmppc_gse_put_u64(gsb, KVMPPC_GSID_GPR(0), data->a); + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_CR)) + kvmppc_gse_put_u32(gsb, KVMPPC_GSID_CR, data->b); + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_PARTITION_TABLE)) + kvmppc_gse_put_part_table(gsb, KVMPPC_GSID_PARTITION_TABLE, + data->c); + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_PROCESS_TABLE)) + kvmppc_gse_put_proc_table(gsb, KVMPPC_GSID_PARTITION_TABLE, + data->d); + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_RUN_INPUT)) + kvmppc_gse_put_buff_info(gsb, KVMPPC_GSID_RUN_INPUT, data->e); + + return 0; +} + +static int test1_refresh_info(struct kvmppc_gs_msg *gsm, + struct kvmppc_gs_buff *gsb) +{ + struct kvmppc_gs_parser gsp = { 0 }; + struct kvmppc_gs_msg_test1_data *data = gsm->data; + struct kvmppc_gs_elem *gse; + int rc; + + rc = kvmppc_gse_parse(&gsp, gsb); + if (rc < 0) + return rc; + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_GPR(0)); + if (gse) + data->a = kvmppc_gse_get_u64(gse); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_CR); + if (gse) + data->b = kvmppc_gse_get_u32(gse); + + return 0; +} + +static struct kvmppc_gs_msg_ops gs_msg_test1_ops = { + .get_size = test1_get_size, + .fill_info = test1_fill_info, + .refresh_info = test1_refresh_info, +}; + +static void test_gs_msg(struct kunit *test) +{ + struct kvmppc_gs_msg_test1_data test1_data = { + .a = 0xdeadbeef, + .b = 0x1, + }; + struct kvmppc_gs_msg *gsm; + struct kvmppc_gs_buff *gsb; + + gsm = kvmppc_gsm_new(&gs_msg_test1_ops, &test1_data, GSM_SEND, + GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsm); + + gsb = kvmppc_gsb_new(kvmppc_gsm_size(gsm), 0, 0, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsb); + + kvmppc_gsm_include(gsm, KVMPPC_GSID_PARTITION_TABLE); + kvmppc_gsm_include(gsm, KVMPPC_GSID_PROCESS_TABLE); + kvmppc_gsm_include(gsm, KVMPPC_GSID_RUN_INPUT); + kvmppc_gsm_include(gsm, KVMPPC_GSID_GPR(0)); + kvmppc_gsm_include(gsm, KVMPPC_GSID_CR); + + kvmppc_gsm_fill_info(gsm, gsb); + + memset(&test1_data, 0, sizeof(test1_data)); + + kvmppc_gsm_refresh_info(gsm, gsb); + KUNIT_EXPECT_EQ(test, test1_data.a, 0xdeadbeef); + KUNIT_EXPECT_EQ(test, test1_data.b, 0x1); + + kvmppc_gsm_free(gsm); +} + +/* Test data struct for hostwide/L0 counters */ +struct kvmppc_gs_msg_test_hostwide_data { + u64 guest_heap; + u64 guest_heap_max; + u64 guest_pgtable_size; + u64 guest_pgtable_size_max; + u64 guest_pgtable_reclaim; +}; + +static size_t test_hostwide_get_size(struct kvmppc_gs_msg *gsm) + +{ + size_t size = 0; + u16 ids[] = { + KVMPPC_GSID_L0_GUEST_HEAP, + KVMPPC_GSID_L0_GUEST_HEAP_MAX, + KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE, + KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX, + KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM + }; + + for (int i = 0; i < ARRAY_SIZE(ids); i++) + size += kvmppc_gse_total_size(kvmppc_gsid_size(ids[i])); + return size; +} + +static int test_hostwide_fill_info(struct kvmppc_gs_buff *gsb, + struct kvmppc_gs_msg *gsm) +{ + struct kvmppc_gs_msg_test_hostwide_data *data = gsm->data; + + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_L0_GUEST_HEAP)) + kvmppc_gse_put_u64(gsb, KVMPPC_GSID_L0_GUEST_HEAP, + data->guest_heap); + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_L0_GUEST_HEAP_MAX)) + kvmppc_gse_put_u64(gsb, KVMPPC_GSID_L0_GUEST_HEAP_MAX, + data->guest_heap_max); + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE)) + kvmppc_gse_put_u64(gsb, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE, + data->guest_pgtable_size); + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX)) + kvmppc_gse_put_u64(gsb, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX, + data->guest_pgtable_size_max); + if (kvmppc_gsm_includes(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM)) + kvmppc_gse_put_u64(gsb, KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM, + data->guest_pgtable_reclaim); + + return 0; +} + +static int test_hostwide_refresh_info(struct kvmppc_gs_msg *gsm, + struct kvmppc_gs_buff *gsb) +{ + struct kvmppc_gs_parser gsp = { 0 }; + struct kvmppc_gs_msg_test_hostwide_data *data = gsm->data; + struct kvmppc_gs_elem *gse; + int rc; + + rc = kvmppc_gse_parse(&gsp, gsb); + if (rc < 0) + return rc; + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_HEAP); + if (gse) + data->guest_heap = kvmppc_gse_get_u64(gse); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_HEAP_MAX); + if (gse) + data->guest_heap_max = kvmppc_gse_get_u64(gse); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE); + if (gse) + data->guest_pgtable_size = kvmppc_gse_get_u64(gse); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX); + if (gse) + data->guest_pgtable_size_max = kvmppc_gse_get_u64(gse); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM); + if (gse) + data->guest_pgtable_reclaim = kvmppc_gse_get_u64(gse); + + return 0; +} + +static struct kvmppc_gs_msg_ops gs_msg_test_hostwide_ops = { + .get_size = test_hostwide_get_size, + .fill_info = test_hostwide_fill_info, + .refresh_info = test_hostwide_refresh_info, +}; + +static void test_gs_hostwide_msg(struct kunit *test) +{ + struct kvmppc_gs_msg_test_hostwide_data test_data = { + .guest_heap = 0xdeadbeef, + .guest_heap_max = ~0ULL, + .guest_pgtable_size = 0xff, + .guest_pgtable_size_max = 0xffffff, + .guest_pgtable_reclaim = 0xdeadbeef, + }; + struct kvmppc_gs_msg *gsm; + struct kvmppc_gs_buff *gsb; + + gsm = kvmppc_gsm_new(&gs_msg_test_hostwide_ops, &test_data, GSM_SEND, + GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsm); + + gsb = kvmppc_gsb_new(kvmppc_gsm_size(gsm), 0, 0, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsb); + + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_HEAP); + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_HEAP_MAX); + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE); + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX); + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM); + + kvmppc_gsm_fill_info(gsm, gsb); + + memset(&test_data, 0, sizeof(test_data)); + + kvmppc_gsm_refresh_info(gsm, gsb); + KUNIT_EXPECT_EQ(test, test_data.guest_heap, 0xdeadbeef); + KUNIT_EXPECT_EQ(test, test_data.guest_heap_max, ~0ULL); + KUNIT_EXPECT_EQ(test, test_data.guest_pgtable_size, 0xff); + KUNIT_EXPECT_EQ(test, test_data.guest_pgtable_size_max, 0xffffff); + KUNIT_EXPECT_EQ(test, test_data.guest_pgtable_reclaim, 0xdeadbeef); + + kvmppc_gsm_free(gsm); +} + +/* Test if the H_GUEST_GET_STATE for hostwide counters works */ +static void test_gs_hostwide_counters(struct kunit *test) +{ + struct kvmppc_gs_msg_test_hostwide_data test_data; + struct kvmppc_gs_parser gsp = { 0 }; + + struct kvmppc_gs_msg *gsm; + struct kvmppc_gs_buff *gsb; + struct kvmppc_gs_elem *gse; + int rc; + + if (!kvmhv_on_pseries()) + kunit_skip(test, "This test need a kmv-hv guest"); + + gsm = kvmppc_gsm_new(&gs_msg_test_hostwide_ops, &test_data, GSM_SEND, + GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsm); + + gsb = kvmppc_gsb_new(kvmppc_gsm_size(gsm), 0, 0, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gsb); + + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_HEAP); + + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_HEAP_MAX); + + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE); + + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX); + + kvmppc_gsm_include(gsm, KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM); + + kvmppc_gsm_fill_info(gsm, gsb); + + /* With HOST_WIDE flags guestid and vcpuid will be ignored */ + rc = kvmppc_gsb_recv(gsb, KVMPPC_GS_FLAGS_HOST_WIDE); + KUNIT_ASSERT_EQ(test, rc, 0); + + /* Parse the guest state buffer is successful */ + rc = kvmppc_gse_parse(&gsp, gsb); + KUNIT_ASSERT_EQ(test, rc, 0); + + /* Parse the GSB and get the counters */ + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_HEAP); + KUNIT_ASSERT_NOT_NULL_MSG(test, gse, "L0 Heap counter missing"); + kunit_info(test, "Guest Heap Size=%llu bytes", + kvmppc_gse_get_u64(gse)); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_HEAP_MAX); + KUNIT_ASSERT_NOT_NULL_MSG(test, gse, "L0 Heap counter max missing"); + kunit_info(test, "Guest Heap Size Max=%llu bytes", + kvmppc_gse_get_u64(gse)); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE); + KUNIT_ASSERT_NOT_NULL_MSG(test, gse, "L0 page-table size missing"); + kunit_info(test, "Guest Page-table Size=%llu bytes", + kvmppc_gse_get_u64(gse)); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_PGTABLE_SIZE_MAX); + KUNIT_ASSERT_NOT_NULL_MSG(test, gse, "L0 page-table size-max missing"); + kunit_info(test, "Guest Page-table Size Max=%llu bytes", + kvmppc_gse_get_u64(gse)); + + gse = kvmppc_gsp_lookup(&gsp, KVMPPC_GSID_L0_GUEST_PGTABLE_RECLAIM); + KUNIT_ASSERT_NOT_NULL_MSG(test, gse, "L0 page-table reclaim size missing"); + kunit_info(test, "Guest Page-table Reclaim Size=%llu bytes", + kvmppc_gse_get_u64(gse)); + + kvmppc_gsm_free(gsm); + kvmppc_gsb_free(gsb); +} + +static struct kunit_case guest_state_buffer_testcases[] = { + KUNIT_CASE(test_creating_buffer), + KUNIT_CASE(test_adding_element), + KUNIT_CASE(test_gs_bitmap), + KUNIT_CASE(test_gs_parsing), + KUNIT_CASE(test_gs_msg), + KUNIT_CASE(test_gs_hostwide_msg), + KUNIT_CASE(test_gs_hostwide_counters), + {} +}; + +static struct kunit_suite guest_state_buffer_test_suite = { + .name = "guest_state_buffer_test", + .test_cases = guest_state_buffer_testcases, +}; + +kunit_test_suites(&guest_state_buffer_test_suite); + +MODULE_DESCRIPTION("KUnit tests for Guest State Buffer APIs"); +MODULE_LICENSE("GPL"); diff --git a/arch/powerpc/kvm/timing.h b/arch/powerpc/kvm/timing.h index 45817ab82bb4..14b0e23f601f 100644 --- a/arch/powerpc/kvm/timing.h +++ b/arch/powerpc/kvm/timing.h @@ -38,11 +38,7 @@ static inline void kvmppc_set_exit_type(struct kvm_vcpu *vcpu, int type) {} static inline void kvmppc_account_exit_stat(struct kvm_vcpu *vcpu, int type) { /* type has to be known at build time for optimization */ - - /* The BUILD_BUG_ON below breaks in funny ways, commented out - * for now ... -BenH BUILD_BUG_ON(!__builtin_constant_p(type)); - */ switch (type) { case EXT_INTR_EXITS: vcpu->stat.ext_intr_exits++; diff --git a/arch/powerpc/kvm/tm.S b/arch/powerpc/kvm/tm.S index 2158f61e317f..b506c4d9a8d9 100644 --- a/arch/powerpc/kvm/tm.S +++ b/arch/powerpc/kvm/tm.S @@ -6,10 +6,10 @@ * Copyright 2011 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com> */ +#include <linux/export.h> #include <asm/reg.h> #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> -#include <asm/export.h> #include <asm/tm.h> #include <asm/cputable.h> diff --git a/arch/powerpc/kvm/trace_book3s.h b/arch/powerpc/kvm/trace_book3s.h index 372a82fa2de3..9260ddbd557f 100644 --- a/arch/powerpc/kvm/trace_book3s.h +++ b/arch/powerpc/kvm/trace_book3s.h @@ -25,6 +25,7 @@ {0xe00, "H_DATA_STORAGE"}, \ {0xe20, "H_INST_STORAGE"}, \ {0xe40, "H_EMUL_ASSIST"}, \ + {0xea0, "H_VIRT"}, \ {0xf00, "PERFMON"}, \ {0xf20, "ALTIVEC"}, \ {0xf40, "VSX"} diff --git a/arch/powerpc/kvm/trace_hv.h b/arch/powerpc/kvm/trace_hv.h index 8d57c8428531..35fccaa575cc 100644 --- a/arch/powerpc/kvm/trace_hv.h +++ b/arch/powerpc/kvm/trace_hv.h @@ -512,6 +512,35 @@ TRACE_EVENT(kvmppc_run_vcpu_exit, __entry->vcpu_id, __entry->exit, __entry->ret) ); +#ifdef CONFIG_PPC_PSERIES + +TRACE_EVENT_FN_COND(kvmppc_vcpu_stats, + TP_PROTO(struct kvm_vcpu *vcpu, u64 l1_to_l2_cs, u64 l2_to_l1_cs, u64 l2_runtime), + + TP_ARGS(vcpu, l1_to_l2_cs, l2_to_l1_cs, l2_runtime), + + TP_CONDITION(l1_to_l2_cs || l2_to_l1_cs || l2_runtime), + + TP_STRUCT__entry( + __field(int, vcpu_id) + __field(u64, l1_to_l2_cs) + __field(u64, l2_to_l1_cs) + __field(u64, l2_runtime) + ), + + TP_fast_assign( + __entry->vcpu_id = vcpu->vcpu_id; + __entry->l1_to_l2_cs = l1_to_l2_cs; + __entry->l2_to_l1_cs = l2_to_l1_cs; + __entry->l2_runtime = l2_runtime; + ), + + TP_printk("VCPU %d: l1_to_l2_cs_time=%llu ns l2_to_l1_cs_time=%llu ns l2_runtime=%llu ns", + __entry->vcpu_id, __entry->l1_to_l2_cs, + __entry->l2_to_l1_cs, __entry->l2_runtime), + kvmhv_counters_tracepoint_regfunc, kvmhv_counters_tracepoint_unregfunc +); +#endif #endif /* _TRACE_KVM_HV_H */ /* This part must be outside protection */ |
