18a05fd9aSRichard Henderson /* 28a05fd9aSRichard Henderson * PowerPC emulation special registers manipulation helpers for qemu. 38a05fd9aSRichard Henderson * 48a05fd9aSRichard Henderson * Copyright (c) 2003-2007 Jocelyn Mayer 58a05fd9aSRichard Henderson * 68a05fd9aSRichard Henderson * This library is free software; you can redistribute it and/or 78a05fd9aSRichard Henderson * modify it under the terms of the GNU Lesser General Public 88a05fd9aSRichard Henderson * License as published by the Free Software Foundation; either 98a05fd9aSRichard Henderson * version 2.1 of the License, or (at your option) any later version. 108a05fd9aSRichard Henderson * 118a05fd9aSRichard Henderson * This library is distributed in the hope that it will be useful, 128a05fd9aSRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of 138a05fd9aSRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 148a05fd9aSRichard Henderson * Lesser General Public License for more details. 158a05fd9aSRichard Henderson * 168a05fd9aSRichard Henderson * You should have received a copy of the GNU Lesser General Public 178a05fd9aSRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>. 188a05fd9aSRichard Henderson */ 198a05fd9aSRichard Henderson 208a05fd9aSRichard Henderson #include "qemu/osdep.h" 212df4fe7aSRichard Henderson #include "cpu.h" 228a05fd9aSRichard Henderson #include "qemu/main-loop.h" 238a05fd9aSRichard Henderson #include "exec/exec-all.h" 248a05fd9aSRichard Henderson #include "sysemu/kvm.h" 258a05fd9aSRichard Henderson #include "helper_regs.h" 26*46d396bdSDaniel Henrique Barboza #include "power8-pmu.h" 278a05fd9aSRichard Henderson 288a05fd9aSRichard Henderson /* Swap temporary saved registers with GPRs */ 298a05fd9aSRichard Henderson void hreg_swap_gpr_tgpr(CPUPPCState *env) 308a05fd9aSRichard Henderson { 318a05fd9aSRichard Henderson target_ulong tmp; 328a05fd9aSRichard Henderson 338a05fd9aSRichard Henderson tmp = env->gpr[0]; 348a05fd9aSRichard Henderson env->gpr[0] = env->tgpr[0]; 358a05fd9aSRichard Henderson env->tgpr[0] = tmp; 368a05fd9aSRichard Henderson tmp = env->gpr[1]; 378a05fd9aSRichard Henderson env->gpr[1] = env->tgpr[1]; 388a05fd9aSRichard Henderson env->tgpr[1] = tmp; 398a05fd9aSRichard Henderson tmp = env->gpr[2]; 408a05fd9aSRichard Henderson env->gpr[2] = env->tgpr[2]; 418a05fd9aSRichard Henderson env->tgpr[2] = tmp; 428a05fd9aSRichard Henderson tmp = env->gpr[3]; 438a05fd9aSRichard Henderson env->gpr[3] = env->tgpr[3]; 448a05fd9aSRichard Henderson env->tgpr[3] = tmp; 458a05fd9aSRichard Henderson } 468a05fd9aSRichard Henderson 472da8a6bcSRichard Henderson static uint32_t hreg_compute_hflags_value(CPUPPCState *env) 488a05fd9aSRichard Henderson { 492df4fe7aSRichard Henderson target_ulong msr = env->msr; 502df4fe7aSRichard Henderson uint32_t ppc_flags = env->flags; 512df4fe7aSRichard Henderson uint32_t hflags = 0; 522df4fe7aSRichard Henderson uint32_t msr_mask; 538a05fd9aSRichard Henderson 542df4fe7aSRichard Henderson /* Some bits come straight across from MSR. */ 552df4fe7aSRichard Henderson QEMU_BUILD_BUG_ON(MSR_LE != HFLAGS_LE); 562df4fe7aSRichard Henderson QEMU_BUILD_BUG_ON(MSR_PR != HFLAGS_PR); 572df4fe7aSRichard Henderson QEMU_BUILD_BUG_ON(MSR_DR != HFLAGS_DR); 582df4fe7aSRichard Henderson QEMU_BUILD_BUG_ON(MSR_FP != HFLAGS_FP); 592df4fe7aSRichard Henderson msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) | 60d764184dSRichard Henderson (1 << MSR_DR) | (1 << MSR_FP)); 6118285046SRichard Henderson 622df4fe7aSRichard Henderson if (ppc_flags & POWERPC_FLAG_HID0_LE) { 6318285046SRichard Henderson /* 6418285046SRichard Henderson * Note that MSR_LE is not set in env->msr_mask for this cpu, 652df4fe7aSRichard Henderson * and so will never be set in msr. 6618285046SRichard Henderson */ 6718285046SRichard Henderson uint32_t le = extract32(env->spr[SPR_HID0], 3, 1); 682df4fe7aSRichard Henderson hflags |= le << MSR_LE; 6918285046SRichard Henderson } 702df4fe7aSRichard Henderson 717da31f26SRichard Henderson if (ppc_flags & POWERPC_FLAG_DE) { 727da31f26SRichard Henderson target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; 737da31f26SRichard Henderson if (dbcr0 & DBCR0_ICMP) { 747da31f26SRichard Henderson hflags |= 1 << HFLAGS_SE; 757da31f26SRichard Henderson } 767da31f26SRichard Henderson if (dbcr0 & DBCR0_BRT) { 777da31f26SRichard Henderson hflags |= 1 << HFLAGS_BE; 787da31f26SRichard Henderson } 797da31f26SRichard Henderson } else { 802df4fe7aSRichard Henderson if (ppc_flags & POWERPC_FLAG_BE) { 812df4fe7aSRichard Henderson QEMU_BUILD_BUG_ON(MSR_BE != HFLAGS_BE); 822df4fe7aSRichard Henderson msr_mask |= 1 << MSR_BE; 832df4fe7aSRichard Henderson } 842df4fe7aSRichard Henderson if (ppc_flags & POWERPC_FLAG_SE) { 852df4fe7aSRichard Henderson QEMU_BUILD_BUG_ON(MSR_SE != HFLAGS_SE); 862df4fe7aSRichard Henderson msr_mask |= 1 << MSR_SE; 872df4fe7aSRichard Henderson } 887da31f26SRichard Henderson } 892df4fe7aSRichard Henderson 902df4fe7aSRichard Henderson if (msr_is_64bit(env, msr)) { 912df4fe7aSRichard Henderson hflags |= 1 << HFLAGS_64; 922df4fe7aSRichard Henderson } 932df4fe7aSRichard Henderson if ((ppc_flags & POWERPC_FLAG_SPE) && (msr & (1 << MSR_SPE))) { 942df4fe7aSRichard Henderson hflags |= 1 << HFLAGS_SPE; 952df4fe7aSRichard Henderson } 962df4fe7aSRichard Henderson if (ppc_flags & POWERPC_FLAG_VRE) { 972df4fe7aSRichard Henderson QEMU_BUILD_BUG_ON(MSR_VR != HFLAGS_VR); 982df4fe7aSRichard Henderson msr_mask |= 1 << MSR_VR; 992df4fe7aSRichard Henderson } 1000e6bac3eSRichard Henderson if (ppc_flags & POWERPC_FLAG_VSX) { 1010e6bac3eSRichard Henderson QEMU_BUILD_BUG_ON(MSR_VSX != HFLAGS_VSX); 1020e6bac3eSRichard Henderson msr_mask |= 1 << MSR_VSX; 1032df4fe7aSRichard Henderson } 1042df4fe7aSRichard Henderson if ((ppc_flags & POWERPC_FLAG_TM) && (msr & (1ull << MSR_TM))) { 1052df4fe7aSRichard Henderson hflags |= 1 << HFLAGS_TM; 1062df4fe7aSRichard Henderson } 107f03de3b4SRichard Henderson if (env->spr[SPR_LPCR] & LPCR_GTSE) { 108f03de3b4SRichard Henderson hflags |= 1 << HFLAGS_GTSE; 109f03de3b4SRichard Henderson } 1101db3632aSMatheus Ferst if (env->spr[SPR_LPCR] & LPCR_HR) { 1111db3632aSMatheus Ferst hflags |= 1 << HFLAGS_HR; 1121db3632aSMatheus Ferst } 113f7460df2SDaniel Henrique Barboza if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) { 114f7460df2SDaniel Henrique Barboza hflags |= 1 << HFLAGS_PMCC0; 115f7460df2SDaniel Henrique Barboza } 116f7460df2SDaniel Henrique Barboza if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) { 117f7460df2SDaniel Henrique Barboza hflags |= 1 << HFLAGS_PMCC1; 118f7460df2SDaniel Henrique Barboza } 1192df4fe7aSRichard Henderson 1202df4fe7aSRichard Henderson #ifndef CONFIG_USER_ONLY 1212df4fe7aSRichard Henderson if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { 1222df4fe7aSRichard Henderson hflags |= 1 << HFLAGS_HV; 1232df4fe7aSRichard Henderson } 124d764184dSRichard Henderson 125*46d396bdSDaniel Henrique Barboza #if defined(TARGET_PPC64) 126*46d396bdSDaniel Henrique Barboza if (pmu_insn_cnt_enabled(env)) { 127*46d396bdSDaniel Henrique Barboza hflags |= 1 << HFLAGS_INSN_CNT; 128*46d396bdSDaniel Henrique Barboza } 129*46d396bdSDaniel Henrique Barboza #endif 130*46d396bdSDaniel Henrique Barboza 131d764184dSRichard Henderson /* 132d764184dSRichard Henderson * This is our encoding for server processors. The architecture 133d764184dSRichard Henderson * specifies that there is no such thing as userspace with 134d764184dSRichard Henderson * translation off, however it appears that MacOS does it and some 135d764184dSRichard Henderson * 32-bit CPUs support it. Weird... 136d764184dSRichard Henderson * 137d764184dSRichard Henderson * 0 = Guest User space virtual mode 138d764184dSRichard Henderson * 1 = Guest Kernel space virtual mode 139d764184dSRichard Henderson * 2 = Guest User space real mode 140d764184dSRichard Henderson * 3 = Guest Kernel space real mode 141d764184dSRichard Henderson * 4 = HV User space virtual mode 142d764184dSRichard Henderson * 5 = HV Kernel space virtual mode 143d764184dSRichard Henderson * 6 = HV User space real mode 144d764184dSRichard Henderson * 7 = HV Kernel space real mode 145d764184dSRichard Henderson * 146d764184dSRichard Henderson * For BookE, we need 8 MMU modes as follow: 147d764184dSRichard Henderson * 148d764184dSRichard Henderson * 0 = AS 0 HV User space 149d764184dSRichard Henderson * 1 = AS 0 HV Kernel space 150d764184dSRichard Henderson * 2 = AS 1 HV User space 151d764184dSRichard Henderson * 3 = AS 1 HV Kernel space 152d764184dSRichard Henderson * 4 = AS 0 Guest User space 153d764184dSRichard Henderson * 5 = AS 0 Guest Kernel space 154d764184dSRichard Henderson * 6 = AS 1 Guest User space 155d764184dSRichard Henderson * 7 = AS 1 Guest Kernel space 156d764184dSRichard Henderson */ 157d764184dSRichard Henderson unsigned immu_idx, dmmu_idx; 158d764184dSRichard Henderson dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1; 159d764184dSRichard Henderson if (env->mmu_model & POWERPC_MMU_BOOKE) { 160d764184dSRichard Henderson dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0; 161d764184dSRichard Henderson immu_idx = dmmu_idx; 162d764184dSRichard Henderson immu_idx |= msr & (1 << MSR_IS) ? 2 : 0; 163d764184dSRichard Henderson dmmu_idx |= msr & (1 << MSR_DS) ? 2 : 0; 164d764184dSRichard Henderson } else { 165d764184dSRichard Henderson dmmu_idx |= msr & (1ull << MSR_HV) ? 4 : 0; 166d764184dSRichard Henderson immu_idx = dmmu_idx; 167d764184dSRichard Henderson immu_idx |= msr & (1 << MSR_IR) ? 0 : 2; 168d764184dSRichard Henderson dmmu_idx |= msr & (1 << MSR_DR) ? 0 : 2; 169d764184dSRichard Henderson } 170d764184dSRichard Henderson hflags |= immu_idx << HFLAGS_IMMU_IDX; 171d764184dSRichard Henderson hflags |= dmmu_idx << HFLAGS_DMMU_IDX; 1722df4fe7aSRichard Henderson #endif 1732df4fe7aSRichard Henderson 1742da8a6bcSRichard Henderson return hflags | (msr & msr_mask); 1758a05fd9aSRichard Henderson } 1768a05fd9aSRichard Henderson 1772da8a6bcSRichard Henderson void hreg_compute_hflags(CPUPPCState *env) 1782da8a6bcSRichard Henderson { 1792da8a6bcSRichard Henderson env->hflags = hreg_compute_hflags_value(env); 1802da8a6bcSRichard Henderson } 1812da8a6bcSRichard Henderson 1822da8a6bcSRichard Henderson #ifdef CONFIG_DEBUG_TCG 1832da8a6bcSRichard Henderson void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, 1842da8a6bcSRichard Henderson target_ulong *cs_base, uint32_t *flags) 1852da8a6bcSRichard Henderson { 1862da8a6bcSRichard Henderson uint32_t hflags_current = env->hflags; 1872da8a6bcSRichard Henderson uint32_t hflags_rebuilt; 1882da8a6bcSRichard Henderson 1892da8a6bcSRichard Henderson *pc = env->nip; 1902da8a6bcSRichard Henderson *cs_base = 0; 1912da8a6bcSRichard Henderson *flags = hflags_current; 1922da8a6bcSRichard Henderson 1932da8a6bcSRichard Henderson hflags_rebuilt = hreg_compute_hflags_value(env); 1942da8a6bcSRichard Henderson if (unlikely(hflags_current != hflags_rebuilt)) { 1952da8a6bcSRichard Henderson cpu_abort(env_cpu(env), 1962da8a6bcSRichard Henderson "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n", 1972da8a6bcSRichard Henderson hflags_current, hflags_rebuilt); 1982da8a6bcSRichard Henderson } 1992da8a6bcSRichard Henderson } 2002da8a6bcSRichard Henderson #endif 2012da8a6bcSRichard Henderson 2028a05fd9aSRichard Henderson void cpu_interrupt_exittb(CPUState *cs) 2038a05fd9aSRichard Henderson { 2048a05fd9aSRichard Henderson if (!kvm_enabled()) { 2058a05fd9aSRichard Henderson return; 2068a05fd9aSRichard Henderson } 2078a05fd9aSRichard Henderson 2088a05fd9aSRichard Henderson if (!qemu_mutex_iothread_locked()) { 2098a05fd9aSRichard Henderson qemu_mutex_lock_iothread(); 2108a05fd9aSRichard Henderson cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); 2118a05fd9aSRichard Henderson qemu_mutex_unlock_iothread(); 2128a05fd9aSRichard Henderson } else { 2138a05fd9aSRichard Henderson cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); 2148a05fd9aSRichard Henderson } 2158a05fd9aSRichard Henderson } 2168a05fd9aSRichard Henderson 2178a05fd9aSRichard Henderson int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) 2188a05fd9aSRichard Henderson { 2198a05fd9aSRichard Henderson int excp; 2208a05fd9aSRichard Henderson #if !defined(CONFIG_USER_ONLY) 2218a05fd9aSRichard Henderson CPUState *cs = env_cpu(env); 2228a05fd9aSRichard Henderson #endif 2238a05fd9aSRichard Henderson 2248a05fd9aSRichard Henderson excp = 0; 2258a05fd9aSRichard Henderson value &= env->msr_mask; 2268a05fd9aSRichard Henderson #if !defined(CONFIG_USER_ONLY) 2278a05fd9aSRichard Henderson /* Neither mtmsr nor guest state can alter HV */ 2288a05fd9aSRichard Henderson if (!alter_hv || !(env->msr & MSR_HVB)) { 2298a05fd9aSRichard Henderson value &= ~MSR_HVB; 2308a05fd9aSRichard Henderson value |= env->msr & MSR_HVB; 2318a05fd9aSRichard Henderson } 2328a05fd9aSRichard Henderson if (((value >> MSR_IR) & 1) != msr_ir || 2338a05fd9aSRichard Henderson ((value >> MSR_DR) & 1) != msr_dr) { 2348a05fd9aSRichard Henderson cpu_interrupt_exittb(cs); 2358a05fd9aSRichard Henderson } 2368a05fd9aSRichard Henderson if ((env->mmu_model & POWERPC_MMU_BOOKE) && 2378a05fd9aSRichard Henderson ((value >> MSR_GS) & 1) != msr_gs) { 2388a05fd9aSRichard Henderson cpu_interrupt_exittb(cs); 2398a05fd9aSRichard Henderson } 2408a05fd9aSRichard Henderson if (unlikely((env->flags & POWERPC_FLAG_TGPR) && 2418a05fd9aSRichard Henderson ((value ^ env->msr) & (1 << MSR_TGPR)))) { 2428a05fd9aSRichard Henderson /* Swap temporary saved registers with GPRs */ 2438a05fd9aSRichard Henderson hreg_swap_gpr_tgpr(env); 2448a05fd9aSRichard Henderson } 2458a05fd9aSRichard Henderson if (unlikely((value >> MSR_EP) & 1) != msr_ep) { 2468a05fd9aSRichard Henderson /* Change the exception prefix on PowerPC 601 */ 2478a05fd9aSRichard Henderson env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; 2488a05fd9aSRichard Henderson } 2498a05fd9aSRichard Henderson /* 2508a05fd9aSRichard Henderson * If PR=1 then EE, IR and DR must be 1 2518a05fd9aSRichard Henderson * 2528a05fd9aSRichard Henderson * Note: We only enforce this on 64-bit server processors. 2538a05fd9aSRichard Henderson * It appears that: 2548a05fd9aSRichard Henderson * - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS 2558a05fd9aSRichard Henderson * exploits it. 2568a05fd9aSRichard Henderson * - 64-bit embedded implementations do not need any operation to be 2578a05fd9aSRichard Henderson * performed when PR is set. 2588a05fd9aSRichard Henderson */ 2598a05fd9aSRichard Henderson if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) { 2608a05fd9aSRichard Henderson value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR); 2618a05fd9aSRichard Henderson } 2628a05fd9aSRichard Henderson #endif 2638a05fd9aSRichard Henderson env->msr = value; 2648a05fd9aSRichard Henderson hreg_compute_hflags(env); 2658a05fd9aSRichard Henderson #if !defined(CONFIG_USER_ONLY) 2668a05fd9aSRichard Henderson if (unlikely(msr_pow == 1)) { 2678a05fd9aSRichard Henderson if (!env->pending_interrupts && (*env->check_pow)(env)) { 2688a05fd9aSRichard Henderson cs->halted = 1; 2698a05fd9aSRichard Henderson excp = EXCP_HALTED; 2708a05fd9aSRichard Henderson } 2718a05fd9aSRichard Henderson } 2728a05fd9aSRichard Henderson #endif 2738a05fd9aSRichard Henderson 2748a05fd9aSRichard Henderson return excp; 2758a05fd9aSRichard Henderson } 2768a05fd9aSRichard Henderson 277c06ba892SLucas Mateus Castro (alqotel) #ifdef CONFIG_SOFTMMU 278c06ba892SLucas Mateus Castro (alqotel) void store_40x_sler(CPUPPCState *env, uint32_t val) 279c06ba892SLucas Mateus Castro (alqotel) { 280c06ba892SLucas Mateus Castro (alqotel) /* XXX: TO BE FIXED */ 281c06ba892SLucas Mateus Castro (alqotel) if (val != 0x00000000) { 282c06ba892SLucas Mateus Castro (alqotel) cpu_abort(env_cpu(env), 283c06ba892SLucas Mateus Castro (alqotel) "Little-endian regions are not supported by now\n"); 284c06ba892SLucas Mateus Castro (alqotel) } 285c06ba892SLucas Mateus Castro (alqotel) env->spr[SPR_405_SLER] = val; 286c06ba892SLucas Mateus Castro (alqotel) } 287c06ba892SLucas Mateus Castro (alqotel) #endif /* CONFIG_SOFTMMU */ 288c06ba892SLucas Mateus Castro (alqotel) 2898a05fd9aSRichard Henderson #ifndef CONFIG_USER_ONLY 2908a05fd9aSRichard Henderson void check_tlb_flush(CPUPPCState *env, bool global) 2918a05fd9aSRichard Henderson { 2928a05fd9aSRichard Henderson CPUState *cs = env_cpu(env); 2938a05fd9aSRichard Henderson 2948a05fd9aSRichard Henderson /* Handle global flushes first */ 2958a05fd9aSRichard Henderson if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { 2968a05fd9aSRichard Henderson env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; 2978a05fd9aSRichard Henderson env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; 2988a05fd9aSRichard Henderson tlb_flush_all_cpus_synced(cs); 2998a05fd9aSRichard Henderson return; 3008a05fd9aSRichard Henderson } 3018a05fd9aSRichard Henderson 3028a05fd9aSRichard Henderson /* Then handle local ones */ 3038a05fd9aSRichard Henderson if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { 3048a05fd9aSRichard Henderson env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; 3058a05fd9aSRichard Henderson tlb_flush(cs); 3068a05fd9aSRichard Henderson } 3078a05fd9aSRichard Henderson } 3088a05fd9aSRichard Henderson #endif 309