162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright IBM Corp. 2007 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Authors: Hollis Blanchard <hollisb@us.ibm.com> 762306a36Sopenharmony_ci * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/errno.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/kvm_host.h> 1362306a36Sopenharmony_ci#include <linux/vmalloc.h> 1462306a36Sopenharmony_ci#include <linux/hrtimer.h> 1562306a36Sopenharmony_ci#include <linux/sched/signal.h> 1662306a36Sopenharmony_ci#include <linux/fs.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/file.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/irqbypass.h> 2162306a36Sopenharmony_ci#include <linux/kvm_irqfd.h> 2262306a36Sopenharmony_ci#include <linux/of.h> 2362306a36Sopenharmony_ci#include <asm/cputable.h> 2462306a36Sopenharmony_ci#include <linux/uaccess.h> 2562306a36Sopenharmony_ci#include <asm/kvm_ppc.h> 2662306a36Sopenharmony_ci#include <asm/cputhreads.h> 2762306a36Sopenharmony_ci#include <asm/irqflags.h> 2862306a36Sopenharmony_ci#include <asm/iommu.h> 2962306a36Sopenharmony_ci#include <asm/switch_to.h> 3062306a36Sopenharmony_ci#include <asm/xive.h> 3162306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 3262306a36Sopenharmony_ci#include <asm/hvcall.h> 3362306a36Sopenharmony_ci#include <asm/plpar_wrappers.h> 3462306a36Sopenharmony_ci#endif 3562306a36Sopenharmony_ci#include <asm/ultravisor.h> 3662306a36Sopenharmony_ci#include <asm/setup.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "timing.h" 3962306a36Sopenharmony_ci#include "../mm/mmu_decl.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 4262306a36Sopenharmony_ci#include "trace.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistruct kvmppc_ops *kvmppc_hv_ops; 4562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_hv_ops); 4662306a36Sopenharmony_cistruct kvmppc_ops *kvmppc_pr_ops; 4762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_pr_ops); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciint kvm_arch_vcpu_runnable(struct kvm_vcpu *v) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci return !!(v->arch.pending_exceptions) || kvm_request_pending(v); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cibool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return kvm_arch_vcpu_runnable(vcpu); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cibool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci return false; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciint kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci return 1; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * Common checks before entering the guest world. Call with interrupts 7262306a36Sopenharmony_ci * disabled. 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * returns: 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * == 1 if we're ready to go into guest state 7762306a36Sopenharmony_ci * <= 0 if we need to go back to the host with return value 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ciint kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci int r; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci WARN_ON(irqs_disabled()); 8462306a36Sopenharmony_ci hard_irq_disable(); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci while (true) { 8762306a36Sopenharmony_ci if (need_resched()) { 8862306a36Sopenharmony_ci local_irq_enable(); 8962306a36Sopenharmony_ci cond_resched(); 9062306a36Sopenharmony_ci hard_irq_disable(); 9162306a36Sopenharmony_ci continue; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (signal_pending(current)) { 9562306a36Sopenharmony_ci kvmppc_account_exit(vcpu, SIGNAL_EXITS); 9662306a36Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_INTR; 9762306a36Sopenharmony_ci r = -EINTR; 9862306a36Sopenharmony_ci break; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci vcpu->mode = IN_GUEST_MODE; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* 10462306a36Sopenharmony_ci * Reading vcpu->requests must happen after setting vcpu->mode, 10562306a36Sopenharmony_ci * so we don't miss a request because the requester sees 10662306a36Sopenharmony_ci * OUTSIDE_GUEST_MODE and assumes we'll be checking requests 10762306a36Sopenharmony_ci * before next entering the guest (and thus doesn't IPI). 10862306a36Sopenharmony_ci * This also orders the write to mode from any reads 10962306a36Sopenharmony_ci * to the page tables done while the VCPU is running. 11062306a36Sopenharmony_ci * Please see the comment in kvm_flush_remote_tlbs. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci smp_mb(); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (kvm_request_pending(vcpu)) { 11562306a36Sopenharmony_ci /* Make sure we process requests preemptable */ 11662306a36Sopenharmony_ci local_irq_enable(); 11762306a36Sopenharmony_ci trace_kvm_check_requests(vcpu); 11862306a36Sopenharmony_ci r = kvmppc_core_check_requests(vcpu); 11962306a36Sopenharmony_ci hard_irq_disable(); 12062306a36Sopenharmony_ci if (r > 0) 12162306a36Sopenharmony_ci continue; 12262306a36Sopenharmony_ci break; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (kvmppc_core_prepare_to_enter(vcpu)) { 12662306a36Sopenharmony_ci /* interrupts got enabled in between, so we 12762306a36Sopenharmony_ci are back at square 1 */ 12862306a36Sopenharmony_ci continue; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci guest_enter_irqoff(); 13262306a36Sopenharmony_ci return 1; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* return to host */ 13662306a36Sopenharmony_ci local_irq_enable(); 13762306a36Sopenharmony_ci return r; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_prepare_to_enter); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE) 14262306a36Sopenharmony_cistatic void kvmppc_swab_shared(struct kvm_vcpu *vcpu) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared; 14562306a36Sopenharmony_ci int i; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci shared->sprg0 = swab64(shared->sprg0); 14862306a36Sopenharmony_ci shared->sprg1 = swab64(shared->sprg1); 14962306a36Sopenharmony_ci shared->sprg2 = swab64(shared->sprg2); 15062306a36Sopenharmony_ci shared->sprg3 = swab64(shared->sprg3); 15162306a36Sopenharmony_ci shared->srr0 = swab64(shared->srr0); 15262306a36Sopenharmony_ci shared->srr1 = swab64(shared->srr1); 15362306a36Sopenharmony_ci shared->dar = swab64(shared->dar); 15462306a36Sopenharmony_ci shared->msr = swab64(shared->msr); 15562306a36Sopenharmony_ci shared->dsisr = swab32(shared->dsisr); 15662306a36Sopenharmony_ci shared->int_pending = swab32(shared->int_pending); 15762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(shared->sr); i++) 15862306a36Sopenharmony_ci shared->sr[i] = swab32(shared->sr[i]); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci#endif 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ciint kvmppc_kvm_pv(struct kvm_vcpu *vcpu) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci int nr = kvmppc_get_gpr(vcpu, 11); 16562306a36Sopenharmony_ci int r; 16662306a36Sopenharmony_ci unsigned long __maybe_unused param1 = kvmppc_get_gpr(vcpu, 3); 16762306a36Sopenharmony_ci unsigned long __maybe_unused param2 = kvmppc_get_gpr(vcpu, 4); 16862306a36Sopenharmony_ci unsigned long __maybe_unused param3 = kvmppc_get_gpr(vcpu, 5); 16962306a36Sopenharmony_ci unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6); 17062306a36Sopenharmony_ci unsigned long r2 = 0; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_SF)) { 17362306a36Sopenharmony_ci /* 32 bit mode */ 17462306a36Sopenharmony_ci param1 &= 0xffffffff; 17562306a36Sopenharmony_ci param2 &= 0xffffffff; 17662306a36Sopenharmony_ci param3 &= 0xffffffff; 17762306a36Sopenharmony_ci param4 &= 0xffffffff; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci switch (nr) { 18162306a36Sopenharmony_ci case KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE): 18262306a36Sopenharmony_ci { 18362306a36Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE) 18462306a36Sopenharmony_ci /* Book3S can be little endian, find it out here */ 18562306a36Sopenharmony_ci int shared_big_endian = true; 18662306a36Sopenharmony_ci if (vcpu->arch.intr_msr & MSR_LE) 18762306a36Sopenharmony_ci shared_big_endian = false; 18862306a36Sopenharmony_ci if (shared_big_endian != vcpu->arch.shared_big_endian) 18962306a36Sopenharmony_ci kvmppc_swab_shared(vcpu); 19062306a36Sopenharmony_ci vcpu->arch.shared_big_endian = shared_big_endian; 19162306a36Sopenharmony_ci#endif 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (!(param2 & MAGIC_PAGE_FLAG_NOT_MAPPED_NX)) { 19462306a36Sopenharmony_ci /* 19562306a36Sopenharmony_ci * Older versions of the Linux magic page code had 19662306a36Sopenharmony_ci * a bug where they would map their trampoline code 19762306a36Sopenharmony_ci * NX. If that's the case, remove !PR NX capability. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci vcpu->arch.disable_kernel_nx = true; 20062306a36Sopenharmony_ci kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci vcpu->arch.magic_page_pa = param1 & ~0xfffULL; 20462306a36Sopenharmony_ci vcpu->arch.magic_page_ea = param2 & ~0xfffULL; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * Make sure our 4k magic page is in the same window of a 64k 20962306a36Sopenharmony_ci * page within the guest and within the host's page. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci if ((vcpu->arch.magic_page_pa & 0xf000) != 21262306a36Sopenharmony_ci ((ulong)vcpu->arch.shared & 0xf000)) { 21362306a36Sopenharmony_ci void *old_shared = vcpu->arch.shared; 21462306a36Sopenharmony_ci ulong shared = (ulong)vcpu->arch.shared; 21562306a36Sopenharmony_ci void *new_shared; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci shared &= PAGE_MASK; 21862306a36Sopenharmony_ci shared |= vcpu->arch.magic_page_pa & 0xf000; 21962306a36Sopenharmony_ci new_shared = (void*)shared; 22062306a36Sopenharmony_ci memcpy(new_shared, old_shared, 0x1000); 22162306a36Sopenharmony_ci vcpu->arch.shared = new_shared; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci#endif 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci r = EV_SUCCESS; 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci case KVM_HCALL_TOKEN(KVM_HC_FEATURES): 23162306a36Sopenharmony_ci r = EV_SUCCESS; 23262306a36Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500V2) 23362306a36Sopenharmony_ci r2 |= (1 << KVM_FEATURE_MAGIC_PAGE); 23462306a36Sopenharmony_ci#endif 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* Second return value is in r4 */ 23762306a36Sopenharmony_ci break; 23862306a36Sopenharmony_ci case EV_HCALL_TOKEN(EV_IDLE): 23962306a36Sopenharmony_ci r = EV_SUCCESS; 24062306a36Sopenharmony_ci kvm_vcpu_halt(vcpu); 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci default: 24362306a36Sopenharmony_ci r = EV_UNIMPLEMENTED; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci kvmppc_set_gpr(vcpu, 4, r2); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return r; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_kvm_pv); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ciint kvmppc_sanity_check(struct kvm_vcpu *vcpu) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci int r = false; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* We have to know what CPU to virtualize */ 25862306a36Sopenharmony_ci if (!vcpu->arch.pvr) 25962306a36Sopenharmony_ci goto out; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* PAPR only works with book3s_64 */ 26262306a36Sopenharmony_ci if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled) 26362306a36Sopenharmony_ci goto out; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* HV KVM can only do PAPR mode for now */ 26662306a36Sopenharmony_ci if (!vcpu->arch.papr_enabled && is_kvmppc_hv_enabled(vcpu->kvm)) 26762306a36Sopenharmony_ci goto out; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOKE_HV 27062306a36Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_EMB_HV)) 27162306a36Sopenharmony_ci goto out; 27262306a36Sopenharmony_ci#endif 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci r = true; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ciout: 27762306a36Sopenharmony_ci vcpu->arch.sane = r; 27862306a36Sopenharmony_ci return r ? 0 : -EINVAL; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_sanity_check); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ciint kvmppc_emulate_mmio(struct kvm_vcpu *vcpu) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci enum emulation_result er; 28562306a36Sopenharmony_ci int r; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci er = kvmppc_emulate_loadstore(vcpu); 28862306a36Sopenharmony_ci switch (er) { 28962306a36Sopenharmony_ci case EMULATE_DONE: 29062306a36Sopenharmony_ci /* Future optimization: only reload non-volatiles if they were 29162306a36Sopenharmony_ci * actually modified. */ 29262306a36Sopenharmony_ci r = RESUME_GUEST_NV; 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci case EMULATE_AGAIN: 29562306a36Sopenharmony_ci r = RESUME_GUEST; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci case EMULATE_DO_MMIO: 29862306a36Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_MMIO; 29962306a36Sopenharmony_ci /* We must reload nonvolatiles because "update" load/store 30062306a36Sopenharmony_ci * instructions modify register state. */ 30162306a36Sopenharmony_ci /* Future optimization: only reload non-volatiles if they were 30262306a36Sopenharmony_ci * actually modified. */ 30362306a36Sopenharmony_ci r = RESUME_HOST_NV; 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci case EMULATE_FAIL: 30662306a36Sopenharmony_ci { 30762306a36Sopenharmony_ci ppc_inst_t last_inst; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); 31062306a36Sopenharmony_ci kvm_debug_ratelimited("Guest access to device memory using unsupported instruction (opcode: %#08x)\n", 31162306a36Sopenharmony_ci ppc_inst_val(last_inst)); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* 31462306a36Sopenharmony_ci * Injecting a Data Storage here is a bit more 31562306a36Sopenharmony_ci * accurate since the instruction that caused the 31662306a36Sopenharmony_ci * access could still be a valid one. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_BOOKE)) { 31962306a36Sopenharmony_ci ulong dsisr = DSISR_BADACCESS; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (vcpu->mmio_is_write) 32262306a36Sopenharmony_ci dsisr |= DSISR_ISSTORE; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci kvmppc_core_queue_data_storage(vcpu, 32562306a36Sopenharmony_ci kvmppc_get_msr(vcpu) & SRR1_PREFIXED, 32662306a36Sopenharmony_ci vcpu->arch.vaddr_accessed, dsisr); 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci /* 32962306a36Sopenharmony_ci * BookE does not send a SIGBUS on a bad 33062306a36Sopenharmony_ci * fault, so use a Program interrupt instead 33162306a36Sopenharmony_ci * to avoid a fault loop. 33262306a36Sopenharmony_ci */ 33362306a36Sopenharmony_ci kvmppc_core_queue_program(vcpu, 0); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci r = RESUME_GUEST; 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci default: 34062306a36Sopenharmony_ci WARN_ON(1); 34162306a36Sopenharmony_ci r = RESUME_GUEST; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return r; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_emulate_mmio); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ciint kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, 34962306a36Sopenharmony_ci bool data) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM & PAGE_MASK; 35262306a36Sopenharmony_ci struct kvmppc_pte pte; 35362306a36Sopenharmony_ci int r = -EINVAL; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci vcpu->stat.st++; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops && vcpu->kvm->arch.kvm_ops->store_to_eaddr) 35862306a36Sopenharmony_ci r = vcpu->kvm->arch.kvm_ops->store_to_eaddr(vcpu, eaddr, ptr, 35962306a36Sopenharmony_ci size); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if ((!r) || (r == -EAGAIN)) 36262306a36Sopenharmony_ci return r; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci r = kvmppc_xlate(vcpu, *eaddr, data ? XLATE_DATA : XLATE_INST, 36562306a36Sopenharmony_ci XLATE_WRITE, &pte); 36662306a36Sopenharmony_ci if (r < 0) 36762306a36Sopenharmony_ci return r; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci *eaddr = pte.raddr; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!pte.may_write) 37262306a36Sopenharmony_ci return -EPERM; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Magic page override */ 37562306a36Sopenharmony_ci if (kvmppc_supports_magic_page(vcpu) && mp_pa && 37662306a36Sopenharmony_ci ((pte.raddr & KVM_PAM & PAGE_MASK) == mp_pa) && 37762306a36Sopenharmony_ci !(kvmppc_get_msr(vcpu) & MSR_PR)) { 37862306a36Sopenharmony_ci void *magic = vcpu->arch.shared; 37962306a36Sopenharmony_ci magic += pte.eaddr & 0xfff; 38062306a36Sopenharmony_ci memcpy(magic, ptr, size); 38162306a36Sopenharmony_ci return EMULATE_DONE; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (kvm_write_guest(vcpu->kvm, pte.raddr, ptr, size)) 38562306a36Sopenharmony_ci return EMULATE_DO_MMIO; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return EMULATE_DONE; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_st); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ciint kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, 39262306a36Sopenharmony_ci bool data) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM & PAGE_MASK; 39562306a36Sopenharmony_ci struct kvmppc_pte pte; 39662306a36Sopenharmony_ci int rc = -EINVAL; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci vcpu->stat.ld++; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops && vcpu->kvm->arch.kvm_ops->load_from_eaddr) 40162306a36Sopenharmony_ci rc = vcpu->kvm->arch.kvm_ops->load_from_eaddr(vcpu, eaddr, ptr, 40262306a36Sopenharmony_ci size); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if ((!rc) || (rc == -EAGAIN)) 40562306a36Sopenharmony_ci return rc; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci rc = kvmppc_xlate(vcpu, *eaddr, data ? XLATE_DATA : XLATE_INST, 40862306a36Sopenharmony_ci XLATE_READ, &pte); 40962306a36Sopenharmony_ci if (rc) 41062306a36Sopenharmony_ci return rc; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci *eaddr = pte.raddr; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!pte.may_read) 41562306a36Sopenharmony_ci return -EPERM; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (!data && !pte.may_execute) 41862306a36Sopenharmony_ci return -ENOEXEC; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Magic page override */ 42162306a36Sopenharmony_ci if (kvmppc_supports_magic_page(vcpu) && mp_pa && 42262306a36Sopenharmony_ci ((pte.raddr & KVM_PAM & PAGE_MASK) == mp_pa) && 42362306a36Sopenharmony_ci !(kvmppc_get_msr(vcpu) & MSR_PR)) { 42462306a36Sopenharmony_ci void *magic = vcpu->arch.shared; 42562306a36Sopenharmony_ci magic += pte.eaddr & 0xfff; 42662306a36Sopenharmony_ci memcpy(ptr, magic, size); 42762306a36Sopenharmony_ci return EMULATE_DONE; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci kvm_vcpu_srcu_read_lock(vcpu); 43162306a36Sopenharmony_ci rc = kvm_read_guest(vcpu->kvm, pte.raddr, ptr, size); 43262306a36Sopenharmony_ci kvm_vcpu_srcu_read_unlock(vcpu); 43362306a36Sopenharmony_ci if (rc) 43462306a36Sopenharmony_ci return EMULATE_DO_MMIO; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return EMULATE_DONE; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_ld); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ciint kvm_arch_init_vm(struct kvm *kvm, unsigned long type) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci struct kvmppc_ops *kvm_ops = NULL; 44362306a36Sopenharmony_ci int r; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* 44662306a36Sopenharmony_ci * if we have both HV and PR enabled, default is HV 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_ci if (type == 0) { 44962306a36Sopenharmony_ci if (kvmppc_hv_ops) 45062306a36Sopenharmony_ci kvm_ops = kvmppc_hv_ops; 45162306a36Sopenharmony_ci else 45262306a36Sopenharmony_ci kvm_ops = kvmppc_pr_ops; 45362306a36Sopenharmony_ci if (!kvm_ops) 45462306a36Sopenharmony_ci goto err_out; 45562306a36Sopenharmony_ci } else if (type == KVM_VM_PPC_HV) { 45662306a36Sopenharmony_ci if (!kvmppc_hv_ops) 45762306a36Sopenharmony_ci goto err_out; 45862306a36Sopenharmony_ci kvm_ops = kvmppc_hv_ops; 45962306a36Sopenharmony_ci } else if (type == KVM_VM_PPC_PR) { 46062306a36Sopenharmony_ci if (!kvmppc_pr_ops) 46162306a36Sopenharmony_ci goto err_out; 46262306a36Sopenharmony_ci kvm_ops = kvmppc_pr_ops; 46362306a36Sopenharmony_ci } else 46462306a36Sopenharmony_ci goto err_out; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (!try_module_get(kvm_ops->owner)) 46762306a36Sopenharmony_ci return -ENOENT; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci kvm->arch.kvm_ops = kvm_ops; 47062306a36Sopenharmony_ci r = kvmppc_core_init_vm(kvm); 47162306a36Sopenharmony_ci if (r) 47262306a36Sopenharmony_ci module_put(kvm_ops->owner); 47362306a36Sopenharmony_ci return r; 47462306a36Sopenharmony_cierr_out: 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_civoid kvm_arch_destroy_vm(struct kvm *kvm) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS 48162306a36Sopenharmony_ci /* 48262306a36Sopenharmony_ci * We call kick_all_cpus_sync() to ensure that all 48362306a36Sopenharmony_ci * CPUs have executed any pending IPIs before we 48462306a36Sopenharmony_ci * continue and free VCPUs structures below. 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci if (is_kvmppc_hv_enabled(kvm)) 48762306a36Sopenharmony_ci kick_all_cpus_sync(); 48862306a36Sopenharmony_ci#endif 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci kvm_destroy_vcpus(kvm); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci mutex_lock(&kvm->lock); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci kvmppc_core_destroy_vm(kvm); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci mutex_unlock(&kvm->lock); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* drop the module reference */ 49962306a36Sopenharmony_ci module_put(kvm->arch.kvm_ops->owner); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ciint kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci int r; 50562306a36Sopenharmony_ci /* Assume we're using HV mode when the HV module is loaded */ 50662306a36Sopenharmony_ci int hv_enabled = kvmppc_hv_ops ? 1 : 0; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (kvm) { 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * Hooray - we know which VM type we're running on. Depend on 51162306a36Sopenharmony_ci * that rather than the guess above. 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci hv_enabled = is_kvmppc_hv_enabled(kvm); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci switch (ext) { 51762306a36Sopenharmony_ci#ifdef CONFIG_BOOKE 51862306a36Sopenharmony_ci case KVM_CAP_PPC_BOOKE_SREGS: 51962306a36Sopenharmony_ci case KVM_CAP_PPC_BOOKE_WATCHDOG: 52062306a36Sopenharmony_ci case KVM_CAP_PPC_EPR: 52162306a36Sopenharmony_ci#else 52262306a36Sopenharmony_ci case KVM_CAP_PPC_SEGSTATE: 52362306a36Sopenharmony_ci case KVM_CAP_PPC_HIOR: 52462306a36Sopenharmony_ci case KVM_CAP_PPC_PAPR: 52562306a36Sopenharmony_ci#endif 52662306a36Sopenharmony_ci case KVM_CAP_PPC_UNSET_IRQ: 52762306a36Sopenharmony_ci case KVM_CAP_PPC_IRQ_LEVEL: 52862306a36Sopenharmony_ci case KVM_CAP_ENABLE_CAP: 52962306a36Sopenharmony_ci case KVM_CAP_ONE_REG: 53062306a36Sopenharmony_ci case KVM_CAP_IOEVENTFD: 53162306a36Sopenharmony_ci case KVM_CAP_DEVICE_CTRL: 53262306a36Sopenharmony_ci case KVM_CAP_IMMEDIATE_EXIT: 53362306a36Sopenharmony_ci case KVM_CAP_SET_GUEST_DEBUG: 53462306a36Sopenharmony_ci r = 1; 53562306a36Sopenharmony_ci break; 53662306a36Sopenharmony_ci case KVM_CAP_PPC_GUEST_DEBUG_SSTEP: 53762306a36Sopenharmony_ci case KVM_CAP_PPC_PAIRED_SINGLES: 53862306a36Sopenharmony_ci case KVM_CAP_PPC_OSI: 53962306a36Sopenharmony_ci case KVM_CAP_PPC_GET_PVINFO: 54062306a36Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) 54162306a36Sopenharmony_ci case KVM_CAP_SW_TLB: 54262306a36Sopenharmony_ci#endif 54362306a36Sopenharmony_ci /* We support this only for PR */ 54462306a36Sopenharmony_ci r = !hv_enabled; 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci#ifdef CONFIG_KVM_MPIC 54762306a36Sopenharmony_ci case KVM_CAP_IRQ_MPIC: 54862306a36Sopenharmony_ci r = 1; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci#endif 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 55362306a36Sopenharmony_ci case KVM_CAP_SPAPR_TCE: 55462306a36Sopenharmony_ci case KVM_CAP_SPAPR_TCE_64: 55562306a36Sopenharmony_ci r = 1; 55662306a36Sopenharmony_ci break; 55762306a36Sopenharmony_ci case KVM_CAP_SPAPR_TCE_VFIO: 55862306a36Sopenharmony_ci r = !!cpu_has_feature(CPU_FTR_HVMODE); 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci case KVM_CAP_PPC_RTAS: 56162306a36Sopenharmony_ci case KVM_CAP_PPC_FIXUP_HCALL: 56262306a36Sopenharmony_ci case KVM_CAP_PPC_ENABLE_HCALL: 56362306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS 56462306a36Sopenharmony_ci case KVM_CAP_IRQ_XICS: 56562306a36Sopenharmony_ci#endif 56662306a36Sopenharmony_ci case KVM_CAP_PPC_GET_CPU_CHAR: 56762306a36Sopenharmony_ci r = 1; 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci#ifdef CONFIG_KVM_XIVE 57062306a36Sopenharmony_ci case KVM_CAP_PPC_IRQ_XIVE: 57162306a36Sopenharmony_ci /* 57262306a36Sopenharmony_ci * We need XIVE to be enabled on the platform (implies 57362306a36Sopenharmony_ci * a POWER9 processor) and the PowerNV platform, as 57462306a36Sopenharmony_ci * nested is not yet supported. 57562306a36Sopenharmony_ci */ 57662306a36Sopenharmony_ci r = xive_enabled() && !!cpu_has_feature(CPU_FTR_HVMODE) && 57762306a36Sopenharmony_ci kvmppc_xive_native_supported(); 57862306a36Sopenharmony_ci break; 57962306a36Sopenharmony_ci#endif 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci#ifdef CONFIG_HAVE_KVM_IRQFD 58262306a36Sopenharmony_ci case KVM_CAP_IRQFD_RESAMPLE: 58362306a36Sopenharmony_ci r = !xive_enabled(); 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci#endif 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci case KVM_CAP_PPC_ALLOC_HTAB: 58862306a36Sopenharmony_ci r = hv_enabled; 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci#endif /* CONFIG_PPC_BOOK3S_64 */ 59162306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 59262306a36Sopenharmony_ci case KVM_CAP_PPC_SMT: 59362306a36Sopenharmony_ci r = 0; 59462306a36Sopenharmony_ci if (kvm) { 59562306a36Sopenharmony_ci if (kvm->arch.emul_smt_mode > 1) 59662306a36Sopenharmony_ci r = kvm->arch.emul_smt_mode; 59762306a36Sopenharmony_ci else 59862306a36Sopenharmony_ci r = kvm->arch.smt_mode; 59962306a36Sopenharmony_ci } else if (hv_enabled) { 60062306a36Sopenharmony_ci if (cpu_has_feature(CPU_FTR_ARCH_300)) 60162306a36Sopenharmony_ci r = 1; 60262306a36Sopenharmony_ci else 60362306a36Sopenharmony_ci r = threads_per_subcore; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case KVM_CAP_PPC_SMT_POSSIBLE: 60762306a36Sopenharmony_ci r = 1; 60862306a36Sopenharmony_ci if (hv_enabled) { 60962306a36Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ARCH_300)) 61062306a36Sopenharmony_ci r = ((threads_per_subcore << 1) - 1); 61162306a36Sopenharmony_ci else 61262306a36Sopenharmony_ci /* P9 can emulate dbells, so allow any mode */ 61362306a36Sopenharmony_ci r = 8 | 4 | 2 | 1; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci case KVM_CAP_PPC_RMA: 61762306a36Sopenharmony_ci r = 0; 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci case KVM_CAP_PPC_HWRNG: 62062306a36Sopenharmony_ci r = kvmppc_hwrng_present(); 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci case KVM_CAP_PPC_MMU_RADIX: 62362306a36Sopenharmony_ci r = !!(hv_enabled && radix_enabled()); 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci case KVM_CAP_PPC_MMU_HASH_V3: 62662306a36Sopenharmony_ci r = !!(hv_enabled && kvmppc_hv_ops->hash_v3_possible && 62762306a36Sopenharmony_ci kvmppc_hv_ops->hash_v3_possible()); 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci case KVM_CAP_PPC_NESTED_HV: 63062306a36Sopenharmony_ci r = !!(hv_enabled && kvmppc_hv_ops->enable_nested && 63162306a36Sopenharmony_ci !kvmppc_hv_ops->enable_nested(NULL)); 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci#endif 63462306a36Sopenharmony_ci case KVM_CAP_SYNC_MMU: 63562306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 63662306a36Sopenharmony_ci r = hv_enabled; 63762306a36Sopenharmony_ci#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER) 63862306a36Sopenharmony_ci r = 1; 63962306a36Sopenharmony_ci#else 64062306a36Sopenharmony_ci r = 0; 64162306a36Sopenharmony_ci#endif 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 64462306a36Sopenharmony_ci case KVM_CAP_PPC_HTAB_FD: 64562306a36Sopenharmony_ci r = hv_enabled; 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci#endif 64862306a36Sopenharmony_ci case KVM_CAP_NR_VCPUS: 64962306a36Sopenharmony_ci /* 65062306a36Sopenharmony_ci * Recommending a number of CPUs is somewhat arbitrary; we 65162306a36Sopenharmony_ci * return the number of present CPUs for -HV (since a host 65262306a36Sopenharmony_ci * will have secondary threads "offline"), and for other KVM 65362306a36Sopenharmony_ci * implementations just count online CPUs. 65462306a36Sopenharmony_ci */ 65562306a36Sopenharmony_ci if (hv_enabled) 65662306a36Sopenharmony_ci r = min_t(unsigned int, num_present_cpus(), KVM_MAX_VCPUS); 65762306a36Sopenharmony_ci else 65862306a36Sopenharmony_ci r = min_t(unsigned int, num_online_cpus(), KVM_MAX_VCPUS); 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci case KVM_CAP_MAX_VCPUS: 66162306a36Sopenharmony_ci r = KVM_MAX_VCPUS; 66262306a36Sopenharmony_ci break; 66362306a36Sopenharmony_ci case KVM_CAP_MAX_VCPU_ID: 66462306a36Sopenharmony_ci r = KVM_MAX_VCPU_IDS; 66562306a36Sopenharmony_ci break; 66662306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 66762306a36Sopenharmony_ci case KVM_CAP_PPC_GET_SMMU_INFO: 66862306a36Sopenharmony_ci r = 1; 66962306a36Sopenharmony_ci break; 67062306a36Sopenharmony_ci case KVM_CAP_SPAPR_MULTITCE: 67162306a36Sopenharmony_ci r = 1; 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci case KVM_CAP_SPAPR_RESIZE_HPT: 67462306a36Sopenharmony_ci r = !!hv_enabled; 67562306a36Sopenharmony_ci break; 67662306a36Sopenharmony_ci#endif 67762306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 67862306a36Sopenharmony_ci case KVM_CAP_PPC_FWNMI: 67962306a36Sopenharmony_ci r = hv_enabled; 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci#endif 68262306a36Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 68362306a36Sopenharmony_ci case KVM_CAP_PPC_HTM: 68462306a36Sopenharmony_ci r = !!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_HTM) || 68562306a36Sopenharmony_ci (hv_enabled && cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)); 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci#endif 68862306a36Sopenharmony_ci#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) 68962306a36Sopenharmony_ci case KVM_CAP_PPC_SECURE_GUEST: 69062306a36Sopenharmony_ci r = hv_enabled && kvmppc_hv_ops->enable_svm && 69162306a36Sopenharmony_ci !kvmppc_hv_ops->enable_svm(NULL); 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci case KVM_CAP_PPC_DAWR1: 69462306a36Sopenharmony_ci r = !!(hv_enabled && kvmppc_hv_ops->enable_dawr1 && 69562306a36Sopenharmony_ci !kvmppc_hv_ops->enable_dawr1(NULL)); 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci case KVM_CAP_PPC_RPT_INVALIDATE: 69862306a36Sopenharmony_ci r = 1; 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci#endif 70162306a36Sopenharmony_ci case KVM_CAP_PPC_AIL_MODE_3: 70262306a36Sopenharmony_ci r = 0; 70362306a36Sopenharmony_ci /* 70462306a36Sopenharmony_ci * KVM PR, POWER7, and some POWER9s don't support AIL=3 mode. 70562306a36Sopenharmony_ci * The POWER9s can support it if the guest runs in hash mode, 70662306a36Sopenharmony_ci * but QEMU doesn't necessarily query the capability in time. 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci if (hv_enabled) { 70962306a36Sopenharmony_ci if (kvmhv_on_pseries()) { 71062306a36Sopenharmony_ci if (pseries_reloc_on_exception()) 71162306a36Sopenharmony_ci r = 1; 71262306a36Sopenharmony_ci } else if (cpu_has_feature(CPU_FTR_ARCH_207S) && 71362306a36Sopenharmony_ci !cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) { 71462306a36Sopenharmony_ci r = 1; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci break; 71862306a36Sopenharmony_ci default: 71962306a36Sopenharmony_ci r = 0; 72062306a36Sopenharmony_ci break; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci return r; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cilong kvm_arch_dev_ioctl(struct file *filp, 72762306a36Sopenharmony_ci unsigned int ioctl, unsigned long arg) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci return -EINVAL; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_civoid kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci kvmppc_core_free_memslot(kvm, slot); 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ciint kvm_arch_prepare_memory_region(struct kvm *kvm, 73862306a36Sopenharmony_ci const struct kvm_memory_slot *old, 73962306a36Sopenharmony_ci struct kvm_memory_slot *new, 74062306a36Sopenharmony_ci enum kvm_mr_change change) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci return kvmppc_core_prepare_memory_region(kvm, old, new, change); 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_civoid kvm_arch_commit_memory_region(struct kvm *kvm, 74662306a36Sopenharmony_ci struct kvm_memory_slot *old, 74762306a36Sopenharmony_ci const struct kvm_memory_slot *new, 74862306a36Sopenharmony_ci enum kvm_mr_change change) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci kvmppc_core_commit_memory_region(kvm, old, new, change); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_civoid kvm_arch_flush_shadow_memslot(struct kvm *kvm, 75462306a36Sopenharmony_ci struct kvm_memory_slot *slot) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci kvmppc_core_flush_memslot(kvm, slot); 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ciint kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci return 0; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic enum hrtimer_restart kvmppc_decrementer_wakeup(struct hrtimer *timer) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct kvm_vcpu *vcpu; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci vcpu = container_of(timer, struct kvm_vcpu, arch.dec_timer); 76962306a36Sopenharmony_ci kvmppc_decrementer_func(vcpu); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return HRTIMER_NORESTART; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ciint kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci int err; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); 77962306a36Sopenharmony_ci vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci#ifdef CONFIG_KVM_EXIT_TIMING 78262306a36Sopenharmony_ci mutex_init(&vcpu->arch.exit_timing_lock); 78362306a36Sopenharmony_ci#endif 78462306a36Sopenharmony_ci err = kvmppc_subarch_vcpu_init(vcpu); 78562306a36Sopenharmony_ci if (err) 78662306a36Sopenharmony_ci return err; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci err = kvmppc_core_vcpu_create(vcpu); 78962306a36Sopenharmony_ci if (err) 79062306a36Sopenharmony_ci goto out_vcpu_uninit; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci rcuwait_init(&vcpu->arch.wait); 79362306a36Sopenharmony_ci vcpu->arch.waitp = &vcpu->arch.wait; 79462306a36Sopenharmony_ci return 0; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ciout_vcpu_uninit: 79762306a36Sopenharmony_ci kvmppc_subarch_vcpu_uninit(vcpu); 79862306a36Sopenharmony_ci return err; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_civoid kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_civoid kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci /* Make sure we're not using the vcpu anymore */ 80862306a36Sopenharmony_ci hrtimer_cancel(&vcpu->arch.dec_timer); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci switch (vcpu->arch.irq_type) { 81162306a36Sopenharmony_ci case KVMPPC_IRQ_MPIC: 81262306a36Sopenharmony_ci kvmppc_mpic_disconnect_vcpu(vcpu->arch.mpic, vcpu); 81362306a36Sopenharmony_ci break; 81462306a36Sopenharmony_ci case KVMPPC_IRQ_XICS: 81562306a36Sopenharmony_ci if (xics_on_xive()) 81662306a36Sopenharmony_ci kvmppc_xive_cleanup_vcpu(vcpu); 81762306a36Sopenharmony_ci else 81862306a36Sopenharmony_ci kvmppc_xics_free_icp(vcpu); 81962306a36Sopenharmony_ci break; 82062306a36Sopenharmony_ci case KVMPPC_IRQ_XIVE: 82162306a36Sopenharmony_ci kvmppc_xive_native_cleanup_vcpu(vcpu); 82262306a36Sopenharmony_ci break; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci kvmppc_core_vcpu_free(vcpu); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci kvmppc_subarch_vcpu_uninit(vcpu); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ciint kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci return kvmppc_core_pending_dec(vcpu); 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_civoid kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci#ifdef CONFIG_BOOKE 83862306a36Sopenharmony_ci /* 83962306a36Sopenharmony_ci * vrsave (formerly usprg0) isn't used by Linux, but may 84062306a36Sopenharmony_ci * be used by the guest. 84162306a36Sopenharmony_ci * 84262306a36Sopenharmony_ci * On non-booke this is associated with Altivec and 84362306a36Sopenharmony_ci * is handled by code in book3s.c. 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ci mtspr(SPRN_VRSAVE, vcpu->arch.vrsave); 84662306a36Sopenharmony_ci#endif 84762306a36Sopenharmony_ci kvmppc_core_vcpu_load(vcpu, cpu); 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_civoid kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci kvmppc_core_vcpu_put(vcpu); 85362306a36Sopenharmony_ci#ifdef CONFIG_BOOKE 85462306a36Sopenharmony_ci vcpu->arch.vrsave = mfspr(SPRN_VRSAVE); 85562306a36Sopenharmony_ci#endif 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci/* 85962306a36Sopenharmony_ci * irq_bypass_add_producer and irq_bypass_del_producer are only 86062306a36Sopenharmony_ci * useful if the architecture supports PCI passthrough. 86162306a36Sopenharmony_ci * irq_bypass_stop and irq_bypass_start are not needed and so 86262306a36Sopenharmony_ci * kvm_ops are not defined for them. 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_cibool kvm_arch_has_irq_bypass(void) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci return ((kvmppc_hv_ops && kvmppc_hv_ops->irq_bypass_add_producer) || 86762306a36Sopenharmony_ci (kvmppc_pr_ops && kvmppc_pr_ops->irq_bypass_add_producer)); 86862306a36Sopenharmony_ci} 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ciint kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons, 87162306a36Sopenharmony_ci struct irq_bypass_producer *prod) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct kvm_kernel_irqfd *irqfd = 87462306a36Sopenharmony_ci container_of(cons, struct kvm_kernel_irqfd, consumer); 87562306a36Sopenharmony_ci struct kvm *kvm = irqfd->kvm; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (kvm->arch.kvm_ops->irq_bypass_add_producer) 87862306a36Sopenharmony_ci return kvm->arch.kvm_ops->irq_bypass_add_producer(cons, prod); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci return 0; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_civoid kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, 88462306a36Sopenharmony_ci struct irq_bypass_producer *prod) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct kvm_kernel_irqfd *irqfd = 88762306a36Sopenharmony_ci container_of(cons, struct kvm_kernel_irqfd, consumer); 88862306a36Sopenharmony_ci struct kvm *kvm = irqfd->kvm; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (kvm->arch.kvm_ops->irq_bypass_del_producer) 89162306a36Sopenharmony_ci kvm->arch.kvm_ops->irq_bypass_del_producer(cons, prod); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci#ifdef CONFIG_VSX 89562306a36Sopenharmony_cistatic inline int kvmppc_get_vsr_dword_offset(int index) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci int offset; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci if ((index != 0) && (index != 1)) 90062306a36Sopenharmony_ci return -1; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 90362306a36Sopenharmony_ci offset = index; 90462306a36Sopenharmony_ci#else 90562306a36Sopenharmony_ci offset = 1 - index; 90662306a36Sopenharmony_ci#endif 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci return offset; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic inline int kvmppc_get_vsr_word_offset(int index) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci int offset; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if ((index > 3) || (index < 0)) 91662306a36Sopenharmony_ci return -1; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci#ifdef __BIG_ENDIAN 91962306a36Sopenharmony_ci offset = index; 92062306a36Sopenharmony_ci#else 92162306a36Sopenharmony_ci offset = 3 - index; 92262306a36Sopenharmony_ci#endif 92362306a36Sopenharmony_ci return offset; 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_cistatic inline void kvmppc_set_vsr_dword(struct kvm_vcpu *vcpu, 92762306a36Sopenharmony_ci u64 gpr) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci union kvmppc_one_reg val; 93062306a36Sopenharmony_ci int offset = kvmppc_get_vsr_dword_offset(vcpu->arch.mmio_vsx_offset); 93162306a36Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (offset == -1) 93462306a36Sopenharmony_ci return; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (index >= 32) { 93762306a36Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index - 32); 93862306a36Sopenharmony_ci val.vsxval[offset] = gpr; 93962306a36Sopenharmony_ci VCPU_VSX_VR(vcpu, index - 32) = val.vval; 94062306a36Sopenharmony_ci } else { 94162306a36Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, offset) = gpr; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic inline void kvmppc_set_vsr_dword_dump(struct kvm_vcpu *vcpu, 94662306a36Sopenharmony_ci u64 gpr) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci union kvmppc_one_reg val; 94962306a36Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (index >= 32) { 95262306a36Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index - 32); 95362306a36Sopenharmony_ci val.vsxval[0] = gpr; 95462306a36Sopenharmony_ci val.vsxval[1] = gpr; 95562306a36Sopenharmony_ci VCPU_VSX_VR(vcpu, index - 32) = val.vval; 95662306a36Sopenharmony_ci } else { 95762306a36Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, 0) = gpr; 95862306a36Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, 1) = gpr; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cistatic inline void kvmppc_set_vsr_word_dump(struct kvm_vcpu *vcpu, 96362306a36Sopenharmony_ci u32 gpr) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci union kvmppc_one_reg val; 96662306a36Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (index >= 32) { 96962306a36Sopenharmony_ci val.vsx32val[0] = gpr; 97062306a36Sopenharmony_ci val.vsx32val[1] = gpr; 97162306a36Sopenharmony_ci val.vsx32val[2] = gpr; 97262306a36Sopenharmony_ci val.vsx32val[3] = gpr; 97362306a36Sopenharmony_ci VCPU_VSX_VR(vcpu, index - 32) = val.vval; 97462306a36Sopenharmony_ci } else { 97562306a36Sopenharmony_ci val.vsx32val[0] = gpr; 97662306a36Sopenharmony_ci val.vsx32val[1] = gpr; 97762306a36Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, 0) = val.vsxval[0]; 97862306a36Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, 1) = val.vsxval[0]; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic inline void kvmppc_set_vsr_word(struct kvm_vcpu *vcpu, 98362306a36Sopenharmony_ci u32 gpr32) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci union kvmppc_one_reg val; 98662306a36Sopenharmony_ci int offset = kvmppc_get_vsr_word_offset(vcpu->arch.mmio_vsx_offset); 98762306a36Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 98862306a36Sopenharmony_ci int dword_offset, word_offset; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (offset == -1) 99162306a36Sopenharmony_ci return; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (index >= 32) { 99462306a36Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index - 32); 99562306a36Sopenharmony_ci val.vsx32val[offset] = gpr32; 99662306a36Sopenharmony_ci VCPU_VSX_VR(vcpu, index - 32) = val.vval; 99762306a36Sopenharmony_ci } else { 99862306a36Sopenharmony_ci dword_offset = offset / 2; 99962306a36Sopenharmony_ci word_offset = offset % 2; 100062306a36Sopenharmony_ci val.vsxval[0] = VCPU_VSX_FPR(vcpu, index, dword_offset); 100162306a36Sopenharmony_ci val.vsx32val[word_offset] = gpr32; 100262306a36Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, dword_offset) = val.vsxval[0]; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci#endif /* CONFIG_VSX */ 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC 100862306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_offset_generic(struct kvm_vcpu *vcpu, 100962306a36Sopenharmony_ci int index, int element_size) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci int offset; 101262306a36Sopenharmony_ci int elts = sizeof(vector128)/element_size; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci if ((index < 0) || (index >= elts)) 101562306a36Sopenharmony_ci return -1; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (kvmppc_need_byteswap(vcpu)) 101862306a36Sopenharmony_ci offset = elts - index - 1; 101962306a36Sopenharmony_ci else 102062306a36Sopenharmony_ci offset = index; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci return offset; 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_dword_offset(struct kvm_vcpu *vcpu, 102662306a36Sopenharmony_ci int index) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci return kvmppc_get_vmx_offset_generic(vcpu, index, 8); 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_word_offset(struct kvm_vcpu *vcpu, 103262306a36Sopenharmony_ci int index) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci return kvmppc_get_vmx_offset_generic(vcpu, index, 4); 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_hword_offset(struct kvm_vcpu *vcpu, 103862306a36Sopenharmony_ci int index) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci return kvmppc_get_vmx_offset_generic(vcpu, index, 2); 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cistatic inline int kvmppc_get_vmx_byte_offset(struct kvm_vcpu *vcpu, 104462306a36Sopenharmony_ci int index) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci return kvmppc_get_vmx_offset_generic(vcpu, index, 1); 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cistatic inline void kvmppc_set_vmx_dword(struct kvm_vcpu *vcpu, 105162306a36Sopenharmony_ci u64 gpr) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci union kvmppc_one_reg val; 105462306a36Sopenharmony_ci int offset = kvmppc_get_vmx_dword_offset(vcpu, 105562306a36Sopenharmony_ci vcpu->arch.mmio_vmx_offset); 105662306a36Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci if (offset == -1) 105962306a36Sopenharmony_ci return; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index); 106262306a36Sopenharmony_ci val.vsxval[offset] = gpr; 106362306a36Sopenharmony_ci VCPU_VSX_VR(vcpu, index) = val.vval; 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic inline void kvmppc_set_vmx_word(struct kvm_vcpu *vcpu, 106762306a36Sopenharmony_ci u32 gpr32) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci union kvmppc_one_reg val; 107062306a36Sopenharmony_ci int offset = kvmppc_get_vmx_word_offset(vcpu, 107162306a36Sopenharmony_ci vcpu->arch.mmio_vmx_offset); 107262306a36Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (offset == -1) 107562306a36Sopenharmony_ci return; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index); 107862306a36Sopenharmony_ci val.vsx32val[offset] = gpr32; 107962306a36Sopenharmony_ci VCPU_VSX_VR(vcpu, index) = val.vval; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic inline void kvmppc_set_vmx_hword(struct kvm_vcpu *vcpu, 108362306a36Sopenharmony_ci u16 gpr16) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci union kvmppc_one_reg val; 108662306a36Sopenharmony_ci int offset = kvmppc_get_vmx_hword_offset(vcpu, 108762306a36Sopenharmony_ci vcpu->arch.mmio_vmx_offset); 108862306a36Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (offset == -1) 109162306a36Sopenharmony_ci return; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index); 109462306a36Sopenharmony_ci val.vsx16val[offset] = gpr16; 109562306a36Sopenharmony_ci VCPU_VSX_VR(vcpu, index) = val.vval; 109662306a36Sopenharmony_ci} 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_cistatic inline void kvmppc_set_vmx_byte(struct kvm_vcpu *vcpu, 109962306a36Sopenharmony_ci u8 gpr8) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci union kvmppc_one_reg val; 110262306a36Sopenharmony_ci int offset = kvmppc_get_vmx_byte_offset(vcpu, 110362306a36Sopenharmony_ci vcpu->arch.mmio_vmx_offset); 110462306a36Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (offset == -1) 110762306a36Sopenharmony_ci return; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index); 111062306a36Sopenharmony_ci val.vsx8val[offset] = gpr8; 111162306a36Sopenharmony_ci VCPU_VSX_VR(vcpu, index) = val.vval; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci#ifdef CONFIG_PPC_FPU 111662306a36Sopenharmony_cistatic inline u64 sp_to_dp(u32 fprs) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci u64 fprd; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci preempt_disable(); 112162306a36Sopenharmony_ci enable_kernel_fp(); 112262306a36Sopenharmony_ci asm ("lfs%U1%X1 0,%1; stfd%U0%X0 0,%0" : "=m<>" (fprd) : "m<>" (fprs) 112362306a36Sopenharmony_ci : "fr0"); 112462306a36Sopenharmony_ci preempt_enable(); 112562306a36Sopenharmony_ci return fprd; 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic inline u32 dp_to_sp(u64 fprd) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci u32 fprs; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci preempt_disable(); 113362306a36Sopenharmony_ci enable_kernel_fp(); 113462306a36Sopenharmony_ci asm ("lfd%U1%X1 0,%1; stfs%U0%X0 0,%0" : "=m<>" (fprs) : "m<>" (fprd) 113562306a36Sopenharmony_ci : "fr0"); 113662306a36Sopenharmony_ci preempt_enable(); 113762306a36Sopenharmony_ci return fprs; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci#else 114162306a36Sopenharmony_ci#define sp_to_dp(x) (x) 114262306a36Sopenharmony_ci#define dp_to_sp(x) (x) 114362306a36Sopenharmony_ci#endif /* CONFIG_PPC_FPU */ 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_cistatic void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu) 114662306a36Sopenharmony_ci{ 114762306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 114862306a36Sopenharmony_ci u64 gpr; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci if (run->mmio.len > sizeof(gpr)) 115162306a36Sopenharmony_ci return; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci if (!vcpu->arch.mmio_host_swabbed) { 115462306a36Sopenharmony_ci switch (run->mmio.len) { 115562306a36Sopenharmony_ci case 8: gpr = *(u64 *)run->mmio.data; break; 115662306a36Sopenharmony_ci case 4: gpr = *(u32 *)run->mmio.data; break; 115762306a36Sopenharmony_ci case 2: gpr = *(u16 *)run->mmio.data; break; 115862306a36Sopenharmony_ci case 1: gpr = *(u8 *)run->mmio.data; break; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci } else { 116162306a36Sopenharmony_ci switch (run->mmio.len) { 116262306a36Sopenharmony_ci case 8: gpr = swab64(*(u64 *)run->mmio.data); break; 116362306a36Sopenharmony_ci case 4: gpr = swab32(*(u32 *)run->mmio.data); break; 116462306a36Sopenharmony_ci case 2: gpr = swab16(*(u16 *)run->mmio.data); break; 116562306a36Sopenharmony_ci case 1: gpr = *(u8 *)run->mmio.data; break; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* conversion between single and double precision */ 117062306a36Sopenharmony_ci if ((vcpu->arch.mmio_sp64_extend) && (run->mmio.len == 4)) 117162306a36Sopenharmony_ci gpr = sp_to_dp(gpr); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (vcpu->arch.mmio_sign_extend) { 117462306a36Sopenharmony_ci switch (run->mmio.len) { 117562306a36Sopenharmony_ci#ifdef CONFIG_PPC64 117662306a36Sopenharmony_ci case 4: 117762306a36Sopenharmony_ci gpr = (s64)(s32)gpr; 117862306a36Sopenharmony_ci break; 117962306a36Sopenharmony_ci#endif 118062306a36Sopenharmony_ci case 2: 118162306a36Sopenharmony_ci gpr = (s64)(s16)gpr; 118262306a36Sopenharmony_ci break; 118362306a36Sopenharmony_ci case 1: 118462306a36Sopenharmony_ci gpr = (s64)(s8)gpr; 118562306a36Sopenharmony_ci break; 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci switch (vcpu->arch.io_gpr & KVM_MMIO_REG_EXT_MASK) { 119062306a36Sopenharmony_ci case KVM_MMIO_REG_GPR: 119162306a36Sopenharmony_ci kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr); 119262306a36Sopenharmony_ci break; 119362306a36Sopenharmony_ci case KVM_MMIO_REG_FPR: 119462306a36Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops->giveup_ext) 119562306a36Sopenharmony_ci vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_FP); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; 119862306a36Sopenharmony_ci break; 119962306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S 120062306a36Sopenharmony_ci case KVM_MMIO_REG_QPR: 120162306a36Sopenharmony_ci vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; 120262306a36Sopenharmony_ci break; 120362306a36Sopenharmony_ci case KVM_MMIO_REG_FQPR: 120462306a36Sopenharmony_ci VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; 120562306a36Sopenharmony_ci vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; 120662306a36Sopenharmony_ci break; 120762306a36Sopenharmony_ci#endif 120862306a36Sopenharmony_ci#ifdef CONFIG_VSX 120962306a36Sopenharmony_ci case KVM_MMIO_REG_VSX: 121062306a36Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops->giveup_ext) 121162306a36Sopenharmony_ci vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_VSX); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (vcpu->arch.mmio_copy_type == KVMPPC_VSX_COPY_DWORD) 121462306a36Sopenharmony_ci kvmppc_set_vsr_dword(vcpu, gpr); 121562306a36Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == KVMPPC_VSX_COPY_WORD) 121662306a36Sopenharmony_ci kvmppc_set_vsr_word(vcpu, gpr); 121762306a36Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == 121862306a36Sopenharmony_ci KVMPPC_VSX_COPY_DWORD_LOAD_DUMP) 121962306a36Sopenharmony_ci kvmppc_set_vsr_dword_dump(vcpu, gpr); 122062306a36Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == 122162306a36Sopenharmony_ci KVMPPC_VSX_COPY_WORD_LOAD_DUMP) 122262306a36Sopenharmony_ci kvmppc_set_vsr_word_dump(vcpu, gpr); 122362306a36Sopenharmony_ci break; 122462306a36Sopenharmony_ci#endif 122562306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC 122662306a36Sopenharmony_ci case KVM_MMIO_REG_VMX: 122762306a36Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops->giveup_ext) 122862306a36Sopenharmony_ci vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_VEC); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (vcpu->arch.mmio_copy_type == KVMPPC_VMX_COPY_DWORD) 123162306a36Sopenharmony_ci kvmppc_set_vmx_dword(vcpu, gpr); 123262306a36Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == KVMPPC_VMX_COPY_WORD) 123362306a36Sopenharmony_ci kvmppc_set_vmx_word(vcpu, gpr); 123462306a36Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == 123562306a36Sopenharmony_ci KVMPPC_VMX_COPY_HWORD) 123662306a36Sopenharmony_ci kvmppc_set_vmx_hword(vcpu, gpr); 123762306a36Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == 123862306a36Sopenharmony_ci KVMPPC_VMX_COPY_BYTE) 123962306a36Sopenharmony_ci kvmppc_set_vmx_byte(vcpu, gpr); 124062306a36Sopenharmony_ci break; 124162306a36Sopenharmony_ci#endif 124262306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 124362306a36Sopenharmony_ci case KVM_MMIO_REG_NESTED_GPR: 124462306a36Sopenharmony_ci if (kvmppc_need_byteswap(vcpu)) 124562306a36Sopenharmony_ci gpr = swab64(gpr); 124662306a36Sopenharmony_ci kvm_vcpu_write_guest(vcpu, vcpu->arch.nested_io_gpr, &gpr, 124762306a36Sopenharmony_ci sizeof(gpr)); 124862306a36Sopenharmony_ci break; 124962306a36Sopenharmony_ci#endif 125062306a36Sopenharmony_ci default: 125162306a36Sopenharmony_ci BUG(); 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic int __kvmppc_handle_load(struct kvm_vcpu *vcpu, 125662306a36Sopenharmony_ci unsigned int rt, unsigned int bytes, 125762306a36Sopenharmony_ci int is_default_endian, int sign_extend) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 126062306a36Sopenharmony_ci int idx, ret; 126162306a36Sopenharmony_ci bool host_swabbed; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci /* Pity C doesn't have a logical XOR operator */ 126462306a36Sopenharmony_ci if (kvmppc_need_byteswap(vcpu)) { 126562306a36Sopenharmony_ci host_swabbed = is_default_endian; 126662306a36Sopenharmony_ci } else { 126762306a36Sopenharmony_ci host_swabbed = !is_default_endian; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (bytes > sizeof(run->mmio.data)) 127162306a36Sopenharmony_ci return EMULATE_FAIL; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci run->mmio.phys_addr = vcpu->arch.paddr_accessed; 127462306a36Sopenharmony_ci run->mmio.len = bytes; 127562306a36Sopenharmony_ci run->mmio.is_write = 0; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci vcpu->arch.io_gpr = rt; 127862306a36Sopenharmony_ci vcpu->arch.mmio_host_swabbed = host_swabbed; 127962306a36Sopenharmony_ci vcpu->mmio_needed = 1; 128062306a36Sopenharmony_ci vcpu->mmio_is_write = 0; 128162306a36Sopenharmony_ci vcpu->arch.mmio_sign_extend = sign_extend; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci idx = srcu_read_lock(&vcpu->kvm->srcu); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, 128662306a36Sopenharmony_ci bytes, &run->mmio.data); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, idx); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (!ret) { 129162306a36Sopenharmony_ci kvmppc_complete_mmio_load(vcpu); 129262306a36Sopenharmony_ci vcpu->mmio_needed = 0; 129362306a36Sopenharmony_ci return EMULATE_DONE; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci return EMULATE_DO_MMIO; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ciint kvmppc_handle_load(struct kvm_vcpu *vcpu, 130062306a36Sopenharmony_ci unsigned int rt, unsigned int bytes, 130162306a36Sopenharmony_ci int is_default_endian) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci return __kvmppc_handle_load(vcpu, rt, bytes, is_default_endian, 0); 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_handle_load); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci/* Same as above, but sign extends */ 130862306a36Sopenharmony_ciint kvmppc_handle_loads(struct kvm_vcpu *vcpu, 130962306a36Sopenharmony_ci unsigned int rt, unsigned int bytes, 131062306a36Sopenharmony_ci int is_default_endian) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci return __kvmppc_handle_load(vcpu, rt, bytes, is_default_endian, 1); 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci#ifdef CONFIG_VSX 131662306a36Sopenharmony_ciint kvmppc_handle_vsx_load(struct kvm_vcpu *vcpu, 131762306a36Sopenharmony_ci unsigned int rt, unsigned int bytes, 131862306a36Sopenharmony_ci int is_default_endian, int mmio_sign_extend) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci enum emulation_result emulated = EMULATE_DONE; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci /* Currently, mmio_vsx_copy_nums only allowed to be 4 or less */ 132362306a36Sopenharmony_ci if (vcpu->arch.mmio_vsx_copy_nums > 4) 132462306a36Sopenharmony_ci return EMULATE_FAIL; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci while (vcpu->arch.mmio_vsx_copy_nums) { 132762306a36Sopenharmony_ci emulated = __kvmppc_handle_load(vcpu, rt, bytes, 132862306a36Sopenharmony_ci is_default_endian, mmio_sign_extend); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci if (emulated != EMULATE_DONE) 133162306a36Sopenharmony_ci break; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci vcpu->arch.paddr_accessed += vcpu->run->mmio.len; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci vcpu->arch.mmio_vsx_copy_nums--; 133662306a36Sopenharmony_ci vcpu->arch.mmio_vsx_offset++; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci return emulated; 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci#endif /* CONFIG_VSX */ 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ciint kvmppc_handle_store(struct kvm_vcpu *vcpu, 134362306a36Sopenharmony_ci u64 val, unsigned int bytes, int is_default_endian) 134462306a36Sopenharmony_ci{ 134562306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 134662306a36Sopenharmony_ci void *data = run->mmio.data; 134762306a36Sopenharmony_ci int idx, ret; 134862306a36Sopenharmony_ci bool host_swabbed; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci /* Pity C doesn't have a logical XOR operator */ 135162306a36Sopenharmony_ci if (kvmppc_need_byteswap(vcpu)) { 135262306a36Sopenharmony_ci host_swabbed = is_default_endian; 135362306a36Sopenharmony_ci } else { 135462306a36Sopenharmony_ci host_swabbed = !is_default_endian; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci if (bytes > sizeof(run->mmio.data)) 135862306a36Sopenharmony_ci return EMULATE_FAIL; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci run->mmio.phys_addr = vcpu->arch.paddr_accessed; 136162306a36Sopenharmony_ci run->mmio.len = bytes; 136262306a36Sopenharmony_ci run->mmio.is_write = 1; 136362306a36Sopenharmony_ci vcpu->mmio_needed = 1; 136462306a36Sopenharmony_ci vcpu->mmio_is_write = 1; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci if ((vcpu->arch.mmio_sp64_extend) && (bytes == 4)) 136762306a36Sopenharmony_ci val = dp_to_sp(val); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci /* Store the value at the lowest bytes in 'data'. */ 137062306a36Sopenharmony_ci if (!host_swabbed) { 137162306a36Sopenharmony_ci switch (bytes) { 137262306a36Sopenharmony_ci case 8: *(u64 *)data = val; break; 137362306a36Sopenharmony_ci case 4: *(u32 *)data = val; break; 137462306a36Sopenharmony_ci case 2: *(u16 *)data = val; break; 137562306a36Sopenharmony_ci case 1: *(u8 *)data = val; break; 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci } else { 137862306a36Sopenharmony_ci switch (bytes) { 137962306a36Sopenharmony_ci case 8: *(u64 *)data = swab64(val); break; 138062306a36Sopenharmony_ci case 4: *(u32 *)data = swab32(val); break; 138162306a36Sopenharmony_ci case 2: *(u16 *)data = swab16(val); break; 138262306a36Sopenharmony_ci case 1: *(u8 *)data = val; break; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci idx = srcu_read_lock(&vcpu->kvm->srcu); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, 138962306a36Sopenharmony_ci bytes, &run->mmio.data); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, idx); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (!ret) { 139462306a36Sopenharmony_ci vcpu->mmio_needed = 0; 139562306a36Sopenharmony_ci return EMULATE_DONE; 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci return EMULATE_DO_MMIO; 139962306a36Sopenharmony_ci} 140062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_handle_store); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci#ifdef CONFIG_VSX 140362306a36Sopenharmony_cistatic inline int kvmppc_get_vsr_data(struct kvm_vcpu *vcpu, int rs, u64 *val) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci u32 dword_offset, word_offset; 140662306a36Sopenharmony_ci union kvmppc_one_reg reg; 140762306a36Sopenharmony_ci int vsx_offset = 0; 140862306a36Sopenharmony_ci int copy_type = vcpu->arch.mmio_copy_type; 140962306a36Sopenharmony_ci int result = 0; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci switch (copy_type) { 141262306a36Sopenharmony_ci case KVMPPC_VSX_COPY_DWORD: 141362306a36Sopenharmony_ci vsx_offset = 141462306a36Sopenharmony_ci kvmppc_get_vsr_dword_offset(vcpu->arch.mmio_vsx_offset); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (vsx_offset == -1) { 141762306a36Sopenharmony_ci result = -1; 141862306a36Sopenharmony_ci break; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (rs < 32) { 142262306a36Sopenharmony_ci *val = VCPU_VSX_FPR(vcpu, rs, vsx_offset); 142362306a36Sopenharmony_ci } else { 142462306a36Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, rs - 32); 142562306a36Sopenharmony_ci *val = reg.vsxval[vsx_offset]; 142662306a36Sopenharmony_ci } 142762306a36Sopenharmony_ci break; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci case KVMPPC_VSX_COPY_WORD: 143062306a36Sopenharmony_ci vsx_offset = 143162306a36Sopenharmony_ci kvmppc_get_vsr_word_offset(vcpu->arch.mmio_vsx_offset); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (vsx_offset == -1) { 143462306a36Sopenharmony_ci result = -1; 143562306a36Sopenharmony_ci break; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (rs < 32) { 143962306a36Sopenharmony_ci dword_offset = vsx_offset / 2; 144062306a36Sopenharmony_ci word_offset = vsx_offset % 2; 144162306a36Sopenharmony_ci reg.vsxval[0] = VCPU_VSX_FPR(vcpu, rs, dword_offset); 144262306a36Sopenharmony_ci *val = reg.vsx32val[word_offset]; 144362306a36Sopenharmony_ci } else { 144462306a36Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, rs - 32); 144562306a36Sopenharmony_ci *val = reg.vsx32val[vsx_offset]; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci break; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci default: 145062306a36Sopenharmony_ci result = -1; 145162306a36Sopenharmony_ci break; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci return result; 145562306a36Sopenharmony_ci} 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ciint kvmppc_handle_vsx_store(struct kvm_vcpu *vcpu, 145862306a36Sopenharmony_ci int rs, unsigned int bytes, int is_default_endian) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci u64 val; 146162306a36Sopenharmony_ci enum emulation_result emulated = EMULATE_DONE; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci vcpu->arch.io_gpr = rs; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci /* Currently, mmio_vsx_copy_nums only allowed to be 4 or less */ 146662306a36Sopenharmony_ci if (vcpu->arch.mmio_vsx_copy_nums > 4) 146762306a36Sopenharmony_ci return EMULATE_FAIL; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci while (vcpu->arch.mmio_vsx_copy_nums) { 147062306a36Sopenharmony_ci if (kvmppc_get_vsr_data(vcpu, rs, &val) == -1) 147162306a36Sopenharmony_ci return EMULATE_FAIL; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci emulated = kvmppc_handle_store(vcpu, 147462306a36Sopenharmony_ci val, bytes, is_default_endian); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci if (emulated != EMULATE_DONE) 147762306a36Sopenharmony_ci break; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci vcpu->arch.paddr_accessed += vcpu->run->mmio.len; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci vcpu->arch.mmio_vsx_copy_nums--; 148262306a36Sopenharmony_ci vcpu->arch.mmio_vsx_offset++; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci return emulated; 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_cistatic int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu) 148962306a36Sopenharmony_ci{ 149062306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 149162306a36Sopenharmony_ci enum emulation_result emulated = EMULATE_FAIL; 149262306a36Sopenharmony_ci int r; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci vcpu->arch.paddr_accessed += run->mmio.len; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci if (!vcpu->mmio_is_write) { 149762306a36Sopenharmony_ci emulated = kvmppc_handle_vsx_load(vcpu, vcpu->arch.io_gpr, 149862306a36Sopenharmony_ci run->mmio.len, 1, vcpu->arch.mmio_sign_extend); 149962306a36Sopenharmony_ci } else { 150062306a36Sopenharmony_ci emulated = kvmppc_handle_vsx_store(vcpu, 150162306a36Sopenharmony_ci vcpu->arch.io_gpr, run->mmio.len, 1); 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci switch (emulated) { 150562306a36Sopenharmony_ci case EMULATE_DO_MMIO: 150662306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_MMIO; 150762306a36Sopenharmony_ci r = RESUME_HOST; 150862306a36Sopenharmony_ci break; 150962306a36Sopenharmony_ci case EMULATE_FAIL: 151062306a36Sopenharmony_ci pr_info("KVM: MMIO emulation failed (VSX repeat)\n"); 151162306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 151262306a36Sopenharmony_ci run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; 151362306a36Sopenharmony_ci r = RESUME_HOST; 151462306a36Sopenharmony_ci break; 151562306a36Sopenharmony_ci default: 151662306a36Sopenharmony_ci r = RESUME_GUEST; 151762306a36Sopenharmony_ci break; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci return r; 152062306a36Sopenharmony_ci} 152162306a36Sopenharmony_ci#endif /* CONFIG_VSX */ 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC 152462306a36Sopenharmony_ciint kvmppc_handle_vmx_load(struct kvm_vcpu *vcpu, 152562306a36Sopenharmony_ci unsigned int rt, unsigned int bytes, int is_default_endian) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci enum emulation_result emulated = EMULATE_DONE; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci if (vcpu->arch.mmio_vmx_copy_nums > 2) 153062306a36Sopenharmony_ci return EMULATE_FAIL; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci while (vcpu->arch.mmio_vmx_copy_nums) { 153362306a36Sopenharmony_ci emulated = __kvmppc_handle_load(vcpu, rt, bytes, 153462306a36Sopenharmony_ci is_default_endian, 0); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (emulated != EMULATE_DONE) 153762306a36Sopenharmony_ci break; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci vcpu->arch.paddr_accessed += vcpu->run->mmio.len; 154062306a36Sopenharmony_ci vcpu->arch.mmio_vmx_copy_nums--; 154162306a36Sopenharmony_ci vcpu->arch.mmio_vmx_offset++; 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci return emulated; 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_cistatic int kvmppc_get_vmx_dword(struct kvm_vcpu *vcpu, int index, u64 *val) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci union kvmppc_one_reg reg; 155062306a36Sopenharmony_ci int vmx_offset = 0; 155162306a36Sopenharmony_ci int result = 0; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci vmx_offset = 155462306a36Sopenharmony_ci kvmppc_get_vmx_dword_offset(vcpu, vcpu->arch.mmio_vmx_offset); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci if (vmx_offset == -1) 155762306a36Sopenharmony_ci return -1; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, index); 156062306a36Sopenharmony_ci *val = reg.vsxval[vmx_offset]; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci return result; 156362306a36Sopenharmony_ci} 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_cistatic int kvmppc_get_vmx_word(struct kvm_vcpu *vcpu, int index, u64 *val) 156662306a36Sopenharmony_ci{ 156762306a36Sopenharmony_ci union kvmppc_one_reg reg; 156862306a36Sopenharmony_ci int vmx_offset = 0; 156962306a36Sopenharmony_ci int result = 0; 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci vmx_offset = 157262306a36Sopenharmony_ci kvmppc_get_vmx_word_offset(vcpu, vcpu->arch.mmio_vmx_offset); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci if (vmx_offset == -1) 157562306a36Sopenharmony_ci return -1; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, index); 157862306a36Sopenharmony_ci *val = reg.vsx32val[vmx_offset]; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci return result; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cistatic int kvmppc_get_vmx_hword(struct kvm_vcpu *vcpu, int index, u64 *val) 158462306a36Sopenharmony_ci{ 158562306a36Sopenharmony_ci union kvmppc_one_reg reg; 158662306a36Sopenharmony_ci int vmx_offset = 0; 158762306a36Sopenharmony_ci int result = 0; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci vmx_offset = 159062306a36Sopenharmony_ci kvmppc_get_vmx_hword_offset(vcpu, vcpu->arch.mmio_vmx_offset); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci if (vmx_offset == -1) 159362306a36Sopenharmony_ci return -1; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, index); 159662306a36Sopenharmony_ci *val = reg.vsx16val[vmx_offset]; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci return result; 159962306a36Sopenharmony_ci} 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic int kvmppc_get_vmx_byte(struct kvm_vcpu *vcpu, int index, u64 *val) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci union kvmppc_one_reg reg; 160462306a36Sopenharmony_ci int vmx_offset = 0; 160562306a36Sopenharmony_ci int result = 0; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci vmx_offset = 160862306a36Sopenharmony_ci kvmppc_get_vmx_byte_offset(vcpu, vcpu->arch.mmio_vmx_offset); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci if (vmx_offset == -1) 161162306a36Sopenharmony_ci return -1; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, index); 161462306a36Sopenharmony_ci *val = reg.vsx8val[vmx_offset]; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci return result; 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ciint kvmppc_handle_vmx_store(struct kvm_vcpu *vcpu, 162062306a36Sopenharmony_ci unsigned int rs, unsigned int bytes, int is_default_endian) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci u64 val = 0; 162362306a36Sopenharmony_ci unsigned int index = rs & KVM_MMIO_REG_MASK; 162462306a36Sopenharmony_ci enum emulation_result emulated = EMULATE_DONE; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci if (vcpu->arch.mmio_vmx_copy_nums > 2) 162762306a36Sopenharmony_ci return EMULATE_FAIL; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci vcpu->arch.io_gpr = rs; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci while (vcpu->arch.mmio_vmx_copy_nums) { 163262306a36Sopenharmony_ci switch (vcpu->arch.mmio_copy_type) { 163362306a36Sopenharmony_ci case KVMPPC_VMX_COPY_DWORD: 163462306a36Sopenharmony_ci if (kvmppc_get_vmx_dword(vcpu, index, &val) == -1) 163562306a36Sopenharmony_ci return EMULATE_FAIL; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci break; 163862306a36Sopenharmony_ci case KVMPPC_VMX_COPY_WORD: 163962306a36Sopenharmony_ci if (kvmppc_get_vmx_word(vcpu, index, &val) == -1) 164062306a36Sopenharmony_ci return EMULATE_FAIL; 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci case KVMPPC_VMX_COPY_HWORD: 164362306a36Sopenharmony_ci if (kvmppc_get_vmx_hword(vcpu, index, &val) == -1) 164462306a36Sopenharmony_ci return EMULATE_FAIL; 164562306a36Sopenharmony_ci break; 164662306a36Sopenharmony_ci case KVMPPC_VMX_COPY_BYTE: 164762306a36Sopenharmony_ci if (kvmppc_get_vmx_byte(vcpu, index, &val) == -1) 164862306a36Sopenharmony_ci return EMULATE_FAIL; 164962306a36Sopenharmony_ci break; 165062306a36Sopenharmony_ci default: 165162306a36Sopenharmony_ci return EMULATE_FAIL; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci emulated = kvmppc_handle_store(vcpu, val, bytes, 165562306a36Sopenharmony_ci is_default_endian); 165662306a36Sopenharmony_ci if (emulated != EMULATE_DONE) 165762306a36Sopenharmony_ci break; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci vcpu->arch.paddr_accessed += vcpu->run->mmio.len; 166062306a36Sopenharmony_ci vcpu->arch.mmio_vmx_copy_nums--; 166162306a36Sopenharmony_ci vcpu->arch.mmio_vmx_offset++; 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci return emulated; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic int kvmppc_emulate_mmio_vmx_loadstore(struct kvm_vcpu *vcpu) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 167062306a36Sopenharmony_ci enum emulation_result emulated = EMULATE_FAIL; 167162306a36Sopenharmony_ci int r; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci vcpu->arch.paddr_accessed += run->mmio.len; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci if (!vcpu->mmio_is_write) { 167662306a36Sopenharmony_ci emulated = kvmppc_handle_vmx_load(vcpu, 167762306a36Sopenharmony_ci vcpu->arch.io_gpr, run->mmio.len, 1); 167862306a36Sopenharmony_ci } else { 167962306a36Sopenharmony_ci emulated = kvmppc_handle_vmx_store(vcpu, 168062306a36Sopenharmony_ci vcpu->arch.io_gpr, run->mmio.len, 1); 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci switch (emulated) { 168462306a36Sopenharmony_ci case EMULATE_DO_MMIO: 168562306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_MMIO; 168662306a36Sopenharmony_ci r = RESUME_HOST; 168762306a36Sopenharmony_ci break; 168862306a36Sopenharmony_ci case EMULATE_FAIL: 168962306a36Sopenharmony_ci pr_info("KVM: MMIO emulation failed (VMX repeat)\n"); 169062306a36Sopenharmony_ci run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 169162306a36Sopenharmony_ci run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; 169262306a36Sopenharmony_ci r = RESUME_HOST; 169362306a36Sopenharmony_ci break; 169462306a36Sopenharmony_ci default: 169562306a36Sopenharmony_ci r = RESUME_GUEST; 169662306a36Sopenharmony_ci break; 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci return r; 169962306a36Sopenharmony_ci} 170062306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ciint kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) 170362306a36Sopenharmony_ci{ 170462306a36Sopenharmony_ci int r = 0; 170562306a36Sopenharmony_ci union kvmppc_one_reg val; 170662306a36Sopenharmony_ci int size; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci size = one_reg_size(reg->id); 170962306a36Sopenharmony_ci if (size > sizeof(val)) 171062306a36Sopenharmony_ci return -EINVAL; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci r = kvmppc_get_one_reg(vcpu, reg->id, &val); 171362306a36Sopenharmony_ci if (r == -EINVAL) { 171462306a36Sopenharmony_ci r = 0; 171562306a36Sopenharmony_ci switch (reg->id) { 171662306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC 171762306a36Sopenharmony_ci case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: 171862306a36Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 171962306a36Sopenharmony_ci r = -ENXIO; 172062306a36Sopenharmony_ci break; 172162306a36Sopenharmony_ci } 172262306a36Sopenharmony_ci val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0]; 172362306a36Sopenharmony_ci break; 172462306a36Sopenharmony_ci case KVM_REG_PPC_VSCR: 172562306a36Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 172662306a36Sopenharmony_ci r = -ENXIO; 172762306a36Sopenharmony_ci break; 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]); 173062306a36Sopenharmony_ci break; 173162306a36Sopenharmony_ci case KVM_REG_PPC_VRSAVE: 173262306a36Sopenharmony_ci val = get_reg_val(reg->id, vcpu->arch.vrsave); 173362306a36Sopenharmony_ci break; 173462306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 173562306a36Sopenharmony_ci default: 173662306a36Sopenharmony_ci r = -EINVAL; 173762306a36Sopenharmony_ci break; 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci } 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci if (r) 174262306a36Sopenharmony_ci return r; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci if (copy_to_user((char __user *)(unsigned long)reg->addr, &val, size)) 174562306a36Sopenharmony_ci r = -EFAULT; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci return r; 174862306a36Sopenharmony_ci} 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ciint kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) 175162306a36Sopenharmony_ci{ 175262306a36Sopenharmony_ci int r; 175362306a36Sopenharmony_ci union kvmppc_one_reg val; 175462306a36Sopenharmony_ci int size; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci size = one_reg_size(reg->id); 175762306a36Sopenharmony_ci if (size > sizeof(val)) 175862306a36Sopenharmony_ci return -EINVAL; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size)) 176162306a36Sopenharmony_ci return -EFAULT; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci r = kvmppc_set_one_reg(vcpu, reg->id, &val); 176462306a36Sopenharmony_ci if (r == -EINVAL) { 176562306a36Sopenharmony_ci r = 0; 176662306a36Sopenharmony_ci switch (reg->id) { 176762306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC 176862306a36Sopenharmony_ci case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: 176962306a36Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 177062306a36Sopenharmony_ci r = -ENXIO; 177162306a36Sopenharmony_ci break; 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval; 177462306a36Sopenharmony_ci break; 177562306a36Sopenharmony_ci case KVM_REG_PPC_VSCR: 177662306a36Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 177762306a36Sopenharmony_ci r = -ENXIO; 177862306a36Sopenharmony_ci break; 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val); 178162306a36Sopenharmony_ci break; 178262306a36Sopenharmony_ci case KVM_REG_PPC_VRSAVE: 178362306a36Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 178462306a36Sopenharmony_ci r = -ENXIO; 178562306a36Sopenharmony_ci break; 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci vcpu->arch.vrsave = set_reg_val(reg->id, val); 178862306a36Sopenharmony_ci break; 178962306a36Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 179062306a36Sopenharmony_ci default: 179162306a36Sopenharmony_ci r = -EINVAL; 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci return r; 179762306a36Sopenharmony_ci} 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) 180062306a36Sopenharmony_ci{ 180162306a36Sopenharmony_ci struct kvm_run *run = vcpu->run; 180262306a36Sopenharmony_ci int r; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci vcpu_load(vcpu); 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci if (vcpu->mmio_needed) { 180762306a36Sopenharmony_ci vcpu->mmio_needed = 0; 180862306a36Sopenharmony_ci if (!vcpu->mmio_is_write) 180962306a36Sopenharmony_ci kvmppc_complete_mmio_load(vcpu); 181062306a36Sopenharmony_ci#ifdef CONFIG_VSX 181162306a36Sopenharmony_ci if (vcpu->arch.mmio_vsx_copy_nums > 0) { 181262306a36Sopenharmony_ci vcpu->arch.mmio_vsx_copy_nums--; 181362306a36Sopenharmony_ci vcpu->arch.mmio_vsx_offset++; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci if (vcpu->arch.mmio_vsx_copy_nums > 0) { 181762306a36Sopenharmony_ci r = kvmppc_emulate_mmio_vsx_loadstore(vcpu); 181862306a36Sopenharmony_ci if (r == RESUME_HOST) { 181962306a36Sopenharmony_ci vcpu->mmio_needed = 1; 182062306a36Sopenharmony_ci goto out; 182162306a36Sopenharmony_ci } 182262306a36Sopenharmony_ci } 182362306a36Sopenharmony_ci#endif 182462306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC 182562306a36Sopenharmony_ci if (vcpu->arch.mmio_vmx_copy_nums > 0) { 182662306a36Sopenharmony_ci vcpu->arch.mmio_vmx_copy_nums--; 182762306a36Sopenharmony_ci vcpu->arch.mmio_vmx_offset++; 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci if (vcpu->arch.mmio_vmx_copy_nums > 0) { 183162306a36Sopenharmony_ci r = kvmppc_emulate_mmio_vmx_loadstore(vcpu); 183262306a36Sopenharmony_ci if (r == RESUME_HOST) { 183362306a36Sopenharmony_ci vcpu->mmio_needed = 1; 183462306a36Sopenharmony_ci goto out; 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci } 183762306a36Sopenharmony_ci#endif 183862306a36Sopenharmony_ci } else if (vcpu->arch.osi_needed) { 183962306a36Sopenharmony_ci u64 *gprs = run->osi.gprs; 184062306a36Sopenharmony_ci int i; 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci for (i = 0; i < 32; i++) 184362306a36Sopenharmony_ci kvmppc_set_gpr(vcpu, i, gprs[i]); 184462306a36Sopenharmony_ci vcpu->arch.osi_needed = 0; 184562306a36Sopenharmony_ci } else if (vcpu->arch.hcall_needed) { 184662306a36Sopenharmony_ci int i; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci kvmppc_set_gpr(vcpu, 3, run->papr_hcall.ret); 184962306a36Sopenharmony_ci for (i = 0; i < 9; ++i) 185062306a36Sopenharmony_ci kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]); 185162306a36Sopenharmony_ci vcpu->arch.hcall_needed = 0; 185262306a36Sopenharmony_ci#ifdef CONFIG_BOOKE 185362306a36Sopenharmony_ci } else if (vcpu->arch.epr_needed) { 185462306a36Sopenharmony_ci kvmppc_set_epr(vcpu, run->epr.epr); 185562306a36Sopenharmony_ci vcpu->arch.epr_needed = 0; 185662306a36Sopenharmony_ci#endif 185762306a36Sopenharmony_ci } 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci kvm_sigset_activate(vcpu); 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci if (run->immediate_exit) 186262306a36Sopenharmony_ci r = -EINTR; 186362306a36Sopenharmony_ci else 186462306a36Sopenharmony_ci r = kvmppc_vcpu_run(vcpu); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci kvm_sigset_deactivate(vcpu); 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci#ifdef CONFIG_ALTIVEC 186962306a36Sopenharmony_ciout: 187062306a36Sopenharmony_ci#endif 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci /* 187362306a36Sopenharmony_ci * We're already returning to userspace, don't pass the 187462306a36Sopenharmony_ci * RESUME_HOST flags along. 187562306a36Sopenharmony_ci */ 187662306a36Sopenharmony_ci if (r > 0) 187762306a36Sopenharmony_ci r = 0; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci vcpu_put(vcpu); 188062306a36Sopenharmony_ci return r; 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ciint kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) 188462306a36Sopenharmony_ci{ 188562306a36Sopenharmony_ci if (irq->irq == KVM_INTERRUPT_UNSET) { 188662306a36Sopenharmony_ci kvmppc_core_dequeue_external(vcpu); 188762306a36Sopenharmony_ci return 0; 188862306a36Sopenharmony_ci } 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci kvmppc_core_queue_external(vcpu, irq); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci kvm_vcpu_kick(vcpu); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci return 0; 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_cistatic int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, 189862306a36Sopenharmony_ci struct kvm_enable_cap *cap) 189962306a36Sopenharmony_ci{ 190062306a36Sopenharmony_ci int r; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci if (cap->flags) 190362306a36Sopenharmony_ci return -EINVAL; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci switch (cap->cap) { 190662306a36Sopenharmony_ci case KVM_CAP_PPC_OSI: 190762306a36Sopenharmony_ci r = 0; 190862306a36Sopenharmony_ci vcpu->arch.osi_enabled = true; 190962306a36Sopenharmony_ci break; 191062306a36Sopenharmony_ci case KVM_CAP_PPC_PAPR: 191162306a36Sopenharmony_ci r = 0; 191262306a36Sopenharmony_ci vcpu->arch.papr_enabled = true; 191362306a36Sopenharmony_ci break; 191462306a36Sopenharmony_ci case KVM_CAP_PPC_EPR: 191562306a36Sopenharmony_ci r = 0; 191662306a36Sopenharmony_ci if (cap->args[0]) 191762306a36Sopenharmony_ci vcpu->arch.epr_flags |= KVMPPC_EPR_USER; 191862306a36Sopenharmony_ci else 191962306a36Sopenharmony_ci vcpu->arch.epr_flags &= ~KVMPPC_EPR_USER; 192062306a36Sopenharmony_ci break; 192162306a36Sopenharmony_ci#ifdef CONFIG_BOOKE 192262306a36Sopenharmony_ci case KVM_CAP_PPC_BOOKE_WATCHDOG: 192362306a36Sopenharmony_ci r = 0; 192462306a36Sopenharmony_ci vcpu->arch.watchdog_enabled = true; 192562306a36Sopenharmony_ci break; 192662306a36Sopenharmony_ci#endif 192762306a36Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) 192862306a36Sopenharmony_ci case KVM_CAP_SW_TLB: { 192962306a36Sopenharmony_ci struct kvm_config_tlb cfg; 193062306a36Sopenharmony_ci void __user *user_ptr = (void __user *)(uintptr_t)cap->args[0]; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci r = -EFAULT; 193362306a36Sopenharmony_ci if (copy_from_user(&cfg, user_ptr, sizeof(cfg))) 193462306a36Sopenharmony_ci break; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci r = kvm_vcpu_ioctl_config_tlb(vcpu, &cfg); 193762306a36Sopenharmony_ci break; 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci#endif 194062306a36Sopenharmony_ci#ifdef CONFIG_KVM_MPIC 194162306a36Sopenharmony_ci case KVM_CAP_IRQ_MPIC: { 194262306a36Sopenharmony_ci struct fd f; 194362306a36Sopenharmony_ci struct kvm_device *dev; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci r = -EBADF; 194662306a36Sopenharmony_ci f = fdget(cap->args[0]); 194762306a36Sopenharmony_ci if (!f.file) 194862306a36Sopenharmony_ci break; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci r = -EPERM; 195162306a36Sopenharmony_ci dev = kvm_device_from_filp(f.file); 195262306a36Sopenharmony_ci if (dev) 195362306a36Sopenharmony_ci r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci fdput(f); 195662306a36Sopenharmony_ci break; 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci#endif 195962306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS 196062306a36Sopenharmony_ci case KVM_CAP_IRQ_XICS: { 196162306a36Sopenharmony_ci struct fd f; 196262306a36Sopenharmony_ci struct kvm_device *dev; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci r = -EBADF; 196562306a36Sopenharmony_ci f = fdget(cap->args[0]); 196662306a36Sopenharmony_ci if (!f.file) 196762306a36Sopenharmony_ci break; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci r = -EPERM; 197062306a36Sopenharmony_ci dev = kvm_device_from_filp(f.file); 197162306a36Sopenharmony_ci if (dev) { 197262306a36Sopenharmony_ci if (xics_on_xive()) 197362306a36Sopenharmony_ci r = kvmppc_xive_connect_vcpu(dev, vcpu, cap->args[1]); 197462306a36Sopenharmony_ci else 197562306a36Sopenharmony_ci r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]); 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci fdput(f); 197962306a36Sopenharmony_ci break; 198062306a36Sopenharmony_ci } 198162306a36Sopenharmony_ci#endif /* CONFIG_KVM_XICS */ 198262306a36Sopenharmony_ci#ifdef CONFIG_KVM_XIVE 198362306a36Sopenharmony_ci case KVM_CAP_PPC_IRQ_XIVE: { 198462306a36Sopenharmony_ci struct fd f; 198562306a36Sopenharmony_ci struct kvm_device *dev; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci r = -EBADF; 198862306a36Sopenharmony_ci f = fdget(cap->args[0]); 198962306a36Sopenharmony_ci if (!f.file) 199062306a36Sopenharmony_ci break; 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci r = -ENXIO; 199362306a36Sopenharmony_ci if (!xive_enabled()) 199462306a36Sopenharmony_ci break; 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci r = -EPERM; 199762306a36Sopenharmony_ci dev = kvm_device_from_filp(f.file); 199862306a36Sopenharmony_ci if (dev) 199962306a36Sopenharmony_ci r = kvmppc_xive_native_connect_vcpu(dev, vcpu, 200062306a36Sopenharmony_ci cap->args[1]); 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci fdput(f); 200362306a36Sopenharmony_ci break; 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci#endif /* CONFIG_KVM_XIVE */ 200662306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 200762306a36Sopenharmony_ci case KVM_CAP_PPC_FWNMI: 200862306a36Sopenharmony_ci r = -EINVAL; 200962306a36Sopenharmony_ci if (!is_kvmppc_hv_enabled(vcpu->kvm)) 201062306a36Sopenharmony_ci break; 201162306a36Sopenharmony_ci r = 0; 201262306a36Sopenharmony_ci vcpu->kvm->arch.fwnmi_enabled = true; 201362306a36Sopenharmony_ci break; 201462306a36Sopenharmony_ci#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ 201562306a36Sopenharmony_ci default: 201662306a36Sopenharmony_ci r = -EINVAL; 201762306a36Sopenharmony_ci break; 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci if (!r) 202162306a36Sopenharmony_ci r = kvmppc_sanity_check(vcpu); 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci return r; 202462306a36Sopenharmony_ci} 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_cibool kvm_arch_intc_initialized(struct kvm *kvm) 202762306a36Sopenharmony_ci{ 202862306a36Sopenharmony_ci#ifdef CONFIG_KVM_MPIC 202962306a36Sopenharmony_ci if (kvm->arch.mpic) 203062306a36Sopenharmony_ci return true; 203162306a36Sopenharmony_ci#endif 203262306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS 203362306a36Sopenharmony_ci if (kvm->arch.xics || kvm->arch.xive) 203462306a36Sopenharmony_ci return true; 203562306a36Sopenharmony_ci#endif 203662306a36Sopenharmony_ci return false; 203762306a36Sopenharmony_ci} 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, 204062306a36Sopenharmony_ci struct kvm_mp_state *mp_state) 204162306a36Sopenharmony_ci{ 204262306a36Sopenharmony_ci return -EINVAL; 204362306a36Sopenharmony_ci} 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, 204662306a36Sopenharmony_ci struct kvm_mp_state *mp_state) 204762306a36Sopenharmony_ci{ 204862306a36Sopenharmony_ci return -EINVAL; 204962306a36Sopenharmony_ci} 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_cilong kvm_arch_vcpu_async_ioctl(struct file *filp, 205262306a36Sopenharmony_ci unsigned int ioctl, unsigned long arg) 205362306a36Sopenharmony_ci{ 205462306a36Sopenharmony_ci struct kvm_vcpu *vcpu = filp->private_data; 205562306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci if (ioctl == KVM_INTERRUPT) { 205862306a36Sopenharmony_ci struct kvm_interrupt irq; 205962306a36Sopenharmony_ci if (copy_from_user(&irq, argp, sizeof(irq))) 206062306a36Sopenharmony_ci return -EFAULT; 206162306a36Sopenharmony_ci return kvm_vcpu_ioctl_interrupt(vcpu, &irq); 206262306a36Sopenharmony_ci } 206362306a36Sopenharmony_ci return -ENOIOCTLCMD; 206462306a36Sopenharmony_ci} 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_cilong kvm_arch_vcpu_ioctl(struct file *filp, 206762306a36Sopenharmony_ci unsigned int ioctl, unsigned long arg) 206862306a36Sopenharmony_ci{ 206962306a36Sopenharmony_ci struct kvm_vcpu *vcpu = filp->private_data; 207062306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 207162306a36Sopenharmony_ci long r; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci switch (ioctl) { 207462306a36Sopenharmony_ci case KVM_ENABLE_CAP: 207562306a36Sopenharmony_ci { 207662306a36Sopenharmony_ci struct kvm_enable_cap cap; 207762306a36Sopenharmony_ci r = -EFAULT; 207862306a36Sopenharmony_ci if (copy_from_user(&cap, argp, sizeof(cap))) 207962306a36Sopenharmony_ci goto out; 208062306a36Sopenharmony_ci vcpu_load(vcpu); 208162306a36Sopenharmony_ci r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); 208262306a36Sopenharmony_ci vcpu_put(vcpu); 208362306a36Sopenharmony_ci break; 208462306a36Sopenharmony_ci } 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci case KVM_SET_ONE_REG: 208762306a36Sopenharmony_ci case KVM_GET_ONE_REG: 208862306a36Sopenharmony_ci { 208962306a36Sopenharmony_ci struct kvm_one_reg reg; 209062306a36Sopenharmony_ci r = -EFAULT; 209162306a36Sopenharmony_ci if (copy_from_user(®, argp, sizeof(reg))) 209262306a36Sopenharmony_ci goto out; 209362306a36Sopenharmony_ci if (ioctl == KVM_SET_ONE_REG) 209462306a36Sopenharmony_ci r = kvm_vcpu_ioctl_set_one_reg(vcpu, ®); 209562306a36Sopenharmony_ci else 209662306a36Sopenharmony_ci r = kvm_vcpu_ioctl_get_one_reg(vcpu, ®); 209762306a36Sopenharmony_ci break; 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) 210162306a36Sopenharmony_ci case KVM_DIRTY_TLB: { 210262306a36Sopenharmony_ci struct kvm_dirty_tlb dirty; 210362306a36Sopenharmony_ci r = -EFAULT; 210462306a36Sopenharmony_ci if (copy_from_user(&dirty, argp, sizeof(dirty))) 210562306a36Sopenharmony_ci goto out; 210662306a36Sopenharmony_ci vcpu_load(vcpu); 210762306a36Sopenharmony_ci r = kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty); 210862306a36Sopenharmony_ci vcpu_put(vcpu); 210962306a36Sopenharmony_ci break; 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci#endif 211262306a36Sopenharmony_ci default: 211362306a36Sopenharmony_ci r = -EINVAL; 211462306a36Sopenharmony_ci } 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ciout: 211762306a36Sopenharmony_ci return r; 211862306a36Sopenharmony_ci} 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_civm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) 212162306a36Sopenharmony_ci{ 212262306a36Sopenharmony_ci return VM_FAULT_SIGBUS; 212362306a36Sopenharmony_ci} 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_cistatic int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo) 212662306a36Sopenharmony_ci{ 212762306a36Sopenharmony_ci u32 inst_nop = 0x60000000; 212862306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOKE_HV 212962306a36Sopenharmony_ci u32 inst_sc1 = 0x44000022; 213062306a36Sopenharmony_ci pvinfo->hcall[0] = cpu_to_be32(inst_sc1); 213162306a36Sopenharmony_ci pvinfo->hcall[1] = cpu_to_be32(inst_nop); 213262306a36Sopenharmony_ci pvinfo->hcall[2] = cpu_to_be32(inst_nop); 213362306a36Sopenharmony_ci pvinfo->hcall[3] = cpu_to_be32(inst_nop); 213462306a36Sopenharmony_ci#else 213562306a36Sopenharmony_ci u32 inst_lis = 0x3c000000; 213662306a36Sopenharmony_ci u32 inst_ori = 0x60000000; 213762306a36Sopenharmony_ci u32 inst_sc = 0x44000002; 213862306a36Sopenharmony_ci u32 inst_imm_mask = 0xffff; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci /* 214162306a36Sopenharmony_ci * The hypercall to get into KVM from within guest context is as 214262306a36Sopenharmony_ci * follows: 214362306a36Sopenharmony_ci * 214462306a36Sopenharmony_ci * lis r0, r0, KVM_SC_MAGIC_R0@h 214562306a36Sopenharmony_ci * ori r0, KVM_SC_MAGIC_R0@l 214662306a36Sopenharmony_ci * sc 214762306a36Sopenharmony_ci * nop 214862306a36Sopenharmony_ci */ 214962306a36Sopenharmony_ci pvinfo->hcall[0] = cpu_to_be32(inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask)); 215062306a36Sopenharmony_ci pvinfo->hcall[1] = cpu_to_be32(inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask)); 215162306a36Sopenharmony_ci pvinfo->hcall[2] = cpu_to_be32(inst_sc); 215262306a36Sopenharmony_ci pvinfo->hcall[3] = cpu_to_be32(inst_nop); 215362306a36Sopenharmony_ci#endif 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci pvinfo->flags = KVM_PPC_PVINFO_FLAGS_EV_IDLE; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci return 0; 215862306a36Sopenharmony_ci} 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_cibool kvm_arch_irqchip_in_kernel(struct kvm *kvm) 216162306a36Sopenharmony_ci{ 216262306a36Sopenharmony_ci int ret = 0; 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci#ifdef CONFIG_KVM_MPIC 216562306a36Sopenharmony_ci ret = ret || (kvm->arch.mpic != NULL); 216662306a36Sopenharmony_ci#endif 216762306a36Sopenharmony_ci#ifdef CONFIG_KVM_XICS 216862306a36Sopenharmony_ci ret = ret || (kvm->arch.xics != NULL); 216962306a36Sopenharmony_ci ret = ret || (kvm->arch.xive != NULL); 217062306a36Sopenharmony_ci#endif 217162306a36Sopenharmony_ci smp_rmb(); 217262306a36Sopenharmony_ci return ret; 217362306a36Sopenharmony_ci} 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ciint kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, 217662306a36Sopenharmony_ci bool line_status) 217762306a36Sopenharmony_ci{ 217862306a36Sopenharmony_ci if (!kvm_arch_irqchip_in_kernel(kvm)) 217962306a36Sopenharmony_ci return -ENXIO; 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 218262306a36Sopenharmony_ci irq_event->irq, irq_event->level, 218362306a36Sopenharmony_ci line_status); 218462306a36Sopenharmony_ci return 0; 218562306a36Sopenharmony_ci} 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ciint kvm_vm_ioctl_enable_cap(struct kvm *kvm, 218962306a36Sopenharmony_ci struct kvm_enable_cap *cap) 219062306a36Sopenharmony_ci{ 219162306a36Sopenharmony_ci int r; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci if (cap->flags) 219462306a36Sopenharmony_ci return -EINVAL; 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci switch (cap->cap) { 219762306a36Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_64_HANDLER 219862306a36Sopenharmony_ci case KVM_CAP_PPC_ENABLE_HCALL: { 219962306a36Sopenharmony_ci unsigned long hcall = cap->args[0]; 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci r = -EINVAL; 220262306a36Sopenharmony_ci if (hcall > MAX_HCALL_OPCODE || (hcall & 3) || 220362306a36Sopenharmony_ci cap->args[1] > 1) 220462306a36Sopenharmony_ci break; 220562306a36Sopenharmony_ci if (!kvmppc_book3s_hcall_implemented(kvm, hcall)) 220662306a36Sopenharmony_ci break; 220762306a36Sopenharmony_ci if (cap->args[1]) 220862306a36Sopenharmony_ci set_bit(hcall / 4, kvm->arch.enabled_hcalls); 220962306a36Sopenharmony_ci else 221062306a36Sopenharmony_ci clear_bit(hcall / 4, kvm->arch.enabled_hcalls); 221162306a36Sopenharmony_ci r = 0; 221262306a36Sopenharmony_ci break; 221362306a36Sopenharmony_ci } 221462306a36Sopenharmony_ci case KVM_CAP_PPC_SMT: { 221562306a36Sopenharmony_ci unsigned long mode = cap->args[0]; 221662306a36Sopenharmony_ci unsigned long flags = cap->args[1]; 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci r = -EINVAL; 221962306a36Sopenharmony_ci if (kvm->arch.kvm_ops->set_smt_mode) 222062306a36Sopenharmony_ci r = kvm->arch.kvm_ops->set_smt_mode(kvm, mode, flags); 222162306a36Sopenharmony_ci break; 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci case KVM_CAP_PPC_NESTED_HV: 222562306a36Sopenharmony_ci r = -EINVAL; 222662306a36Sopenharmony_ci if (!is_kvmppc_hv_enabled(kvm) || 222762306a36Sopenharmony_ci !kvm->arch.kvm_ops->enable_nested) 222862306a36Sopenharmony_ci break; 222962306a36Sopenharmony_ci r = kvm->arch.kvm_ops->enable_nested(kvm); 223062306a36Sopenharmony_ci break; 223162306a36Sopenharmony_ci#endif 223262306a36Sopenharmony_ci#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) 223362306a36Sopenharmony_ci case KVM_CAP_PPC_SECURE_GUEST: 223462306a36Sopenharmony_ci r = -EINVAL; 223562306a36Sopenharmony_ci if (!is_kvmppc_hv_enabled(kvm) || !kvm->arch.kvm_ops->enable_svm) 223662306a36Sopenharmony_ci break; 223762306a36Sopenharmony_ci r = kvm->arch.kvm_ops->enable_svm(kvm); 223862306a36Sopenharmony_ci break; 223962306a36Sopenharmony_ci case KVM_CAP_PPC_DAWR1: 224062306a36Sopenharmony_ci r = -EINVAL; 224162306a36Sopenharmony_ci if (!is_kvmppc_hv_enabled(kvm) || !kvm->arch.kvm_ops->enable_dawr1) 224262306a36Sopenharmony_ci break; 224362306a36Sopenharmony_ci r = kvm->arch.kvm_ops->enable_dawr1(kvm); 224462306a36Sopenharmony_ci break; 224562306a36Sopenharmony_ci#endif 224662306a36Sopenharmony_ci default: 224762306a36Sopenharmony_ci r = -EINVAL; 224862306a36Sopenharmony_ci break; 224962306a36Sopenharmony_ci } 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci return r; 225262306a36Sopenharmony_ci} 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 225562306a36Sopenharmony_ci/* 225662306a36Sopenharmony_ci * These functions check whether the underlying hardware is safe 225762306a36Sopenharmony_ci * against attacks based on observing the effects of speculatively 225862306a36Sopenharmony_ci * executed instructions, and whether it supplies instructions for 225962306a36Sopenharmony_ci * use in workarounds. The information comes from firmware, either 226062306a36Sopenharmony_ci * via the device tree on powernv platforms or from an hcall on 226162306a36Sopenharmony_ci * pseries platforms. 226262306a36Sopenharmony_ci */ 226362306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 226462306a36Sopenharmony_cistatic int pseries_get_cpu_char(struct kvm_ppc_cpu_char *cp) 226562306a36Sopenharmony_ci{ 226662306a36Sopenharmony_ci struct h_cpu_char_result c; 226762306a36Sopenharmony_ci unsigned long rc; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci if (!machine_is(pseries)) 227062306a36Sopenharmony_ci return -ENOTTY; 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci rc = plpar_get_cpu_characteristics(&c); 227362306a36Sopenharmony_ci if (rc == H_SUCCESS) { 227462306a36Sopenharmony_ci cp->character = c.character; 227562306a36Sopenharmony_ci cp->behaviour = c.behaviour; 227662306a36Sopenharmony_ci cp->character_mask = KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 | 227762306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED | 227862306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 | 227962306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 | 228062306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV | 228162306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_BR_HINT_HONOURED | 228262306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_MTTRIG_THR_RECONF | 228362306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS | 228462306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST; 228562306a36Sopenharmony_ci cp->behaviour_mask = KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY | 228662306a36Sopenharmony_ci KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR | 228762306a36Sopenharmony_ci KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR | 228862306a36Sopenharmony_ci KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE; 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci return 0; 229162306a36Sopenharmony_ci} 229262306a36Sopenharmony_ci#else 229362306a36Sopenharmony_cistatic int pseries_get_cpu_char(struct kvm_ppc_cpu_char *cp) 229462306a36Sopenharmony_ci{ 229562306a36Sopenharmony_ci return -ENOTTY; 229662306a36Sopenharmony_ci} 229762306a36Sopenharmony_ci#endif 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_cistatic inline bool have_fw_feat(struct device_node *fw_features, 230062306a36Sopenharmony_ci const char *state, const char *name) 230162306a36Sopenharmony_ci{ 230262306a36Sopenharmony_ci struct device_node *np; 230362306a36Sopenharmony_ci bool r = false; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci np = of_get_child_by_name(fw_features, name); 230662306a36Sopenharmony_ci if (np) { 230762306a36Sopenharmony_ci r = of_property_read_bool(np, state); 230862306a36Sopenharmony_ci of_node_put(np); 230962306a36Sopenharmony_ci } 231062306a36Sopenharmony_ci return r; 231162306a36Sopenharmony_ci} 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_cistatic int kvmppc_get_cpu_char(struct kvm_ppc_cpu_char *cp) 231462306a36Sopenharmony_ci{ 231562306a36Sopenharmony_ci struct device_node *np, *fw_features; 231662306a36Sopenharmony_ci int r; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci memset(cp, 0, sizeof(*cp)); 231962306a36Sopenharmony_ci r = pseries_get_cpu_char(cp); 232062306a36Sopenharmony_ci if (r != -ENOTTY) 232162306a36Sopenharmony_ci return r; 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci np = of_find_node_by_name(NULL, "ibm,opal"); 232462306a36Sopenharmony_ci if (np) { 232562306a36Sopenharmony_ci fw_features = of_get_child_by_name(np, "fw-features"); 232662306a36Sopenharmony_ci of_node_put(np); 232762306a36Sopenharmony_ci if (!fw_features) 232862306a36Sopenharmony_ci return 0; 232962306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 233062306a36Sopenharmony_ci "inst-spec-barrier-ori31,31,0")) 233162306a36Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31; 233262306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 233362306a36Sopenharmony_ci "fw-bcctrl-serialized")) 233462306a36Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED; 233562306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 233662306a36Sopenharmony_ci "inst-l1d-flush-ori30,30,0")) 233762306a36Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30; 233862306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 233962306a36Sopenharmony_ci "inst-l1d-flush-trig2")) 234062306a36Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2; 234162306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 234262306a36Sopenharmony_ci "fw-l1d-thread-split")) 234362306a36Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV; 234462306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 234562306a36Sopenharmony_ci "fw-count-cache-disabled")) 234662306a36Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS; 234762306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 234862306a36Sopenharmony_ci "fw-count-cache-flush-bcctr2,0,0")) 234962306a36Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST; 235062306a36Sopenharmony_ci cp->character_mask = KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 | 235162306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED | 235262306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 | 235362306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 | 235462306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV | 235562306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS | 235662306a36Sopenharmony_ci KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST; 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 235962306a36Sopenharmony_ci "speculation-policy-favor-security")) 236062306a36Sopenharmony_ci cp->behaviour |= KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY; 236162306a36Sopenharmony_ci if (!have_fw_feat(fw_features, "disabled", 236262306a36Sopenharmony_ci "needs-l1d-flush-msr-pr-0-to-1")) 236362306a36Sopenharmony_ci cp->behaviour |= KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR; 236462306a36Sopenharmony_ci if (!have_fw_feat(fw_features, "disabled", 236562306a36Sopenharmony_ci "needs-spec-barrier-for-bound-checks")) 236662306a36Sopenharmony_ci cp->behaviour |= KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR; 236762306a36Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 236862306a36Sopenharmony_ci "needs-count-cache-flush-on-context-switch")) 236962306a36Sopenharmony_ci cp->behaviour |= KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE; 237062306a36Sopenharmony_ci cp->behaviour_mask = KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY | 237162306a36Sopenharmony_ci KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR | 237262306a36Sopenharmony_ci KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR | 237362306a36Sopenharmony_ci KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci of_node_put(fw_features); 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci return 0; 237962306a36Sopenharmony_ci} 238062306a36Sopenharmony_ci#endif 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ciint kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci struct kvm *kvm __maybe_unused = filp->private_data; 238562306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 238662306a36Sopenharmony_ci int r; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci switch (ioctl) { 238962306a36Sopenharmony_ci case KVM_PPC_GET_PVINFO: { 239062306a36Sopenharmony_ci struct kvm_ppc_pvinfo pvinfo; 239162306a36Sopenharmony_ci memset(&pvinfo, 0, sizeof(pvinfo)); 239262306a36Sopenharmony_ci r = kvm_vm_ioctl_get_pvinfo(&pvinfo); 239362306a36Sopenharmony_ci if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) { 239462306a36Sopenharmony_ci r = -EFAULT; 239562306a36Sopenharmony_ci goto out; 239662306a36Sopenharmony_ci } 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci break; 239962306a36Sopenharmony_ci } 240062306a36Sopenharmony_ci#ifdef CONFIG_SPAPR_TCE_IOMMU 240162306a36Sopenharmony_ci case KVM_CREATE_SPAPR_TCE_64: { 240262306a36Sopenharmony_ci struct kvm_create_spapr_tce_64 create_tce_64; 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci r = -EFAULT; 240562306a36Sopenharmony_ci if (copy_from_user(&create_tce_64, argp, sizeof(create_tce_64))) 240662306a36Sopenharmony_ci goto out; 240762306a36Sopenharmony_ci if (create_tce_64.flags) { 240862306a36Sopenharmony_ci r = -EINVAL; 240962306a36Sopenharmony_ci goto out; 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce_64); 241262306a36Sopenharmony_ci goto out; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci case KVM_CREATE_SPAPR_TCE: { 241562306a36Sopenharmony_ci struct kvm_create_spapr_tce create_tce; 241662306a36Sopenharmony_ci struct kvm_create_spapr_tce_64 create_tce_64; 241762306a36Sopenharmony_ci 241862306a36Sopenharmony_ci r = -EFAULT; 241962306a36Sopenharmony_ci if (copy_from_user(&create_tce, argp, sizeof(create_tce))) 242062306a36Sopenharmony_ci goto out; 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci create_tce_64.liobn = create_tce.liobn; 242362306a36Sopenharmony_ci create_tce_64.page_shift = IOMMU_PAGE_SHIFT_4K; 242462306a36Sopenharmony_ci create_tce_64.offset = 0; 242562306a36Sopenharmony_ci create_tce_64.size = create_tce.window_size >> 242662306a36Sopenharmony_ci IOMMU_PAGE_SHIFT_4K; 242762306a36Sopenharmony_ci create_tce_64.flags = 0; 242862306a36Sopenharmony_ci r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce_64); 242962306a36Sopenharmony_ci goto out; 243062306a36Sopenharmony_ci } 243162306a36Sopenharmony_ci#endif 243262306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 243362306a36Sopenharmony_ci case KVM_PPC_GET_SMMU_INFO: { 243462306a36Sopenharmony_ci struct kvm_ppc_smmu_info info; 243562306a36Sopenharmony_ci struct kvm *kvm = filp->private_data; 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 243862306a36Sopenharmony_ci r = kvm->arch.kvm_ops->get_smmu_info(kvm, &info); 243962306a36Sopenharmony_ci if (r >= 0 && copy_to_user(argp, &info, sizeof(info))) 244062306a36Sopenharmony_ci r = -EFAULT; 244162306a36Sopenharmony_ci break; 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci case KVM_PPC_RTAS_DEFINE_TOKEN: { 244462306a36Sopenharmony_ci struct kvm *kvm = filp->private_data; 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci r = kvm_vm_ioctl_rtas_define_token(kvm, argp); 244762306a36Sopenharmony_ci break; 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci case KVM_PPC_CONFIGURE_V3_MMU: { 245062306a36Sopenharmony_ci struct kvm *kvm = filp->private_data; 245162306a36Sopenharmony_ci struct kvm_ppc_mmuv3_cfg cfg; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci r = -EINVAL; 245462306a36Sopenharmony_ci if (!kvm->arch.kvm_ops->configure_mmu) 245562306a36Sopenharmony_ci goto out; 245662306a36Sopenharmony_ci r = -EFAULT; 245762306a36Sopenharmony_ci if (copy_from_user(&cfg, argp, sizeof(cfg))) 245862306a36Sopenharmony_ci goto out; 245962306a36Sopenharmony_ci r = kvm->arch.kvm_ops->configure_mmu(kvm, &cfg); 246062306a36Sopenharmony_ci break; 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci case KVM_PPC_GET_RMMU_INFO: { 246362306a36Sopenharmony_ci struct kvm *kvm = filp->private_data; 246462306a36Sopenharmony_ci struct kvm_ppc_rmmu_info info; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci r = -EINVAL; 246762306a36Sopenharmony_ci if (!kvm->arch.kvm_ops->get_rmmu_info) 246862306a36Sopenharmony_ci goto out; 246962306a36Sopenharmony_ci r = kvm->arch.kvm_ops->get_rmmu_info(kvm, &info); 247062306a36Sopenharmony_ci if (r >= 0 && copy_to_user(argp, &info, sizeof(info))) 247162306a36Sopenharmony_ci r = -EFAULT; 247262306a36Sopenharmony_ci break; 247362306a36Sopenharmony_ci } 247462306a36Sopenharmony_ci case KVM_PPC_GET_CPU_CHAR: { 247562306a36Sopenharmony_ci struct kvm_ppc_cpu_char cpuchar; 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci r = kvmppc_get_cpu_char(&cpuchar); 247862306a36Sopenharmony_ci if (r >= 0 && copy_to_user(argp, &cpuchar, sizeof(cpuchar))) 247962306a36Sopenharmony_ci r = -EFAULT; 248062306a36Sopenharmony_ci break; 248162306a36Sopenharmony_ci } 248262306a36Sopenharmony_ci case KVM_PPC_SVM_OFF: { 248362306a36Sopenharmony_ci struct kvm *kvm = filp->private_data; 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci r = 0; 248662306a36Sopenharmony_ci if (!kvm->arch.kvm_ops->svm_off) 248762306a36Sopenharmony_ci goto out; 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci r = kvm->arch.kvm_ops->svm_off(kvm); 249062306a36Sopenharmony_ci break; 249162306a36Sopenharmony_ci } 249262306a36Sopenharmony_ci default: { 249362306a36Sopenharmony_ci struct kvm *kvm = filp->private_data; 249462306a36Sopenharmony_ci r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg); 249562306a36Sopenharmony_ci } 249662306a36Sopenharmony_ci#else /* CONFIG_PPC_BOOK3S_64 */ 249762306a36Sopenharmony_ci default: 249862306a36Sopenharmony_ci r = -ENOTTY; 249962306a36Sopenharmony_ci#endif 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ciout: 250262306a36Sopenharmony_ci return r; 250362306a36Sopenharmony_ci} 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_cistatic DEFINE_IDA(lpid_inuse); 250662306a36Sopenharmony_cistatic unsigned long nr_lpids; 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_cilong kvmppc_alloc_lpid(void) 250962306a36Sopenharmony_ci{ 251062306a36Sopenharmony_ci int lpid; 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci /* The host LPID must always be 0 (allocation starts at 1) */ 251362306a36Sopenharmony_ci lpid = ida_alloc_range(&lpid_inuse, 1, nr_lpids - 1, GFP_KERNEL); 251462306a36Sopenharmony_ci if (lpid < 0) { 251562306a36Sopenharmony_ci if (lpid == -ENOMEM) 251662306a36Sopenharmony_ci pr_err("%s: Out of memory\n", __func__); 251762306a36Sopenharmony_ci else 251862306a36Sopenharmony_ci pr_err("%s: No LPIDs free\n", __func__); 251962306a36Sopenharmony_ci return -ENOMEM; 252062306a36Sopenharmony_ci } 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci return lpid; 252362306a36Sopenharmony_ci} 252462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_alloc_lpid); 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_civoid kvmppc_free_lpid(long lpid) 252762306a36Sopenharmony_ci{ 252862306a36Sopenharmony_ci ida_free(&lpid_inuse, lpid); 252962306a36Sopenharmony_ci} 253062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_free_lpid); 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci/* nr_lpids_param includes the host LPID */ 253362306a36Sopenharmony_civoid kvmppc_init_lpid(unsigned long nr_lpids_param) 253462306a36Sopenharmony_ci{ 253562306a36Sopenharmony_ci nr_lpids = nr_lpids_param; 253662306a36Sopenharmony_ci} 253762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_init_lpid); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ppc_instr); 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_civoid kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops->create_vcpu_debugfs) 254462306a36Sopenharmony_ci vcpu->kvm->arch.kvm_ops->create_vcpu_debugfs(vcpu, debugfs_dentry); 254562306a36Sopenharmony_ci} 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ciint kvm_arch_create_vm_debugfs(struct kvm *kvm) 254862306a36Sopenharmony_ci{ 254962306a36Sopenharmony_ci if (kvm->arch.kvm_ops->create_vm_debugfs) 255062306a36Sopenharmony_ci kvm->arch.kvm_ops->create_vm_debugfs(kvm); 255162306a36Sopenharmony_ci return 0; 255262306a36Sopenharmony_ci} 2553