blob: c959460f7087d9c9f9c9a3ed2e8dafd0bc645183 [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
Blue Swirlc79c73f2012-05-30 04:23:25 +000046 env->exception_index = POWERPC_EXCP_NONE;
47 env->error_code = 0;
48}
49
50void ppc_hw_interrupt(CPUPPCState *env)
51{
52 env->exception_index = POWERPC_EXCP_NONE;
53 env->error_code = 0;
54}
55#else /* defined(CONFIG_USER_ONLY) */
56static inline void dump_syscall(CPUPPCState *env)
57{
58 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
59 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
60 " nip=" TARGET_FMT_lx "\n",
61 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
62 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
63 ppc_dump_gpr(env, 6), env->nip);
64}
65
66/* Note that this function should be greatly optimized
67 * when called with a constant excp, from ppc_hw_interrupt
68 */
Andreas Färber5c26a5b2012-05-03 05:55:58 +020069static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
Blue Swirlc79c73f2012-05-30 04:23:25 +000070{
Andreas Färber5c26a5b2012-05-03 05:55:58 +020071 CPUPPCState *env = &cpu->env;
Andreas Färber259186a2013-01-17 18:51:17 +010072 CPUState *cs;
Blue Swirlc79c73f2012-05-30 04:23:25 +000073 target_ulong msr, new_msr, vector;
74 int srr0, srr1, asrr0, asrr1;
75 int lpes0, lpes1, lev;
76
77 if (0) {
78 /* XXX: find a suitable condition to enable the hypervisor mode */
79 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
80 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
81 } else {
82 /* Those values ensure we won't enter the hypervisor mode */
83 lpes0 = 0;
84 lpes1 = 1;
85 }
86
87 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
88 " => %08x (%02x)\n", env->nip, excp, env->error_code);
89
90 /* new srr1 value excluding must-be-zero bits */
Scott Wooda1bb7382012-12-21 16:15:41 +000091 if (excp_model == POWERPC_EXCP_BOOKE) {
92 msr = env->msr;
93 } else {
94 msr = env->msr & ~0x783f0000ULL;
95 }
Blue Swirlc79c73f2012-05-30 04:23:25 +000096
97 /* new interrupt handler msr */
98 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
99
100 /* target registers */
101 srr0 = SPR_SRR0;
102 srr1 = SPR_SRR1;
103 asrr0 = -1;
104 asrr1 = -1;
105
106 switch (excp) {
107 case POWERPC_EXCP_NONE:
108 /* Should never happen */
109 return;
110 case POWERPC_EXCP_CRITICAL: /* Critical input */
111 switch (excp_model) {
112 case POWERPC_EXCP_40x:
113 srr0 = SPR_40x_SRR2;
114 srr1 = SPR_40x_SRR3;
115 break;
116 case POWERPC_EXCP_BOOKE:
117 srr0 = SPR_BOOKE_CSRR0;
118 srr1 = SPR_BOOKE_CSRR1;
119 break;
120 case POWERPC_EXCP_G2:
121 break;
122 default:
123 goto excp_invalid;
124 }
125 goto store_next;
126 case POWERPC_EXCP_MCHECK: /* Machine check exception */
127 if (msr_me == 0) {
128 /* Machine check exception is not enabled.
129 * Enter checkstop state.
130 */
131 if (qemu_log_enabled()) {
132 qemu_log("Machine check while not allowed. "
133 "Entering checkstop state\n");
134 } else {
135 fprintf(stderr, "Machine check while not allowed. "
136 "Entering checkstop state\n");
137 }
Andreas Färber259186a2013-01-17 18:51:17 +0100138 cs = CPU(cpu);
139 cs->halted = 1;
140 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000141 }
142 if (0) {
143 /* XXX: find a suitable condition to enable the hypervisor mode */
144 new_msr |= (target_ulong)MSR_HVB;
145 }
146
147 /* machine check exceptions don't have ME set */
148 new_msr &= ~((target_ulong)1 << MSR_ME);
149
150 /* XXX: should also have something loaded in DAR / DSISR */
151 switch (excp_model) {
152 case POWERPC_EXCP_40x:
153 srr0 = SPR_40x_SRR2;
154 srr1 = SPR_40x_SRR3;
155 break;
156 case POWERPC_EXCP_BOOKE:
Scott Wooda1bb7382012-12-21 16:15:41 +0000157 /* FIXME: choose one or the other based on CPU type */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000158 srr0 = SPR_BOOKE_MCSRR0;
159 srr1 = SPR_BOOKE_MCSRR1;
160 asrr0 = SPR_BOOKE_CSRR0;
161 asrr1 = SPR_BOOKE_CSRR1;
162 break;
163 default:
164 break;
165 }
166 goto store_next;
167 case POWERPC_EXCP_DSI: /* Data storage exception */
168 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
169 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
170 if (lpes1 == 0) {
171 new_msr |= (target_ulong)MSR_HVB;
172 }
173 goto store_next;
174 case POWERPC_EXCP_ISI: /* Instruction storage exception */
175 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
176 "\n", msr, env->nip);
177 if (lpes1 == 0) {
178 new_msr |= (target_ulong)MSR_HVB;
179 }
180 msr |= env->error_code;
181 goto store_next;
182 case POWERPC_EXCP_EXTERNAL: /* External input */
183 if (lpes0 == 1) {
184 new_msr |= (target_ulong)MSR_HVB;
185 }
Alexander Graf68c2dd72013-01-04 11:21:04 +0100186 if (env->mpic_proxy) {
187 /* IACK the IRQ on delivery */
188 env->spr[SPR_BOOKE_EPR] = ldl_phys(env->mpic_iack);
189 }
Blue Swirlc79c73f2012-05-30 04:23:25 +0000190 goto store_next;
191 case POWERPC_EXCP_ALIGN: /* Alignment exception */
192 if (lpes1 == 0) {
193 new_msr |= (target_ulong)MSR_HVB;
194 }
195 /* XXX: this is false */
196 /* Get rS/rD and rA from faulting opcode */
Blue Swirl2f5a1892012-05-30 04:23:40 +0000197 env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
198 & 0x03FF0000) >> 16;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000199 goto store_current;
200 case POWERPC_EXCP_PROGRAM: /* Program exception */
201 switch (env->error_code & ~0xF) {
202 case POWERPC_EXCP_FP:
203 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
204 LOG_EXCP("Ignore floating point exception\n");
205 env->exception_index = POWERPC_EXCP_NONE;
206 env->error_code = 0;
207 return;
208 }
209 if (lpes1 == 0) {
210 new_msr |= (target_ulong)MSR_HVB;
211 }
212 msr |= 0x00100000;
213 if (msr_fe0 == msr_fe1) {
214 goto store_next;
215 }
216 msr |= 0x00010000;
217 break;
218 case POWERPC_EXCP_INVAL:
219 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
220 if (lpes1 == 0) {
221 new_msr |= (target_ulong)MSR_HVB;
222 }
223 msr |= 0x00080000;
224 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
225 break;
226 case POWERPC_EXCP_PRIV:
227 if (lpes1 == 0) {
228 new_msr |= (target_ulong)MSR_HVB;
229 }
230 msr |= 0x00040000;
231 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
232 break;
233 case POWERPC_EXCP_TRAP:
234 if (lpes1 == 0) {
235 new_msr |= (target_ulong)MSR_HVB;
236 }
237 msr |= 0x00020000;
238 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
239 break;
240 default:
241 /* Should never occur */
242 cpu_abort(env, "Invalid program exception %d. Aborting\n",
243 env->error_code);
244 break;
245 }
246 goto store_current;
247 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
248 if (lpes1 == 0) {
249 new_msr |= (target_ulong)MSR_HVB;
250 }
251 goto store_current;
252 case POWERPC_EXCP_SYSCALL: /* System call exception */
253 dump_syscall(env);
254 lev = env->error_code;
255 if ((lev == 1) && cpu_ppc_hypercall) {
Andreas Färber1b146702012-05-03 06:03:45 +0200256 cpu_ppc_hypercall(cpu);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000257 return;
258 }
259 if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
260 new_msr |= (target_ulong)MSR_HVB;
261 }
262 goto store_next;
263 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
264 goto store_current;
265 case POWERPC_EXCP_DECR: /* Decrementer exception */
266 if (lpes1 == 0) {
267 new_msr |= (target_ulong)MSR_HVB;
268 }
269 goto store_next;
270 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
271 /* FIT on 4xx */
272 LOG_EXCP("FIT exception\n");
273 goto store_next;
274 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
275 LOG_EXCP("WDT exception\n");
276 switch (excp_model) {
277 case POWERPC_EXCP_BOOKE:
278 srr0 = SPR_BOOKE_CSRR0;
279 srr1 = SPR_BOOKE_CSRR1;
280 break;
281 default:
282 break;
283 }
284 goto store_next;
285 case POWERPC_EXCP_DTLB: /* Data TLB error */
286 goto store_next;
287 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
288 goto store_next;
289 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
290 switch (excp_model) {
291 case POWERPC_EXCP_BOOKE:
Scott Wooda1bb7382012-12-21 16:15:41 +0000292 /* FIXME: choose one or the other based on CPU type */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000293 srr0 = SPR_BOOKE_DSRR0;
294 srr1 = SPR_BOOKE_DSRR1;
295 asrr0 = SPR_BOOKE_CSRR0;
296 asrr1 = SPR_BOOKE_CSRR1;
297 break;
298 default:
299 break;
300 }
301 /* XXX: TODO */
302 cpu_abort(env, "Debug exception is not implemented yet !\n");
303 goto store_next;
304 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
305 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
306 goto store_current;
307 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
308 /* XXX: TODO */
309 cpu_abort(env, "Embedded floating point data exception "
310 "is not implemented yet !\n");
311 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
312 goto store_next;
313 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
314 /* XXX: TODO */
315 cpu_abort(env, "Embedded floating point round exception "
316 "is not implemented yet !\n");
317 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
318 goto store_next;
319 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
320 /* XXX: TODO */
321 cpu_abort(env,
322 "Performance counter exception is not implemented yet !\n");
323 goto store_next;
324 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
325 goto store_next;
326 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
327 srr0 = SPR_BOOKE_CSRR0;
328 srr1 = SPR_BOOKE_CSRR1;
329 goto store_next;
330 case POWERPC_EXCP_RESET: /* System reset exception */
331 if (msr_pow) {
332 /* indicate that we resumed from power save mode */
333 msr |= 0x10000;
334 } else {
335 new_msr &= ~((target_ulong)1 << MSR_ME);
336 }
337
338 if (0) {
339 /* XXX: find a suitable condition to enable the hypervisor mode */
340 new_msr |= (target_ulong)MSR_HVB;
341 }
342 goto store_next;
343 case POWERPC_EXCP_DSEG: /* Data segment exception */
344 if (lpes1 == 0) {
345 new_msr |= (target_ulong)MSR_HVB;
346 }
347 goto store_next;
348 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
349 if (lpes1 == 0) {
350 new_msr |= (target_ulong)MSR_HVB;
351 }
352 goto store_next;
353 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
354 srr0 = SPR_HSRR0;
355 srr1 = SPR_HSRR1;
356 new_msr |= (target_ulong)MSR_HVB;
357 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
358 goto store_next;
359 case POWERPC_EXCP_TRACE: /* Trace exception */
360 if (lpes1 == 0) {
361 new_msr |= (target_ulong)MSR_HVB;
362 }
363 goto store_next;
364 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
365 srr0 = SPR_HSRR0;
366 srr1 = SPR_HSRR1;
367 new_msr |= (target_ulong)MSR_HVB;
368 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
369 goto store_next;
370 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
371 srr0 = SPR_HSRR0;
372 srr1 = SPR_HSRR1;
373 new_msr |= (target_ulong)MSR_HVB;
374 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
375 goto store_next;
376 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
377 srr0 = SPR_HSRR0;
378 srr1 = SPR_HSRR1;
379 new_msr |= (target_ulong)MSR_HVB;
380 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
381 goto store_next;
382 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
383 srr0 = SPR_HSRR0;
384 srr1 = SPR_HSRR1;
385 new_msr |= (target_ulong)MSR_HVB;
386 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
387 goto store_next;
388 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
389 if (lpes1 == 0) {
390 new_msr |= (target_ulong)MSR_HVB;
391 }
392 goto store_current;
393 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
394 LOG_EXCP("PIT exception\n");
395 goto store_next;
396 case POWERPC_EXCP_IO: /* IO error exception */
397 /* XXX: TODO */
398 cpu_abort(env, "601 IO error exception is not implemented yet !\n");
399 goto store_next;
400 case POWERPC_EXCP_RUNM: /* Run mode exception */
401 /* XXX: TODO */
402 cpu_abort(env, "601 run mode exception is not implemented yet !\n");
403 goto store_next;
404 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
405 /* XXX: TODO */
406 cpu_abort(env, "602 emulation trap exception "
407 "is not implemented yet !\n");
408 goto store_next;
409 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
410 if (lpes1 == 0) { /* XXX: check this */
411 new_msr |= (target_ulong)MSR_HVB;
412 }
413 switch (excp_model) {
414 case POWERPC_EXCP_602:
415 case POWERPC_EXCP_603:
416 case POWERPC_EXCP_603E:
417 case POWERPC_EXCP_G2:
418 goto tlb_miss_tgpr;
419 case POWERPC_EXCP_7x5:
420 goto tlb_miss;
421 case POWERPC_EXCP_74xx:
422 goto tlb_miss_74xx;
423 default:
424 cpu_abort(env, "Invalid instruction TLB miss exception\n");
425 break;
426 }
427 break;
428 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
429 if (lpes1 == 0) { /* XXX: check this */
430 new_msr |= (target_ulong)MSR_HVB;
431 }
432 switch (excp_model) {
433 case POWERPC_EXCP_602:
434 case POWERPC_EXCP_603:
435 case POWERPC_EXCP_603E:
436 case POWERPC_EXCP_G2:
437 goto tlb_miss_tgpr;
438 case POWERPC_EXCP_7x5:
439 goto tlb_miss;
440 case POWERPC_EXCP_74xx:
441 goto tlb_miss_74xx;
442 default:
443 cpu_abort(env, "Invalid data load TLB miss exception\n");
444 break;
445 }
446 break;
447 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
448 if (lpes1 == 0) { /* XXX: check this */
449 new_msr |= (target_ulong)MSR_HVB;
450 }
451 switch (excp_model) {
452 case POWERPC_EXCP_602:
453 case POWERPC_EXCP_603:
454 case POWERPC_EXCP_603E:
455 case POWERPC_EXCP_G2:
456 tlb_miss_tgpr:
457 /* Swap temporary saved registers with GPRs */
458 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
459 new_msr |= (target_ulong)1 << MSR_TGPR;
460 hreg_swap_gpr_tgpr(env);
461 }
462 goto tlb_miss;
463 case POWERPC_EXCP_7x5:
464 tlb_miss:
465#if defined(DEBUG_SOFTWARE_TLB)
466 if (qemu_log_enabled()) {
467 const char *es;
468 target_ulong *miss, *cmp;
469 int en;
470
471 if (excp == POWERPC_EXCP_IFTLB) {
472 es = "I";
473 en = 'I';
474 miss = &env->spr[SPR_IMISS];
475 cmp = &env->spr[SPR_ICMP];
476 } else {
477 if (excp == POWERPC_EXCP_DLTLB) {
478 es = "DL";
479 } else {
480 es = "DS";
481 }
482 en = 'D';
483 miss = &env->spr[SPR_DMISS];
484 cmp = &env->spr[SPR_DCMP];
485 }
486 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
487 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
488 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
489 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
490 env->error_code);
491 }
492#endif
493 msr |= env->crf[0] << 28;
494 msr |= env->error_code; /* key, D/I, S/L bits */
495 /* Set way using a LRU mechanism */
496 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
497 break;
498 case POWERPC_EXCP_74xx:
499 tlb_miss_74xx:
500#if defined(DEBUG_SOFTWARE_TLB)
501 if (qemu_log_enabled()) {
502 const char *es;
503 target_ulong *miss, *cmp;
504 int en;
505
506 if (excp == POWERPC_EXCP_IFTLB) {
507 es = "I";
508 en = 'I';
509 miss = &env->spr[SPR_TLBMISS];
510 cmp = &env->spr[SPR_PTEHI];
511 } else {
512 if (excp == POWERPC_EXCP_DLTLB) {
513 es = "DL";
514 } else {
515 es = "DS";
516 }
517 en = 'D';
518 miss = &env->spr[SPR_TLBMISS];
519 cmp = &env->spr[SPR_PTEHI];
520 }
521 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
522 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
523 env->error_code);
524 }
525#endif
526 msr |= env->error_code; /* key bit */
527 break;
528 default:
529 cpu_abort(env, "Invalid data store TLB miss exception\n");
530 break;
531 }
532 goto store_next;
533 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
534 /* XXX: TODO */
535 cpu_abort(env, "Floating point assist exception "
536 "is not implemented yet !\n");
537 goto store_next;
538 case POWERPC_EXCP_DABR: /* Data address breakpoint */
539 /* XXX: TODO */
540 cpu_abort(env, "DABR exception is not implemented yet !\n");
541 goto store_next;
542 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
543 /* XXX: TODO */
544 cpu_abort(env, "IABR exception is not implemented yet !\n");
545 goto store_next;
546 case POWERPC_EXCP_SMI: /* System management interrupt */
547 /* XXX: TODO */
548 cpu_abort(env, "SMI exception is not implemented yet !\n");
549 goto store_next;
550 case POWERPC_EXCP_THERM: /* Thermal interrupt */
551 /* XXX: TODO */
552 cpu_abort(env, "Thermal management exception "
553 "is not implemented yet !\n");
554 goto store_next;
555 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
556 if (lpes1 == 0) {
557 new_msr |= (target_ulong)MSR_HVB;
558 }
559 /* XXX: TODO */
560 cpu_abort(env,
561 "Performance counter exception is not implemented yet !\n");
562 goto store_next;
563 case POWERPC_EXCP_VPUA: /* Vector assist exception */
564 /* XXX: TODO */
565 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
566 goto store_next;
567 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
568 /* XXX: TODO */
569 cpu_abort(env,
570 "970 soft-patch exception is not implemented yet !\n");
571 goto store_next;
572 case POWERPC_EXCP_MAINT: /* Maintenance exception */
573 /* XXX: TODO */
574 cpu_abort(env,
575 "970 maintenance exception is not implemented yet !\n");
576 goto store_next;
577 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
578 /* XXX: TODO */
579 cpu_abort(env, "Maskable external exception "
580 "is not implemented yet !\n");
581 goto store_next;
582 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
583 /* XXX: TODO */
584 cpu_abort(env, "Non maskable external exception "
585 "is not implemented yet !\n");
586 goto store_next;
587 default:
588 excp_invalid:
589 cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
590 break;
591 store_current:
592 /* save current instruction location */
593 env->spr[srr0] = env->nip - 4;
594 break;
595 store_next:
596 /* save next instruction location */
597 env->spr[srr0] = env->nip;
598 break;
599 }
600 /* Save MSR */
601 env->spr[srr1] = msr;
602 /* If any alternate SRR register are defined, duplicate saved values */
603 if (asrr0 != -1) {
604 env->spr[asrr0] = env->spr[srr0];
605 }
606 if (asrr1 != -1) {
607 env->spr[asrr1] = env->spr[srr1];
608 }
609 /* If we disactivated any translation, flush TLBs */
610 if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
611 tlb_flush(env, 1);
612 }
613
Anton Blanchard1e0c7e52013-08-07 10:47:01 +1000614#ifdef TARGET_PPC64
615 if (excp_model == POWERPC_EXCP_POWER7) {
616 if (env->spr[SPR_LPCR] & LPCR_ILE) {
617 new_msr |= (target_ulong)1 << MSR_LE;
618 }
619 } else if (msr_ile) {
620 new_msr |= (target_ulong)1 << MSR_LE;
621 }
622#else
Blue Swirlc79c73f2012-05-30 04:23:25 +0000623 if (msr_ile) {
624 new_msr |= (target_ulong)1 << MSR_LE;
625 }
Anton Blanchard1e0c7e52013-08-07 10:47:01 +1000626#endif
Blue Swirlc79c73f2012-05-30 04:23:25 +0000627
628 /* Jump to handler */
629 vector = env->excp_vectors[excp];
630 if (vector == (target_ulong)-1ULL) {
631 cpu_abort(env, "Raised an exception without defined vector %d\n",
632 excp);
633 }
634 vector |= env->excp_prefix;
635#if defined(TARGET_PPC64)
636 if (excp_model == POWERPC_EXCP_BOOKE) {
Alexander Grafe42a61f2012-06-20 21:20:29 +0200637 if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
638 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
Blue Swirlc79c73f2012-05-30 04:23:25 +0000639 new_msr |= (target_ulong)1 << MSR_CM;
Alexander Grafe42a61f2012-06-20 21:20:29 +0200640 } else {
641 vector = (uint32_t)vector;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000642 }
643 } else {
644 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
645 vector = (uint32_t)vector;
646 } else {
647 new_msr |= (target_ulong)1 << MSR_SF;
648 }
649 }
650#endif
651 /* XXX: we don't use hreg_store_msr here as already have treated
652 * any special case that could occur. Just store MSR and update hflags
653 */
654 env->msr = new_msr & env->msr_mask;
655 hreg_compute_hflags(env);
656 env->nip = vector;
657 /* Reset exception state */
658 env->exception_index = POWERPC_EXCP_NONE;
659 env->error_code = 0;
660
661 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
662 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
663 /* XXX: The BookE changes address space when switching modes,
664 we should probably implement that as different MMU indexes,
665 but for the moment we do it the slow way and flush all. */
666 tlb_flush(env, 1);
667 }
668}
669
Andreas Färber97a8ea52013-02-02 10:57:51 +0100670void ppc_cpu_do_interrupt(CPUState *cs)
Blue Swirlc79c73f2012-05-30 04:23:25 +0000671{
Andreas Färber97a8ea52013-02-02 10:57:51 +0100672 PowerPCCPU *cpu = POWERPC_CPU(cs);
673 CPUPPCState *env = &cpu->env;
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200674
675 powerpc_excp(cpu, env->excp_model, env->exception_index);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000676}
677
678void ppc_hw_interrupt(CPUPPCState *env)
679{
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200680 PowerPCCPU *cpu = ppc_env_get_cpu(env);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000681 int hdice;
Blue Swirlc79c73f2012-05-30 04:23:25 +0000682#if 0
Andreas Färber259186a2013-01-17 18:51:17 +0100683 CPUState *cs = CPU(cpu);
684
Blue Swirlc79c73f2012-05-30 04:23:25 +0000685 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 +0100686 __func__, env, env->pending_interrupts,
687 cs->interrupt_request, (int)msr_me, (int)msr_ee);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000688#endif
689 /* External reset */
690 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
691 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200692 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000693 return;
694 }
695 /* Machine check exception */
696 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
697 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200698 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000699 return;
700 }
701#if 0 /* TODO */
702 /* External debug exception */
703 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
704 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200705 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000706 return;
707 }
708#endif
709 if (0) {
710 /* XXX: find a suitable condition to enable the hypervisor mode */
711 hdice = env->spr[SPR_LPCR] & 1;
712 } else {
713 hdice = 0;
714 }
715 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
716 /* Hypervisor decrementer exception */
717 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
718 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200719 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000720 return;
721 }
722 }
723 if (msr_ce != 0) {
724 /* External critical interrupt */
725 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
726 /* Taking a critical external interrupt does not clear the external
727 * critical interrupt status
728 */
729#if 0
730 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
731#endif
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200732 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000733 return;
734 }
735 }
736 if (msr_ee != 0) {
737 /* Watchdog timer on embedded PowerPC */
738 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
739 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200740 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000741 return;
742 }
743 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
744 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200745 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000746 return;
747 }
748 /* Fixed interval timer on embedded PowerPC */
749 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
750 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200751 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000752 return;
753 }
754 /* Programmable interval timer on embedded PowerPC */
755 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
756 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200757 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000758 return;
759 }
760 /* Decrementer exception */
761 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
762 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200763 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000764 return;
765 }
766 /* External interrupt */
767 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
768 /* Taking an external interrupt does not clear the external
769 * interrupt status
770 */
771#if 0
772 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
773#endif
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200774 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000775 return;
776 }
777 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
778 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200779 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000780 return;
781 }
782 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
783 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200784 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000785 return;
786 }
787 /* Thermal interrupt */
788 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
789 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
Andreas Färber5c26a5b2012-05-03 05:55:58 +0200790 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
Blue Swirlc79c73f2012-05-30 04:23:25 +0000791 return;
792 }
793 }
794}
795#endif /* !CONFIG_USER_ONLY */
796
797#if defined(DEBUG_OP)
798static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
799{
800 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
801 TARGET_FMT_lx "\n", RA, msr);
802}
803#endif
804
Blue Swirlad71ed62012-05-30 04:23:22 +0000805/*****************************************************************************/
806/* Exceptions processing helpers */
807
Blue Swirle5f17ac2012-05-30 04:23:23 +0000808void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
809 uint32_t error_code)
Blue Swirlad71ed62012-05-30 04:23:22 +0000810{
811#if 0
812 printf("Raise exception %3x code : %d\n", exception, error_code);
813#endif
814 env->exception_index = exception;
815 env->error_code = error_code;
816 cpu_loop_exit(env);
817}
818
Blue Swirle5f17ac2012-05-30 04:23:23 +0000819void helper_raise_exception(CPUPPCState *env, uint32_t exception)
Blue Swirlad71ed62012-05-30 04:23:22 +0000820{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000821 helper_raise_exception_err(env, exception, 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000822}
823
824#if !defined(CONFIG_USER_ONLY)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000825void helper_store_msr(CPUPPCState *env, target_ulong val)
Blue Swirlad71ed62012-05-30 04:23:22 +0000826{
Andreas Färber259186a2013-01-17 18:51:17 +0100827 CPUState *cs;
828
Blue Swirlad71ed62012-05-30 04:23:22 +0000829 val = hreg_store_msr(env, val, 0);
830 if (val != 0) {
Andreas Färber259186a2013-01-17 18:51:17 +0100831 cs = CPU(ppc_env_get_cpu(env));
832 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirle5f17ac2012-05-30 04:23:23 +0000833 helper_raise_exception(env, val);
Blue Swirlad71ed62012-05-30 04:23:22 +0000834 }
835}
836
Blue Swirle5f17ac2012-05-30 04:23:23 +0000837static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
Blue Swirlad71ed62012-05-30 04:23:22 +0000838 target_ulong msrm, int keep_msrh)
839{
Andreas Färber259186a2013-01-17 18:51:17 +0100840 CPUState *cs = CPU(ppc_env_get_cpu(env));
841
Blue Swirlad71ed62012-05-30 04:23:22 +0000842#if defined(TARGET_PPC64)
Alexander Grafe42a61f2012-06-20 21:20:29 +0200843 if (msr_is_64bit(env, msr)) {
Blue Swirlad71ed62012-05-30 04:23:22 +0000844 nip = (uint64_t)nip;
845 msr &= (uint64_t)msrm;
846 } else {
847 nip = (uint32_t)nip;
848 msr = (uint32_t)(msr & msrm);
849 if (keep_msrh) {
850 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
851 }
852 }
853#else
854 nip = (uint32_t)nip;
855 msr &= (uint32_t)msrm;
856#endif
857 /* XXX: beware: this is false if VLE is supported */
858 env->nip = nip & ~((target_ulong)0x00000003);
859 hreg_store_msr(env, msr, 1);
860#if defined(DEBUG_OP)
861 cpu_dump_rfi(env->nip, env->msr);
862#endif
863 /* No need to raise an exception here,
864 * as rfi is always the last insn of a TB
865 */
Andreas Färber259186a2013-01-17 18:51:17 +0100866 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
Blue Swirlad71ed62012-05-30 04:23:22 +0000867}
868
Blue Swirle5f17ac2012-05-30 04:23:23 +0000869void helper_rfi(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000870{
Scott Wooda1bb7382012-12-21 16:15:41 +0000871 if (env->excp_model == POWERPC_EXCP_BOOKE) {
872 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
873 ~((target_ulong)0), 0);
874 } else {
875 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
876 ~((target_ulong)0x783F0000), 1);
877 }
Blue Swirlad71ed62012-05-30 04:23:22 +0000878}
879
880#if defined(TARGET_PPC64)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000881void helper_rfid(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000882{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000883 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
Blue Swirlad71ed62012-05-30 04:23:22 +0000884 ~((target_ulong)0x783F0000), 0);
885}
886
Blue Swirle5f17ac2012-05-30 04:23:23 +0000887void helper_hrfid(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000888{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000889 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
Blue Swirlad71ed62012-05-30 04:23:22 +0000890 ~((target_ulong)0x783F0000), 0);
891}
892#endif
893
894/*****************************************************************************/
895/* Embedded PowerPC specific helpers */
Blue Swirle5f17ac2012-05-30 04:23:23 +0000896void helper_40x_rfci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000897{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000898 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
Blue Swirlad71ed62012-05-30 04:23:22 +0000899 ~((target_ulong)0xFFFF0000), 0);
900}
901
Blue Swirle5f17ac2012-05-30 04:23:23 +0000902void helper_rfci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000903{
Scott Wooda1bb7382012-12-21 16:15:41 +0000904 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
905 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000906}
907
Blue Swirle5f17ac2012-05-30 04:23:23 +0000908void helper_rfdi(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000909{
Scott Wooda1bb7382012-12-21 16:15:41 +0000910 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
911 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
912 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000913}
914
Blue Swirle5f17ac2012-05-30 04:23:23 +0000915void helper_rfmci(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000916{
Scott Wooda1bb7382012-12-21 16:15:41 +0000917 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
918 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
919 ~((target_ulong)0), 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000920}
921#endif
922
Blue Swirle5f17ac2012-05-30 04:23:23 +0000923void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
924 uint32_t flags)
Blue Swirlad71ed62012-05-30 04:23:22 +0000925{
926 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
927 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
928 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
929 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
930 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
Blue Swirle5f17ac2012-05-30 04:23:23 +0000931 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
932 POWERPC_EXCP_TRAP);
Blue Swirlad71ed62012-05-30 04:23:22 +0000933 }
934}
935
936#if defined(TARGET_PPC64)
Blue Swirle5f17ac2012-05-30 04:23:23 +0000937void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
938 uint32_t flags)
Blue Swirlad71ed62012-05-30 04:23:22 +0000939{
940 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
941 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
942 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
943 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
944 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
Blue Swirle5f17ac2012-05-30 04:23:23 +0000945 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
946 POWERPC_EXCP_TRAP);
Blue Swirlad71ed62012-05-30 04:23:22 +0000947 }
948}
949#endif
950
951#if !defined(CONFIG_USER_ONLY)
952/*****************************************************************************/
953/* PowerPC 601 specific instructions (POWER bridge) */
954
Blue Swirle5f17ac2012-05-30 04:23:23 +0000955void helper_rfsvc(CPUPPCState *env)
Blue Swirlad71ed62012-05-30 04:23:22 +0000956{
Blue Swirle5f17ac2012-05-30 04:23:23 +0000957 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
Blue Swirlad71ed62012-05-30 04:23:22 +0000958}
959
960/* Embedded.Processor Control */
961static int dbell2irq(target_ulong rb)
962{
963 int msg = rb & DBELL_TYPE_MASK;
964 int irq = -1;
965
966 switch (msg) {
967 case DBELL_TYPE_DBELL:
968 irq = PPC_INTERRUPT_DOORBELL;
969 break;
970 case DBELL_TYPE_DBELL_CRIT:
971 irq = PPC_INTERRUPT_CDOORBELL;
972 break;
973 case DBELL_TYPE_G_DBELL:
974 case DBELL_TYPE_G_DBELL_CRIT:
975 case DBELL_TYPE_G_DBELL_MC:
976 /* XXX implement */
977 default:
978 break;
979 }
980
981 return irq;
982}
983
Blue Swirle5f17ac2012-05-30 04:23:23 +0000984void helper_msgclr(CPUPPCState *env, target_ulong rb)
Blue Swirlad71ed62012-05-30 04:23:22 +0000985{
986 int irq = dbell2irq(rb);
987
988 if (irq < 0) {
989 return;
990 }
991
992 env->pending_interrupts &= ~(1 << irq);
993}
994
995void helper_msgsnd(target_ulong rb)
996{
997 int irq = dbell2irq(rb);
998 int pir = rb & DBELL_PIRTAG_MASK;
Andreas Färber182735e2013-05-29 22:29:20 +0200999 CPUState *cs;
Blue Swirlad71ed62012-05-30 04:23:22 +00001000
1001 if (irq < 0) {
1002 return;
1003 }
1004
Andreas Färberbdc44642013-06-24 23:50:24 +02001005 CPU_FOREACH(cs) {
Andreas Färber182735e2013-05-29 22:29:20 +02001006 PowerPCCPU *cpu = POWERPC_CPU(cs);
1007 CPUPPCState *cenv = &cpu->env;
1008
Blue Swirlad71ed62012-05-30 04:23:22 +00001009 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1010 cenv->pending_interrupts |= 1 << irq;
Andreas Färber182735e2013-05-29 22:29:20 +02001011 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
Blue Swirlad71ed62012-05-30 04:23:22 +00001012 }
1013 }
1014}
1015#endif