blob: 4fa297d7dd14566743fe50521ba7c1ad5d38004c [file] [log] [blame]
Blue Swirlad71ed62012-05-30 04:23:22 +00001/*
2 * PowerPC exception emulation 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 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#include "cpu.h"
Blue Swirlad71ed62012-05-30 04:23:22 +000020#include "helper.h"
21
22#include "helper_regs.h"
23
24//#define DEBUG_OP
25//#define DEBUG_EXCEPTIONS
26
Blue Swirlc79c73f2012-05-30 04:23:25 +000027#ifdef DEBUG_EXCEPTIONS
28# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
29#else
30# define LOG_EXCP(...) do { } while (0)
31#endif
32
33/*****************************************************************************/
34/* PowerPC Hypercall emulation */
35
Andreas Färber1b146702012-05-03 06:03:45 +020036void (*cpu_ppc_hypercall)(PowerPCCPU *);
Blue Swirlc79c73f2012-05-30 04:23:25 +000037
38/*****************************************************************************/
39/* Exception processing */
40#if defined(CONFIG_USER_ONLY)
Andreas Färber97a8ea52013-02-02 10:57:51 +010041void ppc_cpu_do_interrupt(CPUState *cs)
Blue Swirlc79c73f2012-05-30 04:23:25 +000042{
Andreas Färber97a8ea52013-02-02 10:57:51 +010043 PowerPCCPU *cpu = POWERPC_CPU(cs);
44 CPUPPCState *env = &cpu->env;
45
Andreas Färber27103422013-08-26 08:31:06 +020046 cs->exception_index = POWERPC_EXCP_NONE;
Blue Swirlc79c73f2012-05-30 04:23:25 +000047 env->error_code = 0;
48}
49
50void ppc_hw_interrupt(CPUPPCState *env)
51{
Andreas Färber27103422013-08-26 08:31:06 +020052 CPUState *cs = CPU(ppc_env_get_cpu(env));
53
54 cs->exception_index = POWERPC_EXCP_NONE;
Blue Swirlc79c73f2012-05-30 04:23:25 +000055 env->error_code = 0;
56}
57#else /* defined(CONFIG_USER_ONLY) */
58static inline void dump_syscall(CPUPPCState *env)
59{
60 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
61 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
62 " nip=" TARGET_FMT_lx "\n",
63 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
64 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
65 ppc_dump_gpr(env, 6), env->nip);
66}
67
68/* Note that this function should be greatly optimized
69 * when called with a constant excp, from ppc_hw_interrupt
70 */
Andreas Färber5c26a5b2012-05-03 05:55:58 +020071static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
Blue Swirlc79c73f2012-05-30 04:23:25 +000072{
Andreas Färber27103422013-08-26 08:31:06 +020073 CPUState *cs = CPU(cpu);
Andreas Färber5c26a5b2012-05-03 05:55:58 +020074 CPUPPCState *env = &cpu->env;
Blue Swirlc79c73f2012-05-30 04:23:25 +000075 target_ulong msr, new_msr, vector;
76 int srr0, srr1, asrr0, asrr1;
77 int lpes0, lpes1, lev;
78
79 if (0) {
80 /* XXX: find a suitable condition to enable the hypervisor mode */
81 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
82 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
83 } else {
84 /* Those values ensure we won't enter the hypervisor mode */
85 lpes0 = 0;
86 lpes1 = 1;
87 }
88
89 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
90 " => %08x (%02x)\n", env->nip, excp, env->error_code);
91
92 /* new srr1 value excluding must-be-zero bits */
Scott Wooda1bb7382012-12-21 16:15:41 +000093 if (excp_model == POWERPC_EXCP_BOOKE) {
94 msr = env->msr;
95 } else {
96 msr = env->msr & ~0x783f0000ULL;
97 }
Blue Swirlc79c73f2012-05-30 04:23:25 +000098
99 /* new interrupt handler msr */
100 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
101
102 /* target registers */
103 srr0 = SPR_SRR0;
104 srr1 = SPR_SRR1;
105 asrr0 = -1;
106 asrr1 = -1;
107
108 switch (excp) {
109 case POWERPC_EXCP_NONE:
110 /* Should never happen */
111 return;
112 case POWERPC_EXCP_CRITICAL: /* Critical input */
113 switch (excp_model) {
114 case POWERPC_EXCP_40x:
115 srr0 = SPR_40x_SRR2;
116 srr1 = SPR_40x_SRR3;
117 break;
118 case POWERPC_EXCP_BOOKE:
119 srr0 = SPR_BOOKE_CSRR0;
120 srr1 = SPR_BOOKE_CSRR1;
121 break;
122 case POWERPC_EXCP_G2:
123 break;
124 default:
125 goto excp_invalid;
126 }
127 goto store_next;
128 case POWERPC_EXCP_MCHECK: /* Machine check exception */
129 if (msr_me == 0) {
130 /* Machine check exception is not enabled.
131 * Enter checkstop state.
132 */
133 if (qemu_log_enabled()) {
134 qemu_log("Machine check while not allowed. "
135 "Entering checkstop state\n");
136 } else {
137 fprintf(stderr, "Machine check while not allowed. "
138 "Entering checkstop state\n");
139 }
Andreas Färber259186a2013-01-17 18:51:17 +0100140 cs->halted = 1;
141 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000142 }
143 if (0) {
144 /* XXX: find a suitable condition to enable the hypervisor mode */
145 new_msr |= (target_ulong)MSR_HVB;
146 }
147
148 /* machine check exceptions don't have ME set */
149 new_msr &= ~((target_ulong)1 << MSR_ME);
150
151 /* XXX: should also have something loaded in DAR / DSISR */
152 switch (excp_model) {
153 case POWERPC_EXCP_40x:
154 srr0 = SPR_40x_SRR2;
155 srr1 = SPR_40x_SRR3;
156 break;
157 case POWERPC_EXCP_BOOKE:
Scott Wooda1bb7382012-12-21 16:15:41 +0000158 /* FIXME: choose one or the other based on CPU type */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000159 srr0 = SPR_BOOKE_MCSRR0;
160 srr1 = SPR_BOOKE_MCSRR1;
161 asrr0 = SPR_BOOKE_CSRR0;
162 asrr1 = SPR_BOOKE_CSRR1;
163 break;
164 default:
165 break;
166 }
167 goto store_next;
168 case POWERPC_EXCP_DSI: /* Data storage exception */
169 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
170 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
171 if (lpes1 == 0) {
172 new_msr |= (target_ulong)MSR_HVB;
173 }
174 goto store_next;
175 case POWERPC_EXCP_ISI: /* Instruction storage exception */
176 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
177 "\n", msr, env->nip);
178 if (lpes1 == 0) {
179 new_msr |= (target_ulong)MSR_HVB;
180 }
181 msr |= env->error_code;
182 goto store_next;
183 case POWERPC_EXCP_EXTERNAL: /* External input */
Edgar E. Iglesiasfdfba1a2013-11-15 14:46:38 +0100184 cs = CPU(cpu);
185
Blue Swirlc79c73f2012-05-30 04:23:25 +0000186 if (lpes0 == 1) {
187 new_msr |= (target_ulong)MSR_HVB;
188 }
Alexander Graf68c2dd72013-01-04 11:21:04 +0100189 if (env->mpic_proxy) {
190 /* IACK the IRQ on delivery */
Edgar E. Iglesiasfdfba1a2013-11-15 14:46:38 +0100191 env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
Alexander Graf68c2dd72013-01-04 11:21:04 +0100192 }
Blue Swirlc79c73f2012-05-30 04:23:25 +0000193 goto store_next;
194 case POWERPC_EXCP_ALIGN: /* Alignment exception */
195 if (lpes1 == 0) {
196 new_msr |= (target_ulong)MSR_HVB;
197 }
198 /* XXX: this is false */
199 /* Get rS/rD and rA from faulting opcode */
Blue Swirl2f5a1892012-05-30 04:23:40 +0000200 env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
201 & 0x03FF0000) >> 16;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000202 goto store_current;
203 case POWERPC_EXCP_PROGRAM: /* Program exception */
204 switch (env->error_code & ~0xF) {
205 case POWERPC_EXCP_FP:
206 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
207 LOG_EXCP("Ignore floating point exception\n");
Andreas Färber27103422013-08-26 08:31:06 +0200208 cs->exception_index = POWERPC_EXCP_NONE;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000209 env->error_code = 0;
210 return;
211 }
212 if (lpes1 == 0) {
213 new_msr |= (target_ulong)MSR_HVB;
214 }
215 msr |= 0x00100000;
216 if (msr_fe0 == msr_fe1) {
217 goto store_next;
218 }
219 msr |= 0x00010000;
220 break;
221 case POWERPC_EXCP_INVAL:
222 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
223 if (lpes1 == 0) {
224 new_msr |= (target_ulong)MSR_HVB;
225 }
226 msr |= 0x00080000;
227 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
228 break;
229 case POWERPC_EXCP_PRIV:
230 if (lpes1 == 0) {
231 new_msr |= (target_ulong)MSR_HVB;
232 }
233 msr |= 0x00040000;
234 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
235 break;
236 case POWERPC_EXCP_TRAP:
237 if (lpes1 == 0) {
238 new_msr |= (target_ulong)MSR_HVB;
239 }
240 msr |= 0x00020000;
241 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
242 break;
243 default:
244 /* Should never occur */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200245 cpu_abort(cs, "Invalid program exception %d. Aborting\n",
Blue Swirlc79c73f2012-05-30 04:23:25 +0000246 env->error_code);
247 break;
248 }
249 goto store_current;
250 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
251 if (lpes1 == 0) {
252 new_msr |= (target_ulong)MSR_HVB;
253 }
254 goto store_current;
255 case POWERPC_EXCP_SYSCALL: /* System call exception */
256 dump_syscall(env);
257 lev = env->error_code;
258 if ((lev == 1) && cpu_ppc_hypercall) {
Andreas Färber1b146702012-05-03 06:03:45 +0200259 cpu_ppc_hypercall(cpu);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000260 return;
261 }
262 if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
263 new_msr |= (target_ulong)MSR_HVB;
264 }
265 goto store_next;
266 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
267 goto store_current;
268 case POWERPC_EXCP_DECR: /* Decrementer exception */
269 if (lpes1 == 0) {
270 new_msr |= (target_ulong)MSR_HVB;
271 }
272 goto store_next;
273 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
274 /* FIT on 4xx */
275 LOG_EXCP("FIT exception\n");
276 goto store_next;
277 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
278 LOG_EXCP("WDT exception\n");
279 switch (excp_model) {
280 case POWERPC_EXCP_BOOKE:
281 srr0 = SPR_BOOKE_CSRR0;
282 srr1 = SPR_BOOKE_CSRR1;
283 break;
284 default:
285 break;
286 }
287 goto store_next;
288 case POWERPC_EXCP_DTLB: /* Data TLB error */
289 goto store_next;
290 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
291 goto store_next;
292 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
293 switch (excp_model) {
294 case POWERPC_EXCP_BOOKE:
Scott Wooda1bb7382012-12-21 16:15:41 +0000295 /* FIXME: choose one or the other based on CPU type */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000296 srr0 = SPR_BOOKE_DSRR0;
297 srr1 = SPR_BOOKE_DSRR1;
298 asrr0 = SPR_BOOKE_CSRR0;
299 asrr1 = SPR_BOOKE_CSRR1;
300 break;
301 default:
302 break;
303 }
304 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200305 cpu_abort(cs, "Debug exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000306 goto store_next;
307 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
308 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
309 goto store_current;
310 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
311 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200312 cpu_abort(cs, "Embedded floating point data exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000313 "is not implemented yet !\n");
314 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
315 goto store_next;
316 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
317 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200318 cpu_abort(cs, "Embedded floating point round exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000319 "is not implemented yet !\n");
320 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
321 goto store_next;
322 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
323 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200324 cpu_abort(cs,
Blue Swirlc79c73f2012-05-30 04:23:25 +0000325 "Performance counter exception is not implemented yet !\n");
326 goto store_next;
327 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
328 goto store_next;
329 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
330 srr0 = SPR_BOOKE_CSRR0;
331 srr1 = SPR_BOOKE_CSRR1;
332 goto store_next;
333 case POWERPC_EXCP_RESET: /* System reset exception */
334 if (msr_pow) {
335 /* indicate that we resumed from power save mode */
336 msr |= 0x10000;
337 } else {
338 new_msr &= ~((target_ulong)1 << MSR_ME);
339 }
340
341 if (0) {
342 /* XXX: find a suitable condition to enable the hypervisor mode */
343 new_msr |= (target_ulong)MSR_HVB;
344 }
345 goto store_next;
346 case POWERPC_EXCP_DSEG: /* Data segment exception */
347 if (lpes1 == 0) {
348 new_msr |= (target_ulong)MSR_HVB;
349 }
350 goto store_next;
351 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
352 if (lpes1 == 0) {
353 new_msr |= (target_ulong)MSR_HVB;
354 }
355 goto store_next;
356 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
357 srr0 = SPR_HSRR0;
358 srr1 = SPR_HSRR1;
359 new_msr |= (target_ulong)MSR_HVB;
360 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
361 goto store_next;
362 case POWERPC_EXCP_TRACE: /* Trace exception */
363 if (lpes1 == 0) {
364 new_msr |= (target_ulong)MSR_HVB;
365 }
366 goto store_next;
367 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
368 srr0 = SPR_HSRR0;
369 srr1 = SPR_HSRR1;
370 new_msr |= (target_ulong)MSR_HVB;
371 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
372 goto store_next;
373 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
374 srr0 = SPR_HSRR0;
375 srr1 = SPR_HSRR1;
376 new_msr |= (target_ulong)MSR_HVB;
377 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
378 goto store_next;
379 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
380 srr0 = SPR_HSRR0;
381 srr1 = SPR_HSRR1;
382 new_msr |= (target_ulong)MSR_HVB;
383 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
384 goto store_next;
385 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
386 srr0 = SPR_HSRR0;
387 srr1 = SPR_HSRR1;
388 new_msr |= (target_ulong)MSR_HVB;
389 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
390 goto store_next;
391 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
392 if (lpes1 == 0) {
393 new_msr |= (target_ulong)MSR_HVB;
394 }
395 goto store_current;
Tom Musta1f298712013-10-22 22:06:17 +1100396 case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
397 if (lpes1 == 0) {
398 new_msr |= (target_ulong)MSR_HVB;
399 }
400 goto store_current;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000401 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
402 LOG_EXCP("PIT exception\n");
403 goto store_next;
404 case POWERPC_EXCP_IO: /* IO error exception */
405 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200406 cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000407 goto store_next;
408 case POWERPC_EXCP_RUNM: /* Run mode exception */
409 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200410 cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000411 goto store_next;
412 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
413 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200414 cpu_abort(cs, "602 emulation trap exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000415 "is not implemented yet !\n");
416 goto store_next;
417 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
418 if (lpes1 == 0) { /* XXX: check this */
419 new_msr |= (target_ulong)MSR_HVB;
420 }
421 switch (excp_model) {
422 case POWERPC_EXCP_602:
423 case POWERPC_EXCP_603:
424 case POWERPC_EXCP_603E:
425 case POWERPC_EXCP_G2:
426 goto tlb_miss_tgpr;
427 case POWERPC_EXCP_7x5:
428 goto tlb_miss;
429 case POWERPC_EXCP_74xx:
430 goto tlb_miss_74xx;
431 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200432 cpu_abort(cs, "Invalid instruction TLB miss exception\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000433 break;
434 }
435 break;
436 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
437 if (lpes1 == 0) { /* XXX: check this */
438 new_msr |= (target_ulong)MSR_HVB;
439 }
440 switch (excp_model) {
441 case POWERPC_EXCP_602:
442 case POWERPC_EXCP_603:
443 case POWERPC_EXCP_603E:
444 case POWERPC_EXCP_G2:
445 goto tlb_miss_tgpr;
446 case POWERPC_EXCP_7x5:
447 goto tlb_miss;
448 case POWERPC_EXCP_74xx:
449 goto tlb_miss_74xx;
450 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200451 cpu_abort(cs, "Invalid data load TLB miss exception\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000452 break;
453 }
454 break;
455 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
456 if (lpes1 == 0) { /* XXX: check this */
457 new_msr |= (target_ulong)MSR_HVB;
458 }
459 switch (excp_model) {
460 case POWERPC_EXCP_602:
461 case POWERPC_EXCP_603:
462 case POWERPC_EXCP_603E:
463 case POWERPC_EXCP_G2:
464 tlb_miss_tgpr:
465 /* Swap temporary saved registers with GPRs */
466 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
467 new_msr |= (target_ulong)1 << MSR_TGPR;
468 hreg_swap_gpr_tgpr(env);
469 }
470 goto tlb_miss;
471 case POWERPC_EXCP_7x5:
472 tlb_miss:
473#if defined(DEBUG_SOFTWARE_TLB)
474 if (qemu_log_enabled()) {
475 const char *es;
476 target_ulong *miss, *cmp;
477 int en;
478
479 if (excp == POWERPC_EXCP_IFTLB) {
480 es = "I";
481 en = 'I';
482 miss = &env->spr[SPR_IMISS];
483 cmp = &env->spr[SPR_ICMP];
484 } else {
485 if (excp == POWERPC_EXCP_DLTLB) {
486 es = "DL";
487 } else {
488 es = "DS";
489 }
490 en = 'D';
491 miss = &env->spr[SPR_DMISS];
492 cmp = &env->spr[SPR_DCMP];
493 }
494 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
495 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
496 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
497 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
498 env->error_code);
499 }
500#endif
501 msr |= env->crf[0] << 28;
502 msr |= env->error_code; /* key, D/I, S/L bits */
503 /* Set way using a LRU mechanism */
504 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
505 break;
506 case POWERPC_EXCP_74xx:
507 tlb_miss_74xx:
508#if defined(DEBUG_SOFTWARE_TLB)
509 if (qemu_log_enabled()) {
510 const char *es;
511 target_ulong *miss, *cmp;
512 int en;
513
514 if (excp == POWERPC_EXCP_IFTLB) {
515 es = "I";
516 en = 'I';
517 miss = &env->spr[SPR_TLBMISS];
518 cmp = &env->spr[SPR_PTEHI];
519 } else {
520 if (excp == POWERPC_EXCP_DLTLB) {
521 es = "DL";
522 } else {
523 es = "DS";
524 }
525 en = 'D';
526 miss = &env->spr[SPR_TLBMISS];
527 cmp = &env->spr[SPR_PTEHI];
528 }
529 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
530 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
531 env->error_code);
532 }
533#endif
534 msr |= env->error_code; /* key bit */
535 break;
536 default:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200537 cpu_abort(cs, "Invalid data store TLB miss exception\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000538 break;
539 }
540 goto store_next;
541 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
542 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200543 cpu_abort(cs, "Floating point assist exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000544 "is not implemented yet !\n");
545 goto store_next;
546 case POWERPC_EXCP_DABR: /* Data address breakpoint */
547 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200548 cpu_abort(cs, "DABR exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000549 goto store_next;
550 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
551 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200552 cpu_abort(cs, "IABR exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000553 goto store_next;
554 case POWERPC_EXCP_SMI: /* System management interrupt */
555 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200556 cpu_abort(cs, "SMI exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000557 goto store_next;
558 case POWERPC_EXCP_THERM: /* Thermal interrupt */
559 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200560 cpu_abort(cs, "Thermal management exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000561 "is not implemented yet !\n");
562 goto store_next;
563 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
564 if (lpes1 == 0) {
565 new_msr |= (target_ulong)MSR_HVB;
566 }
567 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200568 cpu_abort(cs,
Blue Swirlc79c73f2012-05-30 04:23:25 +0000569 "Performance counter exception is not implemented yet !\n");
570 goto store_next;
571 case POWERPC_EXCP_VPUA: /* Vector assist exception */
572 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200573 cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
Blue Swirlc79c73f2012-05-30 04:23:25 +0000574 goto store_next;
575 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
576 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200577 cpu_abort(cs,
Blue Swirlc79c73f2012-05-30 04:23:25 +0000578 "970 soft-patch exception is not implemented yet !\n");
579 goto store_next;
580 case POWERPC_EXCP_MAINT: /* Maintenance exception */
581 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200582 cpu_abort(cs,
Blue Swirlc79c73f2012-05-30 04:23:25 +0000583 "970 maintenance exception is not implemented yet !\n");
584 goto store_next;
585 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
586 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200587 cpu_abort(cs, "Maskable external exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000588 "is not implemented yet !\n");
589 goto store_next;
590 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
591 /* XXX: TODO */
Andreas Färbera47dddd2013-09-03 17:38:47 +0200592 cpu_abort(cs, "Non maskable external exception "
Blue Swirlc79c73f2012-05-30 04:23:25 +0000593 "is not implemented yet !\n");
594 goto store_next;
595 default:
596 excp_invalid:
Andreas Färbera47dddd2013-09-03 17:38:47 +0200597 cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000598 break;
599 store_current:
600 /* save current instruction location */
601 env->spr[srr0] = env->nip - 4;
602 break;
603 store_next:
604 /* save next instruction location */
605 env->spr[srr0] = env->nip;
606 break;
607 }
608 /* Save MSR */
609 env->spr[srr1] = msr;
610 /* If any alternate SRR register are defined, duplicate saved values */
611 if (asrr0 != -1) {
612 env->spr[asrr0] = env->spr[srr0];
613 }
614 if (asrr1 != -1) {
615 env->spr[asrr1] = env->spr[srr1];
616 }
617 /* If we disactivated any translation, flush TLBs */
618 if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
Andreas Färber00c8cb02013-09-04 02:19:44 +0200619 tlb_flush(cs, 1);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000620 }
621
Anton Blanchard1e0c7e52013-08-07 10:47:01 +1000622#ifdef TARGET_PPC64
623 if (excp_model == POWERPC_EXCP_POWER7) {
624 if (env->spr[SPR_LPCR] & LPCR_ILE) {
625 new_msr |= (target_ulong)1 << MSR_LE;
626 }
627 } else if (msr_ile) {
628 new_msr |= (target_ulong)1 << MSR_LE;
629 }
630#else
Blue Swirlc79c73f2012-05-30 04:23:25 +0000631 if (msr_ile) {
632 new_msr |= (target_ulong)1 << MSR_LE;
633 }
Anton Blanchard1e0c7e52013-08-07 10:47:01 +1000634#endif
Blue Swirlc79c73f2012-05-30 04:23:25 +0000635
636 /* Jump to handler */
637 vector = env->excp_vectors[excp];
638 if (vector == (target_ulong)-1ULL) {
Andreas Färbera47dddd2013-09-03 17:38:47 +0200639 cpu_abort(cs, "Raised an exception without defined vector %d\n",
Blue Swirlc79c73f2012-05-30 04:23:25 +0000640 excp);
641 }
642 vector |= env->excp_prefix;
643#if defined(TARGET_PPC64)
644 if (excp_model == POWERPC_EXCP_BOOKE) {
Alexander Grafe42a61f2012-06-20 21:20:29 +0200645 if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
646 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000647 new_msr |= (target_ulong)1 << MSR_CM;
Alexander Grafe42a61f2012-06-20 21:20:29 +0200648 } else {
649 vector = (uint32_t)vector;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000650 }
651 } else {
652 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
653 vector = (uint32_t)vector;
654 } else {
655 new_msr |= (target_ulong)1 << MSR_SF;
656 }
657 }
658#endif
659 /* XXX: we don't use hreg_store_msr here as already have treated
660 * any special case that could occur. Just store MSR and update hflags
661 */
662 env->msr = new_msr & env->msr_mask;
663 hreg_compute_hflags(env);
664 env->nip = vector;
665 /* Reset exception state */
Andreas Färber27103422013-08-26 08:31:06 +0200666 cs->exception_index = POWERPC_EXCP_NONE;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000667 env->error_code = 0;
668
669 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
670 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
671 /* XXX: The BookE changes address space when switching modes,
672 we should probably implement that as different MMU indexes,
673 but for the moment we do it the slow way and flush all. */
Andreas Färber00c8cb02013-09-04 02:19:44 +0200674 tlb_flush(cs, 1);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000675 }
676}
677
Andreas Färber97a8ea52013-02-02 10:57:51 +0100678void ppc_cpu_do_interrupt(CPUState *cs)
Blue Swirlc79c73f2012-05-30 04:23:25 +0000679{
Andreas Färber97a8ea52013-02-02 10:57:51 +0100680 PowerPCCPU *cpu = POWERPC_CPU(cs);
681 CPUPPCState *env = &cpu->env;
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200682
Andreas Färber27103422013-08-26 08:31:06 +0200683 powerpc_excp(cpu, env->excp_model, cs->exception_index);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000684}
685
686void ppc_hw_interrupt(CPUPPCState *env)
687{
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200688 PowerPCCPU *cpu = ppc_env_get_cpu(env);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000689 int hdice;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000690#if 0
Andreas Färber259186a2013-01-17 18:51:17 +0100691 CPUState *cs = CPU(cpu);
692
Blue Swirlc79c73f2012-05-30 04:23:25 +0000693 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
Andreas Färber259186a2013-01-17 18:51:17 +0100694 __func__, env, env->pending_interrupts,
695 cs->interrupt_request, (int)msr_me, (int)msr_ee);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000696#endif
697 /* External reset */
698 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
699 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200700 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000701 return;
702 }
703 /* Machine check exception */
704 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
705 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200706 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000707 return;
708 }
709#if 0 /* TODO */
710 /* External debug exception */
711 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
712 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200713 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000714 return;
715 }
716#endif
717 if (0) {
718 /* XXX: find a suitable condition to enable the hypervisor mode */
719 hdice = env->spr[SPR_LPCR] & 1;
720 } else {
721 hdice = 0;
722 }
723 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
724 /* Hypervisor decrementer exception */
725 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200726 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000727 return;
728 }
729 }
730 if (msr_ce != 0) {
731 /* External critical interrupt */
732 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
733 /* Taking a critical external interrupt does not clear the external
734 * critical interrupt status
735 */
736#if 0
737 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
738#endif
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200739 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000740 return;
741 }
742 }
743 if (msr_ee != 0) {
744 /* Watchdog timer on embedded PowerPC */
745 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
746 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200747 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000748 return;
749 }
750 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
751 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200752 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000753 return;
754 }
755 /* Fixed interval timer on embedded PowerPC */
756 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
757 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200758 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000759 return;
760 }
761 /* Programmable interval timer on embedded PowerPC */
762 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
763 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200764 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000765 return;
766 }
767 /* Decrementer exception */
768 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
Alexander Grafe81a9822014-04-06 01:32:06 +0200769 if (ppc_decr_clear_on_delivery(env)) {
770 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
771 }
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200772 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000773 return;
774 }
775 /* External interrupt */
776 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
777 /* Taking an external interrupt does not clear the external
778 * interrupt status
779 */
780#if 0
781 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
782#endif
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200783 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000784 return;
785 }
786 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
787 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200788 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000789 return;
790 }
791 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
792 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200793 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000794 return;
795 }
796 /* Thermal interrupt */
797 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
798 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200799 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000800 return;
801 }
802 }
803}
804#endif /* !CONFIG_USER_ONLY */
805
806#if defined(DEBUG_OP)
807static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
808{
809 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
810 TARGET_FMT_lx "\n", RA, msr);
811}
812#endif
813
Blue Swirlad71ed62012-05-30 04:23:22 +0000814/*****************************************************************************/
815/* Exceptions processing helpers */
816
Blue Swirle5f17ac2012-05-30 04:23:23 +0000817void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
818 uint32_t error_code)
Blue Swirlad71ed62012-05-30 04:23:22 +0000819{
Andreas Färber27103422013-08-26 08:31:06 +0200820 CPUState *cs = CPU(ppc_env_get_cpu(env));
821
Blue Swirlad71ed62012-05-30 04:23:22 +0000822#if 0
823 printf("Raise exception %3x code : %d\n", exception, error_code);
824#endif
Andreas Färber27103422013-08-26 08:31:06 +0200825 cs->exception_index = exception;
Blue Swirlad71ed62012-05-30 04:23:22 +0000826 env->error_code = error_code;
Andreas Färber5638d182013-08-27 17:52:12 +0200827 cpu_loop_exit(cs);
Blue Swirlad71ed62012-05-30 04:23:22 +0000828}
829
Blue Swirle5f17ac2012-05-30 04:23:23 +0000830void helper_raise_exception(CPUPPCState *env, uint32_t exception)
Blue Swirlad71ed62012-05-30 04:23:22 +0000831{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000832 helper_raise_exception_err(env, exception, 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000833}
834
835#if !defined(CONFIG_USER_ONLY)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000836void helper_store_msr(CPUPPCState *env, target_ulong val)
Blue Swirlad71ed62012-05-30 04:23:22 +0000837{
Andreas Färber259186a2013-01-17 18:51:17 +0100838 CPUState *cs;
839
Blue Swirlad71ed62012-05-30 04:23:22 +0000840 val = hreg_store_msr(env, val, 0);
841 if (val != 0) {
Andreas Färber259186a2013-01-17 18:51:17 +0100842 cs = CPU(ppc_env_get_cpu(env));
843 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirle5f17ac2012-05-30 04:23:23 +0000844 helper_raise_exception(env, val);
Blue Swirlad71ed62012-05-30 04:23:22 +0000845 }
846}
847
Blue Swirle5f17ac2012-05-30 04:23:23 +0000848static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
Blue Swirlad71ed62012-05-30 04:23:22 +0000849 target_ulong msrm, int keep_msrh)
850{
Andreas Färber259186a2013-01-17 18:51:17 +0100851 CPUState *cs = CPU(ppc_env_get_cpu(env));
852
Blue Swirlad71ed62012-05-30 04:23:22 +0000853#if defined(TARGET_PPC64)
Alexander Grafe42a61f2012-06-20 21:20:29 +0200854 if (msr_is_64bit(env, msr)) {
Blue Swirlad71ed62012-05-30 04:23:22 +0000855 nip = (uint64_t)nip;
856 msr &= (uint64_t)msrm;
857 } else {
858 nip = (uint32_t)nip;
859 msr = (uint32_t)(msr & msrm);
860 if (keep_msrh) {
861 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
862 }
863 }
864#else
865 nip = (uint32_t)nip;
866 msr &= (uint32_t)msrm;
867#endif
868 /* XXX: beware: this is false if VLE is supported */
869 env->nip = nip & ~((target_ulong)0x00000003);
870 hreg_store_msr(env, msr, 1);
871#if defined(DEBUG_OP)
872 cpu_dump_rfi(env->nip, env->msr);
873#endif
874 /* No need to raise an exception here,
875 * as rfi is always the last insn of a TB
876 */
Andreas Färber259186a2013-01-17 18:51:17 +0100877 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirlad71ed62012-05-30 04:23:22 +0000878}
879
Blue Swirle5f17ac2012-05-30 04:23:23 +0000880void helper_rfi(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000881{
Scott Wooda1bb7382012-12-21 16:15:41 +0000882 if (env->excp_model == POWERPC_EXCP_BOOKE) {
883 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
884 ~((target_ulong)0), 0);
885 } else {
886 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
887 ~((target_ulong)0x783F0000), 1);
888 }
Blue Swirlad71ed62012-05-30 04:23:22 +0000889}
890
891#if defined(TARGET_PPC64)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000892void helper_rfid(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000893{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000894 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
Blue Swirlad71ed62012-05-30 04:23:22 +0000895 ~((target_ulong)0x783F0000), 0);
896}
897
Blue Swirle5f17ac2012-05-30 04:23:23 +0000898void helper_hrfid(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000899{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000900 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
Blue Swirlad71ed62012-05-30 04:23:22 +0000901 ~((target_ulong)0x783F0000), 0);
902}
903#endif
904
905/*****************************************************************************/
906/* Embedded PowerPC specific helpers */
Blue Swirle5f17ac2012-05-30 04:23:23 +0000907void helper_40x_rfci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000908{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000909 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
Blue Swirlad71ed62012-05-30 04:23:22 +0000910 ~((target_ulong)0xFFFF0000), 0);
911}
912
Blue Swirle5f17ac2012-05-30 04:23:23 +0000913void helper_rfci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000914{
Scott Wooda1bb7382012-12-21 16:15:41 +0000915 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
916 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000917}
918
Blue Swirle5f17ac2012-05-30 04:23:23 +0000919void helper_rfdi(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000920{
Scott Wooda1bb7382012-12-21 16:15:41 +0000921 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
922 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
923 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000924}
925
Blue Swirle5f17ac2012-05-30 04:23:23 +0000926void helper_rfmci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000927{
Scott Wooda1bb7382012-12-21 16:15:41 +0000928 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
929 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
930 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000931}
932#endif
933
Blue Swirle5f17ac2012-05-30 04:23:23 +0000934void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
935 uint32_t flags)
Blue Swirlad71ed62012-05-30 04:23:22 +0000936{
937 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
938 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
939 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
940 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
941 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
Blue Swirle5f17ac2012-05-30 04:23:23 +0000942 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
943 POWERPC_EXCP_TRAP);
Blue Swirlad71ed62012-05-30 04:23:22 +0000944 }
945}
946
947#if defined(TARGET_PPC64)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000948void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
949 uint32_t flags)
Blue Swirlad71ed62012-05-30 04:23:22 +0000950{
951 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
952 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
953 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
954 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
955 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
Blue Swirle5f17ac2012-05-30 04:23:23 +0000956 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
957 POWERPC_EXCP_TRAP);
Blue Swirlad71ed62012-05-30 04:23:22 +0000958 }
959}
960#endif
961
962#if !defined(CONFIG_USER_ONLY)
963/*****************************************************************************/
964/* PowerPC 601 specific instructions (POWER bridge) */
965
Blue Swirle5f17ac2012-05-30 04:23:23 +0000966void helper_rfsvc(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000967{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000968 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000969}
970
971/* Embedded.Processor Control */
972static int dbell2irq(target_ulong rb)
973{
974 int msg = rb & DBELL_TYPE_MASK;
975 int irq = -1;
976
977 switch (msg) {
978 case DBELL_TYPE_DBELL:
979 irq = PPC_INTERRUPT_DOORBELL;
980 break;
981 case DBELL_TYPE_DBELL_CRIT:
982 irq = PPC_INTERRUPT_CDOORBELL;
983 break;
984 case DBELL_TYPE_G_DBELL:
985 case DBELL_TYPE_G_DBELL_CRIT:
986 case DBELL_TYPE_G_DBELL_MC:
987 /* XXX implement */
988 default:
989 break;
990 }
991
992 return irq;
993}
994
Blue Swirle5f17ac2012-05-30 04:23:23 +0000995void helper_msgclr(CPUPPCState *env, target_ulong rb)
Blue Swirlad71ed62012-05-30 04:23:22 +0000996{
997 int irq = dbell2irq(rb);
998
999 if (irq < 0) {
1000 return;
1001 }
1002
1003 env->pending_interrupts &= ~(1 << irq);
1004}
1005
1006void helper_msgsnd(target_ulong rb)
1007{
1008 int irq = dbell2irq(rb);
1009 int pir = rb & DBELL_PIRTAG_MASK;
Andreas Färber182735e2013-05-29 22:29:20 +02001010 CPUState *cs;
Blue Swirlad71ed62012-05-30 04:23:22 +00001011
1012 if (irq < 0) {
1013 return;
1014 }
1015
Andreas Färberbdc44642013-06-24 23:50:24 +02001016 CPU_FOREACH(cs) {
Andreas Färber182735e2013-05-29 22:29:20 +02001017 PowerPCCPU *cpu = POWERPC_CPU(cs);
1018 CPUPPCState *cenv = &cpu->env;
1019
Blue Swirlad71ed62012-05-30 04:23:22 +00001020 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1021 cenv->pending_interrupts |= 1 << irq;
Andreas Färber182735e2013-05-29 22:29:20 +02001022 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
Blue Swirlad71ed62012-05-30 04:23:22 +00001023 }
1024 }
1025}
1026#endif