]>
Commit | Line | Data |
---|---|---|
8a05fd9a RH |
1 | /* |
2 | * PowerPC emulation special registers manipulation helpers for qemu. | |
3 | * | |
4 | * Copyright (c) 2003-2007 Jocelyn Mayer | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2.1 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include "qemu/osdep.h" | |
2df4fe7a | 21 | #include "cpu.h" |
8a05fd9a RH |
22 | #include "qemu/main-loop.h" |
23 | #include "exec/exec-all.h" | |
24 | #include "sysemu/kvm.h" | |
03ac0a0c | 25 | #include "sysemu/tcg.h" |
8a05fd9a | 26 | #include "helper_regs.h" |
46d396bd | 27 | #include "power8-pmu.h" |
65e0446c FR |
28 | #include "cpu-models.h" |
29 | #include "spr_common.h" | |
8a05fd9a RH |
30 | |
31 | /* Swap temporary saved registers with GPRs */ | |
32 | void hreg_swap_gpr_tgpr(CPUPPCState *env) | |
33 | { | |
34 | target_ulong tmp; | |
35 | ||
36 | tmp = env->gpr[0]; | |
37 | env->gpr[0] = env->tgpr[0]; | |
38 | env->tgpr[0] = tmp; | |
39 | tmp = env->gpr[1]; | |
40 | env->gpr[1] = env->tgpr[1]; | |
41 | env->tgpr[1] = tmp; | |
42 | tmp = env->gpr[2]; | |
43 | env->gpr[2] = env->tgpr[2]; | |
44 | env->tgpr[2] = tmp; | |
45 | tmp = env->gpr[3]; | |
46 | env->gpr[3] = env->tgpr[3]; | |
47 | env->tgpr[3] = tmp; | |
48 | } | |
49 | ||
2da8a6bc | 50 | static uint32_t hreg_compute_hflags_value(CPUPPCState *env) |
8a05fd9a | 51 | { |
2df4fe7a RH |
52 | target_ulong msr = env->msr; |
53 | uint32_t ppc_flags = env->flags; | |
54 | uint32_t hflags = 0; | |
55 | uint32_t msr_mask; | |
8a05fd9a | 56 | |
2df4fe7a RH |
57 | /* Some bits come straight across from MSR. */ |
58 | QEMU_BUILD_BUG_ON(MSR_LE != HFLAGS_LE); | |
59 | QEMU_BUILD_BUG_ON(MSR_PR != HFLAGS_PR); | |
60 | QEMU_BUILD_BUG_ON(MSR_DR != HFLAGS_DR); | |
2df4fe7a | 61 | QEMU_BUILD_BUG_ON(MSR_FP != HFLAGS_FP); |
2df4fe7a | 62 | msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) | |
d764184d | 63 | (1 << MSR_DR) | (1 << MSR_FP)); |
18285046 | 64 | |
7da31f26 RH |
65 | if (ppc_flags & POWERPC_FLAG_DE) { |
66 | target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0]; | |
67935ecd | 67 | if ((dbcr0 & DBCR0_ICMP) && FIELD_EX64(env->msr, MSR, DE)) { |
7da31f26 RH |
68 | hflags |= 1 << HFLAGS_SE; |
69 | } | |
67935ecd | 70 | if ((dbcr0 & DBCR0_BRT) && FIELD_EX64(env->msr, MSR, DE)) { |
7da31f26 RH |
71 | hflags |= 1 << HFLAGS_BE; |
72 | } | |
73 | } else { | |
74 | if (ppc_flags & POWERPC_FLAG_BE) { | |
75 | QEMU_BUILD_BUG_ON(MSR_BE != HFLAGS_BE); | |
76 | msr_mask |= 1 << MSR_BE; | |
77 | } | |
78 | if (ppc_flags & POWERPC_FLAG_SE) { | |
79 | QEMU_BUILD_BUG_ON(MSR_SE != HFLAGS_SE); | |
80 | msr_mask |= 1 << MSR_SE; | |
81 | } | |
2df4fe7a RH |
82 | } |
83 | ||
84 | if (msr_is_64bit(env, msr)) { | |
85 | hflags |= 1 << HFLAGS_64; | |
86 | } | |
87 | if ((ppc_flags & POWERPC_FLAG_SPE) && (msr & (1 << MSR_SPE))) { | |
88 | hflags |= 1 << HFLAGS_SPE; | |
89 | } | |
90 | if (ppc_flags & POWERPC_FLAG_VRE) { | |
91 | QEMU_BUILD_BUG_ON(MSR_VR != HFLAGS_VR); | |
92 | msr_mask |= 1 << MSR_VR; | |
18285046 | 93 | } |
0e6bac3e RH |
94 | if (ppc_flags & POWERPC_FLAG_VSX) { |
95 | QEMU_BUILD_BUG_ON(MSR_VSX != HFLAGS_VSX); | |
96 | msr_mask |= 1 << MSR_VSX; | |
2df4fe7a RH |
97 | } |
98 | if ((ppc_flags & POWERPC_FLAG_TM) && (msr & (1ull << MSR_TM))) { | |
99 | hflags |= 1 << HFLAGS_TM; | |
100 | } | |
f03de3b4 RH |
101 | if (env->spr[SPR_LPCR] & LPCR_GTSE) { |
102 | hflags |= 1 << HFLAGS_GTSE; | |
103 | } | |
1db3632a MF |
104 | if (env->spr[SPR_LPCR] & LPCR_HR) { |
105 | hflags |= 1 << HFLAGS_HR; | |
106 | } | |
f7460df2 DHB |
107 | if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) { |
108 | hflags |= 1 << HFLAGS_PMCC0; | |
109 | } | |
110 | if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) { | |
111 | hflags |= 1 << HFLAGS_PMCC1; | |
112 | } | |
8b3d1c49 LL |
113 | if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCjCE) { |
114 | hflags |= 1 << HFLAGS_PMCJCE; | |
115 | } | |
2df4fe7a RH |
116 | |
117 | #ifndef CONFIG_USER_ONLY | |
118 | if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) { | |
119 | hflags |= 1 << HFLAGS_HV; | |
120 | } | |
d764184d | 121 | |
46d396bd | 122 | #if defined(TARGET_PPC64) |
6e8b9903 | 123 | if (env->pmc_ins_cnt) { |
46d396bd DHB |
124 | hflags |= 1 << HFLAGS_INSN_CNT; |
125 | } | |
8b3d1c49 LL |
126 | if (env->pmc_ins_cnt & 0x1e) { |
127 | hflags |= 1 << HFLAGS_PMC_OTHER; | |
128 | } | |
46d396bd DHB |
129 | #endif |
130 | ||
d764184d RH |
131 | /* |
132 | * This is our encoding for server processors. The architecture | |
133 | * specifies that there is no such thing as userspace with | |
134 | * translation off, however it appears that MacOS does it and some | |
135 | * 32-bit CPUs support it. Weird... | |
136 | * | |
137 | * 0 = Guest User space virtual mode | |
138 | * 1 = Guest Kernel space virtual mode | |
139 | * 2 = Guest User space real mode | |
140 | * 3 = Guest Kernel space real mode | |
141 | * 4 = HV User space virtual mode | |
142 | * 5 = HV Kernel space virtual mode | |
143 | * 6 = HV User space real mode | |
144 | * 7 = HV Kernel space real mode | |
145 | * | |
146 | * For BookE, we need 8 MMU modes as follow: | |
147 | * | |
148 | * 0 = AS 0 HV User space | |
149 | * 1 = AS 0 HV Kernel space | |
150 | * 2 = AS 1 HV User space | |
151 | * 3 = AS 1 HV Kernel space | |
152 | * 4 = AS 0 Guest User space | |
153 | * 5 = AS 0 Guest Kernel space | |
154 | * 6 = AS 1 Guest User space | |
155 | * 7 = AS 1 Guest Kernel space | |
156 | */ | |
157 | unsigned immu_idx, dmmu_idx; | |
158 | dmmu_idx = msr & (1 << MSR_PR) ? 0 : 1; | |
63f38cc3 CLG |
159 | if (env->mmu_model == POWERPC_MMU_BOOKE || |
160 | env->mmu_model == POWERPC_MMU_BOOKE206) { | |
d764184d RH |
161 | dmmu_idx |= msr & (1 << MSR_GS) ? 4 : 0; |
162 | immu_idx = dmmu_idx; | |
163 | immu_idx |= msr & (1 << MSR_IS) ? 2 : 0; | |
164 | dmmu_idx |= msr & (1 << MSR_DS) ? 2 : 0; | |
165 | } else { | |
166 | dmmu_idx |= msr & (1ull << MSR_HV) ? 4 : 0; | |
167 | immu_idx = dmmu_idx; | |
168 | immu_idx |= msr & (1 << MSR_IR) ? 0 : 2; | |
169 | dmmu_idx |= msr & (1 << MSR_DR) ? 0 : 2; | |
170 | } | |
171 | hflags |= immu_idx << HFLAGS_IMMU_IDX; | |
172 | hflags |= dmmu_idx << HFLAGS_DMMU_IDX; | |
2df4fe7a RH |
173 | #endif |
174 | ||
2da8a6bc RH |
175 | return hflags | (msr & msr_mask); |
176 | } | |
177 | ||
178 | void hreg_compute_hflags(CPUPPCState *env) | |
179 | { | |
180 | env->hflags = hreg_compute_hflags_value(env); | |
181 | } | |
182 | ||
183 | #ifdef CONFIG_DEBUG_TCG | |
184 | void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc, | |
185 | target_ulong *cs_base, uint32_t *flags) | |
186 | { | |
187 | uint32_t hflags_current = env->hflags; | |
188 | uint32_t hflags_rebuilt; | |
189 | ||
190 | *pc = env->nip; | |
191 | *cs_base = 0; | |
192 | *flags = hflags_current; | |
193 | ||
194 | hflags_rebuilt = hreg_compute_hflags_value(env); | |
195 | if (unlikely(hflags_current != hflags_rebuilt)) { | |
196 | cpu_abort(env_cpu(env), | |
197 | "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n", | |
198 | hflags_current, hflags_rebuilt); | |
199 | } | |
8a05fd9a | 200 | } |
2da8a6bc | 201 | #endif |
8a05fd9a RH |
202 | |
203 | void cpu_interrupt_exittb(CPUState *cs) | |
204 | { | |
0c0aac01 DHB |
205 | /* |
206 | * We don't need to worry about translation blocks | |
03ac0a0c | 207 | * unless running with TCG. |
0c0aac01 | 208 | */ |
03ac0a0c RH |
209 | if (tcg_enabled()) { |
210 | QEMU_IOTHREAD_LOCK_GUARD(); | |
8a05fd9a RH |
211 | cpu_interrupt(cs, CPU_INTERRUPT_EXITTB); |
212 | } | |
213 | } | |
214 | ||
215 | int hreg_store_msr(CPUPPCState *env, target_ulong value, int alter_hv) | |
216 | { | |
217 | int excp; | |
218 | #if !defined(CONFIG_USER_ONLY) | |
219 | CPUState *cs = env_cpu(env); | |
220 | #endif | |
221 | ||
222 | excp = 0; | |
223 | value &= env->msr_mask; | |
224 | #if !defined(CONFIG_USER_ONLY) | |
225 | /* Neither mtmsr nor guest state can alter HV */ | |
226 | if (!alter_hv || !(env->msr & MSR_HVB)) { | |
227 | value &= ~MSR_HVB; | |
228 | value |= env->msr & MSR_HVB; | |
229 | } | |
e4eea6ef | 230 | if ((value ^ env->msr) & (R_MSR_IR_MASK | R_MSR_DR_MASK)) { |
8a05fd9a RH |
231 | cpu_interrupt_exittb(cs); |
232 | } | |
63f38cc3 CLG |
233 | if ((env->mmu_model == POWERPC_MMU_BOOKE || |
234 | env->mmu_model == POWERPC_MMU_BOOKE206) && | |
10b2b373 | 235 | ((value ^ env->msr) & R_MSR_GS_MASK)) { |
8a05fd9a RH |
236 | cpu_interrupt_exittb(cs); |
237 | } | |
238 | if (unlikely((env->flags & POWERPC_FLAG_TGPR) && | |
239 | ((value ^ env->msr) & (1 << MSR_TGPR)))) { | |
240 | /* Swap temporary saved registers with GPRs */ | |
241 | hreg_swap_gpr_tgpr(env); | |
242 | } | |
50242330 VC |
243 | if (unlikely((value ^ env->msr) & R_MSR_EP_MASK)) { |
244 | env->excp_prefix = FIELD_EX64(value, MSR, EP) * 0xFFF00000; | |
8a05fd9a RH |
245 | } |
246 | /* | |
247 | * If PR=1 then EE, IR and DR must be 1 | |
248 | * | |
249 | * Note: We only enforce this on 64-bit server processors. | |
250 | * It appears that: | |
251 | * - 32-bit implementations supports PR=1 and EE/DR/IR=0 and MacOS | |
252 | * exploits it. | |
253 | * - 64-bit embedded implementations do not need any operation to be | |
254 | * performed when PR is set. | |
255 | */ | |
256 | if (is_book3s_arch2x(env) && ((value >> MSR_PR) & 1)) { | |
257 | value |= (1 << MSR_EE) | (1 << MSR_DR) | (1 << MSR_IR); | |
258 | } | |
259 | #endif | |
260 | env->msr = value; | |
261 | hreg_compute_hflags(env); | |
262 | #if !defined(CONFIG_USER_ONLY) | |
2fdedcbc MF |
263 | ppc_maybe_interrupt(env); |
264 | ||
8e54ad65 | 265 | if (unlikely(FIELD_EX64(env->msr, MSR, POW))) { |
8a05fd9a RH |
266 | if (!env->pending_interrupts && (*env->check_pow)(env)) { |
267 | cs->halted = 1; | |
268 | excp = EXCP_HALTED; | |
269 | } | |
270 | } | |
271 | #endif | |
272 | ||
273 | return excp; | |
274 | } | |
275 | ||
c06ba892 LMC |
276 | #ifdef CONFIG_SOFTMMU |
277 | void store_40x_sler(CPUPPCState *env, uint32_t val) | |
278 | { | |
279 | /* XXX: TO BE FIXED */ | |
280 | if (val != 0x00000000) { | |
281 | cpu_abort(env_cpu(env), | |
282 | "Little-endian regions are not supported by now\n"); | |
283 | } | |
284 | env->spr[SPR_405_SLER] = val; | |
285 | } | |
286 | #endif /* CONFIG_SOFTMMU */ | |
287 | ||
8a05fd9a RH |
288 | #ifndef CONFIG_USER_ONLY |
289 | void check_tlb_flush(CPUPPCState *env, bool global) | |
290 | { | |
291 | CPUState *cs = env_cpu(env); | |
292 | ||
293 | /* Handle global flushes first */ | |
294 | if (global && (env->tlb_need_flush & TLB_NEED_GLOBAL_FLUSH)) { | |
295 | env->tlb_need_flush &= ~TLB_NEED_GLOBAL_FLUSH; | |
296 | env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; | |
4ddc1046 | 297 | tlb_flush_all_cpus(cs); |
8a05fd9a RH |
298 | return; |
299 | } | |
300 | ||
301 | /* Then handle local ones */ | |
302 | if (env->tlb_need_flush & TLB_NEED_LOCAL_FLUSH) { | |
303 | env->tlb_need_flush &= ~TLB_NEED_LOCAL_FLUSH; | |
304 | tlb_flush(cs); | |
305 | } | |
306 | } | |
307 | #endif | |
65e0446c FR |
308 | |
309 | /** | |
310 | * _spr_register | |
311 | * | |
312 | * Register an SPR with all the callbacks required for tcg, | |
313 | * and the ID number for KVM. | |
314 | * | |
315 | * The reason for the conditional compilation is that the tcg functions | |
316 | * may be compiled out, and the system kvm header may not be available | |
317 | * for supplying the ID numbers. This is ugly, but the best we can do. | |
318 | */ | |
319 | void _spr_register(CPUPPCState *env, int num, const char *name, | |
320 | USR_ARG(spr_callback *uea_read) | |
321 | USR_ARG(spr_callback *uea_write) | |
322 | SYS_ARG(spr_callback *oea_read) | |
323 | SYS_ARG(spr_callback *oea_write) | |
324 | SYS_ARG(spr_callback *hea_read) | |
325 | SYS_ARG(spr_callback *hea_write) | |
326 | KVM_ARG(uint64_t one_reg_id) | |
327 | target_ulong initial_value) | |
328 | { | |
329 | ppc_spr_t *spr = &env->spr_cb[num]; | |
330 | ||
331 | /* No SPR should be registered twice. */ | |
332 | assert(spr->name == NULL); | |
333 | assert(name != NULL); | |
334 | ||
335 | spr->name = name; | |
336 | spr->default_value = initial_value; | |
337 | env->spr[num] = initial_value; | |
338 | ||
339 | #ifdef CONFIG_TCG | |
340 | spr->uea_read = uea_read; | |
341 | spr->uea_write = uea_write; | |
342 | # ifndef CONFIG_USER_ONLY | |
343 | spr->oea_read = oea_read; | |
344 | spr->oea_write = oea_write; | |
345 | spr->hea_read = hea_read; | |
346 | spr->hea_write = hea_write; | |
347 | # endif | |
348 | #endif | |
349 | #ifdef CONFIG_KVM | |
350 | spr->one_reg_id = one_reg_id; | |
351 | #endif | |
352 | } | |
353 | ||
354 | /* Generic PowerPC SPRs */ | |
355 | void register_generic_sprs(PowerPCCPU *cpu) | |
356 | { | |
357 | PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); | |
358 | CPUPPCState *env = &cpu->env; | |
359 | ||
360 | /* Integer processing */ | |
361 | spr_register(env, SPR_XER, "XER", | |
362 | &spr_read_xer, &spr_write_xer, | |
363 | &spr_read_xer, &spr_write_xer, | |
364 | 0x00000000); | |
365 | /* Branch control */ | |
366 | spr_register(env, SPR_LR, "LR", | |
367 | &spr_read_lr, &spr_write_lr, | |
368 | &spr_read_lr, &spr_write_lr, | |
369 | 0x00000000); | |
370 | spr_register(env, SPR_CTR, "CTR", | |
371 | &spr_read_ctr, &spr_write_ctr, | |
372 | &spr_read_ctr, &spr_write_ctr, | |
373 | 0x00000000); | |
374 | /* Interrupt processing */ | |
375 | spr_register(env, SPR_SRR0, "SRR0", | |
376 | SPR_NOACCESS, SPR_NOACCESS, | |
377 | &spr_read_generic, &spr_write_generic, | |
378 | 0x00000000); | |
379 | spr_register(env, SPR_SRR1, "SRR1", | |
380 | SPR_NOACCESS, SPR_NOACCESS, | |
381 | &spr_read_generic, &spr_write_generic, | |
382 | 0x00000000); | |
383 | /* Processor control */ | |
384 | spr_register(env, SPR_SPRG0, "SPRG0", | |
385 | SPR_NOACCESS, SPR_NOACCESS, | |
386 | &spr_read_generic, &spr_write_generic, | |
387 | 0x00000000); | |
388 | spr_register(env, SPR_SPRG1, "SPRG1", | |
389 | SPR_NOACCESS, SPR_NOACCESS, | |
390 | &spr_read_generic, &spr_write_generic, | |
391 | 0x00000000); | |
392 | spr_register(env, SPR_SPRG2, "SPRG2", | |
393 | SPR_NOACCESS, SPR_NOACCESS, | |
394 | &spr_read_generic, &spr_write_generic, | |
395 | 0x00000000); | |
396 | spr_register(env, SPR_SPRG3, "SPRG3", | |
397 | SPR_NOACCESS, SPR_NOACCESS, | |
398 | &spr_read_generic, &spr_write_generic, | |
399 | 0x00000000); | |
400 | ||
401 | spr_register(env, SPR_PVR, "PVR", | |
402 | /* Linux permits userspace to read PVR */ | |
403 | #if defined(CONFIG_LINUX_USER) | |
404 | &spr_read_generic, | |
405 | #else | |
406 | SPR_NOACCESS, | |
407 | #endif | |
408 | SPR_NOACCESS, | |
409 | &spr_read_generic, SPR_NOACCESS, | |
410 | pcc->pvr); | |
411 | ||
412 | /* Register SVR if it's defined to anything else than POWERPC_SVR_NONE */ | |
413 | if (pcc->svr != POWERPC_SVR_NONE) { | |
414 | if (pcc->svr & POWERPC_SVR_E500) { | |
415 | spr_register(env, SPR_E500_SVR, "SVR", | |
416 | SPR_NOACCESS, SPR_NOACCESS, | |
417 | &spr_read_generic, SPR_NOACCESS, | |
418 | pcc->svr & ~POWERPC_SVR_E500); | |
419 | } else { | |
420 | spr_register(env, SPR_SVR, "SVR", | |
421 | SPR_NOACCESS, SPR_NOACCESS, | |
422 | &spr_read_generic, SPR_NOACCESS, | |
423 | pcc->svr); | |
424 | } | |
425 | } | |
426 | ||
427 | /* Time base */ | |
428 | spr_register(env, SPR_VTBL, "TBL", | |
429 | &spr_read_tbl, SPR_NOACCESS, | |
430 | &spr_read_tbl, SPR_NOACCESS, | |
431 | 0x00000000); | |
432 | spr_register(env, SPR_TBL, "TBL", | |
433 | &spr_read_tbl, SPR_NOACCESS, | |
434 | &spr_read_tbl, &spr_write_tbl, | |
435 | 0x00000000); | |
436 | spr_register(env, SPR_VTBU, "TBU", | |
437 | &spr_read_tbu, SPR_NOACCESS, | |
438 | &spr_read_tbu, SPR_NOACCESS, | |
439 | 0x00000000); | |
440 | spr_register(env, SPR_TBU, "TBU", | |
441 | &spr_read_tbu, SPR_NOACCESS, | |
442 | &spr_read_tbu, &spr_write_tbu, | |
443 | 0x00000000); | |
444 | } | |
445 | ||
446 | void register_non_embedded_sprs(CPUPPCState *env) | |
447 | { | |
448 | /* Exception processing */ | |
449 | spr_register_kvm(env, SPR_DSISR, "DSISR", | |
450 | SPR_NOACCESS, SPR_NOACCESS, | |
451 | &spr_read_generic, &spr_write_generic, | |
452 | KVM_REG_PPC_DSISR, 0x00000000); | |
453 | spr_register_kvm(env, SPR_DAR, "DAR", | |
454 | SPR_NOACCESS, SPR_NOACCESS, | |
455 | &spr_read_generic, &spr_write_generic, | |
456 | KVM_REG_PPC_DAR, 0x00000000); | |
457 | /* Timer */ | |
458 | spr_register(env, SPR_DECR, "DECR", | |
459 | SPR_NOACCESS, SPR_NOACCESS, | |
460 | &spr_read_decr, &spr_write_decr, | |
461 | 0x00000000); | |
462 | } | |
463 | ||
464 | /* Storage Description Register 1 */ | |
465 | void register_sdr1_sprs(CPUPPCState *env) | |
466 | { | |
467 | #ifndef CONFIG_USER_ONLY | |
468 | if (env->has_hv_mode) { | |
469 | /* | |
470 | * SDR1 is a hypervisor resource on CPUs which have a | |
471 | * hypervisor mode | |
472 | */ | |
473 | spr_register_hv(env, SPR_SDR1, "SDR1", | |
474 | SPR_NOACCESS, SPR_NOACCESS, | |
475 | SPR_NOACCESS, SPR_NOACCESS, | |
476 | &spr_read_generic, &spr_write_sdr1, | |
477 | 0x00000000); | |
478 | } else { | |
479 | spr_register(env, SPR_SDR1, "SDR1", | |
480 | SPR_NOACCESS, SPR_NOACCESS, | |
481 | &spr_read_generic, &spr_write_sdr1, | |
482 | 0x00000000); | |
483 | } | |
484 | #endif | |
485 | } | |
486 | ||
487 | /* BATs 0-3 */ | |
488 | void register_low_BATs(CPUPPCState *env) | |
489 | { | |
490 | #if !defined(CONFIG_USER_ONLY) | |
491 | spr_register(env, SPR_IBAT0U, "IBAT0U", | |
492 | SPR_NOACCESS, SPR_NOACCESS, | |
493 | &spr_read_ibat, &spr_write_ibatu, | |
494 | 0x00000000); | |
495 | spr_register(env, SPR_IBAT0L, "IBAT0L", | |
496 | SPR_NOACCESS, SPR_NOACCESS, | |
497 | &spr_read_ibat, &spr_write_ibatl, | |
498 | 0x00000000); | |
499 | spr_register(env, SPR_IBAT1U, "IBAT1U", | |
500 | SPR_NOACCESS, SPR_NOACCESS, | |
501 | &spr_read_ibat, &spr_write_ibatu, | |
502 | 0x00000000); | |
503 | spr_register(env, SPR_IBAT1L, "IBAT1L", | |
504 | SPR_NOACCESS, SPR_NOACCESS, | |
505 | &spr_read_ibat, &spr_write_ibatl, | |
506 | 0x00000000); | |
507 | spr_register(env, SPR_IBAT2U, "IBAT2U", | |
508 | SPR_NOACCESS, SPR_NOACCESS, | |
509 | &spr_read_ibat, &spr_write_ibatu, | |
510 | 0x00000000); | |
511 | spr_register(env, SPR_IBAT2L, "IBAT2L", | |
512 | SPR_NOACCESS, SPR_NOACCESS, | |
513 | &spr_read_ibat, &spr_write_ibatl, | |
514 | 0x00000000); | |
515 | spr_register(env, SPR_IBAT3U, "IBAT3U", | |
516 | SPR_NOACCESS, SPR_NOACCESS, | |
517 | &spr_read_ibat, &spr_write_ibatu, | |
518 | 0x00000000); | |
519 | spr_register(env, SPR_IBAT3L, "IBAT3L", | |
520 | SPR_NOACCESS, SPR_NOACCESS, | |
521 | &spr_read_ibat, &spr_write_ibatl, | |
522 | 0x00000000); | |
523 | spr_register(env, SPR_DBAT0U, "DBAT0U", | |
524 | SPR_NOACCESS, SPR_NOACCESS, | |
525 | &spr_read_dbat, &spr_write_dbatu, | |
526 | 0x00000000); | |
527 | spr_register(env, SPR_DBAT0L, "DBAT0L", | |
528 | SPR_NOACCESS, SPR_NOACCESS, | |
529 | &spr_read_dbat, &spr_write_dbatl, | |
530 | 0x00000000); | |
531 | spr_register(env, SPR_DBAT1U, "DBAT1U", | |
532 | SPR_NOACCESS, SPR_NOACCESS, | |
533 | &spr_read_dbat, &spr_write_dbatu, | |
534 | 0x00000000); | |
535 | spr_register(env, SPR_DBAT1L, "DBAT1L", | |
536 | SPR_NOACCESS, SPR_NOACCESS, | |
537 | &spr_read_dbat, &spr_write_dbatl, | |
538 | 0x00000000); | |
539 | spr_register(env, SPR_DBAT2U, "DBAT2U", | |
540 | SPR_NOACCESS, SPR_NOACCESS, | |
541 | &spr_read_dbat, &spr_write_dbatu, | |
542 | 0x00000000); | |
543 | spr_register(env, SPR_DBAT2L, "DBAT2L", | |
544 | SPR_NOACCESS, SPR_NOACCESS, | |
545 | &spr_read_dbat, &spr_write_dbatl, | |
546 | 0x00000000); | |
547 | spr_register(env, SPR_DBAT3U, "DBAT3U", | |
548 | SPR_NOACCESS, SPR_NOACCESS, | |
549 | &spr_read_dbat, &spr_write_dbatu, | |
550 | 0x00000000); | |
551 | spr_register(env, SPR_DBAT3L, "DBAT3L", | |
552 | SPR_NOACCESS, SPR_NOACCESS, | |
553 | &spr_read_dbat, &spr_write_dbatl, | |
554 | 0x00000000); | |
555 | env->nb_BATs += 4; | |
556 | #endif | |
557 | } | |
558 | ||
559 | /* BATs 4-7 */ | |
560 | void register_high_BATs(CPUPPCState *env) | |
561 | { | |
562 | #if !defined(CONFIG_USER_ONLY) | |
563 | spr_register(env, SPR_IBAT4U, "IBAT4U", | |
564 | SPR_NOACCESS, SPR_NOACCESS, | |
565 | &spr_read_ibat_h, &spr_write_ibatu_h, | |
566 | 0x00000000); | |
567 | spr_register(env, SPR_IBAT4L, "IBAT4L", | |
568 | SPR_NOACCESS, SPR_NOACCESS, | |
569 | &spr_read_ibat_h, &spr_write_ibatl_h, | |
570 | 0x00000000); | |
571 | spr_register(env, SPR_IBAT5U, "IBAT5U", | |
572 | SPR_NOACCESS, SPR_NOACCESS, | |
573 | &spr_read_ibat_h, &spr_write_ibatu_h, | |
574 | 0x00000000); | |
575 | spr_register(env, SPR_IBAT5L, "IBAT5L", | |
576 | SPR_NOACCESS, SPR_NOACCESS, | |
577 | &spr_read_ibat_h, &spr_write_ibatl_h, | |
578 | 0x00000000); | |
579 | spr_register(env, SPR_IBAT6U, "IBAT6U", | |
580 | SPR_NOACCESS, SPR_NOACCESS, | |
581 | &spr_read_ibat_h, &spr_write_ibatu_h, | |
582 | 0x00000000); | |
583 | spr_register(env, SPR_IBAT6L, "IBAT6L", | |
584 | SPR_NOACCESS, SPR_NOACCESS, | |
585 | &spr_read_ibat_h, &spr_write_ibatl_h, | |
586 | 0x00000000); | |
587 | spr_register(env, SPR_IBAT7U, "IBAT7U", | |
588 | SPR_NOACCESS, SPR_NOACCESS, | |
589 | &spr_read_ibat_h, &spr_write_ibatu_h, | |
590 | 0x00000000); | |
591 | spr_register(env, SPR_IBAT7L, "IBAT7L", | |
592 | SPR_NOACCESS, SPR_NOACCESS, | |
593 | &spr_read_ibat_h, &spr_write_ibatl_h, | |
594 | 0x00000000); | |
595 | spr_register(env, SPR_DBAT4U, "DBAT4U", | |
596 | SPR_NOACCESS, SPR_NOACCESS, | |
597 | &spr_read_dbat_h, &spr_write_dbatu_h, | |
598 | 0x00000000); | |
599 | spr_register(env, SPR_DBAT4L, "DBAT4L", | |
600 | SPR_NOACCESS, SPR_NOACCESS, | |
601 | &spr_read_dbat_h, &spr_write_dbatl_h, | |
602 | 0x00000000); | |
603 | spr_register(env, SPR_DBAT5U, "DBAT5U", | |
604 | SPR_NOACCESS, SPR_NOACCESS, | |
605 | &spr_read_dbat_h, &spr_write_dbatu_h, | |
606 | 0x00000000); | |
607 | spr_register(env, SPR_DBAT5L, "DBAT5L", | |
608 | SPR_NOACCESS, SPR_NOACCESS, | |
609 | &spr_read_dbat_h, &spr_write_dbatl_h, | |
610 | 0x00000000); | |
611 | spr_register(env, SPR_DBAT6U, "DBAT6U", | |
612 | SPR_NOACCESS, SPR_NOACCESS, | |
613 | &spr_read_dbat_h, &spr_write_dbatu_h, | |
614 | 0x00000000); | |
615 | spr_register(env, SPR_DBAT6L, "DBAT6L", | |
616 | SPR_NOACCESS, SPR_NOACCESS, | |
617 | &spr_read_dbat_h, &spr_write_dbatl_h, | |
618 | 0x00000000); | |
619 | spr_register(env, SPR_DBAT7U, "DBAT7U", | |
620 | SPR_NOACCESS, SPR_NOACCESS, | |
621 | &spr_read_dbat_h, &spr_write_dbatu_h, | |
622 | 0x00000000); | |
623 | spr_register(env, SPR_DBAT7L, "DBAT7L", | |
624 | SPR_NOACCESS, SPR_NOACCESS, | |
625 | &spr_read_dbat_h, &spr_write_dbatl_h, | |
626 | 0x00000000); | |
627 | env->nb_BATs += 4; | |
628 | #endif | |
629 | } | |
630 | ||
631 | /* Softare table search registers */ | |
632 | void register_6xx_7xx_soft_tlb(CPUPPCState *env, int nb_tlbs, int nb_ways) | |
633 | { | |
634 | #if !defined(CONFIG_USER_ONLY) | |
635 | env->nb_tlb = nb_tlbs; | |
636 | env->nb_ways = nb_ways; | |
637 | env->id_tlbs = 1; | |
638 | env->tlb_type = TLB_6XX; | |
639 | spr_register(env, SPR_DMISS, "DMISS", | |
640 | SPR_NOACCESS, SPR_NOACCESS, | |
641 | &spr_read_generic, SPR_NOACCESS, | |
642 | 0x00000000); | |
643 | spr_register(env, SPR_DCMP, "DCMP", | |
644 | SPR_NOACCESS, SPR_NOACCESS, | |
645 | &spr_read_generic, SPR_NOACCESS, | |
646 | 0x00000000); | |
647 | spr_register(env, SPR_HASH1, "HASH1", | |
648 | SPR_NOACCESS, SPR_NOACCESS, | |
649 | &spr_read_generic, SPR_NOACCESS, | |
650 | 0x00000000); | |
651 | spr_register(env, SPR_HASH2, "HASH2", | |
652 | SPR_NOACCESS, SPR_NOACCESS, | |
653 | &spr_read_generic, SPR_NOACCESS, | |
654 | 0x00000000); | |
655 | spr_register(env, SPR_IMISS, "IMISS", | |
656 | SPR_NOACCESS, SPR_NOACCESS, | |
657 | &spr_read_generic, SPR_NOACCESS, | |
658 | 0x00000000); | |
659 | spr_register(env, SPR_ICMP, "ICMP", | |
660 | SPR_NOACCESS, SPR_NOACCESS, | |
661 | &spr_read_generic, SPR_NOACCESS, | |
662 | 0x00000000); | |
663 | spr_register(env, SPR_RPA, "RPA", | |
664 | SPR_NOACCESS, SPR_NOACCESS, | |
665 | &spr_read_generic, &spr_write_generic, | |
666 | 0x00000000); | |
667 | #endif | |
668 | } | |
669 | ||
670 | void register_thrm_sprs(CPUPPCState *env) | |
671 | { | |
672 | /* Thermal management */ | |
673 | spr_register(env, SPR_THRM1, "THRM1", | |
674 | SPR_NOACCESS, SPR_NOACCESS, | |
675 | &spr_read_thrm, &spr_write_generic, | |
676 | 0x00000000); | |
677 | ||
678 | spr_register(env, SPR_THRM2, "THRM2", | |
679 | SPR_NOACCESS, SPR_NOACCESS, | |
680 | &spr_read_thrm, &spr_write_generic, | |
681 | 0x00000000); | |
682 | ||
683 | spr_register(env, SPR_THRM3, "THRM3", | |
684 | SPR_NOACCESS, SPR_NOACCESS, | |
685 | &spr_read_thrm, &spr_write_generic, | |
686 | 0x00000000); | |
687 | } | |
688 | ||
689 | void register_usprgh_sprs(CPUPPCState *env) | |
690 | { | |
691 | spr_register(env, SPR_USPRG4, "USPRG4", | |
692 | &spr_read_ureg, SPR_NOACCESS, | |
693 | &spr_read_ureg, SPR_NOACCESS, | |
694 | 0x00000000); | |
695 | spr_register(env, SPR_USPRG5, "USPRG5", | |
696 | &spr_read_ureg, SPR_NOACCESS, | |
697 | &spr_read_ureg, SPR_NOACCESS, | |
698 | 0x00000000); | |
699 | spr_register(env, SPR_USPRG6, "USPRG6", | |
700 | &spr_read_ureg, SPR_NOACCESS, | |
701 | &spr_read_ureg, SPR_NOACCESS, | |
702 | 0x00000000); | |
703 | spr_register(env, SPR_USPRG7, "USPRG7", | |
704 | &spr_read_ureg, SPR_NOACCESS, | |
705 | &spr_read_ureg, SPR_NOACCESS, | |
706 | 0x00000000); | |
707 | } |