Merge remote-tracking branch 'bonzini/scsi-next' into staging
[qemu/opensuse.git] / target-ppc / excp_helper.c
blob0a1ac86a42a23af4fc973ea20e0929b48fdcdb19
1 /*
2 * PowerPC exception emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
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.
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.
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/>.
19 #include "cpu.h"
20 #include "helper.h"
22 #include "helper_regs.h"
24 //#define DEBUG_OP
25 //#define DEBUG_EXCEPTIONS
27 #ifdef DEBUG_EXCEPTIONS
28 # define LOG_EXCP(...) qemu_log(__VA_ARGS__)
29 #else
30 # define LOG_EXCP(...) do { } while (0)
31 #endif
33 /*****************************************************************************/
34 /* PowerPC Hypercall emulation */
36 void (*cpu_ppc_hypercall)(PowerPCCPU *);
38 /*****************************************************************************/
39 /* Exception processing */
40 #if defined(CONFIG_USER_ONLY)
41 void do_interrupt(CPUPPCState *env)
43 env->exception_index = POWERPC_EXCP_NONE;
44 env->error_code = 0;
47 void ppc_hw_interrupt(CPUPPCState *env)
49 env->exception_index = POWERPC_EXCP_NONE;
50 env->error_code = 0;
52 #else /* defined(CONFIG_USER_ONLY) */
53 static inline void dump_syscall(CPUPPCState *env)
55 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
56 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
57 " nip=" TARGET_FMT_lx "\n",
58 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
59 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
60 ppc_dump_gpr(env, 6), env->nip);
63 /* Note that this function should be greatly optimized
64 * when called with a constant excp, from ppc_hw_interrupt
66 static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
68 CPUPPCState *env = &cpu->env;
69 target_ulong msr, new_msr, vector;
70 int srr0, srr1, asrr0, asrr1;
71 int lpes0, lpes1, lev;
73 if (0) {
74 /* XXX: find a suitable condition to enable the hypervisor mode */
75 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
76 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
77 } else {
78 /* Those values ensure we won't enter the hypervisor mode */
79 lpes0 = 0;
80 lpes1 = 1;
83 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
84 " => %08x (%02x)\n", env->nip, excp, env->error_code);
86 /* new srr1 value excluding must-be-zero bits */
87 if (excp_model == POWERPC_EXCP_BOOKE) {
88 msr = env->msr;
89 } else {
90 msr = env->msr & ~0x783f0000ULL;
93 /* new interrupt handler msr */
94 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
96 /* target registers */
97 srr0 = SPR_SRR0;
98 srr1 = SPR_SRR1;
99 asrr0 = -1;
100 asrr1 = -1;
102 switch (excp) {
103 case POWERPC_EXCP_NONE:
104 /* Should never happen */
105 return;
106 case POWERPC_EXCP_CRITICAL: /* Critical input */
107 switch (excp_model) {
108 case POWERPC_EXCP_40x:
109 srr0 = SPR_40x_SRR2;
110 srr1 = SPR_40x_SRR3;
111 break;
112 case POWERPC_EXCP_BOOKE:
113 srr0 = SPR_BOOKE_CSRR0;
114 srr1 = SPR_BOOKE_CSRR1;
115 break;
116 case POWERPC_EXCP_G2:
117 break;
118 default:
119 goto excp_invalid;
121 goto store_next;
122 case POWERPC_EXCP_MCHECK: /* Machine check exception */
123 if (msr_me == 0) {
124 /* Machine check exception is not enabled.
125 * Enter checkstop state.
127 if (qemu_log_enabled()) {
128 qemu_log("Machine check while not allowed. "
129 "Entering checkstop state\n");
130 } else {
131 fprintf(stderr, "Machine check while not allowed. "
132 "Entering checkstop state\n");
134 env->halted = 1;
135 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
137 if (0) {
138 /* XXX: find a suitable condition to enable the hypervisor mode */
139 new_msr |= (target_ulong)MSR_HVB;
142 /* machine check exceptions don't have ME set */
143 new_msr &= ~((target_ulong)1 << MSR_ME);
145 /* XXX: should also have something loaded in DAR / DSISR */
146 switch (excp_model) {
147 case POWERPC_EXCP_40x:
148 srr0 = SPR_40x_SRR2;
149 srr1 = SPR_40x_SRR3;
150 break;
151 case POWERPC_EXCP_BOOKE:
152 /* FIXME: choose one or the other based on CPU type */
153 srr0 = SPR_BOOKE_MCSRR0;
154 srr1 = SPR_BOOKE_MCSRR1;
155 asrr0 = SPR_BOOKE_CSRR0;
156 asrr1 = SPR_BOOKE_CSRR1;
157 break;
158 default:
159 break;
161 goto store_next;
162 case POWERPC_EXCP_DSI: /* Data storage exception */
163 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
164 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
165 if (lpes1 == 0) {
166 new_msr |= (target_ulong)MSR_HVB;
168 goto store_next;
169 case POWERPC_EXCP_ISI: /* Instruction storage exception */
170 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
171 "\n", msr, env->nip);
172 if (lpes1 == 0) {
173 new_msr |= (target_ulong)MSR_HVB;
175 msr |= env->error_code;
176 goto store_next;
177 case POWERPC_EXCP_EXTERNAL: /* External input */
178 if (lpes0 == 1) {
179 new_msr |= (target_ulong)MSR_HVB;
181 if (env->mpic_proxy) {
182 /* IACK the IRQ on delivery */
183 env->spr[SPR_BOOKE_EPR] = ldl_phys(env->mpic_iack);
185 goto store_next;
186 case POWERPC_EXCP_ALIGN: /* Alignment exception */
187 if (lpes1 == 0) {
188 new_msr |= (target_ulong)MSR_HVB;
190 /* XXX: this is false */
191 /* Get rS/rD and rA from faulting opcode */
192 env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
193 & 0x03FF0000) >> 16;
194 goto store_current;
195 case POWERPC_EXCP_PROGRAM: /* Program exception */
196 switch (env->error_code & ~0xF) {
197 case POWERPC_EXCP_FP:
198 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
199 LOG_EXCP("Ignore floating point exception\n");
200 env->exception_index = POWERPC_EXCP_NONE;
201 env->error_code = 0;
202 return;
204 if (lpes1 == 0) {
205 new_msr |= (target_ulong)MSR_HVB;
207 msr |= 0x00100000;
208 if (msr_fe0 == msr_fe1) {
209 goto store_next;
211 msr |= 0x00010000;
212 break;
213 case POWERPC_EXCP_INVAL:
214 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
215 if (lpes1 == 0) {
216 new_msr |= (target_ulong)MSR_HVB;
218 msr |= 0x00080000;
219 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
220 break;
221 case POWERPC_EXCP_PRIV:
222 if (lpes1 == 0) {
223 new_msr |= (target_ulong)MSR_HVB;
225 msr |= 0x00040000;
226 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
227 break;
228 case POWERPC_EXCP_TRAP:
229 if (lpes1 == 0) {
230 new_msr |= (target_ulong)MSR_HVB;
232 msr |= 0x00020000;
233 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
234 break;
235 default:
236 /* Should never occur */
237 cpu_abort(env, "Invalid program exception %d. Aborting\n",
238 env->error_code);
239 break;
241 goto store_current;
242 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
243 if (lpes1 == 0) {
244 new_msr |= (target_ulong)MSR_HVB;
246 goto store_current;
247 case POWERPC_EXCP_SYSCALL: /* System call exception */
248 dump_syscall(env);
249 lev = env->error_code;
250 if ((lev == 1) && cpu_ppc_hypercall) {
251 cpu_ppc_hypercall(cpu);
252 return;
254 if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
255 new_msr |= (target_ulong)MSR_HVB;
257 goto store_next;
258 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
259 goto store_current;
260 case POWERPC_EXCP_DECR: /* Decrementer exception */
261 if (lpes1 == 0) {
262 new_msr |= (target_ulong)MSR_HVB;
264 goto store_next;
265 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
266 /* FIT on 4xx */
267 LOG_EXCP("FIT exception\n");
268 goto store_next;
269 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
270 LOG_EXCP("WDT exception\n");
271 switch (excp_model) {
272 case POWERPC_EXCP_BOOKE:
273 srr0 = SPR_BOOKE_CSRR0;
274 srr1 = SPR_BOOKE_CSRR1;
275 break;
276 default:
277 break;
279 goto store_next;
280 case POWERPC_EXCP_DTLB: /* Data TLB error */
281 goto store_next;
282 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
283 goto store_next;
284 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
285 switch (excp_model) {
286 case POWERPC_EXCP_BOOKE:
287 /* FIXME: choose one or the other based on CPU type */
288 srr0 = SPR_BOOKE_DSRR0;
289 srr1 = SPR_BOOKE_DSRR1;
290 asrr0 = SPR_BOOKE_CSRR0;
291 asrr1 = SPR_BOOKE_CSRR1;
292 break;
293 default:
294 break;
296 /* XXX: TODO */
297 cpu_abort(env, "Debug exception is not implemented yet !\n");
298 goto store_next;
299 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
300 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
301 goto store_current;
302 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
303 /* XXX: TODO */
304 cpu_abort(env, "Embedded floating point data exception "
305 "is not implemented yet !\n");
306 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
307 goto store_next;
308 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
309 /* XXX: TODO */
310 cpu_abort(env, "Embedded floating point round exception "
311 "is not implemented yet !\n");
312 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
313 goto store_next;
314 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
315 /* XXX: TODO */
316 cpu_abort(env,
317 "Performance counter exception is not implemented yet !\n");
318 goto store_next;
319 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
320 goto store_next;
321 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
322 srr0 = SPR_BOOKE_CSRR0;
323 srr1 = SPR_BOOKE_CSRR1;
324 goto store_next;
325 case POWERPC_EXCP_RESET: /* System reset exception */
326 if (msr_pow) {
327 /* indicate that we resumed from power save mode */
328 msr |= 0x10000;
329 } else {
330 new_msr &= ~((target_ulong)1 << MSR_ME);
333 if (0) {
334 /* XXX: find a suitable condition to enable the hypervisor mode */
335 new_msr |= (target_ulong)MSR_HVB;
337 goto store_next;
338 case POWERPC_EXCP_DSEG: /* Data segment exception */
339 if (lpes1 == 0) {
340 new_msr |= (target_ulong)MSR_HVB;
342 goto store_next;
343 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
344 if (lpes1 == 0) {
345 new_msr |= (target_ulong)MSR_HVB;
347 goto store_next;
348 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
349 srr0 = SPR_HSRR0;
350 srr1 = SPR_HSRR1;
351 new_msr |= (target_ulong)MSR_HVB;
352 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
353 goto store_next;
354 case POWERPC_EXCP_TRACE: /* Trace exception */
355 if (lpes1 == 0) {
356 new_msr |= (target_ulong)MSR_HVB;
358 goto store_next;
359 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
360 srr0 = SPR_HSRR0;
361 srr1 = SPR_HSRR1;
362 new_msr |= (target_ulong)MSR_HVB;
363 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
364 goto store_next;
365 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
366 srr0 = SPR_HSRR0;
367 srr1 = SPR_HSRR1;
368 new_msr |= (target_ulong)MSR_HVB;
369 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
370 goto store_next;
371 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
372 srr0 = SPR_HSRR0;
373 srr1 = SPR_HSRR1;
374 new_msr |= (target_ulong)MSR_HVB;
375 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
376 goto store_next;
377 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
378 srr0 = SPR_HSRR0;
379 srr1 = SPR_HSRR1;
380 new_msr |= (target_ulong)MSR_HVB;
381 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
382 goto store_next;
383 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
384 if (lpes1 == 0) {
385 new_msr |= (target_ulong)MSR_HVB;
387 goto store_current;
388 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
389 LOG_EXCP("PIT exception\n");
390 goto store_next;
391 case POWERPC_EXCP_IO: /* IO error exception */
392 /* XXX: TODO */
393 cpu_abort(env, "601 IO error exception is not implemented yet !\n");
394 goto store_next;
395 case POWERPC_EXCP_RUNM: /* Run mode exception */
396 /* XXX: TODO */
397 cpu_abort(env, "601 run mode exception is not implemented yet !\n");
398 goto store_next;
399 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
400 /* XXX: TODO */
401 cpu_abort(env, "602 emulation trap exception "
402 "is not implemented yet !\n");
403 goto store_next;
404 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
405 if (lpes1 == 0) { /* XXX: check this */
406 new_msr |= (target_ulong)MSR_HVB;
408 switch (excp_model) {
409 case POWERPC_EXCP_602:
410 case POWERPC_EXCP_603:
411 case POWERPC_EXCP_603E:
412 case POWERPC_EXCP_G2:
413 goto tlb_miss_tgpr;
414 case POWERPC_EXCP_7x5:
415 goto tlb_miss;
416 case POWERPC_EXCP_74xx:
417 goto tlb_miss_74xx;
418 default:
419 cpu_abort(env, "Invalid instruction TLB miss exception\n");
420 break;
422 break;
423 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
424 if (lpes1 == 0) { /* XXX: check this */
425 new_msr |= (target_ulong)MSR_HVB;
427 switch (excp_model) {
428 case POWERPC_EXCP_602:
429 case POWERPC_EXCP_603:
430 case POWERPC_EXCP_603E:
431 case POWERPC_EXCP_G2:
432 goto tlb_miss_tgpr;
433 case POWERPC_EXCP_7x5:
434 goto tlb_miss;
435 case POWERPC_EXCP_74xx:
436 goto tlb_miss_74xx;
437 default:
438 cpu_abort(env, "Invalid data load TLB miss exception\n");
439 break;
441 break;
442 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
443 if (lpes1 == 0) { /* XXX: check this */
444 new_msr |= (target_ulong)MSR_HVB;
446 switch (excp_model) {
447 case POWERPC_EXCP_602:
448 case POWERPC_EXCP_603:
449 case POWERPC_EXCP_603E:
450 case POWERPC_EXCP_G2:
451 tlb_miss_tgpr:
452 /* Swap temporary saved registers with GPRs */
453 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
454 new_msr |= (target_ulong)1 << MSR_TGPR;
455 hreg_swap_gpr_tgpr(env);
457 goto tlb_miss;
458 case POWERPC_EXCP_7x5:
459 tlb_miss:
460 #if defined(DEBUG_SOFTWARE_TLB)
461 if (qemu_log_enabled()) {
462 const char *es;
463 target_ulong *miss, *cmp;
464 int en;
466 if (excp == POWERPC_EXCP_IFTLB) {
467 es = "I";
468 en = 'I';
469 miss = &env->spr[SPR_IMISS];
470 cmp = &env->spr[SPR_ICMP];
471 } else {
472 if (excp == POWERPC_EXCP_DLTLB) {
473 es = "DL";
474 } else {
475 es = "DS";
477 en = 'D';
478 miss = &env->spr[SPR_DMISS];
479 cmp = &env->spr[SPR_DCMP];
481 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
482 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
483 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
484 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
485 env->error_code);
487 #endif
488 msr |= env->crf[0] << 28;
489 msr |= env->error_code; /* key, D/I, S/L bits */
490 /* Set way using a LRU mechanism */
491 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
492 break;
493 case POWERPC_EXCP_74xx:
494 tlb_miss_74xx:
495 #if defined(DEBUG_SOFTWARE_TLB)
496 if (qemu_log_enabled()) {
497 const char *es;
498 target_ulong *miss, *cmp;
499 int en;
501 if (excp == POWERPC_EXCP_IFTLB) {
502 es = "I";
503 en = 'I';
504 miss = &env->spr[SPR_TLBMISS];
505 cmp = &env->spr[SPR_PTEHI];
506 } else {
507 if (excp == POWERPC_EXCP_DLTLB) {
508 es = "DL";
509 } else {
510 es = "DS";
512 en = 'D';
513 miss = &env->spr[SPR_TLBMISS];
514 cmp = &env->spr[SPR_PTEHI];
516 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
517 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
518 env->error_code);
520 #endif
521 msr |= env->error_code; /* key bit */
522 break;
523 default:
524 cpu_abort(env, "Invalid data store TLB miss exception\n");
525 break;
527 goto store_next;
528 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
529 /* XXX: TODO */
530 cpu_abort(env, "Floating point assist exception "
531 "is not implemented yet !\n");
532 goto store_next;
533 case POWERPC_EXCP_DABR: /* Data address breakpoint */
534 /* XXX: TODO */
535 cpu_abort(env, "DABR exception is not implemented yet !\n");
536 goto store_next;
537 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
538 /* XXX: TODO */
539 cpu_abort(env, "IABR exception is not implemented yet !\n");
540 goto store_next;
541 case POWERPC_EXCP_SMI: /* System management interrupt */
542 /* XXX: TODO */
543 cpu_abort(env, "SMI exception is not implemented yet !\n");
544 goto store_next;
545 case POWERPC_EXCP_THERM: /* Thermal interrupt */
546 /* XXX: TODO */
547 cpu_abort(env, "Thermal management exception "
548 "is not implemented yet !\n");
549 goto store_next;
550 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
551 if (lpes1 == 0) {
552 new_msr |= (target_ulong)MSR_HVB;
554 /* XXX: TODO */
555 cpu_abort(env,
556 "Performance counter exception is not implemented yet !\n");
557 goto store_next;
558 case POWERPC_EXCP_VPUA: /* Vector assist exception */
559 /* XXX: TODO */
560 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
561 goto store_next;
562 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
563 /* XXX: TODO */
564 cpu_abort(env,
565 "970 soft-patch exception is not implemented yet !\n");
566 goto store_next;
567 case POWERPC_EXCP_MAINT: /* Maintenance exception */
568 /* XXX: TODO */
569 cpu_abort(env,
570 "970 maintenance exception is not implemented yet !\n");
571 goto store_next;
572 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
573 /* XXX: TODO */
574 cpu_abort(env, "Maskable external exception "
575 "is not implemented yet !\n");
576 goto store_next;
577 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
578 /* XXX: TODO */
579 cpu_abort(env, "Non maskable external exception "
580 "is not implemented yet !\n");
581 goto store_next;
582 default:
583 excp_invalid:
584 cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
585 break;
586 store_current:
587 /* save current instruction location */
588 env->spr[srr0] = env->nip - 4;
589 break;
590 store_next:
591 /* save next instruction location */
592 env->spr[srr0] = env->nip;
593 break;
595 /* Save MSR */
596 env->spr[srr1] = msr;
597 /* If any alternate SRR register are defined, duplicate saved values */
598 if (asrr0 != -1) {
599 env->spr[asrr0] = env->spr[srr0];
601 if (asrr1 != -1) {
602 env->spr[asrr1] = env->spr[srr1];
604 /* If we disactivated any translation, flush TLBs */
605 if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
606 tlb_flush(env, 1);
609 if (msr_ile) {
610 new_msr |= (target_ulong)1 << MSR_LE;
613 /* Jump to handler */
614 vector = env->excp_vectors[excp];
615 if (vector == (target_ulong)-1ULL) {
616 cpu_abort(env, "Raised an exception without defined vector %d\n",
617 excp);
619 vector |= env->excp_prefix;
620 #if defined(TARGET_PPC64)
621 if (excp_model == POWERPC_EXCP_BOOKE) {
622 if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
623 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
624 new_msr |= (target_ulong)1 << MSR_CM;
625 } else {
626 vector = (uint32_t)vector;
628 } else {
629 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
630 vector = (uint32_t)vector;
631 } else {
632 new_msr |= (target_ulong)1 << MSR_SF;
635 #endif
636 /* XXX: we don't use hreg_store_msr here as already have treated
637 * any special case that could occur. Just store MSR and update hflags
639 env->msr = new_msr & env->msr_mask;
640 hreg_compute_hflags(env);
641 env->nip = vector;
642 /* Reset exception state */
643 env->exception_index = POWERPC_EXCP_NONE;
644 env->error_code = 0;
646 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
647 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
648 /* XXX: The BookE changes address space when switching modes,
649 we should probably implement that as different MMU indexes,
650 but for the moment we do it the slow way and flush all. */
651 tlb_flush(env, 1);
655 void do_interrupt(CPUPPCState *env)
657 PowerPCCPU *cpu = ppc_env_get_cpu(env);
659 powerpc_excp(cpu, env->excp_model, env->exception_index);
662 void ppc_hw_interrupt(CPUPPCState *env)
664 PowerPCCPU *cpu = ppc_env_get_cpu(env);
665 int hdice;
667 #if 0
668 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
669 __func__, env, env->pending_interrupts,
670 env->interrupt_request, (int)msr_me, (int)msr_ee);
671 #endif
672 /* External reset */
673 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
674 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
675 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
676 return;
678 /* Machine check exception */
679 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
680 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
681 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
682 return;
684 #if 0 /* TODO */
685 /* External debug exception */
686 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
687 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
688 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
689 return;
691 #endif
692 if (0) {
693 /* XXX: find a suitable condition to enable the hypervisor mode */
694 hdice = env->spr[SPR_LPCR] & 1;
695 } else {
696 hdice = 0;
698 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
699 /* Hypervisor decrementer exception */
700 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
701 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
702 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
703 return;
706 if (msr_ce != 0) {
707 /* External critical interrupt */
708 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
709 /* Taking a critical external interrupt does not clear the external
710 * critical interrupt status
712 #if 0
713 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
714 #endif
715 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
716 return;
719 if (msr_ee != 0) {
720 /* Watchdog timer on embedded PowerPC */
721 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
722 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
723 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
724 return;
726 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
727 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
728 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
729 return;
731 /* Fixed interval timer on embedded PowerPC */
732 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
733 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
734 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
735 return;
737 /* Programmable interval timer on embedded PowerPC */
738 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
739 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
740 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
741 return;
743 /* Decrementer exception */
744 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
745 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
746 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
747 return;
749 /* External interrupt */
750 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
751 /* Taking an external interrupt does not clear the external
752 * interrupt status
754 #if 0
755 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
756 #endif
757 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
758 return;
760 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
761 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
762 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
763 return;
765 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
766 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
767 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
768 return;
770 /* Thermal interrupt */
771 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
772 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
773 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
774 return;
778 #endif /* !CONFIG_USER_ONLY */
780 #if defined(DEBUG_OP)
781 static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
783 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
784 TARGET_FMT_lx "\n", RA, msr);
786 #endif
788 /*****************************************************************************/
789 /* Exceptions processing helpers */
791 void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
792 uint32_t error_code)
794 #if 0
795 printf("Raise exception %3x code : %d\n", exception, error_code);
796 #endif
797 env->exception_index = exception;
798 env->error_code = error_code;
799 cpu_loop_exit(env);
802 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
804 helper_raise_exception_err(env, exception, 0);
807 #if !defined(CONFIG_USER_ONLY)
808 void helper_store_msr(CPUPPCState *env, target_ulong val)
810 val = hreg_store_msr(env, val, 0);
811 if (val != 0) {
812 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
813 helper_raise_exception(env, val);
817 static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
818 target_ulong msrm, int keep_msrh)
820 #if defined(TARGET_PPC64)
821 if (msr_is_64bit(env, msr)) {
822 nip = (uint64_t)nip;
823 msr &= (uint64_t)msrm;
824 } else {
825 nip = (uint32_t)nip;
826 msr = (uint32_t)(msr & msrm);
827 if (keep_msrh) {
828 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
831 #else
832 nip = (uint32_t)nip;
833 msr &= (uint32_t)msrm;
834 #endif
835 /* XXX: beware: this is false if VLE is supported */
836 env->nip = nip & ~((target_ulong)0x00000003);
837 hreg_store_msr(env, msr, 1);
838 #if defined(DEBUG_OP)
839 cpu_dump_rfi(env->nip, env->msr);
840 #endif
841 /* No need to raise an exception here,
842 * as rfi is always the last insn of a TB
844 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
847 void helper_rfi(CPUPPCState *env)
849 if (env->excp_model == POWERPC_EXCP_BOOKE) {
850 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
851 ~((target_ulong)0), 0);
852 } else {
853 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
854 ~((target_ulong)0x783F0000), 1);
858 #if defined(TARGET_PPC64)
859 void helper_rfid(CPUPPCState *env)
861 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
862 ~((target_ulong)0x783F0000), 0);
865 void helper_hrfid(CPUPPCState *env)
867 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
868 ~((target_ulong)0x783F0000), 0);
870 #endif
872 /*****************************************************************************/
873 /* Embedded PowerPC specific helpers */
874 void helper_40x_rfci(CPUPPCState *env)
876 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
877 ~((target_ulong)0xFFFF0000), 0);
880 void helper_rfci(CPUPPCState *env)
882 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
883 ~((target_ulong)0), 0);
886 void helper_rfdi(CPUPPCState *env)
888 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
889 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
890 ~((target_ulong)0), 0);
893 void helper_rfmci(CPUPPCState *env)
895 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
896 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
897 ~((target_ulong)0), 0);
899 #endif
901 void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
902 uint32_t flags)
904 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
905 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
906 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
907 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
908 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
909 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
910 POWERPC_EXCP_TRAP);
914 #if defined(TARGET_PPC64)
915 void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
916 uint32_t flags)
918 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
919 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
920 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
921 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
922 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
923 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
924 POWERPC_EXCP_TRAP);
927 #endif
929 #if !defined(CONFIG_USER_ONLY)
930 /*****************************************************************************/
931 /* PowerPC 601 specific instructions (POWER bridge) */
933 void helper_rfsvc(CPUPPCState *env)
935 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
938 /* Embedded.Processor Control */
939 static int dbell2irq(target_ulong rb)
941 int msg = rb & DBELL_TYPE_MASK;
942 int irq = -1;
944 switch (msg) {
945 case DBELL_TYPE_DBELL:
946 irq = PPC_INTERRUPT_DOORBELL;
947 break;
948 case DBELL_TYPE_DBELL_CRIT:
949 irq = PPC_INTERRUPT_CDOORBELL;
950 break;
951 case DBELL_TYPE_G_DBELL:
952 case DBELL_TYPE_G_DBELL_CRIT:
953 case DBELL_TYPE_G_DBELL_MC:
954 /* XXX implement */
955 default:
956 break;
959 return irq;
962 void helper_msgclr(CPUPPCState *env, target_ulong rb)
964 int irq = dbell2irq(rb);
966 if (irq < 0) {
967 return;
970 env->pending_interrupts &= ~(1 << irq);
973 void helper_msgsnd(target_ulong rb)
975 int irq = dbell2irq(rb);
976 int pir = rb & DBELL_PIRTAG_MASK;
977 CPUPPCState *cenv;
979 if (irq < 0) {
980 return;
983 for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
984 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
985 cenv->pending_interrupts |= 1 << irq;
986 cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
990 #endif