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" 218a05fd9aSRichard Henderson #include "qemu/main-loop.h" 228a05fd9aSRichard Henderson #include "exec/exec-all.h" 238a05fd9aSRichard Henderson #include "sysemu/kvm.h" 248a05fd9aSRichard Henderson #include "helper_regs.h" 258a05fd9aSRichard Henderson 268a05fd9aSRichard Henderson /* Swap temporary saved registers with GPRs */ 278a05fd9aSRichard Henderson void hreg_swap_gpr_tgpr(CPUPPCState *env) 288a05fd9aSRichard Henderson { 298a05fd9aSRichard Henderson target_ulong tmp; 308a05fd9aSRichard Henderson 318a05fd9aSRichard Henderson tmp = env->gpr[0]; 328a05fd9aSRichard Henderson env->gpr[0] = env->tgpr[0]; 338a05fd9aSRichard Henderson env->tgpr[0] = tmp; 348a05fd9aSRichard Henderson tmp = env->gpr[1]; 358a05fd9aSRichard Henderson env->gpr[1] = env->tgpr[1]; 368a05fd9aSRichard Henderson env->tgpr[1] = tmp; 378a05fd9aSRichard Henderson tmp = env->gpr[2]; 388a05fd9aSRichard Henderson env->gpr[2] = env->tgpr[2]; 398a05fd9aSRichard Henderson env->tgpr[2] = tmp; 408a05fd9aSRichard Henderson tmp = env->gpr[3]; 418a05fd9aSRichard Henderson env->gpr[3] = env->tgpr[3]; 428a05fd9aSRichard Henderson env->tgpr[3] = tmp; 438a05fd9aSRichard Henderson } 448a05fd9aSRichard Henderson 458a05fd9aSRichard Henderson void hreg_compute_mem_idx(CPUPPCState *env) 468a05fd9aSRichard Henderson { 478a05fd9aSRichard Henderson /* 488a05fd9aSRichard Henderson * This is our encoding for server processors. The architecture 498a05fd9aSRichard Henderson * specifies that there is no such thing as userspace with 508a05fd9aSRichard Henderson * translation off, however it appears that MacOS does it and some 518a05fd9aSRichard Henderson * 32-bit CPUs support it. Weird... 528a05fd9aSRichard Henderson * 538a05fd9aSRichard Henderson * 0 = Guest User space virtual mode 548a05fd9aSRichard Henderson * 1 = Guest Kernel space virtual mode 558a05fd9aSRichard Henderson * 2 = Guest User space real mode 568a05fd9aSRichard Henderson * 3 = Guest Kernel space real mode 578a05fd9aSRichard Henderson * 4 = HV User space virtual mode 588a05fd9aSRichard Henderson * 5 = HV Kernel space virtual mode 598a05fd9aSRichard Henderson * 6 = HV User space real mode 608a05fd9aSRichard Henderson * 7 = HV Kernel space real mode 618a05fd9aSRichard Henderson * 628a05fd9aSRichard Henderson * For BookE, we need 8 MMU modes as follow: 638a05fd9aSRichard Henderson * 648a05fd9aSRichard Henderson * 0 = AS 0 HV User space 658a05fd9aSRichard Henderson * 1 = AS 0 HV Kernel space 668a05fd9aSRichard Henderson * 2 = AS 1 HV User space 678a05fd9aSRichard Henderson * 3 = AS 1 HV Kernel space 688a05fd9aSRichard Henderson * 4 = AS 0 Guest User space 698a05fd9aSRichard Henderson * 5 = AS 0 Guest Kernel space 708a05fd9aSRichard Henderson * 6 = AS 1 Guest User space 718a05fd9aSRichard Henderson * 7 = AS 1 Guest Kernel space 728a05fd9aSRichard Henderson */ 738a05fd9aSRichard Henderson if (env->mmu_model & POWERPC_MMU_BOOKE) { 748a05fd9aSRichard Henderson env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1; 758a05fd9aSRichard Henderson env->immu_idx += msr_is ? 2 : 0; 768a05fd9aSRichard Henderson env->dmmu_idx += msr_ds ? 2 : 0; 778a05fd9aSRichard Henderson env->immu_idx += msr_gs ? 4 : 0; 788a05fd9aSRichard Henderson env->dmmu_idx += msr_gs ? 4 : 0; 798a05fd9aSRichard Henderson } else { 808a05fd9aSRichard Henderson env->immu_idx = env->dmmu_idx = msr_pr ? 0 : 1; 818a05fd9aSRichard Henderson env->immu_idx += msr_ir ? 0 : 2; 828a05fd9aSRichard Henderson env->dmmu_idx += msr_dr ? 0 : 2; 838a05fd9aSRichard Henderson env->immu_idx += msr_hv ? 4 : 0; 848a05fd9aSRichard Henderson env->dmmu_idx += msr_hv ? 4 : 0; 858a05fd9aSRichard Henderson } 868a05fd9aSRichard Henderson } 878a05fd9aSRichard Henderson 888a05fd9aSRichard Henderson void hreg_compute_hflags(CPUPPCState *env) 898a05fd9aSRichard Henderson { 908a05fd9aSRichard Henderson target_ulong hflags_mask; 918a05fd9aSRichard Henderson 928a05fd9aSRichard Henderson /* We 'forget' FE0 & FE1: we'll never generate imprecise exceptions */ 938a05fd9aSRichard Henderson hflags_mask = (1 << MSR_VR) | (1 << MSR_AP) | (1 << MSR_SA) | 948a05fd9aSRichard Henderson (1 << MSR_PR) | (1 << MSR_FP) | (1 << MSR_SE) | (1 << MSR_BE) | 958a05fd9aSRichard Henderson (1 << MSR_LE) | (1 << MSR_VSX) | (1 << MSR_IR) | (1 << MSR_DR); 968a05fd9aSRichard Henderson hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF) | MSR_HVB; 978a05fd9aSRichard Henderson hreg_compute_mem_idx(env); 988a05fd9aSRichard Henderson env->hflags = env->msr & hflags_mask; 99*18285046SRichard Henderson 100*18285046SRichard Henderson if (env->flags & POWERPC_FLAG_HID0_LE) { 101*18285046SRichard Henderson /* 102*18285046SRichard Henderson * Note that MSR_LE is not set in env->msr_mask for this cpu, 103*18285046SRichard Henderson * and so will never be set in msr or hflags at this point. 104*18285046SRichard Henderson */ 105*18285046SRichard Henderson uint32_t le = extract32(env->spr[SPR_HID0], 3, 1); 106*18285046SRichard Henderson env->hflags |= le << MSR_LE; 107*18285046SRichard Henderson /* Retain for backward compatibility with migration. */ 108*18285046SRichard Henderson env->hflags_nmsr = le << MSR_LE; 109*18285046SRichard Henderson } 1108a05fd9aSRichard Henderson } 1118a05fd9aSRichard Henderson 1128a05fd9aSRichard Henderson void cpu_interrupt_exittb(CPUState *cs) 1138a05fd9aSRichard Henderson { 1148a05fd9aSRichard Henderson if (!kvm_enabled()) { 1158a05fd9aSRichard Henderson return; 1168a05fd9aSRichard Henderson } 1178a05fd9aSRichard Henderson 1188a05fd9aSRichard Henderson if (!qemu_mutex_iothread_locked()) { 1198a05fd9aSRichard Henderson qemu_mutex_lock_iothread(); 1208a05fd9aSRichard Henderson cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); 1218a05fd9aSRichard Henderson qemu_mutex_unlock_iothread(); 1228a05fd9aSRichard Henderson } else { 1238a05fd9aSRichard Henderson cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); 1248a05fd9aSRichard Henderson } 1258a05fd9aSRichard Henderson } 1268a05fd9aSRichard Henderson 1278a05fd9aSRichard Henderson int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) 1288a05fd9aSRichard Henderson { 1298a05fd9aSRichard Henderson int excp; 1308a05fd9aSRichard Henderson #if !defined(CONFIG_USER_ONLY) 1318a05fd9aSRichard Henderson CPUState *cs = env_cpu(env); 1328a05fd9aSRichard Henderson #endif 1338a05fd9aSRichard Henderson 1348a05fd9aSRichard Henderson excp = 0; 1358a05fd9aSRichard Henderson value &= env->msr_mask; 1368a05fd9aSRichard Henderson #if !defined(CONFIG_USER_ONLY) 1378a05fd9aSRichard Henderson /* Neither mtmsr nor guest state can alter HV */ 1388a05fd9aSRichard Henderson if (!alter_hv || !(env->msr & MSR_HVB)) { 1398a05fd9aSRichard Henderson value &= ~MSR_HVB; 1408a05fd9aSRichard Henderson value |= env->msr & MSR_HVB; 1418a05fd9aSRichard Henderson } 1428a05fd9aSRichard Henderson if (((value >> MSR_IR) & 1) != msr_ir || 1438a05fd9aSRichard Henderson ((value >> MSR_DR) & 1) != msr_dr) { 1448a05fd9aSRichard Henderson cpu_interrupt_exittb(cs); 1458a05fd9aSRichard Henderson } 1468a05fd9aSRichard Henderson if ((env->mmu_model & POWERPC_MMU_BOOKE) && 1478a05fd9aSRichard Henderson ((value >> MSR_GS) & 1) != msr_gs) { 1488a05fd9aSRichard Henderson cpu_interrupt_exittb(cs); 1498a05fd9aSRichard Henderson } 1508a05fd9aSRichard Henderson if (unlikely((env->flags & POWERPC_FLAG_TGPR) && 1518a05fd9aSRichard Henderson ((value ^ env->msr) & (1 << MSR_TGPR)))) { 1528a05fd9aSRichard Henderson /* Swap temporary saved registers with GPRs */ 1538a05fd9aSRichard Henderson hreg_swap_gpr_tgpr(env); 1548a05fd9aSRichard Henderson } 1558a05fd9aSRichard Henderson if (unlikely((value >> MSR_EP) & 1) != msr_ep) { 1568a05fd9aSRichard Henderson /* Change the exception prefix on PowerPC 601 */ 1578a05fd9aSRichard Henderson env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000; 1588a05fd9aSRichard Henderson } 1598a05fd9aSRichard Henderson /* 1608a05fd9aSRichard Henderson * If PR=1 then EE, IR and DR must be 1 1618a05fd9aSRichard Henderson * 1628a05fd9aSRichard Henderson * Note: We only enforce this on 64-bit server processors. 1638a05fd9aSRichard Henderson * It appears that: 1648a05fd9aSRichard Henderson * - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS 1658a05fd9aSRichard Henderson * exploits it. 1668a05fd9aSRichard Henderson * - 64-bit embedded implementations do not need any operation to be 1678a05fd9aSRichard Henderson * performed when PR is set. 1688a05fd9aSRichard Henderson */ 1698a05fd9aSRichard Henderson if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) { 1708a05fd9aSRichard Henderson value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR); 1718a05fd9aSRichard Henderson } 1728a05fd9aSRichard Henderson #endif 1738a05fd9aSRichard Henderson env->msr = value; 1748a05fd9aSRichard Henderson hreg_compute_hflags(env); 1758a05fd9aSRichard Henderson #if !defined(CONFIG_USER_ONLY) 1768a05fd9aSRichard Henderson if (unlikely(msr_pow == 1)) { 1778a05fd9aSRichard Henderson if (!env->pending_interrupts && (*env->check_pow)(env)) { 1788a05fd9aSRichard Henderson cs->halted = 1; 1798a05fd9aSRichard Henderson excp = EXCP_HALTED; 1808a05fd9aSRichard Henderson } 1818a05fd9aSRichard Henderson } 1828a05fd9aSRichard Henderson #endif 1838a05fd9aSRichard Henderson 1848a05fd9aSRichard Henderson return excp; 1858a05fd9aSRichard Henderson } 1868a05fd9aSRichard Henderson 1878a05fd9aSRichard Henderson #ifndef CONFIG_USER_ONLY 1888a05fd9aSRichard Henderson void check_tlb_flush(CPUPPCState *env, bool global) 1898a05fd9aSRichard Henderson { 1908a05fd9aSRichard Henderson CPUState *cs = env_cpu(env); 1918a05fd9aSRichard Henderson 1928a05fd9aSRichard Henderson /* Handle global flushes first */ 1938a05fd9aSRichard Henderson if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { 1948a05fd9aSRichard Henderson env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; 1958a05fd9aSRichard Henderson env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; 1968a05fd9aSRichard Henderson tlb_flush_all_cpus_synced(cs); 1978a05fd9aSRichard Henderson return; 1988a05fd9aSRichard Henderson } 1998a05fd9aSRichard Henderson 2008a05fd9aSRichard Henderson /* Then handle local ones */ 2018a05fd9aSRichard Henderson if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { 2028a05fd9aSRichard Henderson env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; 2038a05fd9aSRichard Henderson tlb_flush(cs); 2048a05fd9aSRichard Henderson } 2058a05fd9aSRichard Henderson } 2068a05fd9aSRichard Henderson #endif 207