]> git.proxmox.com Git - mirror_qemu.git/blame - target-ppc/excp_helper.c
cpu: move exec-all.h inclusion out of cpu.h
[mirror_qemu.git] / target-ppc / excp_helper.c
CommitLineData
ad71ed68
BS
1/*
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 */
0d75590d 19#include "qemu/osdep.h"
ad71ed68 20#include "cpu.h"
2ef6175a 21#include "exec/helper-proto.h"
63c91552 22#include "exec/exec-all.h"
f08b6170 23#include "exec/cpu_ldst.h"
ad71ed68
BS
24
25#include "helper_regs.h"
26
27//#define DEBUG_OP
48880da6 28//#define DEBUG_SOFTWARE_TLB
ad71ed68
BS
29//#define DEBUG_EXCEPTIONS
30
c79c73f6
BS
31#ifdef DEBUG_EXCEPTIONS
32# define LOG_EXCP(...) qemu_log(__VA_ARGS__)
33#else
34# define LOG_EXCP(...) do { } while (0)
35#endif
36
37/*****************************************************************************/
38/* PowerPC Hypercall emulation */
39
1b14670a 40void (*cpu_ppc_hypercall)(PowerPCCPU *);
c79c73f6
BS
41
42/*****************************************************************************/
43/* Exception processing */
44#if defined(CONFIG_USER_ONLY)
97a8ea5a 45void ppc_cpu_do_interrupt(CPUState *cs)
c79c73f6 46{
97a8ea5a
AF
47 PowerPCCPU *cpu = POWERPC_CPU(cs);
48 CPUPPCState *env = &cpu->env;
49
27103424 50 cs->exception_index = POWERPC_EXCP_NONE;
c79c73f6
BS
51 env->error_code = 0;
52}
53
458dd766 54static void ppc_hw_interrupt(CPUPPCState *env)
c79c73f6 55{
27103424
AF
56 CPUState *cs = CPU(ppc_env_get_cpu(env));
57
58 cs->exception_index = POWERPC_EXCP_NONE;
c79c73f6
BS
59 env->error_code = 0;
60}
61#else /* defined(CONFIG_USER_ONLY) */
62static inline void dump_syscall(CPUPPCState *env)
63{
64 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
65 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
66 " nip=" TARGET_FMT_lx "\n",
67 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
68 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
69 ppc_dump_gpr(env, 6), env->nip);
70}
71
72/* Note that this function should be greatly optimized
73 * when called with a constant excp, from ppc_hw_interrupt
74 */
5c26a5b3 75static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
c79c73f6 76{
27103424 77 CPUState *cs = CPU(cpu);
5c26a5b3 78 CPUPPCState *env = &cpu->env;
c79c73f6
BS
79 target_ulong msr, new_msr, vector;
80 int srr0, srr1, asrr0, asrr1;
5c94b2a5 81 int lpes0, lpes1, lev, ail;
c79c73f6
BS
82
83 if (0) {
84 /* XXX: find a suitable condition to enable the hypervisor mode */
85 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
86 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
87 } else {
88 /* Those values ensure we won't enter the hypervisor mode */
89 lpes0 = 0;
90 lpes1 = 1;
91 }
92
93 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
94 " => %08x (%02x)\n", env->nip, excp, env->error_code);
95
96 /* new srr1 value excluding must-be-zero bits */
a1bb7384
SW
97 if (excp_model == POWERPC_EXCP_BOOKE) {
98 msr = env->msr;
99 } else {
100 msr = env->msr & ~0x783f0000ULL;
101 }
c79c73f6
BS
102
103 /* new interrupt handler msr */
104 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
105
106 /* target registers */
107 srr0 = SPR_SRR0;
108 srr1 = SPR_SRR1;
109 asrr0 = -1;
110 asrr1 = -1;
111
5c94b2a5
CLG
112 /* Exception targetting modifiers
113 *
114 * AIL is initialized here but can be cleared by
115 * selected exceptions
116 */
117#if defined(TARGET_PPC64)
118 if (excp_model == POWERPC_EXCP_POWER7 ||
119 excp_model == POWERPC_EXCP_POWER8) {
120 if (excp_model == POWERPC_EXCP_POWER8) {
121 ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
122 } else {
123 ail = 0;
124 }
125 } else
126#endif /* defined(TARGET_PPC64) */
127 {
128 ail = 0;
129 }
130
c79c73f6
BS
131 switch (excp) {
132 case POWERPC_EXCP_NONE:
133 /* Should never happen */
134 return;
135 case POWERPC_EXCP_CRITICAL: /* Critical input */
136 switch (excp_model) {
137 case POWERPC_EXCP_40x:
138 srr0 = SPR_40x_SRR2;
139 srr1 = SPR_40x_SRR3;
140 break;
141 case POWERPC_EXCP_BOOKE:
142 srr0 = SPR_BOOKE_CSRR0;
143 srr1 = SPR_BOOKE_CSRR1;
144 break;
145 case POWERPC_EXCP_G2:
146 break;
147 default:
148 goto excp_invalid;
149 }
150 goto store_next;
151 case POWERPC_EXCP_MCHECK: /* Machine check exception */
152 if (msr_me == 0) {
153 /* Machine check exception is not enabled.
154 * Enter checkstop state.
155 */
013a2942
PB
156 fprintf(stderr, "Machine check while not allowed. "
157 "Entering checkstop state\n");
158 if (qemu_log_separate()) {
c79c73f6
BS
159 qemu_log("Machine check while not allowed. "
160 "Entering checkstop state\n");
c79c73f6 161 }
259186a7
AF
162 cs->halted = 1;
163 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
c79c73f6
BS
164 }
165 if (0) {
166 /* XXX: find a suitable condition to enable the hypervisor mode */
167 new_msr |= (target_ulong)MSR_HVB;
168 }
5c94b2a5 169 ail = 0;
c79c73f6
BS
170
171 /* machine check exceptions don't have ME set */
172 new_msr &= ~((target_ulong)1 << MSR_ME);
173
174 /* XXX: should also have something loaded in DAR / DSISR */
175 switch (excp_model) {
176 case POWERPC_EXCP_40x:
177 srr0 = SPR_40x_SRR2;
178 srr1 = SPR_40x_SRR3;
179 break;
180 case POWERPC_EXCP_BOOKE:
a1bb7384 181 /* FIXME: choose one or the other based on CPU type */
c79c73f6
BS
182 srr0 = SPR_BOOKE_MCSRR0;
183 srr1 = SPR_BOOKE_MCSRR1;
184 asrr0 = SPR_BOOKE_CSRR0;
185 asrr1 = SPR_BOOKE_CSRR1;
186 break;
187 default:
188 break;
189 }
190 goto store_next;
191 case POWERPC_EXCP_DSI: /* Data storage exception */
192 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
193 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
194 if (lpes1 == 0) {
195 new_msr |= (target_ulong)MSR_HVB;
196 }
197 goto store_next;
198 case POWERPC_EXCP_ISI: /* Instruction storage exception */
199 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
200 "\n", msr, env->nip);
201 if (lpes1 == 0) {
202 new_msr |= (target_ulong)MSR_HVB;
203 }
204 msr |= env->error_code;
205 goto store_next;
206 case POWERPC_EXCP_EXTERNAL: /* External input */
fdfba1a2
EI
207 cs = CPU(cpu);
208
c79c73f6
BS
209 if (lpes0 == 1) {
210 new_msr |= (target_ulong)MSR_HVB;
211 }
68c2dd70
AG
212 if (env->mpic_proxy) {
213 /* IACK the IRQ on delivery */
fdfba1a2 214 env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
68c2dd70 215 }
c79c73f6
BS
216 goto store_next;
217 case POWERPC_EXCP_ALIGN: /* Alignment exception */
218 if (lpes1 == 0) {
219 new_msr |= (target_ulong)MSR_HVB;
220 }
221 /* XXX: this is false */
222 /* Get rS/rD and rA from faulting opcode */
2f5a189c
BS
223 env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
224 & 0x03FF0000) >> 16;
6bb9a0a9 225 goto store_next;
c79c73f6
BS
226 case POWERPC_EXCP_PROGRAM: /* Program exception */
227 switch (env->error_code & ~0xF) {
228 case POWERPC_EXCP_FP:
229 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
230 LOG_EXCP("Ignore floating point exception\n");
27103424 231 cs->exception_index = POWERPC_EXCP_NONE;
c79c73f6
BS
232 env->error_code = 0;
233 return;
234 }
235 if (lpes1 == 0) {
236 new_msr |= (target_ulong)MSR_HVB;
237 }
238 msr |= 0x00100000;
239 if (msr_fe0 == msr_fe1) {
240 goto store_next;
241 }
242 msr |= 0x00010000;
243 break;
244 case POWERPC_EXCP_INVAL:
245 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
246 if (lpes1 == 0) {
247 new_msr |= (target_ulong)MSR_HVB;
248 }
249 msr |= 0x00080000;
250 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
251 break;
252 case POWERPC_EXCP_PRIV:
253 if (lpes1 == 0) {
254 new_msr |= (target_ulong)MSR_HVB;
255 }
256 msr |= 0x00040000;
257 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
258 break;
259 case POWERPC_EXCP_TRAP:
260 if (lpes1 == 0) {
261 new_msr |= (target_ulong)MSR_HVB;
262 }
263 msr |= 0x00020000;
264 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
265 break;
266 default:
267 /* Should never occur */
a47dddd7 268 cpu_abort(cs, "Invalid program exception %d. Aborting\n",
c79c73f6
BS
269 env->error_code);
270 break;
271 }
272 goto store_current;
273 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
274 if (lpes1 == 0) {
275 new_msr |= (target_ulong)MSR_HVB;
276 }
277 goto store_current;
278 case POWERPC_EXCP_SYSCALL: /* System call exception */
279 dump_syscall(env);
280 lev = env->error_code;
281 if ((lev == 1) && cpu_ppc_hypercall) {
1b14670a 282 cpu_ppc_hypercall(cpu);
c79c73f6
BS
283 return;
284 }
285 if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
286 new_msr |= (target_ulong)MSR_HVB;
287 }
288 goto store_next;
289 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
290 goto store_current;
291 case POWERPC_EXCP_DECR: /* Decrementer exception */
292 if (lpes1 == 0) {
293 new_msr |= (target_ulong)MSR_HVB;
294 }
295 goto store_next;
296 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
297 /* FIT on 4xx */
298 LOG_EXCP("FIT exception\n");
299 goto store_next;
300 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
301 LOG_EXCP("WDT exception\n");
302 switch (excp_model) {
303 case POWERPC_EXCP_BOOKE:
304 srr0 = SPR_BOOKE_CSRR0;
305 srr1 = SPR_BOOKE_CSRR1;
306 break;
307 default:
308 break;
309 }
310 goto store_next;
311 case POWERPC_EXCP_DTLB: /* Data TLB error */
312 goto store_next;
313 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
314 goto store_next;
315 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
316 switch (excp_model) {
317 case POWERPC_EXCP_BOOKE:
a1bb7384 318 /* FIXME: choose one or the other based on CPU type */
c79c73f6
BS
319 srr0 = SPR_BOOKE_DSRR0;
320 srr1 = SPR_BOOKE_DSRR1;
321 asrr0 = SPR_BOOKE_CSRR0;
322 asrr1 = SPR_BOOKE_CSRR1;
323 break;
324 default:
325 break;
326 }
327 /* XXX: TODO */
a47dddd7 328 cpu_abort(cs, "Debug exception is not implemented yet !\n");
c79c73f6
BS
329 goto store_next;
330 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
331 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
332 goto store_current;
333 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
334 /* XXX: TODO */
a47dddd7 335 cpu_abort(cs, "Embedded floating point data exception "
c79c73f6
BS
336 "is not implemented yet !\n");
337 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
338 goto store_next;
339 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
340 /* XXX: TODO */
a47dddd7 341 cpu_abort(cs, "Embedded floating point round exception "
c79c73f6
BS
342 "is not implemented yet !\n");
343 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
344 goto store_next;
345 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
346 /* XXX: TODO */
a47dddd7 347 cpu_abort(cs,
c79c73f6
BS
348 "Performance counter exception is not implemented yet !\n");
349 goto store_next;
350 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
351 goto store_next;
352 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
353 srr0 = SPR_BOOKE_CSRR0;
354 srr1 = SPR_BOOKE_CSRR1;
355 goto store_next;
356 case POWERPC_EXCP_RESET: /* System reset exception */
357 if (msr_pow) {
358 /* indicate that we resumed from power save mode */
359 msr |= 0x10000;
360 } else {
361 new_msr &= ~((target_ulong)1 << MSR_ME);
362 }
363
364 if (0) {
365 /* XXX: find a suitable condition to enable the hypervisor mode */
366 new_msr |= (target_ulong)MSR_HVB;
367 }
5c94b2a5 368 ail = 0;
c79c73f6
BS
369 goto store_next;
370 case POWERPC_EXCP_DSEG: /* Data segment exception */
371 if (lpes1 == 0) {
372 new_msr |= (target_ulong)MSR_HVB;
373 }
374 goto store_next;
375 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
376 if (lpes1 == 0) {
377 new_msr |= (target_ulong)MSR_HVB;
378 }
379 goto store_next;
380 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
381 srr0 = SPR_HSRR0;
382 srr1 = SPR_HSRR1;
383 new_msr |= (target_ulong)MSR_HVB;
384 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
385 goto store_next;
386 case POWERPC_EXCP_TRACE: /* Trace exception */
387 if (lpes1 == 0) {
388 new_msr |= (target_ulong)MSR_HVB;
389 }
390 goto store_next;
391 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
392 srr0 = SPR_HSRR0;
393 srr1 = SPR_HSRR1;
394 new_msr |= (target_ulong)MSR_HVB;
395 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
396 goto store_next;
397 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
398 srr0 = SPR_HSRR0;
399 srr1 = SPR_HSRR1;
400 new_msr |= (target_ulong)MSR_HVB;
401 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
402 goto store_next;
403 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
404 srr0 = SPR_HSRR0;
405 srr1 = SPR_HSRR1;
406 new_msr |= (target_ulong)MSR_HVB;
407 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
408 goto store_next;
409 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
410 srr0 = SPR_HSRR0;
411 srr1 = SPR_HSRR1;
412 new_msr |= (target_ulong)MSR_HVB;
413 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
414 goto store_next;
415 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
416 if (lpes1 == 0) {
417 new_msr |= (target_ulong)MSR_HVB;
418 }
419 goto store_current;
1f29871c
TM
420 case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
421 if (lpes1 == 0) {
422 new_msr |= (target_ulong)MSR_HVB;
423 }
424 goto store_current;
7019cb3d
AK
425 case POWERPC_EXCP_FU: /* Facility unavailable exception */
426 if (lpes1 == 0) {
427 new_msr |= (target_ulong)MSR_HVB;
428 }
429 goto store_current;
c79c73f6
BS
430 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
431 LOG_EXCP("PIT exception\n");
432 goto store_next;
433 case POWERPC_EXCP_IO: /* IO error exception */
434 /* XXX: TODO */
a47dddd7 435 cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
c79c73f6
BS
436 goto store_next;
437 case POWERPC_EXCP_RUNM: /* Run mode exception */
438 /* XXX: TODO */
a47dddd7 439 cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
c79c73f6
BS
440 goto store_next;
441 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
442 /* XXX: TODO */
a47dddd7 443 cpu_abort(cs, "602 emulation trap exception "
c79c73f6
BS
444 "is not implemented yet !\n");
445 goto store_next;
446 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
447 if (lpes1 == 0) { /* XXX: check this */
448 new_msr |= (target_ulong)MSR_HVB;
449 }
450 switch (excp_model) {
451 case POWERPC_EXCP_602:
452 case POWERPC_EXCP_603:
453 case POWERPC_EXCP_603E:
454 case POWERPC_EXCP_G2:
455 goto tlb_miss_tgpr;
456 case POWERPC_EXCP_7x5:
457 goto tlb_miss;
458 case POWERPC_EXCP_74xx:
459 goto tlb_miss_74xx;
460 default:
a47dddd7 461 cpu_abort(cs, "Invalid instruction TLB miss exception\n");
c79c73f6
BS
462 break;
463 }
464 break;
465 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
466 if (lpes1 == 0) { /* XXX: check this */
467 new_msr |= (target_ulong)MSR_HVB;
468 }
469 switch (excp_model) {
470 case POWERPC_EXCP_602:
471 case POWERPC_EXCP_603:
472 case POWERPC_EXCP_603E:
473 case POWERPC_EXCP_G2:
474 goto tlb_miss_tgpr;
475 case POWERPC_EXCP_7x5:
476 goto tlb_miss;
477 case POWERPC_EXCP_74xx:
478 goto tlb_miss_74xx;
479 default:
a47dddd7 480 cpu_abort(cs, "Invalid data load TLB miss exception\n");
c79c73f6
BS
481 break;
482 }
483 break;
484 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
485 if (lpes1 == 0) { /* XXX: check this */
486 new_msr |= (target_ulong)MSR_HVB;
487 }
488 switch (excp_model) {
489 case POWERPC_EXCP_602:
490 case POWERPC_EXCP_603:
491 case POWERPC_EXCP_603E:
492 case POWERPC_EXCP_G2:
493 tlb_miss_tgpr:
494 /* Swap temporary saved registers with GPRs */
495 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
496 new_msr |= (target_ulong)1 << MSR_TGPR;
497 hreg_swap_gpr_tgpr(env);
498 }
499 goto tlb_miss;
500 case POWERPC_EXCP_7x5:
501 tlb_miss:
502#if defined(DEBUG_SOFTWARE_TLB)
503 if (qemu_log_enabled()) {
504 const char *es;
505 target_ulong *miss, *cmp;
506 int en;
507
508 if (excp == POWERPC_EXCP_IFTLB) {
509 es = "I";
510 en = 'I';
511 miss = &env->spr[SPR_IMISS];
512 cmp = &env->spr[SPR_ICMP];
513 } else {
514 if (excp == POWERPC_EXCP_DLTLB) {
515 es = "DL";
516 } else {
517 es = "DS";
518 }
519 en = 'D';
520 miss = &env->spr[SPR_DMISS];
521 cmp = &env->spr[SPR_DCMP];
522 }
523 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
524 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
525 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
526 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
527 env->error_code);
528 }
529#endif
530 msr |= env->crf[0] << 28;
531 msr |= env->error_code; /* key, D/I, S/L bits */
532 /* Set way using a LRU mechanism */
533 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
534 break;
535 case POWERPC_EXCP_74xx:
536 tlb_miss_74xx:
537#if defined(DEBUG_SOFTWARE_TLB)
538 if (qemu_log_enabled()) {
539 const char *es;
540 target_ulong *miss, *cmp;
541 int en;
542
543 if (excp == POWERPC_EXCP_IFTLB) {
544 es = "I";
545 en = 'I';
546 miss = &env->spr[SPR_TLBMISS];
547 cmp = &env->spr[SPR_PTEHI];
548 } else {
549 if (excp == POWERPC_EXCP_DLTLB) {
550 es = "DL";
551 } else {
552 es = "DS";
553 }
554 en = 'D';
555 miss = &env->spr[SPR_TLBMISS];
556 cmp = &env->spr[SPR_PTEHI];
557 }
558 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
559 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
560 env->error_code);
561 }
562#endif
563 msr |= env->error_code; /* key bit */
564 break;
565 default:
a47dddd7 566 cpu_abort(cs, "Invalid data store TLB miss exception\n");
c79c73f6
BS
567 break;
568 }
569 goto store_next;
570 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
571 /* XXX: TODO */
a47dddd7 572 cpu_abort(cs, "Floating point assist exception "
c79c73f6
BS
573 "is not implemented yet !\n");
574 goto store_next;
575 case POWERPC_EXCP_DABR: /* Data address breakpoint */
576 /* XXX: TODO */
a47dddd7 577 cpu_abort(cs, "DABR exception is not implemented yet !\n");
c79c73f6
BS
578 goto store_next;
579 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
580 /* XXX: TODO */
a47dddd7 581 cpu_abort(cs, "IABR exception is not implemented yet !\n");
c79c73f6
BS
582 goto store_next;
583 case POWERPC_EXCP_SMI: /* System management interrupt */
584 /* XXX: TODO */
a47dddd7 585 cpu_abort(cs, "SMI exception is not implemented yet !\n");
c79c73f6
BS
586 goto store_next;
587 case POWERPC_EXCP_THERM: /* Thermal interrupt */
588 /* XXX: TODO */
a47dddd7 589 cpu_abort(cs, "Thermal management exception "
c79c73f6
BS
590 "is not implemented yet !\n");
591 goto store_next;
592 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
593 if (lpes1 == 0) {
594 new_msr |= (target_ulong)MSR_HVB;
595 }
596 /* XXX: TODO */
a47dddd7 597 cpu_abort(cs,
c79c73f6
BS
598 "Performance counter exception is not implemented yet !\n");
599 goto store_next;
600 case POWERPC_EXCP_VPUA: /* Vector assist exception */
601 /* XXX: TODO */
a47dddd7 602 cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
c79c73f6
BS
603 goto store_next;
604 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
605 /* XXX: TODO */
a47dddd7 606 cpu_abort(cs,
c79c73f6
BS
607 "970 soft-patch exception is not implemented yet !\n");
608 goto store_next;
609 case POWERPC_EXCP_MAINT: /* Maintenance exception */
610 /* XXX: TODO */
a47dddd7 611 cpu_abort(cs,
c79c73f6
BS
612 "970 maintenance exception is not implemented yet !\n");
613 goto store_next;
614 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
615 /* XXX: TODO */
a47dddd7 616 cpu_abort(cs, "Maskable external exception "
c79c73f6
BS
617 "is not implemented yet !\n");
618 goto store_next;
619 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
620 /* XXX: TODO */
a47dddd7 621 cpu_abort(cs, "Non maskable external exception "
c79c73f6
BS
622 "is not implemented yet !\n");
623 goto store_next;
624 default:
625 excp_invalid:
a47dddd7 626 cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
c79c73f6
BS
627 break;
628 store_current:
629 /* save current instruction location */
630 env->spr[srr0] = env->nip - 4;
631 break;
632 store_next:
633 /* save next instruction location */
634 env->spr[srr0] = env->nip;
635 break;
636 }
637 /* Save MSR */
638 env->spr[srr1] = msr;
639 /* If any alternate SRR register are defined, duplicate saved values */
640 if (asrr0 != -1) {
641 env->spr[asrr0] = env->spr[srr0];
642 }
643 if (asrr1 != -1) {
644 env->spr[asrr1] = env->spr[srr1];
645 }
d5ac4f54
AK
646
647 if (env->spr[SPR_LPCR] & LPCR_AIL) {
648 new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
649 } else if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
650 /* If we disactivated any translation, flush TLBs */
00c8cb0a 651 tlb_flush(cs, 1);
c79c73f6
BS
652 }
653
1e0c7e55 654#ifdef TARGET_PPC64
5c94b2a5
CLG
655 if (excp_model == POWERPC_EXCP_POWER7 ||
656 excp_model == POWERPC_EXCP_POWER8) {
1e0c7e55
AB
657 if (env->spr[SPR_LPCR] & LPCR_ILE) {
658 new_msr |= (target_ulong)1 << MSR_LE;
659 }
660 } else if (msr_ile) {
661 new_msr |= (target_ulong)1 << MSR_LE;
662 }
663#else
c79c73f6
BS
664 if (msr_ile) {
665 new_msr |= (target_ulong)1 << MSR_LE;
666 }
1e0c7e55 667#endif
c79c73f6
BS
668
669 /* Jump to handler */
670 vector = env->excp_vectors[excp];
671 if (vector == (target_ulong)-1ULL) {
a47dddd7 672 cpu_abort(cs, "Raised an exception without defined vector %d\n",
c79c73f6
BS
673 excp);
674 }
675 vector |= env->excp_prefix;
5c94b2a5
CLG
676
677 /* AIL only works if there is no HV transition and we are running with
678 * translations enabled
679 */
680 if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1)) {
681 ail = 0;
682 }
683 /* Handle AIL */
684 if (ail) {
685 new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
686 switch(ail) {
687 case AIL_0001_8000:
688 vector |= 0x18000;
689 break;
690 case AIL_C000_0000_0000_4000:
691 vector |= 0xc000000000004000ull;
692 break;
693 default:
694 cpu_abort(cs, "Invalid AIL combination %d\n", ail);
695 break;
696 }
697 }
698
c79c73f6
BS
699#if defined(TARGET_PPC64)
700 if (excp_model == POWERPC_EXCP_BOOKE) {
e42a61f1
AG
701 if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
702 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
c79c73f6 703 new_msr |= (target_ulong)1 << MSR_CM;
e42a61f1
AG
704 } else {
705 vector = (uint32_t)vector;
c79c73f6
BS
706 }
707 } else {
708 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
709 vector = (uint32_t)vector;
710 } else {
711 new_msr |= (target_ulong)1 << MSR_SF;
712 }
713 }
714#endif
715 /* XXX: we don't use hreg_store_msr here as already have treated
716 * any special case that could occur. Just store MSR and update hflags
717 */
718 env->msr = new_msr & env->msr_mask;
719 hreg_compute_hflags(env);
720 env->nip = vector;
721 /* Reset exception state */
27103424 722 cs->exception_index = POWERPC_EXCP_NONE;
c79c73f6
BS
723 env->error_code = 0;
724
725 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
726 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
727 /* XXX: The BookE changes address space when switching modes,
728 we should probably implement that as different MMU indexes,
729 but for the moment we do it the slow way and flush all. */
00c8cb0a 730 tlb_flush(cs, 1);
c79c73f6
BS
731 }
732}
733
97a8ea5a 734void ppc_cpu_do_interrupt(CPUState *cs)
c79c73f6 735{
97a8ea5a
AF
736 PowerPCCPU *cpu = POWERPC_CPU(cs);
737 CPUPPCState *env = &cpu->env;
5c26a5b3 738
27103424 739 powerpc_excp(cpu, env->excp_model, cs->exception_index);
c79c73f6
BS
740}
741
458dd766 742static void ppc_hw_interrupt(CPUPPCState *env)
c79c73f6 743{
5c26a5b3 744 PowerPCCPU *cpu = ppc_env_get_cpu(env);
c79c73f6 745 int hdice;
c79c73f6 746#if 0
259186a7
AF
747 CPUState *cs = CPU(cpu);
748
c79c73f6 749 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
259186a7
AF
750 __func__, env, env->pending_interrupts,
751 cs->interrupt_request, (int)msr_me, (int)msr_ee);
c79c73f6
BS
752#endif
753 /* External reset */
754 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
755 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
5c26a5b3 756 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
c79c73f6
BS
757 return;
758 }
759 /* Machine check exception */
760 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
761 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
5c26a5b3 762 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
c79c73f6
BS
763 return;
764 }
765#if 0 /* TODO */
766 /* External debug exception */
767 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
768 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
5c26a5b3 769 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
c79c73f6
BS
770 return;
771 }
772#endif
773 if (0) {
774 /* XXX: find a suitable condition to enable the hypervisor mode */
775 hdice = env->spr[SPR_LPCR] & 1;
776 } else {
777 hdice = 0;
778 }
779 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
780 /* Hypervisor decrementer exception */
781 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
5c26a5b3 782 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
c79c73f6
BS
783 return;
784 }
785 }
786 if (msr_ce != 0) {
787 /* External critical interrupt */
788 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
789 /* Taking a critical external interrupt does not clear the external
790 * critical interrupt status
791 */
792#if 0
793 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
794#endif
5c26a5b3 795 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
c79c73f6
BS
796 return;
797 }
798 }
799 if (msr_ee != 0) {
800 /* Watchdog timer on embedded PowerPC */
801 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
802 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
5c26a5b3 803 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
c79c73f6
BS
804 return;
805 }
806 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
807 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
5c26a5b3 808 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
c79c73f6
BS
809 return;
810 }
811 /* Fixed interval timer on embedded PowerPC */
812 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
813 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
5c26a5b3 814 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
c79c73f6
BS
815 return;
816 }
817 /* Programmable interval timer on embedded PowerPC */
818 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
819 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
5c26a5b3 820 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
c79c73f6
BS
821 return;
822 }
823 /* Decrementer exception */
824 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
e81a982a
AG
825 if (ppc_decr_clear_on_delivery(env)) {
826 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
827 }
5c26a5b3 828 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
c79c73f6
BS
829 return;
830 }
831 /* External interrupt */
832 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
833 /* Taking an external interrupt does not clear the external
834 * interrupt status
835 */
836#if 0
837 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
838#endif
5c26a5b3 839 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
c79c73f6
BS
840 return;
841 }
842 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
843 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
5c26a5b3 844 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
c79c73f6
BS
845 return;
846 }
847 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
848 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
5c26a5b3 849 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
c79c73f6
BS
850 return;
851 }
852 /* Thermal interrupt */
853 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
854 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
5c26a5b3 855 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
c79c73f6
BS
856 return;
857 }
858 }
859}
34316482
AK
860
861void ppc_cpu_do_system_reset(CPUState *cs)
862{
863 PowerPCCPU *cpu = POWERPC_CPU(cs);
864 CPUPPCState *env = &cpu->env;
865
866 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
867}
c79c73f6
BS
868#endif /* !CONFIG_USER_ONLY */
869
458dd766
RH
870bool ppc_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
871{
872 PowerPCCPU *cpu = POWERPC_CPU(cs);
873 CPUPPCState *env = &cpu->env;
874
875 if (interrupt_request & CPU_INTERRUPT_HARD) {
876 ppc_hw_interrupt(env);
877 if (env->pending_interrupts == 0) {
878 cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
879 }
880 return true;
881 }
882 return false;
883}
884
c79c73f6
BS
885#if defined(DEBUG_OP)
886static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
887{
888 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
889 TARGET_FMT_lx "\n", RA, msr);
890}
891#endif
892
ad71ed68
BS
893/*****************************************************************************/
894/* Exceptions processing helpers */
895
e5f17ac6
BS
896void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
897 uint32_t error_code)
ad71ed68 898{
27103424
AF
899 CPUState *cs = CPU(ppc_env_get_cpu(env));
900
ad71ed68
BS
901#if 0
902 printf("Raise exception %3x code : %d\n", exception, error_code);
903#endif
27103424 904 cs->exception_index = exception;
ad71ed68 905 env->error_code = error_code;
5638d180 906 cpu_loop_exit(cs);
ad71ed68
BS
907}
908
e5f17ac6 909void helper_raise_exception(CPUPPCState *env, uint32_t exception)
ad71ed68 910{
e5f17ac6 911 helper_raise_exception_err(env, exception, 0);
ad71ed68
BS
912}
913
914#if !defined(CONFIG_USER_ONLY)
e5f17ac6 915void helper_store_msr(CPUPPCState *env, target_ulong val)
ad71ed68 916{
259186a7
AF
917 CPUState *cs;
918
ad71ed68
BS
919 val = hreg_store_msr(env, val, 0);
920 if (val != 0) {
259186a7
AF
921 cs = CPU(ppc_env_get_cpu(env));
922 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
e5f17ac6 923 helper_raise_exception(env, val);
ad71ed68
BS
924 }
925}
926
e5f17ac6 927static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
ad71ed68
BS
928 target_ulong msrm, int keep_msrh)
929{
259186a7
AF
930 CPUState *cs = CPU(ppc_env_get_cpu(env));
931
ad71ed68 932#if defined(TARGET_PPC64)
e42a61f1 933 if (msr_is_64bit(env, msr)) {
ad71ed68
BS
934 nip = (uint64_t)nip;
935 msr &= (uint64_t)msrm;
936 } else {
937 nip = (uint32_t)nip;
938 msr = (uint32_t)(msr & msrm);
939 if (keep_msrh) {
940 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
941 }
942 }
943#else
944 nip = (uint32_t)nip;
945 msr &= (uint32_t)msrm;
946#endif
947 /* XXX: beware: this is false if VLE is supported */
948 env->nip = nip & ~((target_ulong)0x00000003);
949 hreg_store_msr(env, msr, 1);
950#if defined(DEBUG_OP)
951 cpu_dump_rfi(env->nip, env->msr);
952#endif
953 /* No need to raise an exception here,
954 * as rfi is always the last insn of a TB
955 */
259186a7 956 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
ad71ed68
BS
957}
958
e5f17ac6 959void helper_rfi(CPUPPCState *env)
ad71ed68 960{
a1bb7384
SW
961 if (env->excp_model == POWERPC_EXCP_BOOKE) {
962 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
963 ~((target_ulong)0), 0);
964 } else {
965 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
966 ~((target_ulong)0x783F0000), 1);
967 }
ad71ed68
BS
968}
969
970#if defined(TARGET_PPC64)
e5f17ac6 971void helper_rfid(CPUPPCState *env)
ad71ed68 972{
e5f17ac6 973 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
ad71ed68
BS
974 ~((target_ulong)0x783F0000), 0);
975}
976
e5f17ac6 977void helper_hrfid(CPUPPCState *env)
ad71ed68 978{
e5f17ac6 979 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
ad71ed68
BS
980 ~((target_ulong)0x783F0000), 0);
981}
982#endif
983
984/*****************************************************************************/
985/* Embedded PowerPC specific helpers */
e5f17ac6 986void helper_40x_rfci(CPUPPCState *env)
ad71ed68 987{
e5f17ac6 988 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
ad71ed68
BS
989 ~((target_ulong)0xFFFF0000), 0);
990}
991
e5f17ac6 992void helper_rfci(CPUPPCState *env)
ad71ed68 993{
a1bb7384
SW
994 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
995 ~((target_ulong)0), 0);
ad71ed68
BS
996}
997
e5f17ac6 998void helper_rfdi(CPUPPCState *env)
ad71ed68 999{
a1bb7384
SW
1000 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
1001 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
1002 ~((target_ulong)0), 0);
ad71ed68
BS
1003}
1004
e5f17ac6 1005void helper_rfmci(CPUPPCState *env)
ad71ed68 1006{
a1bb7384
SW
1007 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
1008 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
1009 ~((target_ulong)0), 0);
ad71ed68
BS
1010}
1011#endif
1012
e5f17ac6
BS
1013void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1014 uint32_t flags)
ad71ed68
BS
1015{
1016 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1017 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1018 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1019 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1020 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
e5f17ac6
BS
1021 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1022 POWERPC_EXCP_TRAP);
ad71ed68
BS
1023 }
1024}
1025
1026#if defined(TARGET_PPC64)
e5f17ac6
BS
1027void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
1028 uint32_t flags)
ad71ed68
BS
1029{
1030 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1031 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1032 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1033 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1034 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
e5f17ac6
BS
1035 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1036 POWERPC_EXCP_TRAP);
ad71ed68
BS
1037 }
1038}
1039#endif
1040
1041#if !defined(CONFIG_USER_ONLY)
1042/*****************************************************************************/
1043/* PowerPC 601 specific instructions (POWER bridge) */
1044
e5f17ac6 1045void helper_rfsvc(CPUPPCState *env)
ad71ed68 1046{
e5f17ac6 1047 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
ad71ed68
BS
1048}
1049
1050/* Embedded.Processor Control */
1051static int dbell2irq(target_ulong rb)
1052{
1053 int msg = rb & DBELL_TYPE_MASK;
1054 int irq = -1;
1055
1056 switch (msg) {
1057 case DBELL_TYPE_DBELL:
1058 irq = PPC_INTERRUPT_DOORBELL;
1059 break;
1060 case DBELL_TYPE_DBELL_CRIT:
1061 irq = PPC_INTERRUPT_CDOORBELL;
1062 break;
1063 case DBELL_TYPE_G_DBELL:
1064 case DBELL_TYPE_G_DBELL_CRIT:
1065 case DBELL_TYPE_G_DBELL_MC:
1066 /* XXX implement */
1067 default:
1068 break;
1069 }
1070
1071 return irq;
1072}
1073
e5f17ac6 1074void helper_msgclr(CPUPPCState *env, target_ulong rb)
ad71ed68
BS
1075{
1076 int irq = dbell2irq(rb);
1077
1078 if (irq < 0) {
1079 return;
1080 }
1081
1082 env->pending_interrupts &= ~(1 << irq);
1083}
1084
1085void helper_msgsnd(target_ulong rb)
1086{
1087 int irq = dbell2irq(rb);
1088 int pir = rb & DBELL_PIRTAG_MASK;
182735ef 1089 CPUState *cs;
ad71ed68
BS
1090
1091 if (irq < 0) {
1092 return;
1093 }
1094
bdc44640 1095 CPU_FOREACH(cs) {
182735ef
AF
1096 PowerPCCPU *cpu = POWERPC_CPU(cs);
1097 CPUPPCState *cenv = &cpu->env;
1098
ad71ed68
BS
1099 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1100 cenv->pending_interrupts |= 1 << irq;
182735ef 1101 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
ad71ed68
BS
1102 }
1103 }
1104}
1105#endif