xref: /openbmc/qemu/target/ppc/misc_helper.c (revision fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0)
1*fcf5ef2aSThomas Huth /*
2*fcf5ef2aSThomas Huth  * Miscellaneous PowerPC emulation helpers for QEMU.
3*fcf5ef2aSThomas Huth  *
4*fcf5ef2aSThomas Huth  *  Copyright (c) 2003-2007 Jocelyn Mayer
5*fcf5ef2aSThomas Huth  *
6*fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
7*fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
8*fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
9*fcf5ef2aSThomas Huth  * version 2 of the License, or (at your option) any later version.
10*fcf5ef2aSThomas Huth  *
11*fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
12*fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
15*fcf5ef2aSThomas Huth  *
16*fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
17*fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*fcf5ef2aSThomas Huth  */
19*fcf5ef2aSThomas Huth #include "qemu/osdep.h"
20*fcf5ef2aSThomas Huth #include "cpu.h"
21*fcf5ef2aSThomas Huth #include "exec/exec-all.h"
22*fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
23*fcf5ef2aSThomas Huth 
24*fcf5ef2aSThomas Huth #include "helper_regs.h"
25*fcf5ef2aSThomas Huth 
26*fcf5ef2aSThomas Huth /*****************************************************************************/
27*fcf5ef2aSThomas Huth /* SPR accesses */
28*fcf5ef2aSThomas Huth void helper_load_dump_spr(CPUPPCState *env, uint32_t sprn)
29*fcf5ef2aSThomas Huth {
30*fcf5ef2aSThomas Huth     qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
31*fcf5ef2aSThomas Huth              env->spr[sprn]);
32*fcf5ef2aSThomas Huth }
33*fcf5ef2aSThomas Huth 
34*fcf5ef2aSThomas Huth void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
35*fcf5ef2aSThomas Huth {
36*fcf5ef2aSThomas Huth     qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
37*fcf5ef2aSThomas Huth              env->spr[sprn]);
38*fcf5ef2aSThomas Huth }
39*fcf5ef2aSThomas Huth 
40*fcf5ef2aSThomas Huth #ifdef TARGET_PPC64
41*fcf5ef2aSThomas Huth static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
42*fcf5ef2aSThomas Huth                                uint32_t sprn, uint32_t cause,
43*fcf5ef2aSThomas Huth                                uintptr_t raddr)
44*fcf5ef2aSThomas Huth {
45*fcf5ef2aSThomas Huth     qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
46*fcf5ef2aSThomas Huth 
47*fcf5ef2aSThomas Huth     env->spr[SPR_FSCR] &= ~((target_ulong)FSCR_IC_MASK << FSCR_IC_POS);
48*fcf5ef2aSThomas Huth     cause &= FSCR_IC_MASK;
49*fcf5ef2aSThomas Huth     env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
50*fcf5ef2aSThomas Huth 
51*fcf5ef2aSThomas Huth     raise_exception_err_ra(env, POWERPC_EXCP_FU, 0, raddr);
52*fcf5ef2aSThomas Huth }
53*fcf5ef2aSThomas Huth #endif
54*fcf5ef2aSThomas Huth 
55*fcf5ef2aSThomas Huth void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
56*fcf5ef2aSThomas Huth                                 uint32_t sprn, uint32_t cause)
57*fcf5ef2aSThomas Huth {
58*fcf5ef2aSThomas Huth #ifdef TARGET_PPC64
59*fcf5ef2aSThomas Huth     if (env->spr[SPR_FSCR] & (1ULL << bit)) {
60*fcf5ef2aSThomas Huth         /* Facility is enabled, continue */
61*fcf5ef2aSThomas Huth         return;
62*fcf5ef2aSThomas Huth     }
63*fcf5ef2aSThomas Huth     raise_fu_exception(env, bit, sprn, cause, GETPC());
64*fcf5ef2aSThomas Huth #endif
65*fcf5ef2aSThomas Huth }
66*fcf5ef2aSThomas Huth 
67*fcf5ef2aSThomas Huth void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
68*fcf5ef2aSThomas Huth                                uint32_t sprn, uint32_t cause)
69*fcf5ef2aSThomas Huth {
70*fcf5ef2aSThomas Huth #ifdef TARGET_PPC64
71*fcf5ef2aSThomas Huth     if (env->msr & (1ULL << bit)) {
72*fcf5ef2aSThomas Huth         /* Facility is enabled, continue */
73*fcf5ef2aSThomas Huth         return;
74*fcf5ef2aSThomas Huth     }
75*fcf5ef2aSThomas Huth     raise_fu_exception(env, bit, sprn, cause, GETPC());
76*fcf5ef2aSThomas Huth #endif
77*fcf5ef2aSThomas Huth }
78*fcf5ef2aSThomas Huth 
79*fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
80*fcf5ef2aSThomas Huth 
81*fcf5ef2aSThomas Huth void helper_store_sdr1(CPUPPCState *env, target_ulong val)
82*fcf5ef2aSThomas Huth {
83*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
84*fcf5ef2aSThomas Huth 
85*fcf5ef2aSThomas Huth     if (!env->external_htab) {
86*fcf5ef2aSThomas Huth         if (env->spr[SPR_SDR1] != val) {
87*fcf5ef2aSThomas Huth             ppc_store_sdr1(env, val);
88*fcf5ef2aSThomas Huth             tlb_flush(CPU(cpu), 1);
89*fcf5ef2aSThomas Huth         }
90*fcf5ef2aSThomas Huth     }
91*fcf5ef2aSThomas Huth }
92*fcf5ef2aSThomas Huth 
93*fcf5ef2aSThomas Huth void helper_store_hid0_601(CPUPPCState *env, target_ulong val)
94*fcf5ef2aSThomas Huth {
95*fcf5ef2aSThomas Huth     target_ulong hid0;
96*fcf5ef2aSThomas Huth 
97*fcf5ef2aSThomas Huth     hid0 = env->spr[SPR_HID0];
98*fcf5ef2aSThomas Huth     if ((val ^ hid0) & 0x00000008) {
99*fcf5ef2aSThomas Huth         /* Change current endianness */
100*fcf5ef2aSThomas Huth         env->hflags &= ~(1 << MSR_LE);
101*fcf5ef2aSThomas Huth         env->hflags_nmsr &= ~(1 << MSR_LE);
102*fcf5ef2aSThomas Huth         env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
103*fcf5ef2aSThomas Huth         env->hflags |= env->hflags_nmsr;
104*fcf5ef2aSThomas Huth         qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
105*fcf5ef2aSThomas Huth                  val & 0x8 ? 'l' : 'b', env->hflags);
106*fcf5ef2aSThomas Huth     }
107*fcf5ef2aSThomas Huth     env->spr[SPR_HID0] = (uint32_t)val;
108*fcf5ef2aSThomas Huth }
109*fcf5ef2aSThomas Huth 
110*fcf5ef2aSThomas Huth void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value)
111*fcf5ef2aSThomas Huth {
112*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
113*fcf5ef2aSThomas Huth 
114*fcf5ef2aSThomas Huth     if (likely(env->pb[num] != value)) {
115*fcf5ef2aSThomas Huth         env->pb[num] = value;
116*fcf5ef2aSThomas Huth         /* Should be optimized */
117*fcf5ef2aSThomas Huth         tlb_flush(CPU(cpu), 1);
118*fcf5ef2aSThomas Huth     }
119*fcf5ef2aSThomas Huth }
120*fcf5ef2aSThomas Huth 
121*fcf5ef2aSThomas Huth void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val)
122*fcf5ef2aSThomas Huth {
123*fcf5ef2aSThomas Huth     store_40x_dbcr0(env, val);
124*fcf5ef2aSThomas Huth }
125*fcf5ef2aSThomas Huth 
126*fcf5ef2aSThomas Huth void helper_store_40x_sler(CPUPPCState *env, target_ulong val)
127*fcf5ef2aSThomas Huth {
128*fcf5ef2aSThomas Huth     store_40x_sler(env, val);
129*fcf5ef2aSThomas Huth }
130*fcf5ef2aSThomas Huth #endif
131*fcf5ef2aSThomas Huth /*****************************************************************************/
132*fcf5ef2aSThomas Huth /* PowerPC 601 specific instructions (POWER bridge) */
133*fcf5ef2aSThomas Huth 
134*fcf5ef2aSThomas Huth target_ulong helper_clcs(CPUPPCState *env, uint32_t arg)
135*fcf5ef2aSThomas Huth {
136*fcf5ef2aSThomas Huth     switch (arg) {
137*fcf5ef2aSThomas Huth     case 0x0CUL:
138*fcf5ef2aSThomas Huth         /* Instruction cache line size */
139*fcf5ef2aSThomas Huth         return env->icache_line_size;
140*fcf5ef2aSThomas Huth         break;
141*fcf5ef2aSThomas Huth     case 0x0DUL:
142*fcf5ef2aSThomas Huth         /* Data cache line size */
143*fcf5ef2aSThomas Huth         return env->dcache_line_size;
144*fcf5ef2aSThomas Huth         break;
145*fcf5ef2aSThomas Huth     case 0x0EUL:
146*fcf5ef2aSThomas Huth         /* Minimum cache line size */
147*fcf5ef2aSThomas Huth         return (env->icache_line_size < env->dcache_line_size) ?
148*fcf5ef2aSThomas Huth             env->icache_line_size : env->dcache_line_size;
149*fcf5ef2aSThomas Huth         break;
150*fcf5ef2aSThomas Huth     case 0x0FUL:
151*fcf5ef2aSThomas Huth         /* Maximum cache line size */
152*fcf5ef2aSThomas Huth         return (env->icache_line_size > env->dcache_line_size) ?
153*fcf5ef2aSThomas Huth             env->icache_line_size : env->dcache_line_size;
154*fcf5ef2aSThomas Huth         break;
155*fcf5ef2aSThomas Huth     default:
156*fcf5ef2aSThomas Huth         /* Undefined */
157*fcf5ef2aSThomas Huth         return 0;
158*fcf5ef2aSThomas Huth         break;
159*fcf5ef2aSThomas Huth     }
160*fcf5ef2aSThomas Huth }
161*fcf5ef2aSThomas Huth 
162*fcf5ef2aSThomas Huth /*****************************************************************************/
163*fcf5ef2aSThomas Huth /* Special registers manipulation */
164*fcf5ef2aSThomas Huth 
165*fcf5ef2aSThomas Huth /* GDBstub can read and write MSR... */
166*fcf5ef2aSThomas Huth void ppc_store_msr(CPUPPCState *env, target_ulong value)
167*fcf5ef2aSThomas Huth {
168*fcf5ef2aSThomas Huth     hreg_store_msr(env, value, 0);
169*fcf5ef2aSThomas Huth }
170*fcf5ef2aSThomas Huth 
171*fcf5ef2aSThomas Huth /* This code is lifted from MacOnLinux. It is called whenever
172*fcf5ef2aSThomas Huth  * THRM1,2 or 3 is read an fixes up the values in such a way
173*fcf5ef2aSThomas Huth  * that will make MacOS not hang. These registers exist on some
174*fcf5ef2aSThomas Huth  * 75x and 74xx processors.
175*fcf5ef2aSThomas Huth  */
176*fcf5ef2aSThomas Huth void helper_fixup_thrm(CPUPPCState *env)
177*fcf5ef2aSThomas Huth {
178*fcf5ef2aSThomas Huth     target_ulong v, t;
179*fcf5ef2aSThomas Huth     int i;
180*fcf5ef2aSThomas Huth 
181*fcf5ef2aSThomas Huth #define THRM1_TIN       (1 << 31)
182*fcf5ef2aSThomas Huth #define THRM1_TIV       (1 << 30)
183*fcf5ef2aSThomas Huth #define THRM1_THRES(x)  (((x) & 0x7f) << 23)
184*fcf5ef2aSThomas Huth #define THRM1_TID       (1 << 2)
185*fcf5ef2aSThomas Huth #define THRM1_TIE       (1 << 1)
186*fcf5ef2aSThomas Huth #define THRM1_V         (1 << 0)
187*fcf5ef2aSThomas Huth #define THRM3_E         (1 << 0)
188*fcf5ef2aSThomas Huth 
189*fcf5ef2aSThomas Huth     if (!(env->spr[SPR_THRM3] & THRM3_E)) {
190*fcf5ef2aSThomas Huth         return;
191*fcf5ef2aSThomas Huth     }
192*fcf5ef2aSThomas Huth 
193*fcf5ef2aSThomas Huth     /* Note: Thermal interrupts are unimplemented */
194*fcf5ef2aSThomas Huth     for (i = SPR_THRM1; i <= SPR_THRM2; i++) {
195*fcf5ef2aSThomas Huth         v = env->spr[i];
196*fcf5ef2aSThomas Huth         if (!(v & THRM1_V)) {
197*fcf5ef2aSThomas Huth             continue;
198*fcf5ef2aSThomas Huth         }
199*fcf5ef2aSThomas Huth         v |= THRM1_TIV;
200*fcf5ef2aSThomas Huth         v &= ~THRM1_TIN;
201*fcf5ef2aSThomas Huth         t = v & THRM1_THRES(127);
202*fcf5ef2aSThomas Huth         if ((v & THRM1_TID) && t < THRM1_THRES(24)) {
203*fcf5ef2aSThomas Huth             v |= THRM1_TIN;
204*fcf5ef2aSThomas Huth         }
205*fcf5ef2aSThomas Huth         if (!(v & THRM1_TID) && t > THRM1_THRES(24)) {
206*fcf5ef2aSThomas Huth             v |= THRM1_TIN;
207*fcf5ef2aSThomas Huth         }
208*fcf5ef2aSThomas Huth         env->spr[i] = v;
209*fcf5ef2aSThomas Huth     }
210*fcf5ef2aSThomas Huth }
211