18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright SUSE Linux Products GmbH 2009 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Authors: Alexander Graf <agraf@suse.de> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/kvm_ppc.h> 108c2ecf20Sopenharmony_ci#include <asm/disassemble.h> 118c2ecf20Sopenharmony_ci#include <asm/kvm_book3s.h> 128c2ecf20Sopenharmony_ci#include <asm/reg.h> 138c2ecf20Sopenharmony_ci#include <asm/switch_to.h> 148c2ecf20Sopenharmony_ci#include <asm/time.h> 158c2ecf20Sopenharmony_ci#include <asm/tm.h> 168c2ecf20Sopenharmony_ci#include "book3s.h" 178c2ecf20Sopenharmony_ci#include <asm/asm-prototypes.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define OP_19_XOP_RFID 18 208c2ecf20Sopenharmony_ci#define OP_19_XOP_RFI 50 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define OP_31_XOP_MFMSR 83 238c2ecf20Sopenharmony_ci#define OP_31_XOP_MTMSR 146 248c2ecf20Sopenharmony_ci#define OP_31_XOP_MTMSRD 178 258c2ecf20Sopenharmony_ci#define OP_31_XOP_MTSR 210 268c2ecf20Sopenharmony_ci#define OP_31_XOP_MTSRIN 242 278c2ecf20Sopenharmony_ci#define OP_31_XOP_TLBIEL 274 288c2ecf20Sopenharmony_ci/* Opcode is officially reserved, reuse it as sc 1 when sc 1 doesn't trap */ 298c2ecf20Sopenharmony_ci#define OP_31_XOP_FAKE_SC1 308 308c2ecf20Sopenharmony_ci#define OP_31_XOP_SLBMTE 402 318c2ecf20Sopenharmony_ci#define OP_31_XOP_SLBIE 434 328c2ecf20Sopenharmony_ci#define OP_31_XOP_SLBIA 498 338c2ecf20Sopenharmony_ci#define OP_31_XOP_MFSR 595 348c2ecf20Sopenharmony_ci#define OP_31_XOP_MFSRIN 659 358c2ecf20Sopenharmony_ci#define OP_31_XOP_DCBA 758 368c2ecf20Sopenharmony_ci#define OP_31_XOP_SLBMFEV 851 378c2ecf20Sopenharmony_ci#define OP_31_XOP_EIOIO 854 388c2ecf20Sopenharmony_ci#define OP_31_XOP_SLBMFEE 915 398c2ecf20Sopenharmony_ci#define OP_31_XOP_SLBFEE 979 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define OP_31_XOP_TBEGIN 654 428c2ecf20Sopenharmony_ci#define OP_31_XOP_TABORT 910 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define OP_31_XOP_TRECLAIM 942 458c2ecf20Sopenharmony_ci#define OP_31_XOP_TRCHKPT 1006 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */ 488c2ecf20Sopenharmony_ci#define OP_31_XOP_DCBZ 1010 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define OP_LFS 48 518c2ecf20Sopenharmony_ci#define OP_LFD 50 528c2ecf20Sopenharmony_ci#define OP_STFS 52 538c2ecf20Sopenharmony_ci#define OP_STFD 54 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define SPRN_GQR0 912 568c2ecf20Sopenharmony_ci#define SPRN_GQR1 913 578c2ecf20Sopenharmony_ci#define SPRN_GQR2 914 588c2ecf20Sopenharmony_ci#define SPRN_GQR3 915 598c2ecf20Sopenharmony_ci#define SPRN_GQR4 916 608c2ecf20Sopenharmony_ci#define SPRN_GQR5 917 618c2ecf20Sopenharmony_ci#define SPRN_GQR6 918 628c2ecf20Sopenharmony_ci#define SPRN_GQR7 919 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Book3S_32 defines mfsrin(v) - but that messes up our abstract 658c2ecf20Sopenharmony_ci * function pointers, so let's just disable the define. */ 668c2ecf20Sopenharmony_ci#undef mfsrin 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cienum priv_level { 698c2ecf20Sopenharmony_ci PRIV_PROBLEM = 0, 708c2ecf20Sopenharmony_ci PRIV_SUPER = 1, 718c2ecf20Sopenharmony_ci PRIV_HYPER = 2, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic bool spr_allowed(struct kvm_vcpu *vcpu, enum priv_level level) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci /* PAPR VMs only access supervisor SPRs */ 778c2ecf20Sopenharmony_ci if (vcpu->arch.papr_enabled && (level > PRIV_SUPER)) 788c2ecf20Sopenharmony_ci return false; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* Limit user space to its own small SPR set */ 818c2ecf20Sopenharmony_ci if ((kvmppc_get_msr(vcpu) & MSR_PR) && level > PRIV_PROBLEM) 828c2ecf20Sopenharmony_ci return false; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return true; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 888c2ecf20Sopenharmony_cistatic inline void kvmppc_copyto_vcpu_tm(struct kvm_vcpu *vcpu) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci memcpy(&vcpu->arch.gpr_tm[0], &vcpu->arch.regs.gpr[0], 918c2ecf20Sopenharmony_ci sizeof(vcpu->arch.gpr_tm)); 928c2ecf20Sopenharmony_ci memcpy(&vcpu->arch.fp_tm, &vcpu->arch.fp, 938c2ecf20Sopenharmony_ci sizeof(struct thread_fp_state)); 948c2ecf20Sopenharmony_ci memcpy(&vcpu->arch.vr_tm, &vcpu->arch.vr, 958c2ecf20Sopenharmony_ci sizeof(struct thread_vr_state)); 968c2ecf20Sopenharmony_ci vcpu->arch.ppr_tm = vcpu->arch.ppr; 978c2ecf20Sopenharmony_ci vcpu->arch.dscr_tm = vcpu->arch.dscr; 988c2ecf20Sopenharmony_ci vcpu->arch.amr_tm = vcpu->arch.amr; 998c2ecf20Sopenharmony_ci vcpu->arch.ctr_tm = vcpu->arch.regs.ctr; 1008c2ecf20Sopenharmony_ci vcpu->arch.tar_tm = vcpu->arch.tar; 1018c2ecf20Sopenharmony_ci vcpu->arch.lr_tm = vcpu->arch.regs.link; 1028c2ecf20Sopenharmony_ci vcpu->arch.cr_tm = vcpu->arch.regs.ccr; 1038c2ecf20Sopenharmony_ci vcpu->arch.xer_tm = vcpu->arch.regs.xer; 1048c2ecf20Sopenharmony_ci vcpu->arch.vrsave_tm = vcpu->arch.vrsave; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic inline void kvmppc_copyfrom_vcpu_tm(struct kvm_vcpu *vcpu) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci memcpy(&vcpu->arch.regs.gpr[0], &vcpu->arch.gpr_tm[0], 1108c2ecf20Sopenharmony_ci sizeof(vcpu->arch.regs.gpr)); 1118c2ecf20Sopenharmony_ci memcpy(&vcpu->arch.fp, &vcpu->arch.fp_tm, 1128c2ecf20Sopenharmony_ci sizeof(struct thread_fp_state)); 1138c2ecf20Sopenharmony_ci memcpy(&vcpu->arch.vr, &vcpu->arch.vr_tm, 1148c2ecf20Sopenharmony_ci sizeof(struct thread_vr_state)); 1158c2ecf20Sopenharmony_ci vcpu->arch.ppr = vcpu->arch.ppr_tm; 1168c2ecf20Sopenharmony_ci vcpu->arch.dscr = vcpu->arch.dscr_tm; 1178c2ecf20Sopenharmony_ci vcpu->arch.amr = vcpu->arch.amr_tm; 1188c2ecf20Sopenharmony_ci vcpu->arch.regs.ctr = vcpu->arch.ctr_tm; 1198c2ecf20Sopenharmony_ci vcpu->arch.tar = vcpu->arch.tar_tm; 1208c2ecf20Sopenharmony_ci vcpu->arch.regs.link = vcpu->arch.lr_tm; 1218c2ecf20Sopenharmony_ci vcpu->arch.regs.ccr = vcpu->arch.cr_tm; 1228c2ecf20Sopenharmony_ci vcpu->arch.regs.xer = vcpu->arch.xer_tm; 1238c2ecf20Sopenharmony_ci vcpu->arch.vrsave = vcpu->arch.vrsave_tm; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void kvmppc_emulate_treclaim(struct kvm_vcpu *vcpu, int ra_val) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci unsigned long guest_msr = kvmppc_get_msr(vcpu); 1298c2ecf20Sopenharmony_ci int fc_val = ra_val ? ra_val : 1; 1308c2ecf20Sopenharmony_ci uint64_t texasr; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* CR0 = 0 | MSR[TS] | 0 */ 1338c2ecf20Sopenharmony_ci vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & ~(CR0_MASK << CR0_SHIFT)) | 1348c2ecf20Sopenharmony_ci (((guest_msr & MSR_TS_MASK) >> (MSR_TS_S_LG - 1)) 1358c2ecf20Sopenharmony_ci << CR0_SHIFT); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci preempt_disable(); 1388c2ecf20Sopenharmony_ci tm_enable(); 1398c2ecf20Sopenharmony_ci texasr = mfspr(SPRN_TEXASR); 1408c2ecf20Sopenharmony_ci kvmppc_save_tm_pr(vcpu); 1418c2ecf20Sopenharmony_ci kvmppc_copyfrom_vcpu_tm(vcpu); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* failure recording depends on Failure Summary bit */ 1448c2ecf20Sopenharmony_ci if (!(texasr & TEXASR_FS)) { 1458c2ecf20Sopenharmony_ci texasr &= ~TEXASR_FC; 1468c2ecf20Sopenharmony_ci texasr |= ((u64)fc_val << TEXASR_FC_LG) | TEXASR_FS; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci texasr &= ~(TEXASR_PR | TEXASR_HV); 1498c2ecf20Sopenharmony_ci if (kvmppc_get_msr(vcpu) & MSR_PR) 1508c2ecf20Sopenharmony_ci texasr |= TEXASR_PR; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (kvmppc_get_msr(vcpu) & MSR_HV) 1538c2ecf20Sopenharmony_ci texasr |= TEXASR_HV; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci vcpu->arch.texasr = texasr; 1568c2ecf20Sopenharmony_ci vcpu->arch.tfiar = kvmppc_get_pc(vcpu); 1578c2ecf20Sopenharmony_ci mtspr(SPRN_TEXASR, texasr); 1588c2ecf20Sopenharmony_ci mtspr(SPRN_TFIAR, vcpu->arch.tfiar); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci tm_disable(); 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * treclaim need quit to non-transactional state. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci guest_msr &= ~(MSR_TS_MASK); 1658c2ecf20Sopenharmony_ci kvmppc_set_msr(vcpu, guest_msr); 1668c2ecf20Sopenharmony_ci preempt_enable(); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (vcpu->arch.shadow_fscr & FSCR_TAR) 1698c2ecf20Sopenharmony_ci mtspr(SPRN_TAR, vcpu->arch.tar); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void kvmppc_emulate_trchkpt(struct kvm_vcpu *vcpu) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci unsigned long guest_msr = kvmppc_get_msr(vcpu); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci preempt_disable(); 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * need flush FP/VEC/VSX to vcpu save area before 1798c2ecf20Sopenharmony_ci * copy. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci kvmppc_giveup_ext(vcpu, MSR_VSX); 1828c2ecf20Sopenharmony_ci kvmppc_giveup_fac(vcpu, FSCR_TAR_LG); 1838c2ecf20Sopenharmony_ci kvmppc_copyto_vcpu_tm(vcpu); 1848c2ecf20Sopenharmony_ci kvmppc_save_tm_sprs(vcpu); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* 1878c2ecf20Sopenharmony_ci * as a result of trecheckpoint. set TS to suspended. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci guest_msr &= ~(MSR_TS_MASK); 1908c2ecf20Sopenharmony_ci guest_msr |= MSR_TS_S; 1918c2ecf20Sopenharmony_ci kvmppc_set_msr(vcpu, guest_msr); 1928c2ecf20Sopenharmony_ci kvmppc_restore_tm_pr(vcpu); 1938c2ecf20Sopenharmony_ci preempt_enable(); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* emulate tabort. at guest privilege state */ 1978c2ecf20Sopenharmony_civoid kvmppc_emulate_tabort(struct kvm_vcpu *vcpu, int ra_val) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci /* currently we only emulate tabort. but no emulation of other 2008c2ecf20Sopenharmony_ci * tabort variants since there is no kernel usage of them at 2018c2ecf20Sopenharmony_ci * present. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci unsigned long guest_msr = kvmppc_get_msr(vcpu); 2048c2ecf20Sopenharmony_ci uint64_t org_texasr; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci preempt_disable(); 2078c2ecf20Sopenharmony_ci tm_enable(); 2088c2ecf20Sopenharmony_ci org_texasr = mfspr(SPRN_TEXASR); 2098c2ecf20Sopenharmony_ci tm_abort(ra_val); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* CR0 = 0 | MSR[TS] | 0 */ 2128c2ecf20Sopenharmony_ci vcpu->arch.regs.ccr = (vcpu->arch.regs.ccr & ~(CR0_MASK << CR0_SHIFT)) | 2138c2ecf20Sopenharmony_ci (((guest_msr & MSR_TS_MASK) >> (MSR_TS_S_LG - 1)) 2148c2ecf20Sopenharmony_ci << CR0_SHIFT); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci vcpu->arch.texasr = mfspr(SPRN_TEXASR); 2178c2ecf20Sopenharmony_ci /* failure recording depends on Failure Summary bit, 2188c2ecf20Sopenharmony_ci * and tabort will be treated as nops in non-transactional 2198c2ecf20Sopenharmony_ci * state. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci if (!(org_texasr & TEXASR_FS) && 2228c2ecf20Sopenharmony_ci MSR_TM_ACTIVE(guest_msr)) { 2238c2ecf20Sopenharmony_ci vcpu->arch.texasr &= ~(TEXASR_PR | TEXASR_HV); 2248c2ecf20Sopenharmony_ci if (guest_msr & MSR_PR) 2258c2ecf20Sopenharmony_ci vcpu->arch.texasr |= TEXASR_PR; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (guest_msr & MSR_HV) 2288c2ecf20Sopenharmony_ci vcpu->arch.texasr |= TEXASR_HV; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci vcpu->arch.tfiar = kvmppc_get_pc(vcpu); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci tm_disable(); 2338c2ecf20Sopenharmony_ci preempt_enable(); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci#endif 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciint kvmppc_core_emulate_op_pr(struct kvm_vcpu *vcpu, 2398c2ecf20Sopenharmony_ci unsigned int inst, int *advance) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci int emulated = EMULATE_DONE; 2428c2ecf20Sopenharmony_ci int rt = get_rt(inst); 2438c2ecf20Sopenharmony_ci int rs = get_rs(inst); 2448c2ecf20Sopenharmony_ci int ra = get_ra(inst); 2458c2ecf20Sopenharmony_ci int rb = get_rb(inst); 2468c2ecf20Sopenharmony_ci u32 inst_sc = 0x44000002; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci switch (get_op(inst)) { 2498c2ecf20Sopenharmony_ci case 0: 2508c2ecf20Sopenharmony_ci emulated = EMULATE_FAIL; 2518c2ecf20Sopenharmony_ci if ((kvmppc_get_msr(vcpu) & MSR_LE) && 2528c2ecf20Sopenharmony_ci (inst == swab32(inst_sc))) { 2538c2ecf20Sopenharmony_ci /* 2548c2ecf20Sopenharmony_ci * This is the byte reversed syscall instruction of our 2558c2ecf20Sopenharmony_ci * hypercall handler. Early versions of LE Linux didn't 2568c2ecf20Sopenharmony_ci * swap the instructions correctly and ended up in 2578c2ecf20Sopenharmony_ci * illegal instructions. 2588c2ecf20Sopenharmony_ci * Just always fail hypercalls on these broken systems. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, 3, EV_UNIMPLEMENTED); 2618c2ecf20Sopenharmony_ci kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) + 4); 2628c2ecf20Sopenharmony_ci emulated = EMULATE_DONE; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci case 19: 2668c2ecf20Sopenharmony_ci switch (get_xop(inst)) { 2678c2ecf20Sopenharmony_ci case OP_19_XOP_RFID: 2688c2ecf20Sopenharmony_ci case OP_19_XOP_RFI: { 2698c2ecf20Sopenharmony_ci unsigned long srr1 = kvmppc_get_srr1(vcpu); 2708c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 2718c2ecf20Sopenharmony_ci unsigned long cur_msr = kvmppc_get_msr(vcpu); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * add rules to fit in ISA specification regarding TM 2758c2ecf20Sopenharmony_ci * state transistion in TM disable/Suspended state, 2768c2ecf20Sopenharmony_ci * and target TM state is TM inactive(00) state. (the 2778c2ecf20Sopenharmony_ci * change should be suppressed). 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ci if (((cur_msr & MSR_TM) == 0) && 2808c2ecf20Sopenharmony_ci ((srr1 & MSR_TM) == 0) && 2818c2ecf20Sopenharmony_ci MSR_TM_SUSPENDED(cur_msr) && 2828c2ecf20Sopenharmony_ci !MSR_TM_ACTIVE(srr1)) 2838c2ecf20Sopenharmony_ci srr1 |= MSR_TS_S; 2848c2ecf20Sopenharmony_ci#endif 2858c2ecf20Sopenharmony_ci kvmppc_set_pc(vcpu, kvmppc_get_srr0(vcpu)); 2868c2ecf20Sopenharmony_ci kvmppc_set_msr(vcpu, srr1); 2878c2ecf20Sopenharmony_ci *advance = 0; 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci default: 2928c2ecf20Sopenharmony_ci emulated = EMULATE_FAIL; 2938c2ecf20Sopenharmony_ci break; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci break; 2968c2ecf20Sopenharmony_ci case 31: 2978c2ecf20Sopenharmony_ci switch (get_xop(inst)) { 2988c2ecf20Sopenharmony_ci case OP_31_XOP_MFMSR: 2998c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, rt, kvmppc_get_msr(vcpu)); 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case OP_31_XOP_MTMSRD: 3028c2ecf20Sopenharmony_ci { 3038c2ecf20Sopenharmony_ci ulong rs_val = kvmppc_get_gpr(vcpu, rs); 3048c2ecf20Sopenharmony_ci if (inst & 0x10000) { 3058c2ecf20Sopenharmony_ci ulong new_msr = kvmppc_get_msr(vcpu); 3068c2ecf20Sopenharmony_ci new_msr &= ~(MSR_RI | MSR_EE); 3078c2ecf20Sopenharmony_ci new_msr |= rs_val & (MSR_RI | MSR_EE); 3088c2ecf20Sopenharmony_ci kvmppc_set_msr_fast(vcpu, new_msr); 3098c2ecf20Sopenharmony_ci } else 3108c2ecf20Sopenharmony_ci kvmppc_set_msr(vcpu, rs_val); 3118c2ecf20Sopenharmony_ci break; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci case OP_31_XOP_MTMSR: 3148c2ecf20Sopenharmony_ci kvmppc_set_msr(vcpu, kvmppc_get_gpr(vcpu, rs)); 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci case OP_31_XOP_MFSR: 3178c2ecf20Sopenharmony_ci { 3188c2ecf20Sopenharmony_ci int srnum; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci srnum = kvmppc_get_field(inst, 12 + 32, 15 + 32); 3218c2ecf20Sopenharmony_ci if (vcpu->arch.mmu.mfsrin) { 3228c2ecf20Sopenharmony_ci u32 sr; 3238c2ecf20Sopenharmony_ci sr = vcpu->arch.mmu.mfsrin(vcpu, srnum); 3248c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, rt, sr); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci case OP_31_XOP_MFSRIN: 3298c2ecf20Sopenharmony_ci { 3308c2ecf20Sopenharmony_ci int srnum; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci srnum = (kvmppc_get_gpr(vcpu, rb) >> 28) & 0xf; 3338c2ecf20Sopenharmony_ci if (vcpu->arch.mmu.mfsrin) { 3348c2ecf20Sopenharmony_ci u32 sr; 3358c2ecf20Sopenharmony_ci sr = vcpu->arch.mmu.mfsrin(vcpu, srnum); 3368c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, rt, sr); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci case OP_31_XOP_MTSR: 3418c2ecf20Sopenharmony_ci vcpu->arch.mmu.mtsrin(vcpu, 3428c2ecf20Sopenharmony_ci (inst >> 16) & 0xf, 3438c2ecf20Sopenharmony_ci kvmppc_get_gpr(vcpu, rs)); 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci case OP_31_XOP_MTSRIN: 3468c2ecf20Sopenharmony_ci vcpu->arch.mmu.mtsrin(vcpu, 3478c2ecf20Sopenharmony_ci (kvmppc_get_gpr(vcpu, rb) >> 28) & 0xf, 3488c2ecf20Sopenharmony_ci kvmppc_get_gpr(vcpu, rs)); 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case OP_31_XOP_TLBIE: 3518c2ecf20Sopenharmony_ci case OP_31_XOP_TLBIEL: 3528c2ecf20Sopenharmony_ci { 3538c2ecf20Sopenharmony_ci bool large = (inst & 0x00200000) ? true : false; 3548c2ecf20Sopenharmony_ci ulong addr = kvmppc_get_gpr(vcpu, rb); 3558c2ecf20Sopenharmony_ci vcpu->arch.mmu.tlbie(vcpu, addr, large); 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 3598c2ecf20Sopenharmony_ci case OP_31_XOP_FAKE_SC1: 3608c2ecf20Sopenharmony_ci { 3618c2ecf20Sopenharmony_ci /* SC 1 papr hypercalls */ 3628c2ecf20Sopenharmony_ci ulong cmd = kvmppc_get_gpr(vcpu, 3); 3638c2ecf20Sopenharmony_ci int i; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if ((kvmppc_get_msr(vcpu) & MSR_PR) || 3668c2ecf20Sopenharmony_ci !vcpu->arch.papr_enabled) { 3678c2ecf20Sopenharmony_ci emulated = EMULATE_FAIL; 3688c2ecf20Sopenharmony_ci break; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (kvmppc_h_pr(vcpu, cmd) == EMULATE_DONE) 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci vcpu->run->papr_hcall.nr = cmd; 3758c2ecf20Sopenharmony_ci for (i = 0; i < 9; ++i) { 3768c2ecf20Sopenharmony_ci ulong gpr = kvmppc_get_gpr(vcpu, 4 + i); 3778c2ecf20Sopenharmony_ci vcpu->run->papr_hcall.args[i] = gpr; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci vcpu->run->exit_reason = KVM_EXIT_PAPR_HCALL; 3818c2ecf20Sopenharmony_ci vcpu->arch.hcall_needed = 1; 3828c2ecf20Sopenharmony_ci emulated = EMULATE_EXIT_USER; 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci#endif 3868c2ecf20Sopenharmony_ci case OP_31_XOP_EIOIO: 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci case OP_31_XOP_SLBMTE: 3898c2ecf20Sopenharmony_ci if (!vcpu->arch.mmu.slbmte) 3908c2ecf20Sopenharmony_ci return EMULATE_FAIL; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci vcpu->arch.mmu.slbmte(vcpu, 3938c2ecf20Sopenharmony_ci kvmppc_get_gpr(vcpu, rs), 3948c2ecf20Sopenharmony_ci kvmppc_get_gpr(vcpu, rb)); 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci case OP_31_XOP_SLBIE: 3978c2ecf20Sopenharmony_ci if (!vcpu->arch.mmu.slbie) 3988c2ecf20Sopenharmony_ci return EMULATE_FAIL; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci vcpu->arch.mmu.slbie(vcpu, 4018c2ecf20Sopenharmony_ci kvmppc_get_gpr(vcpu, rb)); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci case OP_31_XOP_SLBIA: 4048c2ecf20Sopenharmony_ci if (!vcpu->arch.mmu.slbia) 4058c2ecf20Sopenharmony_ci return EMULATE_FAIL; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci vcpu->arch.mmu.slbia(vcpu); 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case OP_31_XOP_SLBFEE: 4108c2ecf20Sopenharmony_ci if (!(inst & 1) || !vcpu->arch.mmu.slbfee) { 4118c2ecf20Sopenharmony_ci return EMULATE_FAIL; 4128c2ecf20Sopenharmony_ci } else { 4138c2ecf20Sopenharmony_ci ulong b, t; 4148c2ecf20Sopenharmony_ci ulong cr = kvmppc_get_cr(vcpu) & ~CR0_MASK; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci b = kvmppc_get_gpr(vcpu, rb); 4178c2ecf20Sopenharmony_ci if (!vcpu->arch.mmu.slbfee(vcpu, b, &t)) 4188c2ecf20Sopenharmony_ci cr |= 2 << CR0_SHIFT; 4198c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, rt, t); 4208c2ecf20Sopenharmony_ci /* copy XER[SO] bit to CR0[SO] */ 4218c2ecf20Sopenharmony_ci cr |= (vcpu->arch.regs.xer & 0x80000000) >> 4228c2ecf20Sopenharmony_ci (31 - CR0_SHIFT); 4238c2ecf20Sopenharmony_ci kvmppc_set_cr(vcpu, cr); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci break; 4268c2ecf20Sopenharmony_ci case OP_31_XOP_SLBMFEE: 4278c2ecf20Sopenharmony_ci if (!vcpu->arch.mmu.slbmfee) { 4288c2ecf20Sopenharmony_ci emulated = EMULATE_FAIL; 4298c2ecf20Sopenharmony_ci } else { 4308c2ecf20Sopenharmony_ci ulong t, rb_val; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci rb_val = kvmppc_get_gpr(vcpu, rb); 4338c2ecf20Sopenharmony_ci t = vcpu->arch.mmu.slbmfee(vcpu, rb_val); 4348c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, rt, t); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci break; 4378c2ecf20Sopenharmony_ci case OP_31_XOP_SLBMFEV: 4388c2ecf20Sopenharmony_ci if (!vcpu->arch.mmu.slbmfev) { 4398c2ecf20Sopenharmony_ci emulated = EMULATE_FAIL; 4408c2ecf20Sopenharmony_ci } else { 4418c2ecf20Sopenharmony_ci ulong t, rb_val; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci rb_val = kvmppc_get_gpr(vcpu, rb); 4448c2ecf20Sopenharmony_ci t = vcpu->arch.mmu.slbmfev(vcpu, rb_val); 4458c2ecf20Sopenharmony_ci kvmppc_set_gpr(vcpu, rt, t); 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci break; 4488c2ecf20Sopenharmony_ci case OP_31_XOP_DCBA: 4498c2ecf20Sopenharmony_ci /* Gets treated as NOP */ 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci case OP_31_XOP_DCBZ: 4528c2ecf20Sopenharmony_ci { 4538c2ecf20Sopenharmony_ci ulong rb_val = kvmppc_get_gpr(vcpu, rb); 4548c2ecf20Sopenharmony_ci ulong ra_val = 0; 4558c2ecf20Sopenharmony_ci ulong addr, vaddr; 4568c2ecf20Sopenharmony_ci u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 4578c2ecf20Sopenharmony_ci u32 dsisr; 4588c2ecf20Sopenharmony_ci int r; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (ra) 4618c2ecf20Sopenharmony_ci ra_val = kvmppc_get_gpr(vcpu, ra); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci addr = (ra_val + rb_val) & ~31ULL; 4648c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_SF)) 4658c2ecf20Sopenharmony_ci addr &= 0xffffffff; 4668c2ecf20Sopenharmony_ci vaddr = addr; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci r = kvmppc_st(vcpu, &addr, 32, zeros, true); 4698c2ecf20Sopenharmony_ci if ((r == -ENOENT) || (r == -EPERM)) { 4708c2ecf20Sopenharmony_ci *advance = 0; 4718c2ecf20Sopenharmony_ci kvmppc_set_dar(vcpu, vaddr); 4728c2ecf20Sopenharmony_ci vcpu->arch.fault_dar = vaddr; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci dsisr = DSISR_ISSTORE; 4758c2ecf20Sopenharmony_ci if (r == -ENOENT) 4768c2ecf20Sopenharmony_ci dsisr |= DSISR_NOHPTE; 4778c2ecf20Sopenharmony_ci else if (r == -EPERM) 4788c2ecf20Sopenharmony_ci dsisr |= DSISR_PROTFAULT; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci kvmppc_set_dsisr(vcpu, dsisr); 4818c2ecf20Sopenharmony_ci vcpu->arch.fault_dsisr = dsisr; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci kvmppc_book3s_queue_irqprio(vcpu, 4848c2ecf20Sopenharmony_ci BOOK3S_INTERRUPT_DATA_STORAGE); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci break; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 4908c2ecf20Sopenharmony_ci case OP_31_XOP_TBEGIN: 4918c2ecf20Sopenharmony_ci { 4928c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_TM)) 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_TM)) { 4968c2ecf20Sopenharmony_ci kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG); 4978c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_PR)) { 5028c2ecf20Sopenharmony_ci preempt_disable(); 5038c2ecf20Sopenharmony_ci vcpu->arch.regs.ccr = (CR0_TBEGIN_FAILURE | 5048c2ecf20Sopenharmony_ci (vcpu->arch.regs.ccr & ~(CR0_MASK << CR0_SHIFT))); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci vcpu->arch.texasr = (TEXASR_FS | TEXASR_EXACT | 5078c2ecf20Sopenharmony_ci (((u64)(TM_CAUSE_EMULATE | TM_CAUSE_PERSISTENT)) 5088c2ecf20Sopenharmony_ci << TEXASR_FC_LG)); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci if ((inst >> 21) & 0x1) 5118c2ecf20Sopenharmony_ci vcpu->arch.texasr |= TEXASR_ROT; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (kvmppc_get_msr(vcpu) & MSR_HV) 5148c2ecf20Sopenharmony_ci vcpu->arch.texasr |= TEXASR_HV; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci vcpu->arch.tfhar = kvmppc_get_pc(vcpu) + 4; 5178c2ecf20Sopenharmony_ci vcpu->arch.tfiar = kvmppc_get_pc(vcpu); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci kvmppc_restore_tm_sprs(vcpu); 5208c2ecf20Sopenharmony_ci preempt_enable(); 5218c2ecf20Sopenharmony_ci } else 5228c2ecf20Sopenharmony_ci emulated = EMULATE_FAIL; 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci case OP_31_XOP_TABORT: 5268c2ecf20Sopenharmony_ci { 5278c2ecf20Sopenharmony_ci ulong guest_msr = kvmppc_get_msr(vcpu); 5288c2ecf20Sopenharmony_ci unsigned long ra_val = 0; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_TM)) 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_TM)) { 5348c2ecf20Sopenharmony_ci kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG); 5358c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* only emulate for privilege guest, since problem state 5408c2ecf20Sopenharmony_ci * guest can run with TM enabled and we don't expect to 5418c2ecf20Sopenharmony_ci * trap at here for that case. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ci WARN_ON(guest_msr & MSR_PR); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (ra) 5468c2ecf20Sopenharmony_ci ra_val = kvmppc_get_gpr(vcpu, ra); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci kvmppc_emulate_tabort(vcpu, ra_val); 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci case OP_31_XOP_TRECLAIM: 5528c2ecf20Sopenharmony_ci { 5538c2ecf20Sopenharmony_ci ulong guest_msr = kvmppc_get_msr(vcpu); 5548c2ecf20Sopenharmony_ci unsigned long ra_val = 0; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_TM)) 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_TM)) { 5608c2ecf20Sopenharmony_ci kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG); 5618c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* generate interrupts based on priorities */ 5668c2ecf20Sopenharmony_ci if (guest_msr & MSR_PR) { 5678c2ecf20Sopenharmony_ci /* Privileged Instruction type Program Interrupt */ 5688c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGPRIV); 5698c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (!MSR_TM_ACTIVE(guest_msr)) { 5748c2ecf20Sopenharmony_ci /* TM bad thing interrupt */ 5758c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGTM); 5768c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (ra) 5818c2ecf20Sopenharmony_ci ra_val = kvmppc_get_gpr(vcpu, ra); 5828c2ecf20Sopenharmony_ci kvmppc_emulate_treclaim(vcpu, ra_val); 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci case OP_31_XOP_TRCHKPT: 5868c2ecf20Sopenharmony_ci { 5878c2ecf20Sopenharmony_ci ulong guest_msr = kvmppc_get_msr(vcpu); 5888c2ecf20Sopenharmony_ci unsigned long texasr; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_TM)) 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_TM)) { 5948c2ecf20Sopenharmony_ci kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG); 5958c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* generate interrupt based on priorities */ 6008c2ecf20Sopenharmony_ci if (guest_msr & MSR_PR) { 6018c2ecf20Sopenharmony_ci /* Privileged Instruction type Program Intr */ 6028c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGPRIV); 6038c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 6048c2ecf20Sopenharmony_ci break; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci tm_enable(); 6088c2ecf20Sopenharmony_ci texasr = mfspr(SPRN_TEXASR); 6098c2ecf20Sopenharmony_ci tm_disable(); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (MSR_TM_ACTIVE(guest_msr) || 6128c2ecf20Sopenharmony_ci !(texasr & (TEXASR_FS))) { 6138c2ecf20Sopenharmony_ci /* TM bad thing interrupt */ 6148c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGTM); 6158c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci kvmppc_emulate_trchkpt(vcpu); 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci#endif 6238c2ecf20Sopenharmony_ci default: 6248c2ecf20Sopenharmony_ci emulated = EMULATE_FAIL; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci default: 6288c2ecf20Sopenharmony_ci emulated = EMULATE_FAIL; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (emulated == EMULATE_FAIL) 6328c2ecf20Sopenharmony_ci emulated = kvmppc_emulate_paired_single(vcpu); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci return emulated; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_civoid kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper, 6388c2ecf20Sopenharmony_ci u32 val) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci if (upper) { 6418c2ecf20Sopenharmony_ci /* Upper BAT */ 6428c2ecf20Sopenharmony_ci u32 bl = (val >> 2) & 0x7ff; 6438c2ecf20Sopenharmony_ci bat->bepi_mask = (~bl << 17); 6448c2ecf20Sopenharmony_ci bat->bepi = val & 0xfffe0000; 6458c2ecf20Sopenharmony_ci bat->vs = (val & 2) ? 1 : 0; 6468c2ecf20Sopenharmony_ci bat->vp = (val & 1) ? 1 : 0; 6478c2ecf20Sopenharmony_ci bat->raw = (bat->raw & 0xffffffff00000000ULL) | val; 6488c2ecf20Sopenharmony_ci } else { 6498c2ecf20Sopenharmony_ci /* Lower BAT */ 6508c2ecf20Sopenharmony_ci bat->brpn = val & 0xfffe0000; 6518c2ecf20Sopenharmony_ci bat->wimg = (val >> 3) & 0xf; 6528c2ecf20Sopenharmony_ci bat->pp = val & 3; 6538c2ecf20Sopenharmony_ci bat->raw = (bat->raw & 0x00000000ffffffffULL) | ((u64)val << 32); 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic struct kvmppc_bat *kvmppc_find_bat(struct kvm_vcpu *vcpu, int sprn) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); 6608c2ecf20Sopenharmony_ci struct kvmppc_bat *bat; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci switch (sprn) { 6638c2ecf20Sopenharmony_ci case SPRN_IBAT0U ... SPRN_IBAT3L: 6648c2ecf20Sopenharmony_ci bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2]; 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci case SPRN_IBAT4U ... SPRN_IBAT7L: 6678c2ecf20Sopenharmony_ci bat = &vcpu_book3s->ibat[4 + ((sprn - SPRN_IBAT4U) / 2)]; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci case SPRN_DBAT0U ... SPRN_DBAT3L: 6708c2ecf20Sopenharmony_ci bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2]; 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci case SPRN_DBAT4U ... SPRN_DBAT7L: 6738c2ecf20Sopenharmony_ci bat = &vcpu_book3s->dbat[4 + ((sprn - SPRN_DBAT4U) / 2)]; 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci default: 6768c2ecf20Sopenharmony_ci BUG(); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return bat; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ciint kvmppc_core_emulate_mtspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci int emulated = EMULATE_DONE; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci switch (sprn) { 6878c2ecf20Sopenharmony_ci case SPRN_SDR1: 6888c2ecf20Sopenharmony_ci if (!spr_allowed(vcpu, PRIV_HYPER)) 6898c2ecf20Sopenharmony_ci goto unprivileged; 6908c2ecf20Sopenharmony_ci to_book3s(vcpu)->sdr1 = spr_val; 6918c2ecf20Sopenharmony_ci break; 6928c2ecf20Sopenharmony_ci case SPRN_DSISR: 6938c2ecf20Sopenharmony_ci kvmppc_set_dsisr(vcpu, spr_val); 6948c2ecf20Sopenharmony_ci break; 6958c2ecf20Sopenharmony_ci case SPRN_DAR: 6968c2ecf20Sopenharmony_ci kvmppc_set_dar(vcpu, spr_val); 6978c2ecf20Sopenharmony_ci break; 6988c2ecf20Sopenharmony_ci case SPRN_HIOR: 6998c2ecf20Sopenharmony_ci to_book3s(vcpu)->hior = spr_val; 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci case SPRN_IBAT0U ... SPRN_IBAT3L: 7028c2ecf20Sopenharmony_ci case SPRN_IBAT4U ... SPRN_IBAT7L: 7038c2ecf20Sopenharmony_ci case SPRN_DBAT0U ... SPRN_DBAT3L: 7048c2ecf20Sopenharmony_ci case SPRN_DBAT4U ... SPRN_DBAT7L: 7058c2ecf20Sopenharmony_ci { 7068c2ecf20Sopenharmony_ci struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci kvmppc_set_bat(vcpu, bat, !(sprn % 2), (u32)spr_val); 7098c2ecf20Sopenharmony_ci /* BAT writes happen so rarely that we're ok to flush 7108c2ecf20Sopenharmony_ci * everything here */ 7118c2ecf20Sopenharmony_ci kvmppc_mmu_pte_flush(vcpu, 0, 0); 7128c2ecf20Sopenharmony_ci kvmppc_mmu_flush_segments(vcpu); 7138c2ecf20Sopenharmony_ci break; 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci case SPRN_HID0: 7168c2ecf20Sopenharmony_ci to_book3s(vcpu)->hid[0] = spr_val; 7178c2ecf20Sopenharmony_ci break; 7188c2ecf20Sopenharmony_ci case SPRN_HID1: 7198c2ecf20Sopenharmony_ci to_book3s(vcpu)->hid[1] = spr_val; 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci case SPRN_HID2: 7228c2ecf20Sopenharmony_ci to_book3s(vcpu)->hid[2] = spr_val; 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci case SPRN_HID2_GEKKO: 7258c2ecf20Sopenharmony_ci to_book3s(vcpu)->hid[2] = spr_val; 7268c2ecf20Sopenharmony_ci /* HID2.PSE controls paired single on gekko */ 7278c2ecf20Sopenharmony_ci switch (vcpu->arch.pvr) { 7288c2ecf20Sopenharmony_ci case 0x00080200: /* lonestar 2.0 */ 7298c2ecf20Sopenharmony_ci case 0x00088202: /* lonestar 2.2 */ 7308c2ecf20Sopenharmony_ci case 0x70000100: /* gekko 1.0 */ 7318c2ecf20Sopenharmony_ci case 0x00080100: /* gekko 2.0 */ 7328c2ecf20Sopenharmony_ci case 0x00083203: /* gekko 2.3a */ 7338c2ecf20Sopenharmony_ci case 0x00083213: /* gekko 2.3b */ 7348c2ecf20Sopenharmony_ci case 0x00083204: /* gekko 2.4 */ 7358c2ecf20Sopenharmony_ci case 0x00083214: /* gekko 2.4e (8SE) - retail HW2 */ 7368c2ecf20Sopenharmony_ci case 0x00087200: /* broadway */ 7378c2ecf20Sopenharmony_ci if (vcpu->arch.hflags & BOOK3S_HFLAG_NATIVE_PS) { 7388c2ecf20Sopenharmony_ci /* Native paired singles */ 7398c2ecf20Sopenharmony_ci } else if (spr_val & (1 << 29)) { /* HID2.PSE */ 7408c2ecf20Sopenharmony_ci vcpu->arch.hflags |= BOOK3S_HFLAG_PAIRED_SINGLE; 7418c2ecf20Sopenharmony_ci kvmppc_giveup_ext(vcpu, MSR_FP); 7428c2ecf20Sopenharmony_ci } else { 7438c2ecf20Sopenharmony_ci vcpu->arch.hflags &= ~BOOK3S_HFLAG_PAIRED_SINGLE; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci break; 7488c2ecf20Sopenharmony_ci case SPRN_HID4: 7498c2ecf20Sopenharmony_ci case SPRN_HID4_GEKKO: 7508c2ecf20Sopenharmony_ci to_book3s(vcpu)->hid[4] = spr_val; 7518c2ecf20Sopenharmony_ci break; 7528c2ecf20Sopenharmony_ci case SPRN_HID5: 7538c2ecf20Sopenharmony_ci to_book3s(vcpu)->hid[5] = spr_val; 7548c2ecf20Sopenharmony_ci /* guest HID5 set can change is_dcbz32 */ 7558c2ecf20Sopenharmony_ci if (vcpu->arch.mmu.is_dcbz32(vcpu) && 7568c2ecf20Sopenharmony_ci (mfmsr() & MSR_HV)) 7578c2ecf20Sopenharmony_ci vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci case SPRN_GQR0: 7608c2ecf20Sopenharmony_ci case SPRN_GQR1: 7618c2ecf20Sopenharmony_ci case SPRN_GQR2: 7628c2ecf20Sopenharmony_ci case SPRN_GQR3: 7638c2ecf20Sopenharmony_ci case SPRN_GQR4: 7648c2ecf20Sopenharmony_ci case SPRN_GQR5: 7658c2ecf20Sopenharmony_ci case SPRN_GQR6: 7668c2ecf20Sopenharmony_ci case SPRN_GQR7: 7678c2ecf20Sopenharmony_ci to_book3s(vcpu)->gqr[sprn - SPRN_GQR0] = spr_val; 7688c2ecf20Sopenharmony_ci break; 7698c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 7708c2ecf20Sopenharmony_ci case SPRN_FSCR: 7718c2ecf20Sopenharmony_ci kvmppc_set_fscr(vcpu, spr_val); 7728c2ecf20Sopenharmony_ci break; 7738c2ecf20Sopenharmony_ci case SPRN_BESCR: 7748c2ecf20Sopenharmony_ci vcpu->arch.bescr = spr_val; 7758c2ecf20Sopenharmony_ci break; 7768c2ecf20Sopenharmony_ci case SPRN_EBBHR: 7778c2ecf20Sopenharmony_ci vcpu->arch.ebbhr = spr_val; 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci case SPRN_EBBRR: 7808c2ecf20Sopenharmony_ci vcpu->arch.ebbrr = spr_val; 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 7838c2ecf20Sopenharmony_ci case SPRN_TFHAR: 7848c2ecf20Sopenharmony_ci case SPRN_TEXASR: 7858c2ecf20Sopenharmony_ci case SPRN_TFIAR: 7868c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_TM)) 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_TM)) { 7908c2ecf20Sopenharmony_ci kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG); 7918c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 7928c2ecf20Sopenharmony_ci break; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci if (MSR_TM_ACTIVE(kvmppc_get_msr(vcpu)) && 7968c2ecf20Sopenharmony_ci !((MSR_TM_SUSPENDED(kvmppc_get_msr(vcpu))) && 7978c2ecf20Sopenharmony_ci (sprn == SPRN_TFHAR))) { 7988c2ecf20Sopenharmony_ci /* it is illegal to mtspr() TM regs in 7998c2ecf20Sopenharmony_ci * other than non-transactional state, with 8008c2ecf20Sopenharmony_ci * the exception of TFHAR in suspend state. 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGTM); 8038c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci tm_enable(); 8088c2ecf20Sopenharmony_ci if (sprn == SPRN_TFHAR) 8098c2ecf20Sopenharmony_ci mtspr(SPRN_TFHAR, spr_val); 8108c2ecf20Sopenharmony_ci else if (sprn == SPRN_TEXASR) 8118c2ecf20Sopenharmony_ci mtspr(SPRN_TEXASR, spr_val); 8128c2ecf20Sopenharmony_ci else 8138c2ecf20Sopenharmony_ci mtspr(SPRN_TFIAR, spr_val); 8148c2ecf20Sopenharmony_ci tm_disable(); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci#endif 8188c2ecf20Sopenharmony_ci#endif 8198c2ecf20Sopenharmony_ci case SPRN_ICTC: 8208c2ecf20Sopenharmony_ci case SPRN_THRM1: 8218c2ecf20Sopenharmony_ci case SPRN_THRM2: 8228c2ecf20Sopenharmony_ci case SPRN_THRM3: 8238c2ecf20Sopenharmony_ci case SPRN_CTRLF: 8248c2ecf20Sopenharmony_ci case SPRN_CTRLT: 8258c2ecf20Sopenharmony_ci case SPRN_L2CR: 8268c2ecf20Sopenharmony_ci case SPRN_DSCR: 8278c2ecf20Sopenharmony_ci case SPRN_MMCR0_GEKKO: 8288c2ecf20Sopenharmony_ci case SPRN_MMCR1_GEKKO: 8298c2ecf20Sopenharmony_ci case SPRN_PMC1_GEKKO: 8308c2ecf20Sopenharmony_ci case SPRN_PMC2_GEKKO: 8318c2ecf20Sopenharmony_ci case SPRN_PMC3_GEKKO: 8328c2ecf20Sopenharmony_ci case SPRN_PMC4_GEKKO: 8338c2ecf20Sopenharmony_ci case SPRN_WPAR_GEKKO: 8348c2ecf20Sopenharmony_ci case SPRN_MSSSR0: 8358c2ecf20Sopenharmony_ci case SPRN_DABR: 8368c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 8378c2ecf20Sopenharmony_ci case SPRN_MMCRS: 8388c2ecf20Sopenharmony_ci case SPRN_MMCRA: 8398c2ecf20Sopenharmony_ci case SPRN_MMCR0: 8408c2ecf20Sopenharmony_ci case SPRN_MMCR1: 8418c2ecf20Sopenharmony_ci case SPRN_MMCR2: 8428c2ecf20Sopenharmony_ci case SPRN_UMMCR2: 8438c2ecf20Sopenharmony_ci#endif 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ciunprivileged: 8468c2ecf20Sopenharmony_ci default: 8478c2ecf20Sopenharmony_ci pr_info_ratelimited("KVM: invalid SPR write: %d\n", sprn); 8488c2ecf20Sopenharmony_ci if (sprn & 0x10) { 8498c2ecf20Sopenharmony_ci if (kvmppc_get_msr(vcpu) & MSR_PR) { 8508c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGPRIV); 8518c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci } else { 8548c2ecf20Sopenharmony_ci if ((kvmppc_get_msr(vcpu) & MSR_PR) || sprn == 0) { 8558c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGILL); 8568c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci break; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return emulated; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ciint kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci int emulated = EMULATE_DONE; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci switch (sprn) { 8708c2ecf20Sopenharmony_ci case SPRN_IBAT0U ... SPRN_IBAT3L: 8718c2ecf20Sopenharmony_ci case SPRN_IBAT4U ... SPRN_IBAT7L: 8728c2ecf20Sopenharmony_ci case SPRN_DBAT0U ... SPRN_DBAT3L: 8738c2ecf20Sopenharmony_ci case SPRN_DBAT4U ... SPRN_DBAT7L: 8748c2ecf20Sopenharmony_ci { 8758c2ecf20Sopenharmony_ci struct kvmppc_bat *bat = kvmppc_find_bat(vcpu, sprn); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (sprn % 2) 8788c2ecf20Sopenharmony_ci *spr_val = bat->raw >> 32; 8798c2ecf20Sopenharmony_ci else 8808c2ecf20Sopenharmony_ci *spr_val = bat->raw; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci break; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci case SPRN_SDR1: 8858c2ecf20Sopenharmony_ci if (!spr_allowed(vcpu, PRIV_HYPER)) 8868c2ecf20Sopenharmony_ci goto unprivileged; 8878c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->sdr1; 8888c2ecf20Sopenharmony_ci break; 8898c2ecf20Sopenharmony_ci case SPRN_DSISR: 8908c2ecf20Sopenharmony_ci *spr_val = kvmppc_get_dsisr(vcpu); 8918c2ecf20Sopenharmony_ci break; 8928c2ecf20Sopenharmony_ci case SPRN_DAR: 8938c2ecf20Sopenharmony_ci *spr_val = kvmppc_get_dar(vcpu); 8948c2ecf20Sopenharmony_ci break; 8958c2ecf20Sopenharmony_ci case SPRN_HIOR: 8968c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->hior; 8978c2ecf20Sopenharmony_ci break; 8988c2ecf20Sopenharmony_ci case SPRN_HID0: 8998c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->hid[0]; 9008c2ecf20Sopenharmony_ci break; 9018c2ecf20Sopenharmony_ci case SPRN_HID1: 9028c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->hid[1]; 9038c2ecf20Sopenharmony_ci break; 9048c2ecf20Sopenharmony_ci case SPRN_HID2: 9058c2ecf20Sopenharmony_ci case SPRN_HID2_GEKKO: 9068c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->hid[2]; 9078c2ecf20Sopenharmony_ci break; 9088c2ecf20Sopenharmony_ci case SPRN_HID4: 9098c2ecf20Sopenharmony_ci case SPRN_HID4_GEKKO: 9108c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->hid[4]; 9118c2ecf20Sopenharmony_ci break; 9128c2ecf20Sopenharmony_ci case SPRN_HID5: 9138c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->hid[5]; 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci case SPRN_CFAR: 9168c2ecf20Sopenharmony_ci case SPRN_DSCR: 9178c2ecf20Sopenharmony_ci *spr_val = 0; 9188c2ecf20Sopenharmony_ci break; 9198c2ecf20Sopenharmony_ci case SPRN_PURR: 9208c2ecf20Sopenharmony_ci /* 9218c2ecf20Sopenharmony_ci * On exit we would have updated purr 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci *spr_val = vcpu->arch.purr; 9248c2ecf20Sopenharmony_ci break; 9258c2ecf20Sopenharmony_ci case SPRN_SPURR: 9268c2ecf20Sopenharmony_ci /* 9278c2ecf20Sopenharmony_ci * On exit we would have updated spurr 9288c2ecf20Sopenharmony_ci */ 9298c2ecf20Sopenharmony_ci *spr_val = vcpu->arch.spurr; 9308c2ecf20Sopenharmony_ci break; 9318c2ecf20Sopenharmony_ci case SPRN_VTB: 9328c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->vtb; 9338c2ecf20Sopenharmony_ci break; 9348c2ecf20Sopenharmony_ci case SPRN_IC: 9358c2ecf20Sopenharmony_ci *spr_val = vcpu->arch.ic; 9368c2ecf20Sopenharmony_ci break; 9378c2ecf20Sopenharmony_ci case SPRN_GQR0: 9388c2ecf20Sopenharmony_ci case SPRN_GQR1: 9398c2ecf20Sopenharmony_ci case SPRN_GQR2: 9408c2ecf20Sopenharmony_ci case SPRN_GQR3: 9418c2ecf20Sopenharmony_ci case SPRN_GQR4: 9428c2ecf20Sopenharmony_ci case SPRN_GQR5: 9438c2ecf20Sopenharmony_ci case SPRN_GQR6: 9448c2ecf20Sopenharmony_ci case SPRN_GQR7: 9458c2ecf20Sopenharmony_ci *spr_val = to_book3s(vcpu)->gqr[sprn - SPRN_GQR0]; 9468c2ecf20Sopenharmony_ci break; 9478c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 9488c2ecf20Sopenharmony_ci case SPRN_FSCR: 9498c2ecf20Sopenharmony_ci *spr_val = vcpu->arch.fscr; 9508c2ecf20Sopenharmony_ci break; 9518c2ecf20Sopenharmony_ci case SPRN_BESCR: 9528c2ecf20Sopenharmony_ci *spr_val = vcpu->arch.bescr; 9538c2ecf20Sopenharmony_ci break; 9548c2ecf20Sopenharmony_ci case SPRN_EBBHR: 9558c2ecf20Sopenharmony_ci *spr_val = vcpu->arch.ebbhr; 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci case SPRN_EBBRR: 9588c2ecf20Sopenharmony_ci *spr_val = vcpu->arch.ebbrr; 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 9618c2ecf20Sopenharmony_ci case SPRN_TFHAR: 9628c2ecf20Sopenharmony_ci case SPRN_TEXASR: 9638c2ecf20Sopenharmony_ci case SPRN_TFIAR: 9648c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_TM)) 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (!(kvmppc_get_msr(vcpu) & MSR_TM)) { 9688c2ecf20Sopenharmony_ci kvmppc_trigger_fac_interrupt(vcpu, FSCR_TM_LG); 9698c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 9708c2ecf20Sopenharmony_ci break; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci tm_enable(); 9748c2ecf20Sopenharmony_ci if (sprn == SPRN_TFHAR) 9758c2ecf20Sopenharmony_ci *spr_val = mfspr(SPRN_TFHAR); 9768c2ecf20Sopenharmony_ci else if (sprn == SPRN_TEXASR) 9778c2ecf20Sopenharmony_ci *spr_val = mfspr(SPRN_TEXASR); 9788c2ecf20Sopenharmony_ci else if (sprn == SPRN_TFIAR) 9798c2ecf20Sopenharmony_ci *spr_val = mfspr(SPRN_TFIAR); 9808c2ecf20Sopenharmony_ci tm_disable(); 9818c2ecf20Sopenharmony_ci break; 9828c2ecf20Sopenharmony_ci#endif 9838c2ecf20Sopenharmony_ci#endif 9848c2ecf20Sopenharmony_ci case SPRN_THRM1: 9858c2ecf20Sopenharmony_ci case SPRN_THRM2: 9868c2ecf20Sopenharmony_ci case SPRN_THRM3: 9878c2ecf20Sopenharmony_ci case SPRN_CTRLF: 9888c2ecf20Sopenharmony_ci case SPRN_CTRLT: 9898c2ecf20Sopenharmony_ci case SPRN_L2CR: 9908c2ecf20Sopenharmony_ci case SPRN_MMCR0_GEKKO: 9918c2ecf20Sopenharmony_ci case SPRN_MMCR1_GEKKO: 9928c2ecf20Sopenharmony_ci case SPRN_PMC1_GEKKO: 9938c2ecf20Sopenharmony_ci case SPRN_PMC2_GEKKO: 9948c2ecf20Sopenharmony_ci case SPRN_PMC3_GEKKO: 9958c2ecf20Sopenharmony_ci case SPRN_PMC4_GEKKO: 9968c2ecf20Sopenharmony_ci case SPRN_WPAR_GEKKO: 9978c2ecf20Sopenharmony_ci case SPRN_MSSSR0: 9988c2ecf20Sopenharmony_ci case SPRN_DABR: 9998c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 10008c2ecf20Sopenharmony_ci case SPRN_MMCRS: 10018c2ecf20Sopenharmony_ci case SPRN_MMCRA: 10028c2ecf20Sopenharmony_ci case SPRN_MMCR0: 10038c2ecf20Sopenharmony_ci case SPRN_MMCR1: 10048c2ecf20Sopenharmony_ci case SPRN_MMCR2: 10058c2ecf20Sopenharmony_ci case SPRN_UMMCR2: 10068c2ecf20Sopenharmony_ci case SPRN_TIR: 10078c2ecf20Sopenharmony_ci#endif 10088c2ecf20Sopenharmony_ci *spr_val = 0; 10098c2ecf20Sopenharmony_ci break; 10108c2ecf20Sopenharmony_ci default: 10118c2ecf20Sopenharmony_ciunprivileged: 10128c2ecf20Sopenharmony_ci pr_info_ratelimited("KVM: invalid SPR read: %d\n", sprn); 10138c2ecf20Sopenharmony_ci if (sprn & 0x10) { 10148c2ecf20Sopenharmony_ci if (kvmppc_get_msr(vcpu) & MSR_PR) { 10158c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGPRIV); 10168c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci } else { 10198c2ecf20Sopenharmony_ci if ((kvmppc_get_msr(vcpu) & MSR_PR) || sprn == 0 || 10208c2ecf20Sopenharmony_ci sprn == 4 || sprn == 5 || sprn == 6) { 10218c2ecf20Sopenharmony_ci kvmppc_core_queue_program(vcpu, SRR1_PROGILL); 10228c2ecf20Sopenharmony_ci emulated = EMULATE_AGAIN; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci return emulated; 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ciu32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci return make_dsisr(inst); 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ciulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64 10408c2ecf20Sopenharmony_ci /* 10418c2ecf20Sopenharmony_ci * Linux's fix_alignment() assumes that DAR is valid, so can we 10428c2ecf20Sopenharmony_ci */ 10438c2ecf20Sopenharmony_ci return vcpu->arch.fault_dar; 10448c2ecf20Sopenharmony_ci#else 10458c2ecf20Sopenharmony_ci ulong dar = 0; 10468c2ecf20Sopenharmony_ci ulong ra = get_ra(inst); 10478c2ecf20Sopenharmony_ci ulong rb = get_rb(inst); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci switch (get_op(inst)) { 10508c2ecf20Sopenharmony_ci case OP_LFS: 10518c2ecf20Sopenharmony_ci case OP_LFD: 10528c2ecf20Sopenharmony_ci case OP_STFD: 10538c2ecf20Sopenharmony_ci case OP_STFS: 10548c2ecf20Sopenharmony_ci if (ra) 10558c2ecf20Sopenharmony_ci dar = kvmppc_get_gpr(vcpu, ra); 10568c2ecf20Sopenharmony_ci dar += (s32)((s16)inst); 10578c2ecf20Sopenharmony_ci break; 10588c2ecf20Sopenharmony_ci case 31: 10598c2ecf20Sopenharmony_ci if (ra) 10608c2ecf20Sopenharmony_ci dar = kvmppc_get_gpr(vcpu, ra); 10618c2ecf20Sopenharmony_ci dar += kvmppc_get_gpr(vcpu, rb); 10628c2ecf20Sopenharmony_ci break; 10638c2ecf20Sopenharmony_ci default: 10648c2ecf20Sopenharmony_ci printk(KERN_INFO "KVM: Unaligned instruction 0x%x\n", inst); 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci return dar; 10698c2ecf20Sopenharmony_ci#endif 10708c2ecf20Sopenharmony_ci} 1071