1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth * Miscellaneous PowerPC emulation helpers for QEMU.
3fcf5ef2aSThomas Huth *
4fcf5ef2aSThomas Huth * Copyright (c) 2003-2007 Jocelyn Mayer
5fcf5ef2aSThomas Huth *
6fcf5ef2aSThomas Huth * This library is free software; you can redistribute it and/or
7fcf5ef2aSThomas Huth * modify it under the terms of the GNU Lesser General Public
8fcf5ef2aSThomas Huth * License as published by the Free Software Foundation; either
96bd039cdSChetan Pant * version 2.1 of the License, or (at your option) any later version.
10fcf5ef2aSThomas Huth *
11fcf5ef2aSThomas Huth * This library is distributed in the hope that it will be useful,
12fcf5ef2aSThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of
13fcf5ef2aSThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14fcf5ef2aSThomas Huth * Lesser General Public License for more details.
15fcf5ef2aSThomas Huth *
16fcf5ef2aSThomas Huth * You should have received a copy of the GNU Lesser General Public
17fcf5ef2aSThomas Huth * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18fcf5ef2aSThomas Huth */
19db725815SMarkus Armbruster
20fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "exec/exec-all.h"
24fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
256b375544SJoel Stanley #include "qemu/error-report.h"
26db725815SMarkus Armbruster #include "qemu/main-loop.h"
2722adb61fSBruno Larsen (billionai) #include "mmu-book3s-v3.h"
287b694df6SMatheus Ferst #include "hw/ppc/ppc.h"
29fcf5ef2aSThomas Huth
30fcf5ef2aSThomas Huth #include "helper_regs.h"
31fcf5ef2aSThomas Huth
32fcf5ef2aSThomas Huth /*****************************************************************************/
33fcf5ef2aSThomas Huth /* SPR accesses */
helper_load_dump_spr(CPUPPCState * env,uint32_t sprn)34fcf5ef2aSThomas Huth void helper_load_dump_spr(CPUPPCState *env, uint32_t sprn)
35fcf5ef2aSThomas Huth {
36fcf5ef2aSThomas Huth qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
37fcf5ef2aSThomas Huth env->spr[sprn]);
38fcf5ef2aSThomas Huth }
39fcf5ef2aSThomas Huth
helper_store_dump_spr(CPUPPCState * env,uint32_t sprn)40fcf5ef2aSThomas Huth void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
41fcf5ef2aSThomas Huth {
42fcf5ef2aSThomas Huth qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
43fcf5ef2aSThomas Huth env->spr[sprn]);
44fcf5ef2aSThomas Huth }
45fcf5ef2aSThomas Huth
helper_spr_core_write_generic(CPUPPCState * env,uint32_t sprn,target_ulong val)469cdfd1b9SNicholas Piggin void helper_spr_core_write_generic(CPUPPCState *env, uint32_t sprn,
479cdfd1b9SNicholas Piggin target_ulong val)
489cdfd1b9SNicholas Piggin {
499cdfd1b9SNicholas Piggin CPUState *cs = env_cpu(env);
509cdfd1b9SNicholas Piggin CPUState *ccs;
519cdfd1b9SNicholas Piggin
5250d8cfb9SNicholas Piggin if (ppc_cpu_core_single_threaded(cs)) {
539cdfd1b9SNicholas Piggin env->spr[sprn] = val;
549cdfd1b9SNicholas Piggin return;
559cdfd1b9SNicholas Piggin }
569cdfd1b9SNicholas Piggin
579cdfd1b9SNicholas Piggin THREAD_SIBLING_FOREACH(cs, ccs) {
589cdfd1b9SNicholas Piggin CPUPPCState *cenv = &POWERPC_CPU(ccs)->env;
599cdfd1b9SNicholas Piggin cenv->spr[sprn] = val;
609cdfd1b9SNicholas Piggin }
619cdfd1b9SNicholas Piggin }
629cdfd1b9SNicholas Piggin
helper_spr_write_CTRL(CPUPPCState * env,uint32_t sprn,target_ulong val)63c5d98a7bSNicholas Piggin void helper_spr_write_CTRL(CPUPPCState *env, uint32_t sprn,
64c5d98a7bSNicholas Piggin target_ulong val)
65c5d98a7bSNicholas Piggin {
66c5d98a7bSNicholas Piggin CPUState *cs = env_cpu(env);
67c5d98a7bSNicholas Piggin CPUState *ccs;
68c5d98a7bSNicholas Piggin uint32_t run = val & 1;
69c5d98a7bSNicholas Piggin uint32_t ts, ts_mask;
70c5d98a7bSNicholas Piggin
71c5d98a7bSNicholas Piggin assert(sprn == SPR_CTRL);
72c5d98a7bSNicholas Piggin
73c5d98a7bSNicholas Piggin env->spr[sprn] &= ~1U;
74c5d98a7bSNicholas Piggin env->spr[sprn] |= run;
75c5d98a7bSNicholas Piggin
76c5d98a7bSNicholas Piggin ts_mask = ~(1U << (8 + env->spr[SPR_TIR]));
77c5d98a7bSNicholas Piggin ts = run << (8 + env->spr[SPR_TIR]);
78c5d98a7bSNicholas Piggin
79c5d98a7bSNicholas Piggin THREAD_SIBLING_FOREACH(cs, ccs) {
80c5d98a7bSNicholas Piggin CPUPPCState *cenv = &POWERPC_CPU(ccs)->env;
81c5d98a7bSNicholas Piggin
82c5d98a7bSNicholas Piggin cenv->spr[sprn] &= ts_mask;
83c5d98a7bSNicholas Piggin cenv->spr[sprn] |= ts;
84c5d98a7bSNicholas Piggin }
85c5d98a7bSNicholas Piggin }
86c5d98a7bSNicholas Piggin
87c5d98a7bSNicholas Piggin
88fcf5ef2aSThomas Huth #ifdef TARGET_PPC64
raise_hv_fu_exception(CPUPPCState * env,uint32_t bit,const char * caller,uint32_t cause,uintptr_t raddr)89493028d8SCédric Le Goater static void raise_hv_fu_exception(CPUPPCState *env, uint32_t bit,
90493028d8SCédric Le Goater const char *caller, uint32_t cause,
91493028d8SCédric Le Goater uintptr_t raddr)
92493028d8SCédric Le Goater {
93493028d8SCédric Le Goater qemu_log_mask(CPU_LOG_INT, "HV Facility %d is unavailable (%s)\n",
94493028d8SCédric Le Goater bit, caller);
95493028d8SCédric Le Goater
96493028d8SCédric Le Goater env->spr[SPR_HFSCR] &= ~((target_ulong)FSCR_IC_MASK << FSCR_IC_POS);
97493028d8SCédric Le Goater
98493028d8SCédric Le Goater raise_exception_err_ra(env, POWERPC_EXCP_HV_FU, cause, raddr);
99493028d8SCédric Le Goater }
100493028d8SCédric Le Goater
raise_fu_exception(CPUPPCState * env,uint32_t bit,uint32_t sprn,uint32_t cause,uintptr_t raddr)101fcf5ef2aSThomas Huth static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
102fcf5ef2aSThomas Huth uint32_t sprn, uint32_t cause,
103fcf5ef2aSThomas Huth uintptr_t raddr)
104fcf5ef2aSThomas Huth {
105fcf5ef2aSThomas Huth qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
106fcf5ef2aSThomas Huth
107fcf5ef2aSThomas Huth env->spr[SPR_FSCR] &= ~((target_ulong)FSCR_IC_MASK << FSCR_IC_POS);
108fcf5ef2aSThomas Huth cause &= FSCR_IC_MASK;
109fcf5ef2aSThomas Huth env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
110fcf5ef2aSThomas Huth
111fcf5ef2aSThomas Huth raise_exception_err_ra(env, POWERPC_EXCP_FU, 0, raddr);
112fcf5ef2aSThomas Huth }
113fcf5ef2aSThomas Huth #endif
114fcf5ef2aSThomas Huth
helper_hfscr_facility_check(CPUPPCState * env,uint32_t bit,const char * caller,uint32_t cause)115493028d8SCédric Le Goater void helper_hfscr_facility_check(CPUPPCState *env, uint32_t bit,
116493028d8SCédric Le Goater const char *caller, uint32_t cause)
117493028d8SCédric Le Goater {
118493028d8SCédric Le Goater #ifdef TARGET_PPC64
1199de754d3SVíctor Colombo if ((env->msr_mask & MSR_HVB) && !FIELD_EX64(env->msr, MSR, HV) &&
120493028d8SCédric Le Goater !(env->spr[SPR_HFSCR] & (1UL << bit))) {
121493028d8SCédric Le Goater raise_hv_fu_exception(env, bit, caller, cause, GETPC());
122493028d8SCédric Le Goater }
123493028d8SCédric Le Goater #endif
124493028d8SCédric Le Goater }
125493028d8SCédric Le Goater
helper_fscr_facility_check(CPUPPCState * env,uint32_t bit,uint32_t sprn,uint32_t cause)126fcf5ef2aSThomas Huth void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
127fcf5ef2aSThomas Huth uint32_t sprn, uint32_t cause)
128fcf5ef2aSThomas Huth {
129fcf5ef2aSThomas Huth #ifdef TARGET_PPC64
130fcf5ef2aSThomas Huth if (env->spr[SPR_FSCR] & (1ULL << bit)) {
131fcf5ef2aSThomas Huth /* Facility is enabled, continue */
132fcf5ef2aSThomas Huth return;
133fcf5ef2aSThomas Huth }
134fcf5ef2aSThomas Huth raise_fu_exception(env, bit, sprn, cause, GETPC());
135fcf5ef2aSThomas Huth #endif
136fcf5ef2aSThomas Huth }
137fcf5ef2aSThomas Huth
helper_msr_facility_check(CPUPPCState * env,uint32_t bit,uint32_t sprn,uint32_t cause)138fcf5ef2aSThomas Huth void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
139fcf5ef2aSThomas Huth uint32_t sprn, uint32_t cause)
140fcf5ef2aSThomas Huth {
141fcf5ef2aSThomas Huth #ifdef TARGET_PPC64
142fcf5ef2aSThomas Huth if (env->msr & (1ULL << bit)) {
143fcf5ef2aSThomas Huth /* Facility is enabled, continue */
144fcf5ef2aSThomas Huth return;
145fcf5ef2aSThomas Huth }
146fcf5ef2aSThomas Huth raise_fu_exception(env, bit, sprn, cause, GETPC());
147fcf5ef2aSThomas Huth #endif
148fcf5ef2aSThomas Huth }
149fcf5ef2aSThomas Huth
150fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
151fcf5ef2aSThomas Huth
1526bfcf1dcSGlenn Miles #ifdef TARGET_PPC64
helper_mmcr0_facility_check(CPUPPCState * env,uint32_t bit,uint32_t sprn,uint32_t cause)1536bfcf1dcSGlenn Miles static void helper_mmcr0_facility_check(CPUPPCState *env, uint32_t bit,
1546bfcf1dcSGlenn Miles uint32_t sprn, uint32_t cause)
1556bfcf1dcSGlenn Miles {
1566bfcf1dcSGlenn Miles if (FIELD_EX64(env->msr, MSR, PR) &&
1576bfcf1dcSGlenn Miles !(env->spr[SPR_POWER_MMCR0] & (1ULL << bit))) {
1586bfcf1dcSGlenn Miles raise_fu_exception(env, bit, sprn, cause, GETPC());
1596bfcf1dcSGlenn Miles }
1606bfcf1dcSGlenn Miles }
1616bfcf1dcSGlenn Miles #endif
1626bfcf1dcSGlenn Miles
helper_store_sdr1(CPUPPCState * env,target_ulong val)163fcf5ef2aSThomas Huth void helper_store_sdr1(CPUPPCState *env, target_ulong val)
164fcf5ef2aSThomas Huth {
165fcf5ef2aSThomas Huth if (env->spr[SPR_SDR1] != val) {
166fcf5ef2aSThomas Huth ppc_store_sdr1(env, val);
167db70b311SRichard Henderson tlb_flush(env_cpu(env));
168fcf5ef2aSThomas Huth }
169fcf5ef2aSThomas Huth }
170fcf5ef2aSThomas Huth
1714a7518e0SCédric Le Goater #if defined(TARGET_PPC64)
helper_store_ptcr(CPUPPCState * env,target_ulong val)1724a7518e0SCédric Le Goater void helper_store_ptcr(CPUPPCState *env, target_ulong val)
1734a7518e0SCédric Le Goater {
1744a7518e0SCédric Le Goater if (env->spr[SPR_PTCR] != val) {
1754d2b0ad3SNicholas Piggin CPUState *cs = env_cpu(env);
17622adb61fSBruno Larsen (billionai) PowerPCCPU *cpu = env_archcpu(env);
17722adb61fSBruno Larsen (billionai) target_ulong ptcr_mask = PTCR_PATB | PTCR_PATS;
17822adb61fSBruno Larsen (billionai) target_ulong patbsize = val & PTCR_PATS;
17922adb61fSBruno Larsen (billionai)
18022adb61fSBruno Larsen (billionai) qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, val);
18122adb61fSBruno Larsen (billionai)
18222adb61fSBruno Larsen (billionai) assert(!cpu->vhyp);
18322adb61fSBruno Larsen (billionai) assert(env->mmu_model & POWERPC_MMU_3_00);
18422adb61fSBruno Larsen (billionai)
18522adb61fSBruno Larsen (billionai) if (val & ~ptcr_mask) {
18622adb61fSBruno Larsen (billionai) error_report("Invalid bits 0x"TARGET_FMT_lx" set in PTCR",
18722adb61fSBruno Larsen (billionai) val & ~ptcr_mask);
18822adb61fSBruno Larsen (billionai) val &= ptcr_mask;
18922adb61fSBruno Larsen (billionai) }
19022adb61fSBruno Larsen (billionai)
19122adb61fSBruno Larsen (billionai) if (patbsize > 24) {
19222adb61fSBruno Larsen (billionai) error_report("Invalid Partition Table size 0x" TARGET_FMT_lx
19322adb61fSBruno Larsen (billionai) " stored in PTCR", patbsize);
19422adb61fSBruno Larsen (billionai) return;
19522adb61fSBruno Larsen (billionai) }
19622adb61fSBruno Larsen (billionai)
19750d8cfb9SNicholas Piggin if (ppc_cpu_lpar_single_threaded(cs)) {
19822adb61fSBruno Larsen (billionai) env->spr[SPR_PTCR] = val;
1994d2b0ad3SNicholas Piggin tlb_flush(cs);
2004d2b0ad3SNicholas Piggin } else {
2014d2b0ad3SNicholas Piggin CPUState *ccs;
2024d2b0ad3SNicholas Piggin
2034d2b0ad3SNicholas Piggin THREAD_SIBLING_FOREACH(cs, ccs) {
2044d2b0ad3SNicholas Piggin PowerPCCPU *ccpu = POWERPC_CPU(ccs);
2054d2b0ad3SNicholas Piggin CPUPPCState *cenv = &ccpu->env;
2064d2b0ad3SNicholas Piggin cenv->spr[SPR_PTCR] = val;
2074d2b0ad3SNicholas Piggin tlb_flush(ccs);
2084d2b0ad3SNicholas Piggin }
2094d2b0ad3SNicholas Piggin }
2104a7518e0SCédric Le Goater }
2114a7518e0SCédric Le Goater }
2126b375544SJoel Stanley
helper_store_pcr(CPUPPCState * env,target_ulong value)2136b375544SJoel Stanley void helper_store_pcr(CPUPPCState *env, target_ulong value)
2146b375544SJoel Stanley {
215db70b311SRichard Henderson PowerPCCPU *cpu = env_archcpu(env);
2166b375544SJoel Stanley PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
2176b375544SJoel Stanley
2186b375544SJoel Stanley env->spr[SPR_PCR] = value & pcc->pcr_mask;
2196b375544SJoel Stanley }
2205ba7ba1dSCédric Le Goater
helper_store_ciabr(CPUPPCState * env,target_ulong value)22114192307SNicholas Piggin void helper_store_ciabr(CPUPPCState *env, target_ulong value)
22214192307SNicholas Piggin {
22314192307SNicholas Piggin ppc_store_ciabr(env, value);
22414192307SNicholas Piggin }
22514192307SNicholas Piggin
helper_store_dawr0(CPUPPCState * env,target_ulong value)226d5ee641cSNicholas Piggin void helper_store_dawr0(CPUPPCState *env, target_ulong value)
227d5ee641cSNicholas Piggin {
228d5ee641cSNicholas Piggin ppc_store_dawr0(env, value);
229d5ee641cSNicholas Piggin }
230d5ee641cSNicholas Piggin
helper_store_dawrx0(CPUPPCState * env,target_ulong value)231d5ee641cSNicholas Piggin void helper_store_dawrx0(CPUPPCState *env, target_ulong value)
232d5ee641cSNicholas Piggin {
233d5ee641cSNicholas Piggin ppc_store_dawrx0(env, value);
234d5ee641cSNicholas Piggin }
235d5ee641cSNicholas Piggin
2365ba7ba1dSCédric Le Goater /*
2375ba7ba1dSCédric Le Goater * DPDES register is shared. Each bit reflects the state of the
2385ba7ba1dSCédric Le Goater * doorbell interrupt of a thread of the same core.
2395ba7ba1dSCédric Le Goater */
helper_load_dpdes(CPUPPCState * env)2405ba7ba1dSCédric Le Goater target_ulong helper_load_dpdes(CPUPPCState *env)
2415ba7ba1dSCédric Le Goater {
242d24e80b2SNicholas Piggin CPUState *cs = env_cpu(env);
243d24e80b2SNicholas Piggin CPUState *ccs;
2445ba7ba1dSCédric Le Goater target_ulong dpdes = 0;
2455ba7ba1dSCédric Le Goater
246493028d8SCédric Le Goater helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP);
247493028d8SCédric Le Goater
24850d8cfb9SNicholas Piggin /* DPDES behaves as 1-thread in LPAR-per-thread mode */
24950d8cfb9SNicholas Piggin if (ppc_cpu_lpar_single_threaded(cs)) {
250f003109fSMatheus Ferst if (env->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
2515ba7ba1dSCédric Le Goater dpdes = 1;
2525ba7ba1dSCédric Le Goater }
253d24e80b2SNicholas Piggin return dpdes;
254d24e80b2SNicholas Piggin }
255d24e80b2SNicholas Piggin
256195801d7SStefan Hajnoczi bql_lock();
257d24e80b2SNicholas Piggin THREAD_SIBLING_FOREACH(cs, ccs) {
258d24e80b2SNicholas Piggin PowerPCCPU *ccpu = POWERPC_CPU(ccs);
259d24e80b2SNicholas Piggin CPUPPCState *cenv = &ccpu->env;
260d24e80b2SNicholas Piggin uint32_t thread_id = ppc_cpu_tir(ccpu);
261d24e80b2SNicholas Piggin
262d24e80b2SNicholas Piggin if (cenv->pending_interrupts & PPC_INTERRUPT_DOORBELL) {
263d24e80b2SNicholas Piggin dpdes |= (0x1 << thread_id);
264d24e80b2SNicholas Piggin }
265d24e80b2SNicholas Piggin }
266195801d7SStefan Hajnoczi bql_unlock();
2675ba7ba1dSCédric Le Goater
2685ba7ba1dSCédric Le Goater return dpdes;
2695ba7ba1dSCédric Le Goater }
2705ba7ba1dSCédric Le Goater
helper_store_dpdes(CPUPPCState * env,target_ulong val)2715ba7ba1dSCédric Le Goater void helper_store_dpdes(CPUPPCState *env, target_ulong val)
2725ba7ba1dSCédric Le Goater {
2735ba7ba1dSCédric Le Goater PowerPCCPU *cpu = env_archcpu(env);
274d24e80b2SNicholas Piggin CPUState *cs = env_cpu(env);
275d24e80b2SNicholas Piggin CPUState *ccs;
2765ba7ba1dSCédric Le Goater
277493028d8SCédric Le Goater helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
278493028d8SCédric Le Goater
27950d8cfb9SNicholas Piggin /* DPDES behaves as 1-thread in LPAR-per-thread mode */
28050d8cfb9SNicholas Piggin if (ppc_cpu_lpar_single_threaded(cs)) {
281d24e80b2SNicholas Piggin ppc_set_irq(cpu, PPC_INTERRUPT_DOORBELL, val & 0x1);
2825ba7ba1dSCédric Le Goater return;
2835ba7ba1dSCédric Le Goater }
2845ba7ba1dSCédric Le Goater
285d24e80b2SNicholas Piggin /* Does iothread need to be locked for walking CPU list? */
286195801d7SStefan Hajnoczi bql_lock();
287d24e80b2SNicholas Piggin THREAD_SIBLING_FOREACH(cs, ccs) {
288d24e80b2SNicholas Piggin PowerPCCPU *ccpu = POWERPC_CPU(ccs);
289d24e80b2SNicholas Piggin uint32_t thread_id = ppc_cpu_tir(ccpu);
290d24e80b2SNicholas Piggin
291*2a14b2f4SNicholas Piggin ppc_set_irq(ccpu, PPC_INTERRUPT_DOORBELL, val & (0x1 << thread_id));
292d24e80b2SNicholas Piggin }
293195801d7SStefan Hajnoczi bql_unlock();
2945ba7ba1dSCédric Le Goater }
2952736432fSNicholas Piggin
29660d30cffSNicholas Piggin /*
29760d30cffSNicholas Piggin * qemu-user breaks with pnv headers, so they go under ifdefs for now.
29860d30cffSNicholas Piggin * A clean up may be to move powernv specific registers and helpers into
29960d30cffSNicholas Piggin * target/ppc/pnv_helper.c
30060d30cffSNicholas Piggin */
30160d30cffSNicholas Piggin #include "hw/ppc/pnv_core.h"
30260d30cffSNicholas Piggin
3032736432fSNicholas Piggin /* Indirect SCOM (SPRC/SPRD) access to SCRATCH0-7 are implemented. */
helper_store_sprc(CPUPPCState * env,target_ulong val)3042736432fSNicholas Piggin void helper_store_sprc(CPUPPCState *env, target_ulong val)
3052736432fSNicholas Piggin {
3062736432fSNicholas Piggin if (val & ~0x3f8ULL) {
3072736432fSNicholas Piggin qemu_log_mask(LOG_GUEST_ERROR, "Invalid SPRC register value "
3082736432fSNicholas Piggin TARGET_FMT_lx"\n", val);
3092736432fSNicholas Piggin return;
3102736432fSNicholas Piggin }
3112736432fSNicholas Piggin env->spr[SPR_POWER_SPRC] = val;
3122736432fSNicholas Piggin }
3132736432fSNicholas Piggin
helper_load_sprd(CPUPPCState * env)3142736432fSNicholas Piggin target_ulong helper_load_sprd(CPUPPCState *env)
3152736432fSNicholas Piggin {
31660d30cffSNicholas Piggin /*
31760d30cffSNicholas Piggin * SPRD is a HV-only register for Power CPUs, so this will only be
31860d30cffSNicholas Piggin * accessed by powernv machines.
31960d30cffSNicholas Piggin */
32060d30cffSNicholas Piggin PowerPCCPU *cpu = env_archcpu(env);
32160d30cffSNicholas Piggin PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
3222736432fSNicholas Piggin target_ulong sprc = env->spr[SPR_POWER_SPRC];
3232736432fSNicholas Piggin
32460d30cffSNicholas Piggin switch (sprc & 0x3e0) {
32560d30cffSNicholas Piggin case 0: /* SCRATCH0-3 */
32660d30cffSNicholas Piggin case 1: /* SCRATCH4-7 */
32760d30cffSNicholas Piggin return pc->scratch[(sprc >> 3) & 0x7];
32816ffcb34SNicholas Piggin
32916ffcb34SNicholas Piggin case 0x1e0: /* core thread state */
33016ffcb34SNicholas Piggin if (env->excp_model == POWERPC_EXCP_POWER9) {
33116ffcb34SNicholas Piggin /*
33216ffcb34SNicholas Piggin * Only implement for POWER9 because skiboot uses it to check
33316ffcb34SNicholas Piggin * big-core mode. Other bits are unimplemented so we would
33416ffcb34SNicholas Piggin * prefer to get unimplemented message on POWER10 if it were
33516ffcb34SNicholas Piggin * used anywhere.
33616ffcb34SNicholas Piggin */
33716ffcb34SNicholas Piggin if (pc->big_core) {
33816ffcb34SNicholas Piggin return PPC_BIT(63);
33916ffcb34SNicholas Piggin } else {
34016ffcb34SNicholas Piggin return 0;
34116ffcb34SNicholas Piggin }
34216ffcb34SNicholas Piggin }
34316ffcb34SNicholas Piggin /* fallthru */
34416ffcb34SNicholas Piggin
3452736432fSNicholas Piggin default:
3462736432fSNicholas Piggin qemu_log_mask(LOG_UNIMP, "mfSPRD: Unimplemented SPRC:0x"
3472736432fSNicholas Piggin TARGET_FMT_lx"\n", sprc);
3482736432fSNicholas Piggin break;
3492736432fSNicholas Piggin }
3502736432fSNicholas Piggin return 0;
3512736432fSNicholas Piggin }
3522736432fSNicholas Piggin
helper_store_sprd(CPUPPCState * env,target_ulong val)3532736432fSNicholas Piggin void helper_store_sprd(CPUPPCState *env, target_ulong val)
3542736432fSNicholas Piggin {
3552736432fSNicholas Piggin target_ulong sprc = env->spr[SPR_POWER_SPRC];
35660d30cffSNicholas Piggin PowerPCCPU *cpu = env_archcpu(env);
35760d30cffSNicholas Piggin PnvCore *pc = pnv_cpu_state(cpu)->pnv_core;
35860d30cffSNicholas Piggin int nr;
3592736432fSNicholas Piggin
36060d30cffSNicholas Piggin switch (sprc & 0x3e0) {
36160d30cffSNicholas Piggin case 0: /* SCRATCH0-3 */
36260d30cffSNicholas Piggin case 1: /* SCRATCH4-7 */
36360d30cffSNicholas Piggin /*
36460d30cffSNicholas Piggin * Log stores to SCRATCH, because some firmware uses these for
36560d30cffSNicholas Piggin * debugging and logging, but they would normally be read by the BMC,
36660d30cffSNicholas Piggin * which is not implemented in QEMU yet. This gives a way to get at the
36760d30cffSNicholas Piggin * information. Could also dump these upon checkstop.
36860d30cffSNicholas Piggin */
36960d30cffSNicholas Piggin nr = (sprc >> 3) & 0x7;
37060d30cffSNicholas Piggin qemu_log("SPRD write 0x" TARGET_FMT_lx " to SCRATCH%d\n", val, nr);
37160d30cffSNicholas Piggin pc->scratch[nr] = val;
3722736432fSNicholas Piggin break;
3732736432fSNicholas Piggin default:
37460d30cffSNicholas Piggin qemu_log_mask(LOG_UNIMP, "mtSPRD: Unimplemented SPRC:0x"
3752736432fSNicholas Piggin TARGET_FMT_lx"\n", sprc);
3762736432fSNicholas Piggin break;
3772736432fSNicholas Piggin }
3782736432fSNicholas Piggin }
3794a7518e0SCédric Le Goater #endif /* defined(TARGET_PPC64) */
3804a7518e0SCédric Le Goater
helper_store_pidr(CPUPPCState * env,target_ulong val)38131b2b0f8SSuraj Jitindar Singh void helper_store_pidr(CPUPPCState *env, target_ulong val)
38231b2b0f8SSuraj Jitindar Singh {
383fbda88f7SNicholas Piggin env->spr[SPR_BOOKS_PID] = (uint32_t)val;
384db70b311SRichard Henderson tlb_flush(env_cpu(env));
38531b2b0f8SSuraj Jitindar Singh }
38631b2b0f8SSuraj Jitindar Singh
helper_store_lpidr(CPUPPCState * env,target_ulong val)387c4dae9cdSBenjamin Herrenschmidt void helper_store_lpidr(CPUPPCState *env, target_ulong val)
388c4dae9cdSBenjamin Herrenschmidt {
389fbda88f7SNicholas Piggin env->spr[SPR_LPIDR] = (uint32_t)val;
390c4dae9cdSBenjamin Herrenschmidt
391c4dae9cdSBenjamin Herrenschmidt /*
392c4dae9cdSBenjamin Herrenschmidt * We need to flush the TLB on LPID changes as we only tag HV vs
393c4dae9cdSBenjamin Herrenschmidt * guest in TCG TLB. Also the quadrants means the HV will
394c4dae9cdSBenjamin Herrenschmidt * potentially access and cache entries for the current LPID as
395c4dae9cdSBenjamin Herrenschmidt * well.
396c4dae9cdSBenjamin Herrenschmidt */
397db70b311SRichard Henderson tlb_flush(env_cpu(env));
398c4dae9cdSBenjamin Herrenschmidt }
399c4dae9cdSBenjamin Herrenschmidt
helper_store_40x_dbcr0(CPUPPCState * env,target_ulong val)400fcf5ef2aSThomas Huth void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val)
401fcf5ef2aSThomas Huth {
4027da31f26SRichard Henderson /* Bits 26 & 27 affect single-stepping. */
4037da31f26SRichard Henderson hreg_compute_hflags(env);
4047da31f26SRichard Henderson /* Bits 28 & 29 affect reset or shutdown. */
405fcf5ef2aSThomas Huth store_40x_dbcr0(env, val);
406fcf5ef2aSThomas Huth }
407fcf5ef2aSThomas Huth
helper_store_40x_sler(CPUPPCState * env,target_ulong val)408fcf5ef2aSThomas Huth void helper_store_40x_sler(CPUPPCState *env, target_ulong val)
409fcf5ef2aSThomas Huth {
410fcf5ef2aSThomas Huth store_40x_sler(env, val);
411fcf5ef2aSThomas Huth }
412fcf5ef2aSThomas Huth #endif
413fcf5ef2aSThomas Huth
414fcf5ef2aSThomas Huth /*****************************************************************************/
415fcf5ef2aSThomas Huth /* Special registers manipulation */
416fcf5ef2aSThomas Huth
417d81b4327SDavid Gibson /*
418d81b4327SDavid Gibson * This code is lifted from MacOnLinux. It is called whenever THRM1,2
419d81b4327SDavid Gibson * or 3 is read an fixes up the values in such a way that will make
420d81b4327SDavid Gibson * MacOS not hang. These registers exist on some 75x and 74xx
421d81b4327SDavid Gibson * processors.
422fcf5ef2aSThomas Huth */
helper_fixup_thrm(CPUPPCState * env)423fcf5ef2aSThomas Huth void helper_fixup_thrm(CPUPPCState *env)
424fcf5ef2aSThomas Huth {
425fcf5ef2aSThomas Huth target_ulong v, t;
426fcf5ef2aSThomas Huth int i;
427fcf5ef2aSThomas Huth
428fcf5ef2aSThomas Huth #define THRM1_TIN (1 << 31)
429fcf5ef2aSThomas Huth #define THRM1_TIV (1 << 30)
430fcf5ef2aSThomas Huth #define THRM1_THRES(x) (((x) & 0x7f) << 23)
431fcf5ef2aSThomas Huth #define THRM1_TID (1 << 2)
432fcf5ef2aSThomas Huth #define THRM1_TIE (1 << 1)
433fcf5ef2aSThomas Huth #define THRM1_V (1 << 0)
434fcf5ef2aSThomas Huth #define THRM3_E (1 << 0)
435fcf5ef2aSThomas Huth
436fcf5ef2aSThomas Huth if (!(env->spr[SPR_THRM3] & THRM3_E)) {
437fcf5ef2aSThomas Huth return;
438fcf5ef2aSThomas Huth }
439fcf5ef2aSThomas Huth
440fcf5ef2aSThomas Huth /* Note: Thermal interrupts are unimplemented */
441fcf5ef2aSThomas Huth for (i = SPR_THRM1; i <= SPR_THRM2; i++) {
442fcf5ef2aSThomas Huth v = env->spr[i];
443fcf5ef2aSThomas Huth if (!(v & THRM1_V)) {
444fcf5ef2aSThomas Huth continue;
445fcf5ef2aSThomas Huth }
446fcf5ef2aSThomas Huth v |= THRM1_TIV;
447fcf5ef2aSThomas Huth v &= ~THRM1_TIN;
448fcf5ef2aSThomas Huth t = v & THRM1_THRES(127);
449fcf5ef2aSThomas Huth if ((v & THRM1_TID) && t < THRM1_THRES(24)) {
450fcf5ef2aSThomas Huth v |= THRM1_TIN;
451fcf5ef2aSThomas Huth }
452fcf5ef2aSThomas Huth if (!(v & THRM1_TID) && t > THRM1_THRES(24)) {
453fcf5ef2aSThomas Huth v |= THRM1_TIN;
454fcf5ef2aSThomas Huth }
455fcf5ef2aSThomas Huth env->spr[i] = v;
456fcf5ef2aSThomas Huth }
457fcf5ef2aSThomas Huth }
4586bfcf1dcSGlenn Miles
4596bfcf1dcSGlenn Miles #if !defined(CONFIG_USER_ONLY)
4606bfcf1dcSGlenn Miles #if defined(TARGET_PPC64)
helper_clrbhrb(CPUPPCState * env)4616bfcf1dcSGlenn Miles void helper_clrbhrb(CPUPPCState *env)
4626bfcf1dcSGlenn Miles {
4636bfcf1dcSGlenn Miles helper_hfscr_facility_check(env, HFSCR_BHRB, "clrbhrb", FSCR_IC_BHRB);
4646bfcf1dcSGlenn Miles
4656bfcf1dcSGlenn Miles helper_mmcr0_facility_check(env, MMCR0_BHRBA_NR, 0, FSCR_IC_BHRB);
4666bfcf1dcSGlenn Miles
4676bfcf1dcSGlenn Miles if (env->flags & POWERPC_FLAG_BHRB) {
4686bfcf1dcSGlenn Miles memset(env->bhrb, 0, sizeof(env->bhrb));
4696bfcf1dcSGlenn Miles }
4706bfcf1dcSGlenn Miles }
4716bfcf1dcSGlenn Miles
helper_mfbhrbe(CPUPPCState * env,uint32_t bhrbe)4726bfcf1dcSGlenn Miles uint64_t helper_mfbhrbe(CPUPPCState *env, uint32_t bhrbe)
4736bfcf1dcSGlenn Miles {
4746bfcf1dcSGlenn Miles unsigned int index;
4756bfcf1dcSGlenn Miles
4766bfcf1dcSGlenn Miles helper_hfscr_facility_check(env, HFSCR_BHRB, "mfbhrbe", FSCR_IC_BHRB);
4776bfcf1dcSGlenn Miles
4786bfcf1dcSGlenn Miles helper_mmcr0_facility_check(env, MMCR0_BHRBA_NR, 0, FSCR_IC_BHRB);
4796bfcf1dcSGlenn Miles
4806bfcf1dcSGlenn Miles if (!(env->flags & POWERPC_FLAG_BHRB) ||
4816bfcf1dcSGlenn Miles (bhrbe >= env->bhrb_num_entries) ||
4826bfcf1dcSGlenn Miles (env->spr[SPR_POWER_MMCR0] & MMCR0_PMAE)) {
4836bfcf1dcSGlenn Miles return 0;
4846bfcf1dcSGlenn Miles }
4856bfcf1dcSGlenn Miles
4866bfcf1dcSGlenn Miles /*
4876bfcf1dcSGlenn Miles * Note: bhrb_offset is the byte offset for writing the
4886bfcf1dcSGlenn Miles * next entry (over the oldest entry), which is why we
4896bfcf1dcSGlenn Miles * must offset bhrbe by 1 to get to the 0th entry.
4906bfcf1dcSGlenn Miles */
4916bfcf1dcSGlenn Miles index = ((env->bhrb_offset / sizeof(uint64_t)) - (bhrbe + 1)) %
4926bfcf1dcSGlenn Miles env->bhrb_num_entries;
4936bfcf1dcSGlenn Miles return env->bhrb[index];
4946bfcf1dcSGlenn Miles }
4956bfcf1dcSGlenn Miles #endif
4966bfcf1dcSGlenn Miles #endif
497