Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Alexander Graf | 1492 | 29.32% | 39 | 25.49% |
Paul Mackerras | 1476 | 29.00% | 35 | 22.88% |
Aneesh Kumar K.V | 517 | 10.16% | 8 | 5.23% |
Jing Zhang | 339 | 6.66% | 2 | 1.31% |
David Gibson | 304 | 5.97% | 2 | 1.31% |
Cédric Le Goater | 156 | 3.07% | 3 | 1.96% |
Benjamin Herrenschmidt | 156 | 3.07% | 5 | 3.27% |
Hollis Blanchard | 118 | 2.32% | 3 | 1.96% |
Mihai Caraman | 97 | 1.91% | 3 | 1.96% |
Jordan Niethe | 79 | 1.55% | 3 | 1.96% |
Thomas Huth | 55 | 1.08% | 2 | 1.31% |
Sean Christopherson | 52 | 1.02% | 7 | 4.58% |
Nicholas Piggin | 51 | 1.00% | 4 | 2.61% |
Scott Wood | 36 | 0.71% | 3 | 1.96% |
Christoffer Dall | 31 | 0.61% | 3 | 1.96% |
Bharat Bhushan | 20 | 0.39% | 3 | 1.96% |
Greg Kurz | 14 | 0.28% | 2 | 1.31% |
Xiantao Zhang | 10 | 0.20% | 1 | 0.65% |
Michael S. Tsirkin | 9 | 0.18% | 2 | 1.31% |
Madhavan Srinivasan | 9 | 0.18% | 1 | 0.65% |
Michael Ellerman | 8 | 0.16% | 1 | 0.65% |
Bharata B Rao | 6 | 0.12% | 1 | 0.65% |
Emanuele Giuseppe Esposito | 6 | 0.12% | 1 | 0.65% |
Sheng Yang | 6 | 0.12% | 1 | 0.65% |
Yang Zhang | 6 | 0.12% | 1 | 0.65% |
Marcelo Tosatti | 4 | 0.08% | 2 | 1.31% |
Gleb Natapov | 3 | 0.06% | 2 | 1.31% |
Carsten Otte | 3 | 0.06% | 1 | 0.65% |
Dan J Williams | 3 | 0.06% | 1 | 0.65% |
Paul Gortmaker | 3 | 0.06% | 1 | 0.65% |
Stephen Rothwell | 3 | 0.06% | 1 | 0.65% |
Paolo Bonzini | 3 | 0.06% | 1 | 0.65% |
Tejun Heo | 2 | 0.04% | 1 | 0.65% |
Mahesh Salgaonkar | 2 | 0.04% | 1 | 0.65% |
Thomas Gleixner | 2 | 0.04% | 1 | 0.65% |
Takuya Yoshikawa | 2 | 0.04% | 1 | 0.65% |
Avi Kivity | 2 | 0.04% | 1 | 0.65% |
Jan Kiszka | 2 | 0.04% | 1 | 0.65% |
Simon Guo | 1 | 0.02% | 1 | 0.65% |
Alexey Kardashevskiy | 1 | 0.02% | 1 | 0.65% |
Total | 5089 | 153 |
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009. SUSE Linux Products GmbH. All rights reserved. * * Authors: * Alexander Graf <agraf@suse.de> * Kevin Wolf <mail@kevin-wolf.de> * * Description: * This file is derived from arch/powerpc/kvm/44x.c, * by Hollis Blanchard <hollisb@us.ibm.com>. */ #include <linux/kvm_host.h> #include <linux/err.h> #include <linux/export.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/miscdevice.h> #include <linux/gfp.h> #include <linux/sched.h> #include <linux/vmalloc.h> #include <linux/highmem.h> #include <asm/reg.h> #include <asm/cputable.h> #include <asm/cacheflush.h> #include <linux/uaccess.h> #include <asm/io.h> #include <asm/kvm_ppc.h> #include <asm/kvm_book3s.h> #include <asm/mmu_context.h> #include <asm/page.h> #include <asm/xive.h> #include "book3s.h" #include "trace.h" /* #define EXIT_DEBUG */ const struct _kvm_stats_desc kvm_vm_stats_desc[] = { KVM_GENERIC_VM_STATS(), STATS_DESC_ICOUNTER(VM, num_2M_pages), STATS_DESC_ICOUNTER(VM, num_1G_pages) }; const struct kvm_stats_header kvm_vm_stats_header = { .name_size = KVM_STATS_NAME_SIZE, .num_desc = ARRAY_SIZE(kvm_vm_stats_desc), .id_offset = sizeof(struct kvm_stats_header), .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE, .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + sizeof(kvm_vm_stats_desc), }; const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { KVM_GENERIC_VCPU_STATS(), STATS_DESC_COUNTER(VCPU, sum_exits), STATS_DESC_COUNTER(VCPU, mmio_exits), STATS_DESC_COUNTER(VCPU, signal_exits), STATS_DESC_COUNTER(VCPU, light_exits), STATS_DESC_COUNTER(VCPU, itlb_real_miss_exits), STATS_DESC_COUNTER(VCPU, itlb_virt_miss_exits), STATS_DESC_COUNTER(VCPU, dtlb_real_miss_exits), STATS_DESC_COUNTER(VCPU, dtlb_virt_miss_exits), STATS_DESC_COUNTER(VCPU, syscall_exits), STATS_DESC_COUNTER(VCPU, isi_exits), STATS_DESC_COUNTER(VCPU, dsi_exits), STATS_DESC_COUNTER(VCPU, emulated_inst_exits), STATS_DESC_COUNTER(VCPU, dec_exits), STATS_DESC_COUNTER(VCPU, ext_intr_exits), STATS_DESC_COUNTER(VCPU, halt_successful_wait), STATS_DESC_COUNTER(VCPU, dbell_exits), STATS_DESC_COUNTER(VCPU, gdbell_exits), STATS_DESC_COUNTER(VCPU, ld), STATS_DESC_COUNTER(VCPU, st), STATS_DESC_COUNTER(VCPU, pf_storage), STATS_DESC_COUNTER(VCPU, pf_instruc), STATS_DESC_COUNTER(VCPU, sp_storage), STATS_DESC_COUNTER(VCPU, sp_instruc), STATS_DESC_COUNTER(VCPU, queue_intr), STATS_DESC_COUNTER(VCPU, ld_slow), STATS_DESC_COUNTER(VCPU, st_slow), STATS_DESC_COUNTER(VCPU, pthru_all), STATS_DESC_COUNTER(VCPU, pthru_host), STATS_DESC_COUNTER(VCPU, pthru_bad_aff) }; const struct kvm_stats_header kvm_vcpu_stats_header = { .name_size = KVM_STATS_NAME_SIZE, .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc), .id_offset = sizeof(struct kvm_stats_header), .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE, .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + sizeof(kvm_vcpu_stats_desc), }; static inline void kvmppc_update_int_pending(struct kvm_vcpu *vcpu, unsigned long pending_now, unsigned long old_pending) { if (is_kvmppc_hv_enabled(vcpu->kvm)) return; if (pending_now) kvmppc_set_int_pending(vcpu, 1); else if (old_pending) kvmppc_set_int_pending(vcpu, 0); } static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu) { ulong crit_raw; ulong crit_r1; bool crit; if (is_kvmppc_hv_enabled(vcpu->kvm)) return false; crit_raw = kvmppc_get_critical(vcpu); crit_r1 = kvmppc_get_gpr(vcpu, 1); /* Truncate crit indicators in 32 bit mode */ if (!(kvmppc_get_msr(vcpu) & MSR_SF)) { crit_raw &= 0xffffffff; crit_r1 &= 0xffffffff; } /* Critical section when crit == r1 */ crit = (crit_raw == crit_r1); /* ... and we're in supervisor mode */ crit = crit && !(kvmppc_get_msr(vcpu) & MSR_PR); return crit; } void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags) { vcpu->kvm->arch.kvm_ops->inject_interrupt(vcpu, vec, flags); } static int kvmppc_book3s_vec2irqprio(unsigned int vec) { unsigned int prio; switch (vec) { case 0x100: prio = BOOK3S_IRQPRIO_SYSTEM_RESET; break; case 0x200: prio = BOOK3S_IRQPRIO_MACHINE_CHECK; break; case 0x300: prio = BOOK3S_IRQPRIO_DATA_STORAGE; break; case 0x380: prio = BOOK3S_IRQPRIO_DATA_SEGMENT; break; case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break; case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break; case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break; case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break; case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break; case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break; case 0x900: prio = BOOK3S_IRQPRIO_DECREMENTER; break; case 0xc00: prio = BOOK3S_IRQPRIO_SYSCALL; break; case 0xd00: prio = BOOK3S_IRQPRIO_DEBUG; break; case 0xf20: prio = BOOK3S_IRQPRIO_ALTIVEC; break; case 0xf40: prio = BOOK3S_IRQPRIO_VSX; break; case 0xf60: prio = BOOK3S_IRQPRIO_FAC_UNAVAIL; break; default: prio = BOOK3S_IRQPRIO_MAX; break; } return prio; } void kvmppc_book3s_dequeue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) { unsigned long old_pending = vcpu->arch.pending_exceptions; clear_bit(kvmppc_book3s_vec2irqprio(vec), &vcpu->arch.pending_exceptions); kvmppc_update_int_pending(vcpu, vcpu->arch.pending_exceptions, old_pending); } void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) { vcpu->stat.queue_intr++; set_bit(kvmppc_book3s_vec2irqprio(vec), &vcpu->arch.pending_exceptions); #ifdef EXIT_DEBUG printk(KERN_INFO "Queueing interrupt %x\n", vec); #endif } EXPORT_SYMBOL_GPL(kvmppc_book3s_queue_irqprio); 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, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_machine_check); void kvmppc_core_queue_syscall(struct kvm_vcpu *vcpu) { kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_SYSCALL, 0); } EXPORT_SYMBOL(kvmppc_core_queue_syscall); 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, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_program); 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, srr1_flags); } 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, srr1_flags); } 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, srr1_flags); } void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) { kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_dec); int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) { return test_bit(BOOK3S_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions); } EXPORT_SYMBOL_GPL(kvmppc_core_pending_dec); void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu) { kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER); } EXPORT_SYMBOL_GPL(kvmppc_core_dequeue_dec); void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { /* * This case (KVM_INTERRUPT_SET) should never actually arise for * a pseries guest (because pseries guests expect their interrupt * controllers to continue asserting an external interrupt request * until it is acknowledged at the interrupt controller), but is * included to avoid ABI breakage and potentially for other * sorts of guest. * * There is a subtlety here: HV KVM does not test the * external_oneshot flag in the code that synthesizes * external interrupts for the guest just before entering * the guest. That is OK even if userspace did do a * KVM_INTERRUPT_SET on a pseries guest vcpu, because the * caller (kvm_vcpu_ioctl_interrupt) does a kvm_vcpu_kick() * which ends up doing a smp_send_reschedule(), which will * pull the guest all the way out to the host, meaning that * we will call kvmppc_core_prepare_to_enter() before entering * the guest again, and that will handle the external_oneshot * flag correctly. */ if (irq->irq == KVM_INTERRUPT_SET) vcpu->arch.external_oneshot = 1; kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); } 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 srr1_flags, ulong dar, ulong dsisr) { kvmppc_set_dar(vcpu, dar); 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 srr1_flags) { kvmppc_inject_interrupt(vcpu, BOOK3S_INTERRUPT_INST_STORAGE, srr1_flags); } EXPORT_SYMBOL_GPL(kvmppc_core_queue_inst_storage); static int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) { int deliver = 1; int vec = 0; bool crit = kvmppc_critical_section(vcpu); switch (priority) { case BOOK3S_IRQPRIO_DECREMENTER: deliver = !kvmhv_is_nestedv2() && (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; vec = BOOK3S_INTERRUPT_DECREMENTER; break; case BOOK3S_IRQPRIO_EXTERNAL: deliver = !kvmhv_is_nestedv2() && (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; vec = BOOK3S_INTERRUPT_EXTERNAL; break; case BOOK3S_IRQPRIO_SYSTEM_RESET: vec = BOOK3S_INTERRUPT_SYSTEM_RESET; break; case BOOK3S_IRQPRIO_MACHINE_CHECK: vec = BOOK3S_INTERRUPT_MACHINE_CHECK; break; case BOOK3S_IRQPRIO_DATA_STORAGE: vec = BOOK3S_INTERRUPT_DATA_STORAGE; break; case BOOK3S_IRQPRIO_INST_STORAGE: vec = BOOK3S_INTERRUPT_INST_STORAGE; break; case BOOK3S_IRQPRIO_DATA_SEGMENT: vec = BOOK3S_INTERRUPT_DATA_SEGMENT; break; case BOOK3S_IRQPRIO_INST_SEGMENT: vec = BOOK3S_INTERRUPT_INST_SEGMENT; break; case BOOK3S_IRQPRIO_ALIGNMENT: vec = BOOK3S_INTERRUPT_ALIGNMENT; break; case BOOK3S_IRQPRIO_PROGRAM: vec = BOOK3S_INTERRUPT_PROGRAM; break; case BOOK3S_IRQPRIO_VSX: vec = BOOK3S_INTERRUPT_VSX; break; case BOOK3S_IRQPRIO_ALTIVEC: vec = BOOK3S_INTERRUPT_ALTIVEC; break; case BOOK3S_IRQPRIO_FP_UNAVAIL: vec = BOOK3S_INTERRUPT_FP_UNAVAIL; break; case BOOK3S_IRQPRIO_SYSCALL: vec = BOOK3S_INTERRUPT_SYSCALL; break; case BOOK3S_IRQPRIO_DEBUG: vec = BOOK3S_INTERRUPT_TRACE; break; case BOOK3S_IRQPRIO_PERFORMANCE_MONITOR: vec = BOOK3S_INTERRUPT_PERFMON; break; case BOOK3S_IRQPRIO_FAC_UNAVAIL: vec = BOOK3S_INTERRUPT_FAC_UNAVAIL; break; default: deliver = 0; printk(KERN_ERR "KVM: Unknown interrupt: 0x%x\n", priority); break; } if (deliver) kvmppc_inject_interrupt(vcpu, vec, 0); return deliver; } /* * This function determines if an irqprio should be cleared once issued. */ static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority) { switch (priority) { case BOOK3S_IRQPRIO_DECREMENTER: /* DEC interrupts get cleared by mtdec */ return false; case BOOK3S_IRQPRIO_EXTERNAL: /* * External interrupts get cleared by userspace * except when set by the KVM_INTERRUPT ioctl with * KVM_INTERRUPT_SET (not KVM_INTERRUPT_SET_LEVEL). */ if (vcpu->arch.external_oneshot) { vcpu->arch.external_oneshot = 0; return true; } return false; } return true; } int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu) { unsigned long *pending = &vcpu->arch.pending_exceptions; unsigned long old_pending = vcpu->arch.pending_exceptions; unsigned int priority; #ifdef EXIT_DEBUG if (vcpu->arch.pending_exceptions) printk(KERN_EMERG "KVM: Check pending: %lx\n", vcpu->arch.pending_exceptions); #endif priority = __ffs(*pending); while (priority < BOOK3S_IRQPRIO_MAX) { if (kvmppc_book3s_irqprio_deliver(vcpu, priority) && clear_irqprio(vcpu, priority)) { clear_bit(priority, &vcpu->arch.pending_exceptions); break; } priority = find_next_bit(pending, BITS_PER_BYTE * sizeof(*pending), priority + 1); } /* Tell the guest about our interrupt status */ kvmppc_update_int_pending(vcpu, *pending, old_pending); return 0; } 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) { ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM; gfn_t gfn = gpa >> PAGE_SHIFT; if (!(kvmppc_get_msr(vcpu) & MSR_SF)) mp_pa = (uint32_t)mp_pa; /* Magic page override */ gpa &= ~0xFFFULL; if (unlikely(mp_pa) && unlikely((gpa & KVM_PAM) == mp_pa)) { ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK; kvm_pfn_t pfn; pfn = (kvm_pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT; get_page(pfn_to_page(pfn)); if (writable) *writable = true; return pfn; } return gfn_to_pfn_prot(vcpu->kvm, gfn, writing, writable); } EXPORT_SYMBOL_GPL(kvmppc_gpa_to_pfn); int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, enum xlate_instdata xlid, enum xlate_readwrite xlrw, struct kvmppc_pte *pte) { bool data = (xlid == XLATE_DATA); bool iswrite = (xlrw == XLATE_WRITE); int relocated = (kvmppc_get_msr(vcpu) & (data ? MSR_DR : MSR_IR)); int r; if (relocated) { r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data, iswrite); } else { pte->eaddr = eaddr; pte->raddr = eaddr & KVM_PAM; pte->vpage = VSID_REAL | eaddr >> 12; pte->may_read = true; pte->may_write = true; pte->may_execute = true; r = 0; if ((kvmppc_get_msr(vcpu) & (MSR_IR | MSR_DR)) == MSR_DR && !data) { if ((vcpu->arch.hflags & BOOK3S_HFLAG_SPLIT_HACK) && ((eaddr & SPLIT_HACK_MASK) == SPLIT_HACK_OFFS)) pte->raddr &= ~SPLIT_HACK_MASK; } } 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, 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), &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); int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu) { return 0; } void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu) { } int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { int ret; vcpu_load(vcpu); ret = vcpu->kvm->arch.kvm_ops->get_sregs(vcpu, sregs); vcpu_put(vcpu); return ret; } int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { int ret; vcpu_load(vcpu); ret = vcpu->kvm->arch.kvm_ops->set_sregs(vcpu, sregs); vcpu_put(vcpu); return ret; } int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) { int i; regs->pc = kvmppc_get_pc(vcpu); regs->cr = kvmppc_get_cr(vcpu); regs->ctr = kvmppc_get_ctr(vcpu); regs->lr = kvmppc_get_lr(vcpu); regs->xer = kvmppc_get_xer(vcpu); regs->msr = kvmppc_get_msr(vcpu); regs->srr0 = kvmppc_get_srr0(vcpu); regs->srr1 = kvmppc_get_srr1(vcpu); regs->pid = kvmppc_get_pid(vcpu); regs->sprg0 = kvmppc_get_sprg0(vcpu); regs->sprg1 = kvmppc_get_sprg1(vcpu); regs->sprg2 = kvmppc_get_sprg2(vcpu); regs->sprg3 = kvmppc_get_sprg3(vcpu); regs->sprg4 = kvmppc_get_sprg4(vcpu); regs->sprg5 = kvmppc_get_sprg5(vcpu); regs->sprg6 = kvmppc_get_sprg6(vcpu); regs->sprg7 = kvmppc_get_sprg7(vcpu); for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) regs->gpr[i] = kvmppc_get_gpr(vcpu, i); return 0; } int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) { int i; kvmppc_set_pc(vcpu, regs->pc); kvmppc_set_cr(vcpu, regs->cr); kvmppc_set_ctr(vcpu, regs->ctr); kvmppc_set_lr(vcpu, regs->lr); kvmppc_set_xer(vcpu, regs->xer); kvmppc_set_msr(vcpu, regs->msr); kvmppc_set_srr0(vcpu, regs->srr0); kvmppc_set_srr1(vcpu, regs->srr1); kvmppc_set_sprg0(vcpu, regs->sprg0); kvmppc_set_sprg1(vcpu, regs->sprg1); kvmppc_set_sprg2(vcpu, regs->sprg2); kvmppc_set_sprg3(vcpu, regs->sprg3); kvmppc_set_sprg4(vcpu, regs->sprg4); kvmppc_set_sprg5(vcpu, regs->sprg5); kvmppc_set_sprg6(vcpu, regs->sprg6); kvmppc_set_sprg7(vcpu, regs->sprg7); for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) kvmppc_set_gpr(vcpu, i, regs->gpr[i]); return 0; } int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { return -EOPNOTSUPP; } int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { return -EOPNOTSUPP; } int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val) { int r = 0; long int i; r = vcpu->kvm->arch.kvm_ops->get_one_reg(vcpu, id, val); if (r == -EINVAL) { r = 0; switch (id) { case KVM_REG_PPC_DAR: *val = get_reg_val(id, kvmppc_get_dar(vcpu)); break; case KVM_REG_PPC_DSISR: *val = get_reg_val(id, kvmppc_get_dsisr(vcpu)); break; case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: i = id - KVM_REG_PPC_FPR0; *val = get_reg_val(id, kvmppc_get_fpr(vcpu, i)); break; case KVM_REG_PPC_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] = kvmppc_get_vsx_fpr(vcpu, i, 0); val->vsxval[1] = kvmppc_get_vsx_fpr(vcpu, i, 1); } else { r = -ENXIO; } break; #endif /* CONFIG_VSX */ case KVM_REG_PPC_DEBUG_INST: *val = get_reg_val(id, INS_TW); break; #ifdef CONFIG_KVM_XICS case KVM_REG_PPC_ICP_STATE: if (!vcpu->arch.icp && !vcpu->arch.xive_vcpu) { r = -ENXIO; break; } if (xics_on_xive()) *val = get_reg_val(id, kvmppc_xive_get_icp(vcpu)); else *val = get_reg_val(id, kvmppc_xics_get_icp(vcpu)); break; #endif /* CONFIG_KVM_XICS */ #ifdef CONFIG_KVM_XIVE case KVM_REG_PPC_VP_STATE: if (!vcpu->arch.xive_vcpu) { r = -ENXIO; break; } if (xive_enabled()) r = kvmppc_xive_native_get_vp(vcpu, val); else r = -ENXIO; break; #endif /* CONFIG_KVM_XIVE */ case KVM_REG_PPC_FSCR: *val = get_reg_val(id, vcpu->arch.fscr); break; case KVM_REG_PPC_TAR: *val = get_reg_val(id, kvmppc_get_tar(vcpu)); break; case KVM_REG_PPC_EBBHR: *val = get_reg_val(id, kvmppc_get_ebbhr(vcpu)); break; case KVM_REG_PPC_EBBRR: *val = get_reg_val(id, kvmppc_get_ebbrr(vcpu)); break; case KVM_REG_PPC_BESCR: *val = get_reg_val(id, kvmppc_get_bescr(vcpu)); break; case KVM_REG_PPC_IC: *val = get_reg_val(id, kvmppc_get_ic(vcpu)); break; default: r = -EINVAL; break; } } return r; } int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id, union kvmppc_one_reg *val) { int r = 0; long int i; r = vcpu->kvm->arch.kvm_ops->set_one_reg(vcpu, id, val); if (r == -EINVAL) { r = 0; switch (id) { case KVM_REG_PPC_DAR: kvmppc_set_dar(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_DSISR: kvmppc_set_dsisr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31: i = id - KVM_REG_PPC_FPR0; 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); 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; kvmppc_set_vsx_fpr(vcpu, i, 0, val->vsxval[0]); kvmppc_set_vsx_fpr(vcpu, i, 1, val->vsxval[1]); } else { r = -ENXIO; } break; #endif /* CONFIG_VSX */ #ifdef CONFIG_KVM_XICS case KVM_REG_PPC_ICP_STATE: if (!vcpu->arch.icp && !vcpu->arch.xive_vcpu) { r = -ENXIO; break; } if (xics_on_xive()) r = kvmppc_xive_set_icp(vcpu, set_reg_val(id, *val)); else r = kvmppc_xics_set_icp(vcpu, set_reg_val(id, *val)); break; #endif /* CONFIG_KVM_XICS */ #ifdef CONFIG_KVM_XIVE case KVM_REG_PPC_VP_STATE: if (!vcpu->arch.xive_vcpu) { r = -ENXIO; break; } if (xive_enabled()) r = kvmppc_xive_native_set_vp(vcpu, val); else r = -ENXIO; break; #endif /* CONFIG_KVM_XIVE */ case KVM_REG_PPC_FSCR: kvmppc_set_fpscr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_TAR: kvmppc_set_tar(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_EBBHR: kvmppc_set_ebbhr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_EBBRR: kvmppc_set_ebbrr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_BESCR: kvmppc_set_bescr(vcpu, set_reg_val(id, *val)); break; case KVM_REG_PPC_IC: kvmppc_set_ic(vcpu, set_reg_val(id, *val)); break; default: r = -EINVAL; break; } } return r; } void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { vcpu->kvm->arch.kvm_ops->vcpu_load(vcpu, cpu); } void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) { vcpu->kvm->arch.kvm_ops->vcpu_put(vcpu); } void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) { vcpu->kvm->arch.kvm_ops->set_msr(vcpu, msr); } EXPORT_SYMBOL_GPL(kvmppc_set_msr); int kvmppc_vcpu_run(struct kvm_vcpu *vcpu) { return vcpu->kvm->arch.kvm_ops->vcpu_run(vcpu); } int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, struct kvm_translation *tr) { return 0; } int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { vcpu_load(vcpu); vcpu->guest_debug = dbg->control; vcpu_put(vcpu); return 0; } void kvmppc_decrementer_func(struct kvm_vcpu *vcpu) { kvmppc_core_queue_dec(vcpu); kvm_vcpu_kick(vcpu); } int kvmppc_core_vcpu_create(struct kvm_vcpu *vcpu) { return vcpu->kvm->arch.kvm_ops->vcpu_create(vcpu); } void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) { vcpu->kvm->arch.kvm_ops->vcpu_free(vcpu); } int kvmppc_core_check_requests(struct kvm_vcpu *vcpu) { return vcpu->kvm->arch.kvm_ops->check_requests(vcpu); } void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot) { } int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) { return kvm->arch.kvm_ops->get_dirty_log(kvm, log); } void kvmppc_core_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) { kvm->arch.kvm_ops->free_memslot(slot); } void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot) { kvm->arch.kvm_ops->flush_memslot(kvm, memslot); } int kvmppc_core_prepare_memory_region(struct kvm *kvm, const struct kvm_memory_slot *old, struct kvm_memory_slot *new, enum kvm_mr_change change) { return kvm->arch.kvm_ops->prepare_memory_region(kvm, old, new, change); } void kvmppc_core_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *old, const struct kvm_memory_slot *new, enum kvm_mr_change change) { kvm->arch.kvm_ops->commit_memory_region(kvm, old, new, change); } bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range) { return kvm->arch.kvm_ops->unmap_gfn_range(kvm, range); } bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) { return kvm->arch.kvm_ops->age_gfn(kvm, range); } bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) { return kvm->arch.kvm_ops->test_age_gfn(kvm, range); } int kvmppc_core_init_vm(struct kvm *kvm) { #ifdef CONFIG_PPC64 INIT_LIST_HEAD_RCU(&kvm->arch.spapr_tce_tables); INIT_LIST_HEAD(&kvm->arch.rtas_tokens); mutex_init(&kvm->arch.rtas_token_lock); #endif return kvm->arch.kvm_ops->init_vm(kvm); } void kvmppc_core_destroy_vm(struct kvm *kvm) { kvm->arch.kvm_ops->destroy_vm(kvm); #ifdef CONFIG_PPC64 kvmppc_rtas_tokens_free(kvm); WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables)); #endif #ifdef CONFIG_KVM_XICS /* * Free the XIVE and XICS devices which are not directly freed by the * device 'release' method */ kfree(kvm->arch.xive_devices.native); kvm->arch.xive_devices.native = NULL; kfree(kvm->arch.xive_devices.xics_on_xive); kvm->arch.xive_devices.xics_on_xive = NULL; kfree(kvm->arch.xics_device); kvm->arch.xics_device = NULL; #endif /* CONFIG_KVM_XICS */ } int kvmppc_h_logical_ci_load(struct kvm_vcpu *vcpu) { unsigned long size = kvmppc_get_gpr(vcpu, 4); unsigned long addr = kvmppc_get_gpr(vcpu, 5); u64 buf; int srcu_idx; int ret; if (!is_power_of_2(size) || (size > sizeof(buf))) return H_TOO_HARD; srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, addr, size, &buf); srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); if (ret != 0) return H_TOO_HARD; switch (size) { case 1: kvmppc_set_gpr(vcpu, 4, *(u8 *)&buf); break; case 2: kvmppc_set_gpr(vcpu, 4, be16_to_cpu(*(__be16 *)&buf)); break; case 4: kvmppc_set_gpr(vcpu, 4, be32_to_cpu(*(__be32 *)&buf)); break; case 8: kvmppc_set_gpr(vcpu, 4, be64_to_cpu(*(__be64 *)&buf)); break; default: BUG(); } return H_SUCCESS; } EXPORT_SYMBOL_GPL(kvmppc_h_logical_ci_load); int kvmppc_h_logical_ci_store(struct kvm_vcpu *vcpu) { unsigned long size = kvmppc_get_gpr(vcpu, 4); unsigned long addr = kvmppc_get_gpr(vcpu, 5); unsigned long val = kvmppc_get_gpr(vcpu, 6); u64 buf; int srcu_idx; int ret; switch (size) { case 1: *(u8 *)&buf = val; break; case 2: *(__be16 *)&buf = cpu_to_be16(val); break; case 4: *(__be32 *)&buf = cpu_to_be32(val); break; case 8: *(__be64 *)&buf = cpu_to_be64(val); break; default: return H_TOO_HARD; } srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, addr, size, &buf); srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx); if (ret != 0) return H_TOO_HARD; return H_SUCCESS; } EXPORT_SYMBOL_GPL(kvmppc_h_logical_ci_store); int kvmppc_book3s_hcall_implemented(struct kvm *kvm, unsigned long hcall) { return kvm->arch.kvm_ops->hcall_implemented(hcall); } #ifdef CONFIG_KVM_XICS int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level, bool line_status) { if (xics_on_xive()) return kvmppc_xive_set_irq(kvm, irq_source_id, irq, level, line_status); else return kvmppc_xics_set_irq(kvm, irq_source_id, irq, level, line_status); } int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *irq_entry, struct kvm *kvm, int irq_source_id, int level, bool line_status) { return kvm_set_irq(kvm, irq_source_id, irq_entry->gsi, level, line_status); } static int kvmppc_book3s_set_irq(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int irq_source_id, int level, bool line_status) { return kvm_set_irq(kvm, irq_source_id, e->gsi, level, line_status); } int kvm_irq_map_gsi(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *entries, int gsi) { entries->gsi = gsi; entries->type = KVM_IRQ_ROUTING_IRQCHIP; entries->set = kvmppc_book3s_set_irq; entries->irqchip.irqchip = 0; entries->irqchip.pin = gsi; return 1; } int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin) { return pin; } #endif /* CONFIG_KVM_XICS */ static int kvmppc_book3s_init(void) { int r; r = kvm_init(sizeof(struct kvm_vcpu), 0, THIS_MODULE); if (r) return r; #ifdef CONFIG_KVM_BOOK3S_32_HANDLER r = kvmppc_book3s_init_pr(); #endif #ifdef CONFIG_KVM_XICS #ifdef CONFIG_KVM_XIVE if (xics_on_xive()) { kvm_register_device_ops(&kvm_xive_ops, KVM_DEV_TYPE_XICS); if (kvmppc_xive_native_supported()) kvm_register_device_ops(&kvm_xive_native_ops, KVM_DEV_TYPE_XIVE); } else #endif kvm_register_device_ops(&kvm_xics_ops, KVM_DEV_TYPE_XICS); #endif return r; } static void kvmppc_book3s_exit(void) { #ifdef CONFIG_KVM_BOOK3S_32_HANDLER kvmppc_book3s_exit_pr(); #endif kvm_exit(); } module_init(kvmppc_book3s_init); module_exit(kvmppc_book3s_exit); /* On 32bit this is our one and only kernel module */ #ifdef CONFIG_KVM_BOOK3S_32_HANDLER MODULE_ALIAS_MISCDEV(KVM_MINOR); MODULE_ALIAS("devname:kvm"); #endif
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1