18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2007 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: Hollis Blanchard <hollisb@us.ibm.com> 78c2ecf20Sopenharmony_ci * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 138c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 148c2ecf20Sopenharmony_ci#include <linux/hrtimer.h> 158c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 168c2ecf20Sopenharmony_ci#include <linux/fs.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/file.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/irqbypass.h> 218c2ecf20Sopenharmony_ci#include <linux/kvm_irqfd.h> 228c2ecf20Sopenharmony_ci#include <asm/cputable.h> 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci#include <asm/kvm_ppc.h> 258c2ecf20Sopenharmony_ci#include <asm/cputhreads.h> 268c2ecf20Sopenharmony_ci#include <asm/irqflags.h> 278c2ecf20Sopenharmony_ci#include <asm/iommu.h> 288c2ecf20Sopenharmony_ci#include <asm/switch_to.h> 298c2ecf20Sopenharmony_ci#include <asm/xive.h> 308c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 318c2ecf20Sopenharmony_ci#include <asm/hvcall.h> 328c2ecf20Sopenharmony_ci#include <asm/plpar_wrappers.h> 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci#include <asm/ultravisor.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "timing.h" 378c2ecf20Sopenharmony_ci#include "irq.h" 388c2ecf20Sopenharmony_ci#include "../mm/mmu_decl.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 418c2ecf20Sopenharmony_ci#include "trace.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct kvmppc_ops *kvmppc_hv_ops; 448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_hv_ops); 458c2ecf20Sopenharmony_cistruct kvmppc_ops *kvmppc_pr_ops; 468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_pr_ops); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciint kvm_arch_vcpu_runnable(struct kvm_vcpu *v) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci return !!(v->arch.pending_exceptions) || kvm_request_pending(v); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cibool kvm_arch_dy_runnable(struct kvm_vcpu *vcpu) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci return kvm_arch_vcpu_runnable(vcpu); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cibool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci return false; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciint kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci return 1; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* 708c2ecf20Sopenharmony_ci * Common checks before entering the guest world. Call with interrupts 718c2ecf20Sopenharmony_ci * disabled. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * returns: 748c2ecf20Sopenharmony_ci * 758c2ecf20Sopenharmony_ci * == 1 if we're ready to go into guest state 768c2ecf20Sopenharmony_ci * <= 0 if we need to go back to the host with return value 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ciint kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int r; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci WARN_ON(irqs_disabled()); 838c2ecf20Sopenharmony_ci hard_irq_disable(); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci while (true) { 868c2ecf20Sopenharmony_ci if (need_resched()) { 878c2ecf20Sopenharmony_ci local_irq_enable(); 888c2ecf20Sopenharmony_ci cond_resched(); 898c2ecf20Sopenharmony_ci hard_irq_disable(); 908c2ecf20Sopenharmony_ci continue; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (signal_pending(current)) { 948c2ecf20Sopenharmony_ci kvmppc_account_exit(vcpu, SIGNAL_EXITS); 958c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_INTR; 968c2ecf20Sopenharmony_ci r = -EINTR; 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci vcpu->mode = IN_GUEST_MODE; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* 1038c2ecf20Sopenharmony_ci * Reading vcpu->requests must happen after setting vcpu->mode, 1048c2ecf20Sopenharmony_ci * so we don't miss a request because the requester sees 1058c2ecf20Sopenharmony_ci * OUTSIDE_GUEST_MODE and assumes we'll be checking requests 1068c2ecf20Sopenharmony_ci * before next entering the guest (and thus doesn't IPI). 1078c2ecf20Sopenharmony_ci * This also orders the write to mode from any reads 1088c2ecf20Sopenharmony_ci * to the page tables done while the VCPU is running. 1098c2ecf20Sopenharmony_ci * Please see the comment in kvm_flush_remote_tlbs. 1108c2ecf20Sopenharmony_ci */ 1118c2ecf20Sopenharmony_ci smp_mb(); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (kvm_request_pending(vcpu)) { 1148c2ecf20Sopenharmony_ci /* Make sure we process requests preemptable */ 1158c2ecf20Sopenharmony_ci local_irq_enable(); 1168c2ecf20Sopenharmony_ci trace_kvm_check_requests(vcpu); 1178c2ecf20Sopenharmony_ci r = kvmppc_core_check_requests(vcpu); 1188c2ecf20Sopenharmony_ci hard_irq_disable(); 1198c2ecf20Sopenharmony_ci if (r > 0) 1208c2ecf20Sopenharmony_ci continue; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (kvmppc_core_prepare_to_enter(vcpu)) { 1258c2ecf20Sopenharmony_ci /* interrupts got enabled in between, so we 1268c2ecf20Sopenharmony_ci are back at square 1 */ 1278c2ecf20Sopenharmony_ci continue; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci guest_enter_irqoff(); 1318c2ecf20Sopenharmony_ci return 1; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* return to host */ 1358c2ecf20Sopenharmony_ci local_irq_enable(); 1368c2ecf20Sopenharmony_ci return r; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_prepare_to_enter); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE) 1418c2ecf20Sopenharmony_cistatic void kvmppc_swab_shared(struct kvm_vcpu *vcpu) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct kvm_vcpu_arch_shared *shared = vcpu->arch.shared; 1448c2ecf20Sopenharmony_ci int i; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci shared->sprg0 = swab64(shared->sprg0); 1478c2ecf20Sopenharmony_ci shared->sprg1 = swab64(shared->sprg1); 1488c2ecf20Sopenharmony_ci shared->sprg2 = swab64(shared->sprg2); 1498c2ecf20Sopenharmony_ci shared->sprg3 = swab64(shared->sprg3); 1508c2ecf20Sopenharmony_ci shared->srr0 = swab64(shared->srr0); 1518c2ecf20Sopenharmony_ci shared->srr1 = swab64(shared->srr1); 1528c2ecf20Sopenharmony_ci shared->dar = swab64(shared->dar); 1538c2ecf20Sopenharmony_ci shared->msr = swab64(shared->msr); 1548c2ecf20Sopenharmony_ci shared->dsisr = swab32(shared->dsisr); 1558c2ecf20Sopenharmony_ci shared->int_pending = swab32(shared->int_pending); 1568c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(shared->sr); i++) 1578c2ecf20Sopenharmony_ci shared->sr[i] = swab32(shared->sr[i]); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci#endif 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ciint kvmppc_kvm_pv(struct kvm_vcpu *vcpu) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci int nr = kvmppc_get_gpr(vcpu, 11); 1648c2ecf20Sopenharmony_ci int r; 1658c2ecf20Sopenharmony_ci unsigned long __maybe_unused param1 = kvmppc_get_gpr(vcpu, 3); 1668c2ecf20Sopenharmony_ci unsigned long __maybe_unused param2 = kvmppc_get_gpr(vcpu, 4); 1678c2ecf20Sopenharmony_ci unsigned long __maybe_unused param3 = kvmppc_get_gpr(vcpu, 5); 1688c2ecf20Sopenharmony_ci unsigned long __maybe_unused param4 = kvmppc_get_gpr(vcpu, 6); 1698c2ecf20Sopenharmony_ci unsigned long r2 = 0; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_SF)) { 1728c2ecf20Sopenharmony_ci /* 32 bit mode */ 1738c2ecf20Sopenharmony_ci param1 &= 0xffffffff; 1748c2ecf20Sopenharmony_ci param2 &= 0xffffffff; 1758c2ecf20Sopenharmony_ci param3 &= 0xffffffff; 1768c2ecf20Sopenharmony_ci param4 &= 0xffffffff; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci switch (nr) { 1808c2ecf20Sopenharmony_ci case KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE): 1818c2ecf20Sopenharmony_ci { 1828c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S_64) && defined(CONFIG_KVM_BOOK3S_PR_POSSIBLE) 1838c2ecf20Sopenharmony_ci /* Book3S can be little endian, find it out here */ 1848c2ecf20Sopenharmony_ci int shared_big_endian = true; 1858c2ecf20Sopenharmony_ci if (vcpu->arch.intr_msr & MSR_LE) 1868c2ecf20Sopenharmony_ci shared_big_endian = false; 1878c2ecf20Sopenharmony_ci if (shared_big_endian != vcpu->arch.shared_big_endian) 1888c2ecf20Sopenharmony_ci kvmppc_swab_shared(vcpu); 1898c2ecf20Sopenharmony_ci vcpu->arch.shared_big_endian = shared_big_endian; 1908c2ecf20Sopenharmony_ci#endif 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!(param2 & MAGIC_PAGE_FLAG_NOT_MAPPED_NX)) { 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * Older versions of the Linux magic page code had 1958c2ecf20Sopenharmony_ci * a bug where they would map their trampoline code 1968c2ecf20Sopenharmony_ci * NX. If that's the case, remove !PR NX capability. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci vcpu->arch.disable_kernel_nx = true; 1998c2ecf20Sopenharmony_ci kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci vcpu->arch.magic_page_pa = param1 & ~0xfffULL; 2038c2ecf20Sopenharmony_ci vcpu->arch.magic_page_ea = param2 & ~0xfffULL; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_64K_PAGES 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * Make sure our 4k magic page is in the same window of a 64k 2088c2ecf20Sopenharmony_ci * page within the guest and within the host's page. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_ci if ((vcpu->arch.magic_page_pa & 0xf000) != 2118c2ecf20Sopenharmony_ci ((ulong)vcpu->arch.shared & 0xf000)) { 2128c2ecf20Sopenharmony_ci void *old_shared = vcpu->arch.shared; 2138c2ecf20Sopenharmony_ci ulong shared = (ulong)vcpu->arch.shared; 2148c2ecf20Sopenharmony_ci void *new_shared; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci shared &= PAGE_MASK; 2178c2ecf20Sopenharmony_ci shared |= vcpu->arch.magic_page_pa & 0xf000; 2188c2ecf20Sopenharmony_ci new_shared = (void*)shared; 2198c2ecf20Sopenharmony_ci memcpy(new_shared, old_shared, 0x1000); 2208c2ecf20Sopenharmony_ci vcpu->arch.shared = new_shared; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci#endif 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci r = EV_SUCCESS; 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci case KVM_HCALL_TOKEN(KVM_HC_FEATURES): 2308c2ecf20Sopenharmony_ci r = EV_SUCCESS; 2318c2ecf20Sopenharmony_ci#if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500V2) 2328c2ecf20Sopenharmony_ci r2 |= (1 << KVM_FEATURE_MAGIC_PAGE); 2338c2ecf20Sopenharmony_ci#endif 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* Second return value is in r4 */ 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci case EV_HCALL_TOKEN(EV_IDLE): 2388c2ecf20Sopenharmony_ci r = EV_SUCCESS; 2398c2ecf20Sopenharmony_ci kvm_vcpu_block(vcpu); 2408c2ecf20Sopenharmony_ci kvm_clear_request(KVM_REQ_UNHALT, vcpu); 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci default: 2438c2ecf20Sopenharmony_ci r = EV_UNIMPLEMENTED; 2448c2ecf20Sopenharmony_ci break; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, 4, r2); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return r; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_kvm_pv); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ciint kvmppc_sanity_check(struct kvm_vcpu *vcpu) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci int r = false; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* We have to know what CPU to virtualize */ 2588c2ecf20Sopenharmony_ci if (!vcpu->arch.pvr) 2598c2ecf20Sopenharmony_ci goto out; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* PAPR only works with book3s_64 */ 2628c2ecf20Sopenharmony_ci if ((vcpu->arch.cpu_type != KVM_CPU_3S_64) && vcpu->arch.papr_enabled) 2638c2ecf20Sopenharmony_ci goto out; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* HV KVM can only do PAPR mode for now */ 2668c2ecf20Sopenharmony_ci if (!vcpu->arch.papr_enabled && is_kvmppc_hv_enabled(vcpu->kvm)) 2678c2ecf20Sopenharmony_ci goto out; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOKE_HV 2708c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_EMB_HV)) 2718c2ecf20Sopenharmony_ci goto out; 2728c2ecf20Sopenharmony_ci#endif 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci r = true; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ciout: 2778c2ecf20Sopenharmony_ci vcpu->arch.sane = r; 2788c2ecf20Sopenharmony_ci return r ? 0 : -EINVAL; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_sanity_check); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ciint kvmppc_emulate_mmio(struct kvm_vcpu *vcpu) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci enum emulation_result er; 2858c2ecf20Sopenharmony_ci int r; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci er = kvmppc_emulate_loadstore(vcpu); 2888c2ecf20Sopenharmony_ci switch (er) { 2898c2ecf20Sopenharmony_ci case EMULATE_DONE: 2908c2ecf20Sopenharmony_ci /* Future optimization: only reload non-volatiles if they were 2918c2ecf20Sopenharmony_ci * actually modified. */ 2928c2ecf20Sopenharmony_ci r = RESUME_GUEST_NV; 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci case EMULATE_AGAIN: 2958c2ecf20Sopenharmony_ci r = RESUME_GUEST; 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci case EMULATE_DO_MMIO: 2988c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_MMIO; 2998c2ecf20Sopenharmony_ci /* We must reload nonvolatiles because "update" load/store 3008c2ecf20Sopenharmony_ci * instructions modify register state. */ 3018c2ecf20Sopenharmony_ci /* Future optimization: only reload non-volatiles if they were 3028c2ecf20Sopenharmony_ci * actually modified. */ 3038c2ecf20Sopenharmony_ci r = RESUME_HOST_NV; 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci case EMULATE_FAIL: 3068c2ecf20Sopenharmony_ci { 3078c2ecf20Sopenharmony_ci u32 last_inst; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst); 3108c2ecf20Sopenharmony_ci /* XXX Deliver Program interrupt to guest. */ 3118c2ecf20Sopenharmony_ci pr_emerg("%s: emulation failed (%08x)\n", __func__, last_inst); 3128c2ecf20Sopenharmony_ci r = RESUME_HOST; 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci default: 3168c2ecf20Sopenharmony_ci WARN_ON(1); 3178c2ecf20Sopenharmony_ci r = RESUME_GUEST; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci return r; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_emulate_mmio); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ciint kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, 3258c2ecf20Sopenharmony_ci bool data) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM & PAGE_MASK; 3288c2ecf20Sopenharmony_ci struct kvmppc_pte pte; 3298c2ecf20Sopenharmony_ci int r = -EINVAL; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci vcpu->stat.st++; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops && vcpu->kvm->arch.kvm_ops->store_to_eaddr) 3348c2ecf20Sopenharmony_ci r = vcpu->kvm->arch.kvm_ops->store_to_eaddr(vcpu, eaddr, ptr, 3358c2ecf20Sopenharmony_ci size); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if ((!r) || (r == -EAGAIN)) 3388c2ecf20Sopenharmony_ci return r; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci r = kvmppc_xlate(vcpu, *eaddr, data ? XLATE_DATA : XLATE_INST, 3418c2ecf20Sopenharmony_ci XLATE_WRITE, &pte); 3428c2ecf20Sopenharmony_ci if (r < 0) 3438c2ecf20Sopenharmony_ci return r; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci *eaddr = pte.raddr; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (!pte.may_write) 3488c2ecf20Sopenharmony_ci return -EPERM; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* Magic page override */ 3518c2ecf20Sopenharmony_ci if (kvmppc_supports_magic_page(vcpu) && mp_pa && 3528c2ecf20Sopenharmony_ci ((pte.raddr & KVM_PAM & PAGE_MASK) == mp_pa) && 3538c2ecf20Sopenharmony_ci !(kvmppc_get_msr(vcpu) & MSR_PR)) { 3548c2ecf20Sopenharmony_ci void *magic = vcpu->arch.shared; 3558c2ecf20Sopenharmony_ci magic += pte.eaddr & 0xfff; 3568c2ecf20Sopenharmony_ci memcpy(magic, ptr, size); 3578c2ecf20Sopenharmony_ci return EMULATE_DONE; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (kvm_write_guest(vcpu->kvm, pte.raddr, ptr, size)) 3618c2ecf20Sopenharmony_ci return EMULATE_DO_MMIO; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return EMULATE_DONE; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_st); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciint kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, 3688c2ecf20Sopenharmony_ci bool data) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM & PAGE_MASK; 3718c2ecf20Sopenharmony_ci struct kvmppc_pte pte; 3728c2ecf20Sopenharmony_ci int rc = -EINVAL; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci vcpu->stat.ld++; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops && vcpu->kvm->arch.kvm_ops->load_from_eaddr) 3778c2ecf20Sopenharmony_ci rc = vcpu->kvm->arch.kvm_ops->load_from_eaddr(vcpu, eaddr, ptr, 3788c2ecf20Sopenharmony_ci size); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if ((!rc) || (rc == -EAGAIN)) 3818c2ecf20Sopenharmony_ci return rc; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci rc = kvmppc_xlate(vcpu, *eaddr, data ? XLATE_DATA : XLATE_INST, 3848c2ecf20Sopenharmony_ci XLATE_READ, &pte); 3858c2ecf20Sopenharmony_ci if (rc) 3868c2ecf20Sopenharmony_ci return rc; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci *eaddr = pte.raddr; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (!pte.may_read) 3918c2ecf20Sopenharmony_ci return -EPERM; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (!data && !pte.may_execute) 3948c2ecf20Sopenharmony_ci return -ENOEXEC; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Magic page override */ 3978c2ecf20Sopenharmony_ci if (kvmppc_supports_magic_page(vcpu) && mp_pa && 3988c2ecf20Sopenharmony_ci ((pte.raddr & KVM_PAM & PAGE_MASK) == mp_pa) && 3998c2ecf20Sopenharmony_ci !(kvmppc_get_msr(vcpu) & MSR_PR)) { 4008c2ecf20Sopenharmony_ci void *magic = vcpu->arch.shared; 4018c2ecf20Sopenharmony_ci magic += pte.eaddr & 0xfff; 4028c2ecf20Sopenharmony_ci memcpy(ptr, magic, size); 4038c2ecf20Sopenharmony_ci return EMULATE_DONE; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 4078c2ecf20Sopenharmony_ci rc = kvm_read_guest(vcpu->kvm, pte.raddr, ptr, size); 4088c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx); 4098c2ecf20Sopenharmony_ci if (rc) 4108c2ecf20Sopenharmony_ci return EMULATE_DO_MMIO; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return EMULATE_DONE; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_ld); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ciint kvm_arch_hardware_enable(void) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ciint kvm_arch_hardware_setup(void *opaque) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ciint kvm_arch_check_processor_compat(void *opaque) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci return kvmppc_core_check_processor_compat(); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ciint kvm_arch_init_vm(struct kvm *kvm, unsigned long type) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct kvmppc_ops *kvm_ops = NULL; 4348c2ecf20Sopenharmony_ci /* 4358c2ecf20Sopenharmony_ci * if we have both HV and PR enabled, default is HV 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ci if (type == 0) { 4388c2ecf20Sopenharmony_ci if (kvmppc_hv_ops) 4398c2ecf20Sopenharmony_ci kvm_ops = kvmppc_hv_ops; 4408c2ecf20Sopenharmony_ci else 4418c2ecf20Sopenharmony_ci kvm_ops = kvmppc_pr_ops; 4428c2ecf20Sopenharmony_ci if (!kvm_ops) 4438c2ecf20Sopenharmony_ci goto err_out; 4448c2ecf20Sopenharmony_ci } else if (type == KVM_VM_PPC_HV) { 4458c2ecf20Sopenharmony_ci if (!kvmppc_hv_ops) 4468c2ecf20Sopenharmony_ci goto err_out; 4478c2ecf20Sopenharmony_ci kvm_ops = kvmppc_hv_ops; 4488c2ecf20Sopenharmony_ci } else if (type == KVM_VM_PPC_PR) { 4498c2ecf20Sopenharmony_ci if (!kvmppc_pr_ops) 4508c2ecf20Sopenharmony_ci goto err_out; 4518c2ecf20Sopenharmony_ci kvm_ops = kvmppc_pr_ops; 4528c2ecf20Sopenharmony_ci } else 4538c2ecf20Sopenharmony_ci goto err_out; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (kvm_ops->owner && !try_module_get(kvm_ops->owner)) 4568c2ecf20Sopenharmony_ci return -ENOENT; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci kvm->arch.kvm_ops = kvm_ops; 4598c2ecf20Sopenharmony_ci return kvmppc_core_init_vm(kvm); 4608c2ecf20Sopenharmony_cierr_out: 4618c2ecf20Sopenharmony_ci return -EINVAL; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_civoid kvm_arch_destroy_vm(struct kvm *kvm) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci unsigned int i; 4678c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_XICS 4708c2ecf20Sopenharmony_ci /* 4718c2ecf20Sopenharmony_ci * We call kick_all_cpus_sync() to ensure that all 4728c2ecf20Sopenharmony_ci * CPUs have executed any pending IPIs before we 4738c2ecf20Sopenharmony_ci * continue and free VCPUs structures below. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci if (is_kvmppc_hv_enabled(kvm)) 4768c2ecf20Sopenharmony_ci kick_all_cpus_sync(); 4778c2ecf20Sopenharmony_ci#endif 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci kvm_for_each_vcpu(i, vcpu, kvm) 4808c2ecf20Sopenharmony_ci kvm_vcpu_destroy(vcpu); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci mutex_lock(&kvm->lock); 4838c2ecf20Sopenharmony_ci for (i = 0; i < atomic_read(&kvm->online_vcpus); i++) 4848c2ecf20Sopenharmony_ci kvm->vcpus[i] = NULL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci atomic_set(&kvm->online_vcpus, 0); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci kvmppc_core_destroy_vm(kvm); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci mutex_unlock(&kvm->lock); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* drop the module reference */ 4938c2ecf20Sopenharmony_ci module_put(kvm->arch.kvm_ops->owner); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ciint kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci int r; 4998c2ecf20Sopenharmony_ci /* Assume we're using HV mode when the HV module is loaded */ 5008c2ecf20Sopenharmony_ci int hv_enabled = kvmppc_hv_ops ? 1 : 0; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (kvm) { 5038c2ecf20Sopenharmony_ci /* 5048c2ecf20Sopenharmony_ci * Hooray - we know which VM type we're running on. Depend on 5058c2ecf20Sopenharmony_ci * that rather than the guess above. 5068c2ecf20Sopenharmony_ci */ 5078c2ecf20Sopenharmony_ci hv_enabled = is_kvmppc_hv_enabled(kvm); 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci switch (ext) { 5118c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOKE 5128c2ecf20Sopenharmony_ci case KVM_CAP_PPC_BOOKE_SREGS: 5138c2ecf20Sopenharmony_ci case KVM_CAP_PPC_BOOKE_WATCHDOG: 5148c2ecf20Sopenharmony_ci case KVM_CAP_PPC_EPR: 5158c2ecf20Sopenharmony_ci#else 5168c2ecf20Sopenharmony_ci case KVM_CAP_PPC_SEGSTATE: 5178c2ecf20Sopenharmony_ci case KVM_CAP_PPC_HIOR: 5188c2ecf20Sopenharmony_ci case KVM_CAP_PPC_PAPR: 5198c2ecf20Sopenharmony_ci#endif 5208c2ecf20Sopenharmony_ci case KVM_CAP_PPC_UNSET_IRQ: 5218c2ecf20Sopenharmony_ci case KVM_CAP_PPC_IRQ_LEVEL: 5228c2ecf20Sopenharmony_ci case KVM_CAP_ENABLE_CAP: 5238c2ecf20Sopenharmony_ci case KVM_CAP_ONE_REG: 5248c2ecf20Sopenharmony_ci case KVM_CAP_IOEVENTFD: 5258c2ecf20Sopenharmony_ci case KVM_CAP_DEVICE_CTRL: 5268c2ecf20Sopenharmony_ci case KVM_CAP_IMMEDIATE_EXIT: 5278c2ecf20Sopenharmony_ci case KVM_CAP_SET_GUEST_DEBUG: 5288c2ecf20Sopenharmony_ci r = 1; 5298c2ecf20Sopenharmony_ci break; 5308c2ecf20Sopenharmony_ci case KVM_CAP_PPC_GUEST_DEBUG_SSTEP: 5318c2ecf20Sopenharmony_ci case KVM_CAP_PPC_PAIRED_SINGLES: 5328c2ecf20Sopenharmony_ci case KVM_CAP_PPC_OSI: 5338c2ecf20Sopenharmony_ci case KVM_CAP_PPC_GET_PVINFO: 5348c2ecf20Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) 5358c2ecf20Sopenharmony_ci case KVM_CAP_SW_TLB: 5368c2ecf20Sopenharmony_ci#endif 5378c2ecf20Sopenharmony_ci /* We support this only for PR */ 5388c2ecf20Sopenharmony_ci r = !hv_enabled; 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_MPIC 5418c2ecf20Sopenharmony_ci case KVM_CAP_IRQ_MPIC: 5428c2ecf20Sopenharmony_ci r = 1; 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci#endif 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 5478c2ecf20Sopenharmony_ci case KVM_CAP_SPAPR_TCE: 5488c2ecf20Sopenharmony_ci case KVM_CAP_SPAPR_TCE_64: 5498c2ecf20Sopenharmony_ci r = 1; 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci case KVM_CAP_SPAPR_TCE_VFIO: 5528c2ecf20Sopenharmony_ci r = !!cpu_has_feature(CPU_FTR_HVMODE); 5538c2ecf20Sopenharmony_ci break; 5548c2ecf20Sopenharmony_ci case KVM_CAP_PPC_RTAS: 5558c2ecf20Sopenharmony_ci case KVM_CAP_PPC_FIXUP_HCALL: 5568c2ecf20Sopenharmony_ci case KVM_CAP_PPC_ENABLE_HCALL: 5578c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_XICS 5588c2ecf20Sopenharmony_ci case KVM_CAP_IRQ_XICS: 5598c2ecf20Sopenharmony_ci#endif 5608c2ecf20Sopenharmony_ci case KVM_CAP_PPC_GET_CPU_CHAR: 5618c2ecf20Sopenharmony_ci r = 1; 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_XIVE 5648c2ecf20Sopenharmony_ci case KVM_CAP_PPC_IRQ_XIVE: 5658c2ecf20Sopenharmony_ci /* 5668c2ecf20Sopenharmony_ci * We need XIVE to be enabled on the platform (implies 5678c2ecf20Sopenharmony_ci * a POWER9 processor) and the PowerNV platform, as 5688c2ecf20Sopenharmony_ci * nested is not yet supported. 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_ci r = xive_enabled() && !!cpu_has_feature(CPU_FTR_HVMODE) && 5718c2ecf20Sopenharmony_ci kvmppc_xive_native_supported(); 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci#endif 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci case KVM_CAP_PPC_ALLOC_HTAB: 5768c2ecf20Sopenharmony_ci r = hv_enabled; 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_BOOK3S_64 */ 5798c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 5808c2ecf20Sopenharmony_ci case KVM_CAP_PPC_SMT: 5818c2ecf20Sopenharmony_ci r = 0; 5828c2ecf20Sopenharmony_ci if (kvm) { 5838c2ecf20Sopenharmony_ci if (kvm->arch.emul_smt_mode > 1) 5848c2ecf20Sopenharmony_ci r = kvm->arch.emul_smt_mode; 5858c2ecf20Sopenharmony_ci else 5868c2ecf20Sopenharmony_ci r = kvm->arch.smt_mode; 5878c2ecf20Sopenharmony_ci } else if (hv_enabled) { 5888c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_ARCH_300)) 5898c2ecf20Sopenharmony_ci r = 1; 5908c2ecf20Sopenharmony_ci else 5918c2ecf20Sopenharmony_ci r = threads_per_subcore; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci case KVM_CAP_PPC_SMT_POSSIBLE: 5958c2ecf20Sopenharmony_ci r = 1; 5968c2ecf20Sopenharmony_ci if (hv_enabled) { 5978c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ARCH_300)) 5988c2ecf20Sopenharmony_ci r = ((threads_per_subcore << 1) - 1); 5998c2ecf20Sopenharmony_ci else 6008c2ecf20Sopenharmony_ci /* P9 can emulate dbells, so allow any mode */ 6018c2ecf20Sopenharmony_ci r = 8 | 4 | 2 | 1; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci case KVM_CAP_PPC_RMA: 6058c2ecf20Sopenharmony_ci r = 0; 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci case KVM_CAP_PPC_HWRNG: 6088c2ecf20Sopenharmony_ci r = kvmppc_hwrng_present(); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case KVM_CAP_PPC_MMU_RADIX: 6118c2ecf20Sopenharmony_ci r = !!(hv_enabled && radix_enabled()); 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci case KVM_CAP_PPC_MMU_HASH_V3: 6148c2ecf20Sopenharmony_ci r = !!(hv_enabled && cpu_has_feature(CPU_FTR_ARCH_300) && 6158c2ecf20Sopenharmony_ci cpu_has_feature(CPU_FTR_HVMODE)); 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci case KVM_CAP_PPC_NESTED_HV: 6188c2ecf20Sopenharmony_ci r = !!(hv_enabled && kvmppc_hv_ops->enable_nested && 6198c2ecf20Sopenharmony_ci !kvmppc_hv_ops->enable_nested(NULL)); 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci#endif 6228c2ecf20Sopenharmony_ci case KVM_CAP_SYNC_MMU: 6238c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 6248c2ecf20Sopenharmony_ci r = hv_enabled; 6258c2ecf20Sopenharmony_ci#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER) 6268c2ecf20Sopenharmony_ci r = 1; 6278c2ecf20Sopenharmony_ci#else 6288c2ecf20Sopenharmony_ci r = 0; 6298c2ecf20Sopenharmony_ci#endif 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 6328c2ecf20Sopenharmony_ci case KVM_CAP_PPC_HTAB_FD: 6338c2ecf20Sopenharmony_ci r = hv_enabled; 6348c2ecf20Sopenharmony_ci break; 6358c2ecf20Sopenharmony_ci#endif 6368c2ecf20Sopenharmony_ci case KVM_CAP_NR_VCPUS: 6378c2ecf20Sopenharmony_ci /* 6388c2ecf20Sopenharmony_ci * Recommending a number of CPUs is somewhat arbitrary; we 6398c2ecf20Sopenharmony_ci * return the number of present CPUs for -HV (since a host 6408c2ecf20Sopenharmony_ci * will have secondary threads "offline"), and for other KVM 6418c2ecf20Sopenharmony_ci * implementations just count online CPUs. 6428c2ecf20Sopenharmony_ci */ 6438c2ecf20Sopenharmony_ci if (hv_enabled) 6448c2ecf20Sopenharmony_ci r = num_present_cpus(); 6458c2ecf20Sopenharmony_ci else 6468c2ecf20Sopenharmony_ci r = num_online_cpus(); 6478c2ecf20Sopenharmony_ci break; 6488c2ecf20Sopenharmony_ci case KVM_CAP_MAX_VCPUS: 6498c2ecf20Sopenharmony_ci r = KVM_MAX_VCPUS; 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci case KVM_CAP_MAX_VCPU_ID: 6528c2ecf20Sopenharmony_ci r = KVM_MAX_VCPU_ID; 6538c2ecf20Sopenharmony_ci break; 6548c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 6558c2ecf20Sopenharmony_ci case KVM_CAP_PPC_GET_SMMU_INFO: 6568c2ecf20Sopenharmony_ci r = 1; 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci case KVM_CAP_SPAPR_MULTITCE: 6598c2ecf20Sopenharmony_ci r = 1; 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case KVM_CAP_SPAPR_RESIZE_HPT: 6628c2ecf20Sopenharmony_ci r = !!hv_enabled; 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci#endif 6658c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 6668c2ecf20Sopenharmony_ci case KVM_CAP_PPC_FWNMI: 6678c2ecf20Sopenharmony_ci r = hv_enabled; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci#endif 6708c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 6718c2ecf20Sopenharmony_ci case KVM_CAP_PPC_HTM: 6728c2ecf20Sopenharmony_ci r = !!(cur_cpu_spec->cpu_user_features2 & PPC_FEATURE2_HTM) || 6738c2ecf20Sopenharmony_ci (hv_enabled && cpu_has_feature(CPU_FTR_P9_TM_HV_ASSIST)); 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci#endif 6768c2ecf20Sopenharmony_ci#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) 6778c2ecf20Sopenharmony_ci case KVM_CAP_PPC_SECURE_GUEST: 6788c2ecf20Sopenharmony_ci r = hv_enabled && kvmppc_hv_ops->enable_svm && 6798c2ecf20Sopenharmony_ci !kvmppc_hv_ops->enable_svm(NULL); 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci#endif 6828c2ecf20Sopenharmony_ci default: 6838c2ecf20Sopenharmony_ci r = 0; 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci return r; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cilong kvm_arch_dev_ioctl(struct file *filp, 6918c2ecf20Sopenharmony_ci unsigned int ioctl, unsigned long arg) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci return -EINVAL; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_civoid kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci kvmppc_core_free_memslot(kvm, slot); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ciint kvm_arch_prepare_memory_region(struct kvm *kvm, 7028c2ecf20Sopenharmony_ci struct kvm_memory_slot *memslot, 7038c2ecf20Sopenharmony_ci const struct kvm_userspace_memory_region *mem, 7048c2ecf20Sopenharmony_ci enum kvm_mr_change change) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci return kvmppc_core_prepare_memory_region(kvm, memslot, mem, change); 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_civoid kvm_arch_commit_memory_region(struct kvm *kvm, 7108c2ecf20Sopenharmony_ci const struct kvm_userspace_memory_region *mem, 7118c2ecf20Sopenharmony_ci struct kvm_memory_slot *old, 7128c2ecf20Sopenharmony_ci const struct kvm_memory_slot *new, 7138c2ecf20Sopenharmony_ci enum kvm_mr_change change) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci kvmppc_core_commit_memory_region(kvm, mem, old, new, change); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_civoid kvm_arch_flush_shadow_memslot(struct kvm *kvm, 7198c2ecf20Sopenharmony_ci struct kvm_memory_slot *slot) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci kvmppc_core_flush_memslot(kvm, slot); 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ciint kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic enum hrtimer_restart kvmppc_decrementer_wakeup(struct hrtimer *timer) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci vcpu = container_of(timer, struct kvm_vcpu, arch.dec_timer); 7348c2ecf20Sopenharmony_ci kvmppc_decrementer_func(vcpu); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ciint kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci int err; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); 7448c2ecf20Sopenharmony_ci vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup; 7458c2ecf20Sopenharmony_ci vcpu->arch.dec_expires = get_tb(); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_EXIT_TIMING 7488c2ecf20Sopenharmony_ci mutex_init(&vcpu->arch.exit_timing_lock); 7498c2ecf20Sopenharmony_ci#endif 7508c2ecf20Sopenharmony_ci err = kvmppc_subarch_vcpu_init(vcpu); 7518c2ecf20Sopenharmony_ci if (err) 7528c2ecf20Sopenharmony_ci return err; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci err = kvmppc_core_vcpu_create(vcpu); 7558c2ecf20Sopenharmony_ci if (err) 7568c2ecf20Sopenharmony_ci goto out_vcpu_uninit; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci vcpu->arch.waitp = &vcpu->wait; 7598c2ecf20Sopenharmony_ci kvmppc_create_vcpu_debugfs(vcpu, vcpu->vcpu_id); 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ciout_vcpu_uninit: 7638c2ecf20Sopenharmony_ci kvmppc_subarch_vcpu_uninit(vcpu); 7648c2ecf20Sopenharmony_ci return err; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_civoid kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_civoid kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci /* Make sure we're not using the vcpu anymore */ 7748c2ecf20Sopenharmony_ci hrtimer_cancel(&vcpu->arch.dec_timer); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci kvmppc_remove_vcpu_debugfs(vcpu); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci switch (vcpu->arch.irq_type) { 7798c2ecf20Sopenharmony_ci case KVMPPC_IRQ_MPIC: 7808c2ecf20Sopenharmony_ci kvmppc_mpic_disconnect_vcpu(vcpu->arch.mpic, vcpu); 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci case KVMPPC_IRQ_XICS: 7838c2ecf20Sopenharmony_ci if (xics_on_xive()) 7848c2ecf20Sopenharmony_ci kvmppc_xive_cleanup_vcpu(vcpu); 7858c2ecf20Sopenharmony_ci else 7868c2ecf20Sopenharmony_ci kvmppc_xics_free_icp(vcpu); 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case KVMPPC_IRQ_XIVE: 7898c2ecf20Sopenharmony_ci kvmppc_xive_native_cleanup_vcpu(vcpu); 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci kvmppc_core_vcpu_free(vcpu); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci kvmppc_subarch_vcpu_uninit(vcpu); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ciint kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci return kvmppc_core_pending_dec(vcpu); 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_civoid kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOKE 8068c2ecf20Sopenharmony_ci /* 8078c2ecf20Sopenharmony_ci * vrsave (formerly usprg0) isn't used by Linux, but may 8088c2ecf20Sopenharmony_ci * be used by the guest. 8098c2ecf20Sopenharmony_ci * 8108c2ecf20Sopenharmony_ci * On non-booke this is associated with Altivec and 8118c2ecf20Sopenharmony_ci * is handled by code in book3s.c. 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_ci mtspr(SPRN_VRSAVE, vcpu->arch.vrsave); 8148c2ecf20Sopenharmony_ci#endif 8158c2ecf20Sopenharmony_ci kvmppc_core_vcpu_load(vcpu, cpu); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_civoid kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci kvmppc_core_vcpu_put(vcpu); 8218c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOKE 8228c2ecf20Sopenharmony_ci vcpu->arch.vrsave = mfspr(SPRN_VRSAVE); 8238c2ecf20Sopenharmony_ci#endif 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci/* 8278c2ecf20Sopenharmony_ci * irq_bypass_add_producer and irq_bypass_del_producer are only 8288c2ecf20Sopenharmony_ci * useful if the architecture supports PCI passthrough. 8298c2ecf20Sopenharmony_ci * irq_bypass_stop and irq_bypass_start are not needed and so 8308c2ecf20Sopenharmony_ci * kvm_ops are not defined for them. 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_cibool kvm_arch_has_irq_bypass(void) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci return ((kvmppc_hv_ops && kvmppc_hv_ops->irq_bypass_add_producer) || 8358c2ecf20Sopenharmony_ci (kvmppc_pr_ops && kvmppc_pr_ops->irq_bypass_add_producer)); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ciint kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons, 8398c2ecf20Sopenharmony_ci struct irq_bypass_producer *prod) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct kvm_kernel_irqfd *irqfd = 8428c2ecf20Sopenharmony_ci container_of(cons, struct kvm_kernel_irqfd, consumer); 8438c2ecf20Sopenharmony_ci struct kvm *kvm = irqfd->kvm; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (kvm->arch.kvm_ops->irq_bypass_add_producer) 8468c2ecf20Sopenharmony_ci return kvm->arch.kvm_ops->irq_bypass_add_producer(cons, prod); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci return 0; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_civoid kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, 8528c2ecf20Sopenharmony_ci struct irq_bypass_producer *prod) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct kvm_kernel_irqfd *irqfd = 8558c2ecf20Sopenharmony_ci container_of(cons, struct kvm_kernel_irqfd, consumer); 8568c2ecf20Sopenharmony_ci struct kvm *kvm = irqfd->kvm; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (kvm->arch.kvm_ops->irq_bypass_del_producer) 8598c2ecf20Sopenharmony_ci kvm->arch.kvm_ops->irq_bypass_del_producer(cons, prod); 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX 8638c2ecf20Sopenharmony_cistatic inline int kvmppc_get_vsr_dword_offset(int index) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci int offset; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if ((index != 0) && (index != 1)) 8688c2ecf20Sopenharmony_ci return -1; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 8718c2ecf20Sopenharmony_ci offset = index; 8728c2ecf20Sopenharmony_ci#else 8738c2ecf20Sopenharmony_ci offset = 1 - index; 8748c2ecf20Sopenharmony_ci#endif 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci return offset; 8778c2ecf20Sopenharmony_ci} 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic inline int kvmppc_get_vsr_word_offset(int index) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci int offset; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if ((index > 3) || (index < 0)) 8848c2ecf20Sopenharmony_ci return -1; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 8878c2ecf20Sopenharmony_ci offset = index; 8888c2ecf20Sopenharmony_ci#else 8898c2ecf20Sopenharmony_ci offset = 3 - index; 8908c2ecf20Sopenharmony_ci#endif 8918c2ecf20Sopenharmony_ci return offset; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic inline void kvmppc_set_vsr_dword(struct kvm_vcpu *vcpu, 8958c2ecf20Sopenharmony_ci u64 gpr) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 8988c2ecf20Sopenharmony_ci int offset = kvmppc_get_vsr_dword_offset(vcpu->arch.mmio_vsx_offset); 8998c2ecf20Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci if (offset == -1) 9028c2ecf20Sopenharmony_ci return; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (index >= 32) { 9058c2ecf20Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index - 32); 9068c2ecf20Sopenharmony_ci val.vsxval[offset] = gpr; 9078c2ecf20Sopenharmony_ci VCPU_VSX_VR(vcpu, index - 32) = val.vval; 9088c2ecf20Sopenharmony_ci } else { 9098c2ecf20Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, offset) = gpr; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic inline void kvmppc_set_vsr_dword_dump(struct kvm_vcpu *vcpu, 9148c2ecf20Sopenharmony_ci u64 gpr) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 9178c2ecf20Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (index >= 32) { 9208c2ecf20Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index - 32); 9218c2ecf20Sopenharmony_ci val.vsxval[0] = gpr; 9228c2ecf20Sopenharmony_ci val.vsxval[1] = gpr; 9238c2ecf20Sopenharmony_ci VCPU_VSX_VR(vcpu, index - 32) = val.vval; 9248c2ecf20Sopenharmony_ci } else { 9258c2ecf20Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, 0) = gpr; 9268c2ecf20Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, 1) = gpr; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_cistatic inline void kvmppc_set_vsr_word_dump(struct kvm_vcpu *vcpu, 9318c2ecf20Sopenharmony_ci u32 gpr) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 9348c2ecf20Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (index >= 32) { 9378c2ecf20Sopenharmony_ci val.vsx32val[0] = gpr; 9388c2ecf20Sopenharmony_ci val.vsx32val[1] = gpr; 9398c2ecf20Sopenharmony_ci val.vsx32val[2] = gpr; 9408c2ecf20Sopenharmony_ci val.vsx32val[3] = gpr; 9418c2ecf20Sopenharmony_ci VCPU_VSX_VR(vcpu, index - 32) = val.vval; 9428c2ecf20Sopenharmony_ci } else { 9438c2ecf20Sopenharmony_ci val.vsx32val[0] = gpr; 9448c2ecf20Sopenharmony_ci val.vsx32val[1] = gpr; 9458c2ecf20Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, 0) = val.vsxval[0]; 9468c2ecf20Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, 1) = val.vsxval[0]; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic inline void kvmppc_set_vsr_word(struct kvm_vcpu *vcpu, 9518c2ecf20Sopenharmony_ci u32 gpr32) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 9548c2ecf20Sopenharmony_ci int offset = kvmppc_get_vsr_word_offset(vcpu->arch.mmio_vsx_offset); 9558c2ecf20Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 9568c2ecf20Sopenharmony_ci int dword_offset, word_offset; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (offset == -1) 9598c2ecf20Sopenharmony_ci return; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (index >= 32) { 9628c2ecf20Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index - 32); 9638c2ecf20Sopenharmony_ci val.vsx32val[offset] = gpr32; 9648c2ecf20Sopenharmony_ci VCPU_VSX_VR(vcpu, index - 32) = val.vval; 9658c2ecf20Sopenharmony_ci } else { 9668c2ecf20Sopenharmony_ci dword_offset = offset / 2; 9678c2ecf20Sopenharmony_ci word_offset = offset % 2; 9688c2ecf20Sopenharmony_ci val.vsxval[0] = VCPU_VSX_FPR(vcpu, index, dword_offset); 9698c2ecf20Sopenharmony_ci val.vsx32val[word_offset] = gpr32; 9708c2ecf20Sopenharmony_ci VCPU_VSX_FPR(vcpu, index, dword_offset) = val.vsxval[0]; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */ 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC 9768c2ecf20Sopenharmony_cistatic inline int kvmppc_get_vmx_offset_generic(struct kvm_vcpu *vcpu, 9778c2ecf20Sopenharmony_ci int index, int element_size) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci int offset; 9808c2ecf20Sopenharmony_ci int elts = sizeof(vector128)/element_size; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if ((index < 0) || (index >= elts)) 9838c2ecf20Sopenharmony_ci return -1; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (kvmppc_need_byteswap(vcpu)) 9868c2ecf20Sopenharmony_ci offset = elts - index - 1; 9878c2ecf20Sopenharmony_ci else 9888c2ecf20Sopenharmony_ci offset = index; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return offset; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistatic inline int kvmppc_get_vmx_dword_offset(struct kvm_vcpu *vcpu, 9948c2ecf20Sopenharmony_ci int index) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci return kvmppc_get_vmx_offset_generic(vcpu, index, 8); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic inline int kvmppc_get_vmx_word_offset(struct kvm_vcpu *vcpu, 10008c2ecf20Sopenharmony_ci int index) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci return kvmppc_get_vmx_offset_generic(vcpu, index, 4); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic inline int kvmppc_get_vmx_hword_offset(struct kvm_vcpu *vcpu, 10068c2ecf20Sopenharmony_ci int index) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci return kvmppc_get_vmx_offset_generic(vcpu, index, 2); 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic inline int kvmppc_get_vmx_byte_offset(struct kvm_vcpu *vcpu, 10128c2ecf20Sopenharmony_ci int index) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci return kvmppc_get_vmx_offset_generic(vcpu, index, 1); 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic inline void kvmppc_set_vmx_dword(struct kvm_vcpu *vcpu, 10198c2ecf20Sopenharmony_ci u64 gpr) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 10228c2ecf20Sopenharmony_ci int offset = kvmppc_get_vmx_dword_offset(vcpu, 10238c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_offset); 10248c2ecf20Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (offset == -1) 10278c2ecf20Sopenharmony_ci return; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index); 10308c2ecf20Sopenharmony_ci val.vsxval[offset] = gpr; 10318c2ecf20Sopenharmony_ci VCPU_VSX_VR(vcpu, index) = val.vval; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cistatic inline void kvmppc_set_vmx_word(struct kvm_vcpu *vcpu, 10358c2ecf20Sopenharmony_ci u32 gpr32) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 10388c2ecf20Sopenharmony_ci int offset = kvmppc_get_vmx_word_offset(vcpu, 10398c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_offset); 10408c2ecf20Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (offset == -1) 10438c2ecf20Sopenharmony_ci return; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index); 10468c2ecf20Sopenharmony_ci val.vsx32val[offset] = gpr32; 10478c2ecf20Sopenharmony_ci VCPU_VSX_VR(vcpu, index) = val.vval; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic inline void kvmppc_set_vmx_hword(struct kvm_vcpu *vcpu, 10518c2ecf20Sopenharmony_ci u16 gpr16) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 10548c2ecf20Sopenharmony_ci int offset = kvmppc_get_vmx_hword_offset(vcpu, 10558c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_offset); 10568c2ecf20Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (offset == -1) 10598c2ecf20Sopenharmony_ci return; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index); 10628c2ecf20Sopenharmony_ci val.vsx16val[offset] = gpr16; 10638c2ecf20Sopenharmony_ci VCPU_VSX_VR(vcpu, index) = val.vval; 10648c2ecf20Sopenharmony_ci} 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_cistatic inline void kvmppc_set_vmx_byte(struct kvm_vcpu *vcpu, 10678c2ecf20Sopenharmony_ci u8 gpr8) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 10708c2ecf20Sopenharmony_ci int offset = kvmppc_get_vmx_byte_offset(vcpu, 10718c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_offset); 10728c2ecf20Sopenharmony_ci int index = vcpu->arch.io_gpr & KVM_MMIO_REG_MASK; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (offset == -1) 10758c2ecf20Sopenharmony_ci return; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci val.vval = VCPU_VSX_VR(vcpu, index); 10788c2ecf20Sopenharmony_ci val.vsx8val[offset] = gpr8; 10798c2ecf20Sopenharmony_ci VCPU_VSX_VR(vcpu, index) = val.vval; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_FPU 10848c2ecf20Sopenharmony_cistatic inline u64 sp_to_dp(u32 fprs) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci u64 fprd; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci preempt_disable(); 10898c2ecf20Sopenharmony_ci enable_kernel_fp(); 10908c2ecf20Sopenharmony_ci asm ("lfs%U1%X1 0,%1; stfd%U0%X0 0,%0" : "=m" (fprd) : "m" (fprs) 10918c2ecf20Sopenharmony_ci : "fr0"); 10928c2ecf20Sopenharmony_ci preempt_enable(); 10938c2ecf20Sopenharmony_ci return fprd; 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic inline u32 dp_to_sp(u64 fprd) 10978c2ecf20Sopenharmony_ci{ 10988c2ecf20Sopenharmony_ci u32 fprs; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci preempt_disable(); 11018c2ecf20Sopenharmony_ci enable_kernel_fp(); 11028c2ecf20Sopenharmony_ci asm ("lfd%U1%X1 0,%1; stfs%U0%X0 0,%0" : "=m" (fprs) : "m" (fprd) 11038c2ecf20Sopenharmony_ci : "fr0"); 11048c2ecf20Sopenharmony_ci preempt_enable(); 11058c2ecf20Sopenharmony_ci return fprs; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci#else 11098c2ecf20Sopenharmony_ci#define sp_to_dp(x) (x) 11108c2ecf20Sopenharmony_ci#define dp_to_sp(x) (x) 11118c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_FPU */ 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu) 11148c2ecf20Sopenharmony_ci{ 11158c2ecf20Sopenharmony_ci struct kvm_run *run = vcpu->run; 11168c2ecf20Sopenharmony_ci u64 gpr; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci if (run->mmio.len > sizeof(gpr)) { 11198c2ecf20Sopenharmony_ci printk(KERN_ERR "bad MMIO length: %d\n", run->mmio.len); 11208c2ecf20Sopenharmony_ci return; 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci if (!vcpu->arch.mmio_host_swabbed) { 11248c2ecf20Sopenharmony_ci switch (run->mmio.len) { 11258c2ecf20Sopenharmony_ci case 8: gpr = *(u64 *)run->mmio.data; break; 11268c2ecf20Sopenharmony_ci case 4: gpr = *(u32 *)run->mmio.data; break; 11278c2ecf20Sopenharmony_ci case 2: gpr = *(u16 *)run->mmio.data; break; 11288c2ecf20Sopenharmony_ci case 1: gpr = *(u8 *)run->mmio.data; break; 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci } else { 11318c2ecf20Sopenharmony_ci switch (run->mmio.len) { 11328c2ecf20Sopenharmony_ci case 8: gpr = swab64(*(u64 *)run->mmio.data); break; 11338c2ecf20Sopenharmony_ci case 4: gpr = swab32(*(u32 *)run->mmio.data); break; 11348c2ecf20Sopenharmony_ci case 2: gpr = swab16(*(u16 *)run->mmio.data); break; 11358c2ecf20Sopenharmony_ci case 1: gpr = *(u8 *)run->mmio.data; break; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* conversion between single and double precision */ 11408c2ecf20Sopenharmony_ci if ((vcpu->arch.mmio_sp64_extend) && (run->mmio.len == 4)) 11418c2ecf20Sopenharmony_ci gpr = sp_to_dp(gpr); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_sign_extend) { 11448c2ecf20Sopenharmony_ci switch (run->mmio.len) { 11458c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 11468c2ecf20Sopenharmony_ci case 4: 11478c2ecf20Sopenharmony_ci gpr = (s64)(s32)gpr; 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci#endif 11508c2ecf20Sopenharmony_ci case 2: 11518c2ecf20Sopenharmony_ci gpr = (s64)(s16)gpr; 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci case 1: 11548c2ecf20Sopenharmony_ci gpr = (s64)(s8)gpr; 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci switch (vcpu->arch.io_gpr & KVM_MMIO_REG_EXT_MASK) { 11608c2ecf20Sopenharmony_ci case KVM_MMIO_REG_GPR: 11618c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr); 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci case KVM_MMIO_REG_FPR: 11648c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops->giveup_ext) 11658c2ecf20Sopenharmony_ci vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_FP); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; 11688c2ecf20Sopenharmony_ci break; 11698c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S 11708c2ecf20Sopenharmony_ci case KVM_MMIO_REG_QPR: 11718c2ecf20Sopenharmony_ci vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; 11728c2ecf20Sopenharmony_ci break; 11738c2ecf20Sopenharmony_ci case KVM_MMIO_REG_FQPR: 11748c2ecf20Sopenharmony_ci VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr; 11758c2ecf20Sopenharmony_ci vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr; 11768c2ecf20Sopenharmony_ci break; 11778c2ecf20Sopenharmony_ci#endif 11788c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX 11798c2ecf20Sopenharmony_ci case KVM_MMIO_REG_VSX: 11808c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops->giveup_ext) 11818c2ecf20Sopenharmony_ci vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_VSX); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_copy_type == KVMPPC_VSX_COPY_DWORD) 11848c2ecf20Sopenharmony_ci kvmppc_set_vsr_dword(vcpu, gpr); 11858c2ecf20Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == KVMPPC_VSX_COPY_WORD) 11868c2ecf20Sopenharmony_ci kvmppc_set_vsr_word(vcpu, gpr); 11878c2ecf20Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == 11888c2ecf20Sopenharmony_ci KVMPPC_VSX_COPY_DWORD_LOAD_DUMP) 11898c2ecf20Sopenharmony_ci kvmppc_set_vsr_dword_dump(vcpu, gpr); 11908c2ecf20Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == 11918c2ecf20Sopenharmony_ci KVMPPC_VSX_COPY_WORD_LOAD_DUMP) 11928c2ecf20Sopenharmony_ci kvmppc_set_vsr_word_dump(vcpu, gpr); 11938c2ecf20Sopenharmony_ci break; 11948c2ecf20Sopenharmony_ci#endif 11958c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC 11968c2ecf20Sopenharmony_ci case KVM_MMIO_REG_VMX: 11978c2ecf20Sopenharmony_ci if (vcpu->kvm->arch.kvm_ops->giveup_ext) 11988c2ecf20Sopenharmony_ci vcpu->kvm->arch.kvm_ops->giveup_ext(vcpu, MSR_VEC); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_copy_type == KVMPPC_VMX_COPY_DWORD) 12018c2ecf20Sopenharmony_ci kvmppc_set_vmx_dword(vcpu, gpr); 12028c2ecf20Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == KVMPPC_VMX_COPY_WORD) 12038c2ecf20Sopenharmony_ci kvmppc_set_vmx_word(vcpu, gpr); 12048c2ecf20Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == 12058c2ecf20Sopenharmony_ci KVMPPC_VMX_COPY_HWORD) 12068c2ecf20Sopenharmony_ci kvmppc_set_vmx_hword(vcpu, gpr); 12078c2ecf20Sopenharmony_ci else if (vcpu->arch.mmio_copy_type == 12088c2ecf20Sopenharmony_ci KVMPPC_VMX_COPY_BYTE) 12098c2ecf20Sopenharmony_ci kvmppc_set_vmx_byte(vcpu, gpr); 12108c2ecf20Sopenharmony_ci break; 12118c2ecf20Sopenharmony_ci#endif 12128c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 12138c2ecf20Sopenharmony_ci case KVM_MMIO_REG_NESTED_GPR: 12148c2ecf20Sopenharmony_ci if (kvmppc_need_byteswap(vcpu)) 12158c2ecf20Sopenharmony_ci gpr = swab64(gpr); 12168c2ecf20Sopenharmony_ci kvm_vcpu_write_guest(vcpu, vcpu->arch.nested_io_gpr, &gpr, 12178c2ecf20Sopenharmony_ci sizeof(gpr)); 12188c2ecf20Sopenharmony_ci break; 12198c2ecf20Sopenharmony_ci#endif 12208c2ecf20Sopenharmony_ci default: 12218c2ecf20Sopenharmony_ci BUG(); 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic int __kvmppc_handle_load(struct kvm_vcpu *vcpu, 12268c2ecf20Sopenharmony_ci unsigned int rt, unsigned int bytes, 12278c2ecf20Sopenharmony_ci int is_default_endian, int sign_extend) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci struct kvm_run *run = vcpu->run; 12308c2ecf20Sopenharmony_ci int idx, ret; 12318c2ecf20Sopenharmony_ci bool host_swabbed; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci /* Pity C doesn't have a logical XOR operator */ 12348c2ecf20Sopenharmony_ci if (kvmppc_need_byteswap(vcpu)) { 12358c2ecf20Sopenharmony_ci host_swabbed = is_default_endian; 12368c2ecf20Sopenharmony_ci } else { 12378c2ecf20Sopenharmony_ci host_swabbed = !is_default_endian; 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (bytes > sizeof(run->mmio.data)) { 12418c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, 12428c2ecf20Sopenharmony_ci run->mmio.len); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci run->mmio.phys_addr = vcpu->arch.paddr_accessed; 12468c2ecf20Sopenharmony_ci run->mmio.len = bytes; 12478c2ecf20Sopenharmony_ci run->mmio.is_write = 0; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci vcpu->arch.io_gpr = rt; 12508c2ecf20Sopenharmony_ci vcpu->arch.mmio_host_swabbed = host_swabbed; 12518c2ecf20Sopenharmony_ci vcpu->mmio_needed = 1; 12528c2ecf20Sopenharmony_ci vcpu->mmio_is_write = 0; 12538c2ecf20Sopenharmony_ci vcpu->arch.mmio_sign_extend = sign_extend; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci idx = srcu_read_lock(&vcpu->kvm->srcu); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, 12588c2ecf20Sopenharmony_ci bytes, &run->mmio.data); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, idx); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (!ret) { 12638c2ecf20Sopenharmony_ci kvmppc_complete_mmio_load(vcpu); 12648c2ecf20Sopenharmony_ci vcpu->mmio_needed = 0; 12658c2ecf20Sopenharmony_ci return EMULATE_DONE; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci return EMULATE_DO_MMIO; 12698c2ecf20Sopenharmony_ci} 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ciint kvmppc_handle_load(struct kvm_vcpu *vcpu, 12728c2ecf20Sopenharmony_ci unsigned int rt, unsigned int bytes, 12738c2ecf20Sopenharmony_ci int is_default_endian) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci return __kvmppc_handle_load(vcpu, rt, bytes, is_default_endian, 0); 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_handle_load); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci/* Same as above, but sign extends */ 12808c2ecf20Sopenharmony_ciint kvmppc_handle_loads(struct kvm_vcpu *vcpu, 12818c2ecf20Sopenharmony_ci unsigned int rt, unsigned int bytes, 12828c2ecf20Sopenharmony_ci int is_default_endian) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci return __kvmppc_handle_load(vcpu, rt, bytes, is_default_endian, 1); 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX 12888c2ecf20Sopenharmony_ciint kvmppc_handle_vsx_load(struct kvm_vcpu *vcpu, 12898c2ecf20Sopenharmony_ci unsigned int rt, unsigned int bytes, 12908c2ecf20Sopenharmony_ci int is_default_endian, int mmio_sign_extend) 12918c2ecf20Sopenharmony_ci{ 12928c2ecf20Sopenharmony_ci enum emulation_result emulated = EMULATE_DONE; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* Currently, mmio_vsx_copy_nums only allowed to be 4 or less */ 12958c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_vsx_copy_nums > 4) 12968c2ecf20Sopenharmony_ci return EMULATE_FAIL; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci while (vcpu->arch.mmio_vsx_copy_nums) { 12998c2ecf20Sopenharmony_ci emulated = __kvmppc_handle_load(vcpu, rt, bytes, 13008c2ecf20Sopenharmony_ci is_default_endian, mmio_sign_extend); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci if (emulated != EMULATE_DONE) 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci vcpu->arch.paddr_accessed += vcpu->run->mmio.len; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci vcpu->arch.mmio_vsx_copy_nums--; 13088c2ecf20Sopenharmony_ci vcpu->arch.mmio_vsx_offset++; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci return emulated; 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */ 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ciint kvmppc_handle_store(struct kvm_vcpu *vcpu, 13158c2ecf20Sopenharmony_ci u64 val, unsigned int bytes, int is_default_endian) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci struct kvm_run *run = vcpu->run; 13188c2ecf20Sopenharmony_ci void *data = run->mmio.data; 13198c2ecf20Sopenharmony_ci int idx, ret; 13208c2ecf20Sopenharmony_ci bool host_swabbed; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci /* Pity C doesn't have a logical XOR operator */ 13238c2ecf20Sopenharmony_ci if (kvmppc_need_byteswap(vcpu)) { 13248c2ecf20Sopenharmony_ci host_swabbed = is_default_endian; 13258c2ecf20Sopenharmony_ci } else { 13268c2ecf20Sopenharmony_ci host_swabbed = !is_default_endian; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (bytes > sizeof(run->mmio.data)) { 13308c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__, 13318c2ecf20Sopenharmony_ci run->mmio.len); 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci run->mmio.phys_addr = vcpu->arch.paddr_accessed; 13358c2ecf20Sopenharmony_ci run->mmio.len = bytes; 13368c2ecf20Sopenharmony_ci run->mmio.is_write = 1; 13378c2ecf20Sopenharmony_ci vcpu->mmio_needed = 1; 13388c2ecf20Sopenharmony_ci vcpu->mmio_is_write = 1; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if ((vcpu->arch.mmio_sp64_extend) && (bytes == 4)) 13418c2ecf20Sopenharmony_ci val = dp_to_sp(val); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* Store the value at the lowest bytes in 'data'. */ 13448c2ecf20Sopenharmony_ci if (!host_swabbed) { 13458c2ecf20Sopenharmony_ci switch (bytes) { 13468c2ecf20Sopenharmony_ci case 8: *(u64 *)data = val; break; 13478c2ecf20Sopenharmony_ci case 4: *(u32 *)data = val; break; 13488c2ecf20Sopenharmony_ci case 2: *(u16 *)data = val; break; 13498c2ecf20Sopenharmony_ci case 1: *(u8 *)data = val; break; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci } else { 13528c2ecf20Sopenharmony_ci switch (bytes) { 13538c2ecf20Sopenharmony_ci case 8: *(u64 *)data = swab64(val); break; 13548c2ecf20Sopenharmony_ci case 4: *(u32 *)data = swab32(val); break; 13558c2ecf20Sopenharmony_ci case 2: *(u16 *)data = swab16(val); break; 13568c2ecf20Sopenharmony_ci case 1: *(u8 *)data = val; break; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci idx = srcu_read_lock(&vcpu->kvm->srcu); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, run->mmio.phys_addr, 13638c2ecf20Sopenharmony_ci bytes, &run->mmio.data); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci srcu_read_unlock(&vcpu->kvm->srcu, idx); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (!ret) { 13688c2ecf20Sopenharmony_ci vcpu->mmio_needed = 0; 13698c2ecf20Sopenharmony_ci return EMULATE_DONE; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci return EMULATE_DO_MMIO; 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_handle_store); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX 13778c2ecf20Sopenharmony_cistatic inline int kvmppc_get_vsr_data(struct kvm_vcpu *vcpu, int rs, u64 *val) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci u32 dword_offset, word_offset; 13808c2ecf20Sopenharmony_ci union kvmppc_one_reg reg; 13818c2ecf20Sopenharmony_ci int vsx_offset = 0; 13828c2ecf20Sopenharmony_ci int copy_type = vcpu->arch.mmio_copy_type; 13838c2ecf20Sopenharmony_ci int result = 0; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci switch (copy_type) { 13868c2ecf20Sopenharmony_ci case KVMPPC_VSX_COPY_DWORD: 13878c2ecf20Sopenharmony_ci vsx_offset = 13888c2ecf20Sopenharmony_ci kvmppc_get_vsr_dword_offset(vcpu->arch.mmio_vsx_offset); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci if (vsx_offset == -1) { 13918c2ecf20Sopenharmony_ci result = -1; 13928c2ecf20Sopenharmony_ci break; 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci if (rs < 32) { 13968c2ecf20Sopenharmony_ci *val = VCPU_VSX_FPR(vcpu, rs, vsx_offset); 13978c2ecf20Sopenharmony_ci } else { 13988c2ecf20Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, rs - 32); 13998c2ecf20Sopenharmony_ci *val = reg.vsxval[vsx_offset]; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci break; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci case KVMPPC_VSX_COPY_WORD: 14048c2ecf20Sopenharmony_ci vsx_offset = 14058c2ecf20Sopenharmony_ci kvmppc_get_vsr_word_offset(vcpu->arch.mmio_vsx_offset); 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci if (vsx_offset == -1) { 14088c2ecf20Sopenharmony_ci result = -1; 14098c2ecf20Sopenharmony_ci break; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (rs < 32) { 14138c2ecf20Sopenharmony_ci dword_offset = vsx_offset / 2; 14148c2ecf20Sopenharmony_ci word_offset = vsx_offset % 2; 14158c2ecf20Sopenharmony_ci reg.vsxval[0] = VCPU_VSX_FPR(vcpu, rs, dword_offset); 14168c2ecf20Sopenharmony_ci *val = reg.vsx32val[word_offset]; 14178c2ecf20Sopenharmony_ci } else { 14188c2ecf20Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, rs - 32); 14198c2ecf20Sopenharmony_ci *val = reg.vsx32val[vsx_offset]; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci break; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci default: 14248c2ecf20Sopenharmony_ci result = -1; 14258c2ecf20Sopenharmony_ci break; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci return result; 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ciint kvmppc_handle_vsx_store(struct kvm_vcpu *vcpu, 14328c2ecf20Sopenharmony_ci int rs, unsigned int bytes, int is_default_endian) 14338c2ecf20Sopenharmony_ci{ 14348c2ecf20Sopenharmony_ci u64 val; 14358c2ecf20Sopenharmony_ci enum emulation_result emulated = EMULATE_DONE; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci vcpu->arch.io_gpr = rs; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* Currently, mmio_vsx_copy_nums only allowed to be 4 or less */ 14408c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_vsx_copy_nums > 4) 14418c2ecf20Sopenharmony_ci return EMULATE_FAIL; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci while (vcpu->arch.mmio_vsx_copy_nums) { 14448c2ecf20Sopenharmony_ci if (kvmppc_get_vsr_data(vcpu, rs, &val) == -1) 14458c2ecf20Sopenharmony_ci return EMULATE_FAIL; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci emulated = kvmppc_handle_store(vcpu, 14488c2ecf20Sopenharmony_ci val, bytes, is_default_endian); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (emulated != EMULATE_DONE) 14518c2ecf20Sopenharmony_ci break; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci vcpu->arch.paddr_accessed += vcpu->run->mmio.len; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci vcpu->arch.mmio_vsx_copy_nums--; 14568c2ecf20Sopenharmony_ci vcpu->arch.mmio_vsx_offset++; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci return emulated; 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cistatic int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci struct kvm_run *run = vcpu->run; 14658c2ecf20Sopenharmony_ci enum emulation_result emulated = EMULATE_FAIL; 14668c2ecf20Sopenharmony_ci int r; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci vcpu->arch.paddr_accessed += run->mmio.len; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (!vcpu->mmio_is_write) { 14718c2ecf20Sopenharmony_ci emulated = kvmppc_handle_vsx_load(vcpu, vcpu->arch.io_gpr, 14728c2ecf20Sopenharmony_ci run->mmio.len, 1, vcpu->arch.mmio_sign_extend); 14738c2ecf20Sopenharmony_ci } else { 14748c2ecf20Sopenharmony_ci emulated = kvmppc_handle_vsx_store(vcpu, 14758c2ecf20Sopenharmony_ci vcpu->arch.io_gpr, run->mmio.len, 1); 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci switch (emulated) { 14798c2ecf20Sopenharmony_ci case EMULATE_DO_MMIO: 14808c2ecf20Sopenharmony_ci run->exit_reason = KVM_EXIT_MMIO; 14818c2ecf20Sopenharmony_ci r = RESUME_HOST; 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci case EMULATE_FAIL: 14848c2ecf20Sopenharmony_ci pr_info("KVM: MMIO emulation failed (VSX repeat)\n"); 14858c2ecf20Sopenharmony_ci run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 14868c2ecf20Sopenharmony_ci run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; 14878c2ecf20Sopenharmony_ci r = RESUME_HOST; 14888c2ecf20Sopenharmony_ci break; 14898c2ecf20Sopenharmony_ci default: 14908c2ecf20Sopenharmony_ci r = RESUME_GUEST; 14918c2ecf20Sopenharmony_ci break; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci return r; 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */ 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC 14988c2ecf20Sopenharmony_ciint kvmppc_handle_vmx_load(struct kvm_vcpu *vcpu, 14998c2ecf20Sopenharmony_ci unsigned int rt, unsigned int bytes, int is_default_endian) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci enum emulation_result emulated = EMULATE_DONE; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_vmx_copy_nums > 2) 15048c2ecf20Sopenharmony_ci return EMULATE_FAIL; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci while (vcpu->arch.mmio_vmx_copy_nums) { 15078c2ecf20Sopenharmony_ci emulated = __kvmppc_handle_load(vcpu, rt, bytes, 15088c2ecf20Sopenharmony_ci is_default_endian, 0); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci if (emulated != EMULATE_DONE) 15118c2ecf20Sopenharmony_ci break; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci vcpu->arch.paddr_accessed += vcpu->run->mmio.len; 15148c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_copy_nums--; 15158c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_offset++; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci return emulated; 15198c2ecf20Sopenharmony_ci} 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_cistatic int kvmppc_get_vmx_dword(struct kvm_vcpu *vcpu, int index, u64 *val) 15228c2ecf20Sopenharmony_ci{ 15238c2ecf20Sopenharmony_ci union kvmppc_one_reg reg; 15248c2ecf20Sopenharmony_ci int vmx_offset = 0; 15258c2ecf20Sopenharmony_ci int result = 0; 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci vmx_offset = 15288c2ecf20Sopenharmony_ci kvmppc_get_vmx_dword_offset(vcpu, vcpu->arch.mmio_vmx_offset); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (vmx_offset == -1) 15318c2ecf20Sopenharmony_ci return -1; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, index); 15348c2ecf20Sopenharmony_ci *val = reg.vsxval[vmx_offset]; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci return result; 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_cistatic int kvmppc_get_vmx_word(struct kvm_vcpu *vcpu, int index, u64 *val) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci union kvmppc_one_reg reg; 15428c2ecf20Sopenharmony_ci int vmx_offset = 0; 15438c2ecf20Sopenharmony_ci int result = 0; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci vmx_offset = 15468c2ecf20Sopenharmony_ci kvmppc_get_vmx_word_offset(vcpu, vcpu->arch.mmio_vmx_offset); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci if (vmx_offset == -1) 15498c2ecf20Sopenharmony_ci return -1; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, index); 15528c2ecf20Sopenharmony_ci *val = reg.vsx32val[vmx_offset]; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci return result; 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic int kvmppc_get_vmx_hword(struct kvm_vcpu *vcpu, int index, u64 *val) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci union kvmppc_one_reg reg; 15608c2ecf20Sopenharmony_ci int vmx_offset = 0; 15618c2ecf20Sopenharmony_ci int result = 0; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci vmx_offset = 15648c2ecf20Sopenharmony_ci kvmppc_get_vmx_hword_offset(vcpu, vcpu->arch.mmio_vmx_offset); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci if (vmx_offset == -1) 15678c2ecf20Sopenharmony_ci return -1; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, index); 15708c2ecf20Sopenharmony_ci *val = reg.vsx16val[vmx_offset]; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci return result; 15738c2ecf20Sopenharmony_ci} 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_cistatic int kvmppc_get_vmx_byte(struct kvm_vcpu *vcpu, int index, u64 *val) 15768c2ecf20Sopenharmony_ci{ 15778c2ecf20Sopenharmony_ci union kvmppc_one_reg reg; 15788c2ecf20Sopenharmony_ci int vmx_offset = 0; 15798c2ecf20Sopenharmony_ci int result = 0; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci vmx_offset = 15828c2ecf20Sopenharmony_ci kvmppc_get_vmx_byte_offset(vcpu, vcpu->arch.mmio_vmx_offset); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci if (vmx_offset == -1) 15858c2ecf20Sopenharmony_ci return -1; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci reg.vval = VCPU_VSX_VR(vcpu, index); 15888c2ecf20Sopenharmony_ci *val = reg.vsx8val[vmx_offset]; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci return result; 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ciint kvmppc_handle_vmx_store(struct kvm_vcpu *vcpu, 15948c2ecf20Sopenharmony_ci unsigned int rs, unsigned int bytes, int is_default_endian) 15958c2ecf20Sopenharmony_ci{ 15968c2ecf20Sopenharmony_ci u64 val = 0; 15978c2ecf20Sopenharmony_ci unsigned int index = rs & KVM_MMIO_REG_MASK; 15988c2ecf20Sopenharmony_ci enum emulation_result emulated = EMULATE_DONE; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_vmx_copy_nums > 2) 16018c2ecf20Sopenharmony_ci return EMULATE_FAIL; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci vcpu->arch.io_gpr = rs; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci while (vcpu->arch.mmio_vmx_copy_nums) { 16068c2ecf20Sopenharmony_ci switch (vcpu->arch.mmio_copy_type) { 16078c2ecf20Sopenharmony_ci case KVMPPC_VMX_COPY_DWORD: 16088c2ecf20Sopenharmony_ci if (kvmppc_get_vmx_dword(vcpu, index, &val) == -1) 16098c2ecf20Sopenharmony_ci return EMULATE_FAIL; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci break; 16128c2ecf20Sopenharmony_ci case KVMPPC_VMX_COPY_WORD: 16138c2ecf20Sopenharmony_ci if (kvmppc_get_vmx_word(vcpu, index, &val) == -1) 16148c2ecf20Sopenharmony_ci return EMULATE_FAIL; 16158c2ecf20Sopenharmony_ci break; 16168c2ecf20Sopenharmony_ci case KVMPPC_VMX_COPY_HWORD: 16178c2ecf20Sopenharmony_ci if (kvmppc_get_vmx_hword(vcpu, index, &val) == -1) 16188c2ecf20Sopenharmony_ci return EMULATE_FAIL; 16198c2ecf20Sopenharmony_ci break; 16208c2ecf20Sopenharmony_ci case KVMPPC_VMX_COPY_BYTE: 16218c2ecf20Sopenharmony_ci if (kvmppc_get_vmx_byte(vcpu, index, &val) == -1) 16228c2ecf20Sopenharmony_ci return EMULATE_FAIL; 16238c2ecf20Sopenharmony_ci break; 16248c2ecf20Sopenharmony_ci default: 16258c2ecf20Sopenharmony_ci return EMULATE_FAIL; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci emulated = kvmppc_handle_store(vcpu, val, bytes, 16298c2ecf20Sopenharmony_ci is_default_endian); 16308c2ecf20Sopenharmony_ci if (emulated != EMULATE_DONE) 16318c2ecf20Sopenharmony_ci break; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci vcpu->arch.paddr_accessed += vcpu->run->mmio.len; 16348c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_copy_nums--; 16358c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_offset++; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci return emulated; 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_cistatic int kvmppc_emulate_mmio_vmx_loadstore(struct kvm_vcpu *vcpu) 16428c2ecf20Sopenharmony_ci{ 16438c2ecf20Sopenharmony_ci struct kvm_run *run = vcpu->run; 16448c2ecf20Sopenharmony_ci enum emulation_result emulated = EMULATE_FAIL; 16458c2ecf20Sopenharmony_ci int r; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci vcpu->arch.paddr_accessed += run->mmio.len; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (!vcpu->mmio_is_write) { 16508c2ecf20Sopenharmony_ci emulated = kvmppc_handle_vmx_load(vcpu, 16518c2ecf20Sopenharmony_ci vcpu->arch.io_gpr, run->mmio.len, 1); 16528c2ecf20Sopenharmony_ci } else { 16538c2ecf20Sopenharmony_ci emulated = kvmppc_handle_vmx_store(vcpu, 16548c2ecf20Sopenharmony_ci vcpu->arch.io_gpr, run->mmio.len, 1); 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci switch (emulated) { 16588c2ecf20Sopenharmony_ci case EMULATE_DO_MMIO: 16598c2ecf20Sopenharmony_ci run->exit_reason = KVM_EXIT_MMIO; 16608c2ecf20Sopenharmony_ci r = RESUME_HOST; 16618c2ecf20Sopenharmony_ci break; 16628c2ecf20Sopenharmony_ci case EMULATE_FAIL: 16638c2ecf20Sopenharmony_ci pr_info("KVM: MMIO emulation failed (VMX repeat)\n"); 16648c2ecf20Sopenharmony_ci run->exit_reason = KVM_EXIT_INTERNAL_ERROR; 16658c2ecf20Sopenharmony_ci run->internal.suberror = KVM_INTERNAL_ERROR_EMULATION; 16668c2ecf20Sopenharmony_ci r = RESUME_HOST; 16678c2ecf20Sopenharmony_ci break; 16688c2ecf20Sopenharmony_ci default: 16698c2ecf20Sopenharmony_ci r = RESUME_GUEST; 16708c2ecf20Sopenharmony_ci break; 16718c2ecf20Sopenharmony_ci } 16728c2ecf20Sopenharmony_ci return r; 16738c2ecf20Sopenharmony_ci} 16748c2ecf20Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ciint kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci int r = 0; 16798c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 16808c2ecf20Sopenharmony_ci int size; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci size = one_reg_size(reg->id); 16838c2ecf20Sopenharmony_ci if (size > sizeof(val)) 16848c2ecf20Sopenharmony_ci return -EINVAL; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci r = kvmppc_get_one_reg(vcpu, reg->id, &val); 16878c2ecf20Sopenharmony_ci if (r == -EINVAL) { 16888c2ecf20Sopenharmony_ci r = 0; 16898c2ecf20Sopenharmony_ci switch (reg->id) { 16908c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC 16918c2ecf20Sopenharmony_ci case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: 16928c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 16938c2ecf20Sopenharmony_ci r = -ENXIO; 16948c2ecf20Sopenharmony_ci break; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0]; 16978c2ecf20Sopenharmony_ci break; 16988c2ecf20Sopenharmony_ci case KVM_REG_PPC_VSCR: 16998c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 17008c2ecf20Sopenharmony_ci r = -ENXIO; 17018c2ecf20Sopenharmony_ci break; 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]); 17048c2ecf20Sopenharmony_ci break; 17058c2ecf20Sopenharmony_ci case KVM_REG_PPC_VRSAVE: 17068c2ecf20Sopenharmony_ci val = get_reg_val(reg->id, vcpu->arch.vrsave); 17078c2ecf20Sopenharmony_ci break; 17088c2ecf20Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 17098c2ecf20Sopenharmony_ci default: 17108c2ecf20Sopenharmony_ci r = -EINVAL; 17118c2ecf20Sopenharmony_ci break; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (r) 17168c2ecf20Sopenharmony_ci return r; 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci if (copy_to_user((char __user *)(unsigned long)reg->addr, &val, size)) 17198c2ecf20Sopenharmony_ci r = -EFAULT; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci return r; 17228c2ecf20Sopenharmony_ci} 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ciint kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg) 17258c2ecf20Sopenharmony_ci{ 17268c2ecf20Sopenharmony_ci int r; 17278c2ecf20Sopenharmony_ci union kvmppc_one_reg val; 17288c2ecf20Sopenharmony_ci int size; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci size = one_reg_size(reg->id); 17318c2ecf20Sopenharmony_ci if (size > sizeof(val)) 17328c2ecf20Sopenharmony_ci return -EINVAL; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci if (copy_from_user(&val, (char __user *)(unsigned long)reg->addr, size)) 17358c2ecf20Sopenharmony_ci return -EFAULT; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci r = kvmppc_set_one_reg(vcpu, reg->id, &val); 17388c2ecf20Sopenharmony_ci if (r == -EINVAL) { 17398c2ecf20Sopenharmony_ci r = 0; 17408c2ecf20Sopenharmony_ci switch (reg->id) { 17418c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC 17428c2ecf20Sopenharmony_ci case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31: 17438c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 17448c2ecf20Sopenharmony_ci r = -ENXIO; 17458c2ecf20Sopenharmony_ci break; 17468c2ecf20Sopenharmony_ci } 17478c2ecf20Sopenharmony_ci vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval; 17488c2ecf20Sopenharmony_ci break; 17498c2ecf20Sopenharmony_ci case KVM_REG_PPC_VSCR: 17508c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 17518c2ecf20Sopenharmony_ci r = -ENXIO; 17528c2ecf20Sopenharmony_ci break; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val); 17558c2ecf20Sopenharmony_ci break; 17568c2ecf20Sopenharmony_ci case KVM_REG_PPC_VRSAVE: 17578c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_ALTIVEC)) { 17588c2ecf20Sopenharmony_ci r = -ENXIO; 17598c2ecf20Sopenharmony_ci break; 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci vcpu->arch.vrsave = set_reg_val(reg->id, val); 17628c2ecf20Sopenharmony_ci break; 17638c2ecf20Sopenharmony_ci#endif /* CONFIG_ALTIVEC */ 17648c2ecf20Sopenharmony_ci default: 17658c2ecf20Sopenharmony_ci r = -EINVAL; 17668c2ecf20Sopenharmony_ci break; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci return r; 17718c2ecf20Sopenharmony_ci} 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) 17748c2ecf20Sopenharmony_ci{ 17758c2ecf20Sopenharmony_ci struct kvm_run *run = vcpu->run; 17768c2ecf20Sopenharmony_ci int r; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci vcpu_load(vcpu); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (vcpu->mmio_needed) { 17818c2ecf20Sopenharmony_ci vcpu->mmio_needed = 0; 17828c2ecf20Sopenharmony_ci if (!vcpu->mmio_is_write) 17838c2ecf20Sopenharmony_ci kvmppc_complete_mmio_load(vcpu); 17848c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX 17858c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_vsx_copy_nums > 0) { 17868c2ecf20Sopenharmony_ci vcpu->arch.mmio_vsx_copy_nums--; 17878c2ecf20Sopenharmony_ci vcpu->arch.mmio_vsx_offset++; 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_vsx_copy_nums > 0) { 17918c2ecf20Sopenharmony_ci r = kvmppc_emulate_mmio_vsx_loadstore(vcpu); 17928c2ecf20Sopenharmony_ci if (r == RESUME_HOST) { 17938c2ecf20Sopenharmony_ci vcpu->mmio_needed = 1; 17948c2ecf20Sopenharmony_ci goto out; 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci#endif 17988c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC 17998c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_vmx_copy_nums > 0) { 18008c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_copy_nums--; 18018c2ecf20Sopenharmony_ci vcpu->arch.mmio_vmx_offset++; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci if (vcpu->arch.mmio_vmx_copy_nums > 0) { 18058c2ecf20Sopenharmony_ci r = kvmppc_emulate_mmio_vmx_loadstore(vcpu); 18068c2ecf20Sopenharmony_ci if (r == RESUME_HOST) { 18078c2ecf20Sopenharmony_ci vcpu->mmio_needed = 1; 18088c2ecf20Sopenharmony_ci goto out; 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci#endif 18128c2ecf20Sopenharmony_ci } else if (vcpu->arch.osi_needed) { 18138c2ecf20Sopenharmony_ci u64 *gprs = run->osi.gprs; 18148c2ecf20Sopenharmony_ci int i; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) 18178c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, i, gprs[i]); 18188c2ecf20Sopenharmony_ci vcpu->arch.osi_needed = 0; 18198c2ecf20Sopenharmony_ci } else if (vcpu->arch.hcall_needed) { 18208c2ecf20Sopenharmony_ci int i; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, 3, run->papr_hcall.ret); 18238c2ecf20Sopenharmony_ci for (i = 0; i < 9; ++i) 18248c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, 4 + i, run->papr_hcall.args[i]); 18258c2ecf20Sopenharmony_ci vcpu->arch.hcall_needed = 0; 18268c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOKE 18278c2ecf20Sopenharmony_ci } else if (vcpu->arch.epr_needed) { 18288c2ecf20Sopenharmony_ci kvmppc_set_epr(vcpu, run->epr.epr); 18298c2ecf20Sopenharmony_ci vcpu->arch.epr_needed = 0; 18308c2ecf20Sopenharmony_ci#endif 18318c2ecf20Sopenharmony_ci } 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci kvm_sigset_activate(vcpu); 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (run->immediate_exit) 18368c2ecf20Sopenharmony_ci r = -EINTR; 18378c2ecf20Sopenharmony_ci else 18388c2ecf20Sopenharmony_ci r = kvmppc_vcpu_run(vcpu); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci kvm_sigset_deactivate(vcpu); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC 18438c2ecf20Sopenharmony_ciout: 18448c2ecf20Sopenharmony_ci#endif 18458c2ecf20Sopenharmony_ci vcpu_put(vcpu); 18468c2ecf20Sopenharmony_ci return r; 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ciint kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) 18508c2ecf20Sopenharmony_ci{ 18518c2ecf20Sopenharmony_ci if (irq->irq == KVM_INTERRUPT_UNSET) { 18528c2ecf20Sopenharmony_ci kvmppc_core_dequeue_external(vcpu); 18538c2ecf20Sopenharmony_ci return 0; 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci kvmppc_core_queue_external(vcpu, irq); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci kvm_vcpu_kick(vcpu); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci return 0; 18618c2ecf20Sopenharmony_ci} 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_cistatic int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, 18648c2ecf20Sopenharmony_ci struct kvm_enable_cap *cap) 18658c2ecf20Sopenharmony_ci{ 18668c2ecf20Sopenharmony_ci int r; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (cap->flags) 18698c2ecf20Sopenharmony_ci return -EINVAL; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci switch (cap->cap) { 18728c2ecf20Sopenharmony_ci case KVM_CAP_PPC_OSI: 18738c2ecf20Sopenharmony_ci r = 0; 18748c2ecf20Sopenharmony_ci vcpu->arch.osi_enabled = true; 18758c2ecf20Sopenharmony_ci break; 18768c2ecf20Sopenharmony_ci case KVM_CAP_PPC_PAPR: 18778c2ecf20Sopenharmony_ci r = 0; 18788c2ecf20Sopenharmony_ci vcpu->arch.papr_enabled = true; 18798c2ecf20Sopenharmony_ci break; 18808c2ecf20Sopenharmony_ci case KVM_CAP_PPC_EPR: 18818c2ecf20Sopenharmony_ci r = 0; 18828c2ecf20Sopenharmony_ci if (cap->args[0]) 18838c2ecf20Sopenharmony_ci vcpu->arch.epr_flags |= KVMPPC_EPR_USER; 18848c2ecf20Sopenharmony_ci else 18858c2ecf20Sopenharmony_ci vcpu->arch.epr_flags &= ~KVMPPC_EPR_USER; 18868c2ecf20Sopenharmony_ci break; 18878c2ecf20Sopenharmony_ci#ifdef CONFIG_BOOKE 18888c2ecf20Sopenharmony_ci case KVM_CAP_PPC_BOOKE_WATCHDOG: 18898c2ecf20Sopenharmony_ci r = 0; 18908c2ecf20Sopenharmony_ci vcpu->arch.watchdog_enabled = true; 18918c2ecf20Sopenharmony_ci break; 18928c2ecf20Sopenharmony_ci#endif 18938c2ecf20Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) 18948c2ecf20Sopenharmony_ci case KVM_CAP_SW_TLB: { 18958c2ecf20Sopenharmony_ci struct kvm_config_tlb cfg; 18968c2ecf20Sopenharmony_ci void __user *user_ptr = (void __user *)(uintptr_t)cap->args[0]; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci r = -EFAULT; 18998c2ecf20Sopenharmony_ci if (copy_from_user(&cfg, user_ptr, sizeof(cfg))) 19008c2ecf20Sopenharmony_ci break; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci r = kvm_vcpu_ioctl_config_tlb(vcpu, &cfg); 19038c2ecf20Sopenharmony_ci break; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci#endif 19068c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_MPIC 19078c2ecf20Sopenharmony_ci case KVM_CAP_IRQ_MPIC: { 19088c2ecf20Sopenharmony_ci struct fd f; 19098c2ecf20Sopenharmony_ci struct kvm_device *dev; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci r = -EBADF; 19128c2ecf20Sopenharmony_ci f = fdget(cap->args[0]); 19138c2ecf20Sopenharmony_ci if (!f.file) 19148c2ecf20Sopenharmony_ci break; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci r = -EPERM; 19178c2ecf20Sopenharmony_ci dev = kvm_device_from_filp(f.file); 19188c2ecf20Sopenharmony_ci if (dev) 19198c2ecf20Sopenharmony_ci r = kvmppc_mpic_connect_vcpu(dev, vcpu, cap->args[1]); 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci fdput(f); 19228c2ecf20Sopenharmony_ci break; 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci#endif 19258c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_XICS 19268c2ecf20Sopenharmony_ci case KVM_CAP_IRQ_XICS: { 19278c2ecf20Sopenharmony_ci struct fd f; 19288c2ecf20Sopenharmony_ci struct kvm_device *dev; 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci r = -EBADF; 19318c2ecf20Sopenharmony_ci f = fdget(cap->args[0]); 19328c2ecf20Sopenharmony_ci if (!f.file) 19338c2ecf20Sopenharmony_ci break; 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci r = -EPERM; 19368c2ecf20Sopenharmony_ci dev = kvm_device_from_filp(f.file); 19378c2ecf20Sopenharmony_ci if (dev) { 19388c2ecf20Sopenharmony_ci if (xics_on_xive()) 19398c2ecf20Sopenharmony_ci r = kvmppc_xive_connect_vcpu(dev, vcpu, cap->args[1]); 19408c2ecf20Sopenharmony_ci else 19418c2ecf20Sopenharmony_ci r = kvmppc_xics_connect_vcpu(dev, vcpu, cap->args[1]); 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci fdput(f); 19458c2ecf20Sopenharmony_ci break; 19468c2ecf20Sopenharmony_ci } 19478c2ecf20Sopenharmony_ci#endif /* CONFIG_KVM_XICS */ 19488c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_XIVE 19498c2ecf20Sopenharmony_ci case KVM_CAP_PPC_IRQ_XIVE: { 19508c2ecf20Sopenharmony_ci struct fd f; 19518c2ecf20Sopenharmony_ci struct kvm_device *dev; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci r = -EBADF; 19548c2ecf20Sopenharmony_ci f = fdget(cap->args[0]); 19558c2ecf20Sopenharmony_ci if (!f.file) 19568c2ecf20Sopenharmony_ci break; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci r = -ENXIO; 19598c2ecf20Sopenharmony_ci if (!xive_enabled()) 19608c2ecf20Sopenharmony_ci break; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci r = -EPERM; 19638c2ecf20Sopenharmony_ci dev = kvm_device_from_filp(f.file); 19648c2ecf20Sopenharmony_ci if (dev) 19658c2ecf20Sopenharmony_ci r = kvmppc_xive_native_connect_vcpu(dev, vcpu, 19668c2ecf20Sopenharmony_ci cap->args[1]); 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci fdput(f); 19698c2ecf20Sopenharmony_ci break; 19708c2ecf20Sopenharmony_ci } 19718c2ecf20Sopenharmony_ci#endif /* CONFIG_KVM_XIVE */ 19728c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 19738c2ecf20Sopenharmony_ci case KVM_CAP_PPC_FWNMI: 19748c2ecf20Sopenharmony_ci r = -EINVAL; 19758c2ecf20Sopenharmony_ci if (!is_kvmppc_hv_enabled(vcpu->kvm)) 19768c2ecf20Sopenharmony_ci break; 19778c2ecf20Sopenharmony_ci r = 0; 19788c2ecf20Sopenharmony_ci vcpu->kvm->arch.fwnmi_enabled = true; 19798c2ecf20Sopenharmony_ci break; 19808c2ecf20Sopenharmony_ci#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ 19818c2ecf20Sopenharmony_ci default: 19828c2ecf20Sopenharmony_ci r = -EINVAL; 19838c2ecf20Sopenharmony_ci break; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (!r) 19878c2ecf20Sopenharmony_ci r = kvmppc_sanity_check(vcpu); 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci return r; 19908c2ecf20Sopenharmony_ci} 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_cibool kvm_arch_intc_initialized(struct kvm *kvm) 19938c2ecf20Sopenharmony_ci{ 19948c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_MPIC 19958c2ecf20Sopenharmony_ci if (kvm->arch.mpic) 19968c2ecf20Sopenharmony_ci return true; 19978c2ecf20Sopenharmony_ci#endif 19988c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_XICS 19998c2ecf20Sopenharmony_ci if (kvm->arch.xics || kvm->arch.xive) 20008c2ecf20Sopenharmony_ci return true; 20018c2ecf20Sopenharmony_ci#endif 20028c2ecf20Sopenharmony_ci return false; 20038c2ecf20Sopenharmony_ci} 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, 20068c2ecf20Sopenharmony_ci struct kvm_mp_state *mp_state) 20078c2ecf20Sopenharmony_ci{ 20088c2ecf20Sopenharmony_ci return -EINVAL; 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ciint kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, 20128c2ecf20Sopenharmony_ci struct kvm_mp_state *mp_state) 20138c2ecf20Sopenharmony_ci{ 20148c2ecf20Sopenharmony_ci return -EINVAL; 20158c2ecf20Sopenharmony_ci} 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_cilong kvm_arch_vcpu_async_ioctl(struct file *filp, 20188c2ecf20Sopenharmony_ci unsigned int ioctl, unsigned long arg) 20198c2ecf20Sopenharmony_ci{ 20208c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = filp->private_data; 20218c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci if (ioctl == KVM_INTERRUPT) { 20248c2ecf20Sopenharmony_ci struct kvm_interrupt irq; 20258c2ecf20Sopenharmony_ci if (copy_from_user(&irq, argp, sizeof(irq))) 20268c2ecf20Sopenharmony_ci return -EFAULT; 20278c2ecf20Sopenharmony_ci return kvm_vcpu_ioctl_interrupt(vcpu, &irq); 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 20308c2ecf20Sopenharmony_ci} 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_cilong kvm_arch_vcpu_ioctl(struct file *filp, 20338c2ecf20Sopenharmony_ci unsigned int ioctl, unsigned long arg) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci struct kvm_vcpu *vcpu = filp->private_data; 20368c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 20378c2ecf20Sopenharmony_ci long r; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci switch (ioctl) { 20408c2ecf20Sopenharmony_ci case KVM_ENABLE_CAP: 20418c2ecf20Sopenharmony_ci { 20428c2ecf20Sopenharmony_ci struct kvm_enable_cap cap; 20438c2ecf20Sopenharmony_ci r = -EFAULT; 20448c2ecf20Sopenharmony_ci if (copy_from_user(&cap, argp, sizeof(cap))) 20458c2ecf20Sopenharmony_ci goto out; 20468c2ecf20Sopenharmony_ci vcpu_load(vcpu); 20478c2ecf20Sopenharmony_ci r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); 20488c2ecf20Sopenharmony_ci vcpu_put(vcpu); 20498c2ecf20Sopenharmony_ci break; 20508c2ecf20Sopenharmony_ci } 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci case KVM_SET_ONE_REG: 20538c2ecf20Sopenharmony_ci case KVM_GET_ONE_REG: 20548c2ecf20Sopenharmony_ci { 20558c2ecf20Sopenharmony_ci struct kvm_one_reg reg; 20568c2ecf20Sopenharmony_ci r = -EFAULT; 20578c2ecf20Sopenharmony_ci if (copy_from_user(®, argp, sizeof(reg))) 20588c2ecf20Sopenharmony_ci goto out; 20598c2ecf20Sopenharmony_ci if (ioctl == KVM_SET_ONE_REG) 20608c2ecf20Sopenharmony_ci r = kvm_vcpu_ioctl_set_one_reg(vcpu, ®); 20618c2ecf20Sopenharmony_ci else 20628c2ecf20Sopenharmony_ci r = kvm_vcpu_ioctl_get_one_reg(vcpu, ®); 20638c2ecf20Sopenharmony_ci break; 20648c2ecf20Sopenharmony_ci } 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC) 20678c2ecf20Sopenharmony_ci case KVM_DIRTY_TLB: { 20688c2ecf20Sopenharmony_ci struct kvm_dirty_tlb dirty; 20698c2ecf20Sopenharmony_ci r = -EFAULT; 20708c2ecf20Sopenharmony_ci if (copy_from_user(&dirty, argp, sizeof(dirty))) 20718c2ecf20Sopenharmony_ci goto out; 20728c2ecf20Sopenharmony_ci vcpu_load(vcpu); 20738c2ecf20Sopenharmony_ci r = kvm_vcpu_ioctl_dirty_tlb(vcpu, &dirty); 20748c2ecf20Sopenharmony_ci vcpu_put(vcpu); 20758c2ecf20Sopenharmony_ci break; 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci#endif 20788c2ecf20Sopenharmony_ci default: 20798c2ecf20Sopenharmony_ci r = -EINVAL; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ciout: 20838c2ecf20Sopenharmony_ci return r; 20848c2ecf20Sopenharmony_ci} 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_civm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) 20878c2ecf20Sopenharmony_ci{ 20888c2ecf20Sopenharmony_ci return VM_FAULT_SIGBUS; 20898c2ecf20Sopenharmony_ci} 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_cistatic int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo) 20928c2ecf20Sopenharmony_ci{ 20938c2ecf20Sopenharmony_ci u32 inst_nop = 0x60000000; 20948c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOKE_HV 20958c2ecf20Sopenharmony_ci u32 inst_sc1 = 0x44000022; 20968c2ecf20Sopenharmony_ci pvinfo->hcall[0] = cpu_to_be32(inst_sc1); 20978c2ecf20Sopenharmony_ci pvinfo->hcall[1] = cpu_to_be32(inst_nop); 20988c2ecf20Sopenharmony_ci pvinfo->hcall[2] = cpu_to_be32(inst_nop); 20998c2ecf20Sopenharmony_ci pvinfo->hcall[3] = cpu_to_be32(inst_nop); 21008c2ecf20Sopenharmony_ci#else 21018c2ecf20Sopenharmony_ci u32 inst_lis = 0x3c000000; 21028c2ecf20Sopenharmony_ci u32 inst_ori = 0x60000000; 21038c2ecf20Sopenharmony_ci u32 inst_sc = 0x44000002; 21048c2ecf20Sopenharmony_ci u32 inst_imm_mask = 0xffff; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci /* 21078c2ecf20Sopenharmony_ci * The hypercall to get into KVM from within guest context is as 21088c2ecf20Sopenharmony_ci * follows: 21098c2ecf20Sopenharmony_ci * 21108c2ecf20Sopenharmony_ci * lis r0, r0, KVM_SC_MAGIC_R0@h 21118c2ecf20Sopenharmony_ci * ori r0, KVM_SC_MAGIC_R0@l 21128c2ecf20Sopenharmony_ci * sc 21138c2ecf20Sopenharmony_ci * nop 21148c2ecf20Sopenharmony_ci */ 21158c2ecf20Sopenharmony_ci pvinfo->hcall[0] = cpu_to_be32(inst_lis | ((KVM_SC_MAGIC_R0 >> 16) & inst_imm_mask)); 21168c2ecf20Sopenharmony_ci pvinfo->hcall[1] = cpu_to_be32(inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask)); 21178c2ecf20Sopenharmony_ci pvinfo->hcall[2] = cpu_to_be32(inst_sc); 21188c2ecf20Sopenharmony_ci pvinfo->hcall[3] = cpu_to_be32(inst_nop); 21198c2ecf20Sopenharmony_ci#endif 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci pvinfo->flags = KVM_PPC_PVINFO_FLAGS_EV_IDLE; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci return 0; 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ciint kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, 21278c2ecf20Sopenharmony_ci bool line_status) 21288c2ecf20Sopenharmony_ci{ 21298c2ecf20Sopenharmony_ci if (!irqchip_in_kernel(kvm)) 21308c2ecf20Sopenharmony_ci return -ENXIO; 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID, 21338c2ecf20Sopenharmony_ci irq_event->irq, irq_event->level, 21348c2ecf20Sopenharmony_ci line_status); 21358c2ecf20Sopenharmony_ci return 0; 21368c2ecf20Sopenharmony_ci} 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ciint kvm_vm_ioctl_enable_cap(struct kvm *kvm, 21408c2ecf20Sopenharmony_ci struct kvm_enable_cap *cap) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci int r; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci if (cap->flags) 21458c2ecf20Sopenharmony_ci return -EINVAL; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci switch (cap->cap) { 21488c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_64_HANDLER 21498c2ecf20Sopenharmony_ci case KVM_CAP_PPC_ENABLE_HCALL: { 21508c2ecf20Sopenharmony_ci unsigned long hcall = cap->args[0]; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci r = -EINVAL; 21538c2ecf20Sopenharmony_ci if (hcall > MAX_HCALL_OPCODE || (hcall & 3) || 21548c2ecf20Sopenharmony_ci cap->args[1] > 1) 21558c2ecf20Sopenharmony_ci break; 21568c2ecf20Sopenharmony_ci if (!kvmppc_book3s_hcall_implemented(kvm, hcall)) 21578c2ecf20Sopenharmony_ci break; 21588c2ecf20Sopenharmony_ci if (cap->args[1]) 21598c2ecf20Sopenharmony_ci set_bit(hcall / 4, kvm->arch.enabled_hcalls); 21608c2ecf20Sopenharmony_ci else 21618c2ecf20Sopenharmony_ci clear_bit(hcall / 4, kvm->arch.enabled_hcalls); 21628c2ecf20Sopenharmony_ci r = 0; 21638c2ecf20Sopenharmony_ci break; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci case KVM_CAP_PPC_SMT: { 21668c2ecf20Sopenharmony_ci unsigned long mode = cap->args[0]; 21678c2ecf20Sopenharmony_ci unsigned long flags = cap->args[1]; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci r = -EINVAL; 21708c2ecf20Sopenharmony_ci if (kvm->arch.kvm_ops->set_smt_mode) 21718c2ecf20Sopenharmony_ci r = kvm->arch.kvm_ops->set_smt_mode(kvm, mode, flags); 21728c2ecf20Sopenharmony_ci break; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci case KVM_CAP_PPC_NESTED_HV: 21768c2ecf20Sopenharmony_ci r = -EINVAL; 21778c2ecf20Sopenharmony_ci if (!is_kvmppc_hv_enabled(kvm) || 21788c2ecf20Sopenharmony_ci !kvm->arch.kvm_ops->enable_nested) 21798c2ecf20Sopenharmony_ci break; 21808c2ecf20Sopenharmony_ci r = kvm->arch.kvm_ops->enable_nested(kvm); 21818c2ecf20Sopenharmony_ci break; 21828c2ecf20Sopenharmony_ci#endif 21838c2ecf20Sopenharmony_ci#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE) 21848c2ecf20Sopenharmony_ci case KVM_CAP_PPC_SECURE_GUEST: 21858c2ecf20Sopenharmony_ci r = -EINVAL; 21868c2ecf20Sopenharmony_ci if (!is_kvmppc_hv_enabled(kvm) || !kvm->arch.kvm_ops->enable_svm) 21878c2ecf20Sopenharmony_ci break; 21888c2ecf20Sopenharmony_ci r = kvm->arch.kvm_ops->enable_svm(kvm); 21898c2ecf20Sopenharmony_ci break; 21908c2ecf20Sopenharmony_ci#endif 21918c2ecf20Sopenharmony_ci default: 21928c2ecf20Sopenharmony_ci r = -EINVAL; 21938c2ecf20Sopenharmony_ci break; 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci return r; 21978c2ecf20Sopenharmony_ci} 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 22008c2ecf20Sopenharmony_ci/* 22018c2ecf20Sopenharmony_ci * These functions check whether the underlying hardware is safe 22028c2ecf20Sopenharmony_ci * against attacks based on observing the effects of speculatively 22038c2ecf20Sopenharmony_ci * executed instructions, and whether it supplies instructions for 22048c2ecf20Sopenharmony_ci * use in workarounds. The information comes from firmware, either 22058c2ecf20Sopenharmony_ci * via the device tree on powernv platforms or from an hcall on 22068c2ecf20Sopenharmony_ci * pseries platforms. 22078c2ecf20Sopenharmony_ci */ 22088c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 22098c2ecf20Sopenharmony_cistatic int pseries_get_cpu_char(struct kvm_ppc_cpu_char *cp) 22108c2ecf20Sopenharmony_ci{ 22118c2ecf20Sopenharmony_ci struct h_cpu_char_result c; 22128c2ecf20Sopenharmony_ci unsigned long rc; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (!machine_is(pseries)) 22158c2ecf20Sopenharmony_ci return -ENOTTY; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci rc = plpar_get_cpu_characteristics(&c); 22188c2ecf20Sopenharmony_ci if (rc == H_SUCCESS) { 22198c2ecf20Sopenharmony_ci cp->character = c.character; 22208c2ecf20Sopenharmony_ci cp->behaviour = c.behaviour; 22218c2ecf20Sopenharmony_ci cp->character_mask = KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 | 22228c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED | 22238c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 | 22248c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 | 22258c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV | 22268c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_BR_HINT_HONOURED | 22278c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_MTTRIG_THR_RECONF | 22288c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS | 22298c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST; 22308c2ecf20Sopenharmony_ci cp->behaviour_mask = KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY | 22318c2ecf20Sopenharmony_ci KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR | 22328c2ecf20Sopenharmony_ci KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR | 22338c2ecf20Sopenharmony_ci KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE; 22348c2ecf20Sopenharmony_ci } 22358c2ecf20Sopenharmony_ci return 0; 22368c2ecf20Sopenharmony_ci} 22378c2ecf20Sopenharmony_ci#else 22388c2ecf20Sopenharmony_cistatic int pseries_get_cpu_char(struct kvm_ppc_cpu_char *cp) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci return -ENOTTY; 22418c2ecf20Sopenharmony_ci} 22428c2ecf20Sopenharmony_ci#endif 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_cistatic inline bool have_fw_feat(struct device_node *fw_features, 22458c2ecf20Sopenharmony_ci const char *state, const char *name) 22468c2ecf20Sopenharmony_ci{ 22478c2ecf20Sopenharmony_ci struct device_node *np; 22488c2ecf20Sopenharmony_ci bool r = false; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci np = of_get_child_by_name(fw_features, name); 22518c2ecf20Sopenharmony_ci if (np) { 22528c2ecf20Sopenharmony_ci r = of_property_read_bool(np, state); 22538c2ecf20Sopenharmony_ci of_node_put(np); 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci return r; 22568c2ecf20Sopenharmony_ci} 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_cistatic int kvmppc_get_cpu_char(struct kvm_ppc_cpu_char *cp) 22598c2ecf20Sopenharmony_ci{ 22608c2ecf20Sopenharmony_ci struct device_node *np, *fw_features; 22618c2ecf20Sopenharmony_ci int r; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci memset(cp, 0, sizeof(*cp)); 22648c2ecf20Sopenharmony_ci r = pseries_get_cpu_char(cp); 22658c2ecf20Sopenharmony_ci if (r != -ENOTTY) 22668c2ecf20Sopenharmony_ci return r; 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci np = of_find_node_by_name(NULL, "ibm,opal"); 22698c2ecf20Sopenharmony_ci if (np) { 22708c2ecf20Sopenharmony_ci fw_features = of_get_child_by_name(np, "fw-features"); 22718c2ecf20Sopenharmony_ci of_node_put(np); 22728c2ecf20Sopenharmony_ci if (!fw_features) 22738c2ecf20Sopenharmony_ci return 0; 22748c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 22758c2ecf20Sopenharmony_ci "inst-spec-barrier-ori31,31,0")) 22768c2ecf20Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31; 22778c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 22788c2ecf20Sopenharmony_ci "fw-bcctrl-serialized")) 22798c2ecf20Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED; 22808c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 22818c2ecf20Sopenharmony_ci "inst-l1d-flush-ori30,30,0")) 22828c2ecf20Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30; 22838c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 22848c2ecf20Sopenharmony_ci "inst-l1d-flush-trig2")) 22858c2ecf20Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2; 22868c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 22878c2ecf20Sopenharmony_ci "fw-l1d-thread-split")) 22888c2ecf20Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV; 22898c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 22908c2ecf20Sopenharmony_ci "fw-count-cache-disabled")) 22918c2ecf20Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS; 22928c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 22938c2ecf20Sopenharmony_ci "fw-count-cache-flush-bcctr2,0,0")) 22948c2ecf20Sopenharmony_ci cp->character |= KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST; 22958c2ecf20Sopenharmony_ci cp->character_mask = KVM_PPC_CPU_CHAR_SPEC_BAR_ORI31 | 22968c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_BCCTRL_SERIALISED | 22978c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_FLUSH_ORI30 | 22988c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_FLUSH_TRIG2 | 22998c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_L1D_THREAD_PRIV | 23008c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_COUNT_CACHE_DIS | 23018c2ecf20Sopenharmony_ci KVM_PPC_CPU_CHAR_BCCTR_FLUSH_ASSIST; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 23048c2ecf20Sopenharmony_ci "speculation-policy-favor-security")) 23058c2ecf20Sopenharmony_ci cp->behaviour |= KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY; 23068c2ecf20Sopenharmony_ci if (!have_fw_feat(fw_features, "disabled", 23078c2ecf20Sopenharmony_ci "needs-l1d-flush-msr-pr-0-to-1")) 23088c2ecf20Sopenharmony_ci cp->behaviour |= KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR; 23098c2ecf20Sopenharmony_ci if (!have_fw_feat(fw_features, "disabled", 23108c2ecf20Sopenharmony_ci "needs-spec-barrier-for-bound-checks")) 23118c2ecf20Sopenharmony_ci cp->behaviour |= KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR; 23128c2ecf20Sopenharmony_ci if (have_fw_feat(fw_features, "enabled", 23138c2ecf20Sopenharmony_ci "needs-count-cache-flush-on-context-switch")) 23148c2ecf20Sopenharmony_ci cp->behaviour |= KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE; 23158c2ecf20Sopenharmony_ci cp->behaviour_mask = KVM_PPC_CPU_BEHAV_FAVOUR_SECURITY | 23168c2ecf20Sopenharmony_ci KVM_PPC_CPU_BEHAV_L1D_FLUSH_PR | 23178c2ecf20Sopenharmony_ci KVM_PPC_CPU_BEHAV_BNDS_CHK_SPEC_BAR | 23188c2ecf20Sopenharmony_ci KVM_PPC_CPU_BEHAV_FLUSH_COUNT_CACHE; 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci of_node_put(fw_features); 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci return 0; 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci#endif 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_cilong kvm_arch_vm_ioctl(struct file *filp, 23288c2ecf20Sopenharmony_ci unsigned int ioctl, unsigned long arg) 23298c2ecf20Sopenharmony_ci{ 23308c2ecf20Sopenharmony_ci struct kvm *kvm __maybe_unused = filp->private_data; 23318c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 23328c2ecf20Sopenharmony_ci long r; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci switch (ioctl) { 23358c2ecf20Sopenharmony_ci case KVM_PPC_GET_PVINFO: { 23368c2ecf20Sopenharmony_ci struct kvm_ppc_pvinfo pvinfo; 23378c2ecf20Sopenharmony_ci memset(&pvinfo, 0, sizeof(pvinfo)); 23388c2ecf20Sopenharmony_ci r = kvm_vm_ioctl_get_pvinfo(&pvinfo); 23398c2ecf20Sopenharmony_ci if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) { 23408c2ecf20Sopenharmony_ci r = -EFAULT; 23418c2ecf20Sopenharmony_ci goto out; 23428c2ecf20Sopenharmony_ci } 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci break; 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci#ifdef CONFIG_SPAPR_TCE_IOMMU 23478c2ecf20Sopenharmony_ci case KVM_CREATE_SPAPR_TCE_64: { 23488c2ecf20Sopenharmony_ci struct kvm_create_spapr_tce_64 create_tce_64; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci r = -EFAULT; 23518c2ecf20Sopenharmony_ci if (copy_from_user(&create_tce_64, argp, sizeof(create_tce_64))) 23528c2ecf20Sopenharmony_ci goto out; 23538c2ecf20Sopenharmony_ci if (create_tce_64.flags) { 23548c2ecf20Sopenharmony_ci r = -EINVAL; 23558c2ecf20Sopenharmony_ci goto out; 23568c2ecf20Sopenharmony_ci } 23578c2ecf20Sopenharmony_ci r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce_64); 23588c2ecf20Sopenharmony_ci goto out; 23598c2ecf20Sopenharmony_ci } 23608c2ecf20Sopenharmony_ci case KVM_CREATE_SPAPR_TCE: { 23618c2ecf20Sopenharmony_ci struct kvm_create_spapr_tce create_tce; 23628c2ecf20Sopenharmony_ci struct kvm_create_spapr_tce_64 create_tce_64; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci r = -EFAULT; 23658c2ecf20Sopenharmony_ci if (copy_from_user(&create_tce, argp, sizeof(create_tce))) 23668c2ecf20Sopenharmony_ci goto out; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci create_tce_64.liobn = create_tce.liobn; 23698c2ecf20Sopenharmony_ci create_tce_64.page_shift = IOMMU_PAGE_SHIFT_4K; 23708c2ecf20Sopenharmony_ci create_tce_64.offset = 0; 23718c2ecf20Sopenharmony_ci create_tce_64.size = create_tce.window_size >> 23728c2ecf20Sopenharmony_ci IOMMU_PAGE_SHIFT_4K; 23738c2ecf20Sopenharmony_ci create_tce_64.flags = 0; 23748c2ecf20Sopenharmony_ci r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce_64); 23758c2ecf20Sopenharmony_ci goto out; 23768c2ecf20Sopenharmony_ci } 23778c2ecf20Sopenharmony_ci#endif 23788c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 23798c2ecf20Sopenharmony_ci case KVM_PPC_GET_SMMU_INFO: { 23808c2ecf20Sopenharmony_ci struct kvm_ppc_smmu_info info; 23818c2ecf20Sopenharmony_ci struct kvm *kvm = filp->private_data; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 23848c2ecf20Sopenharmony_ci r = kvm->arch.kvm_ops->get_smmu_info(kvm, &info); 23858c2ecf20Sopenharmony_ci if (r >= 0 && copy_to_user(argp, &info, sizeof(info))) 23868c2ecf20Sopenharmony_ci r = -EFAULT; 23878c2ecf20Sopenharmony_ci break; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci case KVM_PPC_RTAS_DEFINE_TOKEN: { 23908c2ecf20Sopenharmony_ci struct kvm *kvm = filp->private_data; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci r = kvm_vm_ioctl_rtas_define_token(kvm, argp); 23938c2ecf20Sopenharmony_ci break; 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci case KVM_PPC_CONFIGURE_V3_MMU: { 23968c2ecf20Sopenharmony_ci struct kvm *kvm = filp->private_data; 23978c2ecf20Sopenharmony_ci struct kvm_ppc_mmuv3_cfg cfg; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci r = -EINVAL; 24008c2ecf20Sopenharmony_ci if (!kvm->arch.kvm_ops->configure_mmu) 24018c2ecf20Sopenharmony_ci goto out; 24028c2ecf20Sopenharmony_ci r = -EFAULT; 24038c2ecf20Sopenharmony_ci if (copy_from_user(&cfg, argp, sizeof(cfg))) 24048c2ecf20Sopenharmony_ci goto out; 24058c2ecf20Sopenharmony_ci r = kvm->arch.kvm_ops->configure_mmu(kvm, &cfg); 24068c2ecf20Sopenharmony_ci break; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci case KVM_PPC_GET_RMMU_INFO: { 24098c2ecf20Sopenharmony_ci struct kvm *kvm = filp->private_data; 24108c2ecf20Sopenharmony_ci struct kvm_ppc_rmmu_info info; 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci r = -EINVAL; 24138c2ecf20Sopenharmony_ci if (!kvm->arch.kvm_ops->get_rmmu_info) 24148c2ecf20Sopenharmony_ci goto out; 24158c2ecf20Sopenharmony_ci r = kvm->arch.kvm_ops->get_rmmu_info(kvm, &info); 24168c2ecf20Sopenharmony_ci if (r >= 0 && copy_to_user(argp, &info, sizeof(info))) 24178c2ecf20Sopenharmony_ci r = -EFAULT; 24188c2ecf20Sopenharmony_ci break; 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci case KVM_PPC_GET_CPU_CHAR: { 24218c2ecf20Sopenharmony_ci struct kvm_ppc_cpu_char cpuchar; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ci r = kvmppc_get_cpu_char(&cpuchar); 24248c2ecf20Sopenharmony_ci if (r >= 0 && copy_to_user(argp, &cpuchar, sizeof(cpuchar))) 24258c2ecf20Sopenharmony_ci r = -EFAULT; 24268c2ecf20Sopenharmony_ci break; 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci case KVM_PPC_SVM_OFF: { 24298c2ecf20Sopenharmony_ci struct kvm *kvm = filp->private_data; 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci r = 0; 24328c2ecf20Sopenharmony_ci if (!kvm->arch.kvm_ops->svm_off) 24338c2ecf20Sopenharmony_ci goto out; 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci r = kvm->arch.kvm_ops->svm_off(kvm); 24368c2ecf20Sopenharmony_ci break; 24378c2ecf20Sopenharmony_ci } 24388c2ecf20Sopenharmony_ci default: { 24398c2ecf20Sopenharmony_ci struct kvm *kvm = filp->private_data; 24408c2ecf20Sopenharmony_ci r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg); 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci#else /* CONFIG_PPC_BOOK3S_64 */ 24438c2ecf20Sopenharmony_ci default: 24448c2ecf20Sopenharmony_ci r = -ENOTTY; 24458c2ecf20Sopenharmony_ci#endif 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ciout: 24488c2ecf20Sopenharmony_ci return r; 24498c2ecf20Sopenharmony_ci} 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_cistatic unsigned long lpid_inuse[BITS_TO_LONGS(KVMPPC_NR_LPIDS)]; 24528c2ecf20Sopenharmony_cistatic unsigned long nr_lpids; 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_cilong kvmppc_alloc_lpid(void) 24558c2ecf20Sopenharmony_ci{ 24568c2ecf20Sopenharmony_ci long lpid; 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci do { 24598c2ecf20Sopenharmony_ci lpid = find_first_zero_bit(lpid_inuse, KVMPPC_NR_LPIDS); 24608c2ecf20Sopenharmony_ci if (lpid >= nr_lpids) { 24618c2ecf20Sopenharmony_ci pr_err("%s: No LPIDs free\n", __func__); 24628c2ecf20Sopenharmony_ci return -ENOMEM; 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci } while (test_and_set_bit(lpid, lpid_inuse)); 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci return lpid; 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_alloc_lpid); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_civoid kvmppc_claim_lpid(long lpid) 24718c2ecf20Sopenharmony_ci{ 24728c2ecf20Sopenharmony_ci set_bit(lpid, lpid_inuse); 24738c2ecf20Sopenharmony_ci} 24748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_claim_lpid); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_civoid kvmppc_free_lpid(long lpid) 24778c2ecf20Sopenharmony_ci{ 24788c2ecf20Sopenharmony_ci clear_bit(lpid, lpid_inuse); 24798c2ecf20Sopenharmony_ci} 24808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_free_lpid); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_civoid kvmppc_init_lpid(unsigned long nr_lpids_param) 24838c2ecf20Sopenharmony_ci{ 24848c2ecf20Sopenharmony_ci nr_lpids = min_t(unsigned long, KVMPPC_NR_LPIDS, nr_lpids_param); 24858c2ecf20Sopenharmony_ci memset(lpid_inuse, 0, sizeof(lpid_inuse)); 24868c2ecf20Sopenharmony_ci} 24878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kvmppc_init_lpid); 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ciint kvm_arch_init(void *opaque) 24908c2ecf20Sopenharmony_ci{ 24918c2ecf20Sopenharmony_ci return 0; 24928c2ecf20Sopenharmony_ci} 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ppc_instr); 2495