ui/cocoa.m: Update to new DisplayChangeListener member names
[qemu/pbrook.git] / target-ppc / excp_helper.c
blob5e34ad08a8cd4d1369994a37101a698f2afd1621
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 msr = env->msr & ~0x783f0000ULL;
89 /* new interrupt handler msr */
90 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
92 /* target registers */
93 srr0 = SPR_SRR0;
94 srr1 = SPR_SRR1;
95 asrr0 = -1;
96 asrr1 = -1;
98 switch (excp) {
99 case POWERPC_EXCP_NONE:
100 /* Should never happen */
101 return;
102 case POWERPC_EXCP_CRITICAL: /* Critical input */
103 switch (excp_model) {
104 case POWERPC_EXCP_40x:
105 srr0 = SPR_40x_SRR2;
106 srr1 = SPR_40x_SRR3;
107 break;
108 case POWERPC_EXCP_BOOKE:
109 srr0 = SPR_BOOKE_CSRR0;
110 srr1 = SPR_BOOKE_CSRR1;
111 break;
112 case POWERPC_EXCP_G2:
113 break;
114 default:
115 goto excp_invalid;
117 goto store_next;
118 case POWERPC_EXCP_MCHECK: /* Machine check exception */
119 if (msr_me == 0) {
120 /* Machine check exception is not enabled.
121 * Enter checkstop state.
123 if (qemu_log_enabled()) {
124 qemu_log("Machine check while not allowed. "
125 "Entering checkstop state\n");
126 } else {
127 fprintf(stderr, "Machine check while not allowed. "
128 "Entering checkstop state\n");
130 env->halted = 1;
131 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
133 if (0) {
134 /* XXX: find a suitable condition to enable the hypervisor mode */
135 new_msr |= (target_ulong)MSR_HVB;
138 /* machine check exceptions don't have ME set */
139 new_msr &= ~((target_ulong)1 << MSR_ME);
141 /* XXX: should also have something loaded in DAR / DSISR */
142 switch (excp_model) {
143 case POWERPC_EXCP_40x:
144 srr0 = SPR_40x_SRR2;
145 srr1 = SPR_40x_SRR3;
146 break;
147 case POWERPC_EXCP_BOOKE:
148 srr0 = SPR_BOOKE_MCSRR0;
149 srr1 = SPR_BOOKE_MCSRR1;
150 asrr0 = SPR_BOOKE_CSRR0;
151 asrr1 = SPR_BOOKE_CSRR1;
152 break;
153 default:
154 break;
156 goto store_next;
157 case POWERPC_EXCP_DSI: /* Data storage exception */
158 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
159 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
160 if (lpes1 == 0) {
161 new_msr |= (target_ulong)MSR_HVB;
163 goto store_next;
164 case POWERPC_EXCP_ISI: /* Instruction storage exception */
165 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
166 "\n", msr, env->nip);
167 if (lpes1 == 0) {
168 new_msr |= (target_ulong)MSR_HVB;
170 msr |= env->error_code;
171 goto store_next;
172 case POWERPC_EXCP_EXTERNAL: /* External input */
173 if (lpes0 == 1) {
174 new_msr |= (target_ulong)MSR_HVB;
176 goto store_next;
177 case POWERPC_EXCP_ALIGN: /* Alignment exception */
178 if (lpes1 == 0) {
179 new_msr |= (target_ulong)MSR_HVB;
181 /* XXX: this is false */
182 /* Get rS/rD and rA from faulting opcode */
183 env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
184 & 0x03FF0000) >> 16;
185 goto store_current;
186 case POWERPC_EXCP_PROGRAM: /* Program exception */
187 switch (env->error_code & ~0xF) {
188 case POWERPC_EXCP_FP:
189 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
190 LOG_EXCP("Ignore floating point exception\n");
191 env->exception_index = POWERPC_EXCP_NONE;
192 env->error_code = 0;
193 return;
195 if (lpes1 == 0) {
196 new_msr |= (target_ulong)MSR_HVB;
198 msr |= 0x00100000;
199 if (msr_fe0 == msr_fe1) {
200 goto store_next;
202 msr |= 0x00010000;
203 break;
204 case POWERPC_EXCP_INVAL:
205 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
206 if (lpes1 == 0) {
207 new_msr |= (target_ulong)MSR_HVB;
209 msr |= 0x00080000;
210 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
211 break;
212 case POWERPC_EXCP_PRIV:
213 if (lpes1 == 0) {
214 new_msr |= (target_ulong)MSR_HVB;
216 msr |= 0x00040000;
217 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
218 break;
219 case POWERPC_EXCP_TRAP:
220 if (lpes1 == 0) {
221 new_msr |= (target_ulong)MSR_HVB;
223 msr |= 0x00020000;
224 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
225 break;
226 default:
227 /* Should never occur */
228 cpu_abort(env, "Invalid program exception %d. Aborting\n",
229 env->error_code);
230 break;
232 goto store_current;
233 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
234 if (lpes1 == 0) {
235 new_msr |= (target_ulong)MSR_HVB;
237 goto store_current;
238 case POWERPC_EXCP_SYSCALL: /* System call exception */
239 dump_syscall(env);
240 lev = env->error_code;
241 if ((lev == 1) && cpu_ppc_hypercall) {
242 cpu_ppc_hypercall(cpu);
243 return;
245 if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
246 new_msr |= (target_ulong)MSR_HVB;
248 goto store_next;
249 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
250 goto store_current;
251 case POWERPC_EXCP_DECR: /* Decrementer exception */
252 if (lpes1 == 0) {
253 new_msr |= (target_ulong)MSR_HVB;
255 goto store_next;
256 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
257 /* FIT on 4xx */
258 LOG_EXCP("FIT exception\n");
259 goto store_next;
260 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
261 LOG_EXCP("WDT exception\n");
262 switch (excp_model) {
263 case POWERPC_EXCP_BOOKE:
264 srr0 = SPR_BOOKE_CSRR0;
265 srr1 = SPR_BOOKE_CSRR1;
266 break;
267 default:
268 break;
270 goto store_next;
271 case POWERPC_EXCP_DTLB: /* Data TLB error */
272 goto store_next;
273 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
274 goto store_next;
275 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
276 switch (excp_model) {
277 case POWERPC_EXCP_BOOKE:
278 srr0 = SPR_BOOKE_DSRR0;
279 srr1 = SPR_BOOKE_DSRR1;
280 asrr0 = SPR_BOOKE_CSRR0;
281 asrr1 = SPR_BOOKE_CSRR1;
282 break;
283 default:
284 break;
286 /* XXX: TODO */
287 cpu_abort(env, "Debug exception is not implemented yet !\n");
288 goto store_next;
289 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
290 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
291 goto store_current;
292 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
293 /* XXX: TODO */
294 cpu_abort(env, "Embedded floating point data exception "
295 "is not implemented yet !\n");
296 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
297 goto store_next;
298 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
299 /* XXX: TODO */
300 cpu_abort(env, "Embedded floating point round exception "
301 "is not implemented yet !\n");
302 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
303 goto store_next;
304 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
305 /* XXX: TODO */
306 cpu_abort(env,
307 "Performance counter exception is not implemented yet !\n");
308 goto store_next;
309 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
310 goto store_next;
311 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
312 srr0 = SPR_BOOKE_CSRR0;
313 srr1 = SPR_BOOKE_CSRR1;
314 goto store_next;
315 case POWERPC_EXCP_RESET: /* System reset exception */
316 if (msr_pow) {
317 /* indicate that we resumed from power save mode */
318 msr |= 0x10000;
319 } else {
320 new_msr &= ~((target_ulong)1 << MSR_ME);
323 if (0) {
324 /* XXX: find a suitable condition to enable the hypervisor mode */
325 new_msr |= (target_ulong)MSR_HVB;
327 goto store_next;
328 case POWERPC_EXCP_DSEG: /* Data segment exception */
329 if (lpes1 == 0) {
330 new_msr |= (target_ulong)MSR_HVB;
332 goto store_next;
333 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
334 if (lpes1 == 0) {
335 new_msr |= (target_ulong)MSR_HVB;
337 goto store_next;
338 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
339 srr0 = SPR_HSRR0;
340 srr1 = SPR_HSRR1;
341 new_msr |= (target_ulong)MSR_HVB;
342 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
343 goto store_next;
344 case POWERPC_EXCP_TRACE: /* Trace exception */
345 if (lpes1 == 0) {
346 new_msr |= (target_ulong)MSR_HVB;
348 goto store_next;
349 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
350 srr0 = SPR_HSRR0;
351 srr1 = SPR_HSRR1;
352 new_msr |= (target_ulong)MSR_HVB;
353 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
354 goto store_next;
355 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
356 srr0 = SPR_HSRR0;
357 srr1 = SPR_HSRR1;
358 new_msr |= (target_ulong)MSR_HVB;
359 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
360 goto store_next;
361 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
362 srr0 = SPR_HSRR0;
363 srr1 = SPR_HSRR1;
364 new_msr |= (target_ulong)MSR_HVB;
365 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
366 goto store_next;
367 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
368 srr0 = SPR_HSRR0;
369 srr1 = SPR_HSRR1;
370 new_msr |= (target_ulong)MSR_HVB;
371 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
372 goto store_next;
373 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
374 if (lpes1 == 0) {
375 new_msr |= (target_ulong)MSR_HVB;
377 goto store_current;
378 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
379 LOG_EXCP("PIT exception\n");
380 goto store_next;
381 case POWERPC_EXCP_IO: /* IO error exception */
382 /* XXX: TODO */
383 cpu_abort(env, "601 IO error exception is not implemented yet !\n");
384 goto store_next;
385 case POWERPC_EXCP_RUNM: /* Run mode exception */
386 /* XXX: TODO */
387 cpu_abort(env, "601 run mode exception is not implemented yet !\n");
388 goto store_next;
389 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
390 /* XXX: TODO */
391 cpu_abort(env, "602 emulation trap exception "
392 "is not implemented yet !\n");
393 goto store_next;
394 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
395 if (lpes1 == 0) { /* XXX: check this */
396 new_msr |= (target_ulong)MSR_HVB;
398 switch (excp_model) {
399 case POWERPC_EXCP_602:
400 case POWERPC_EXCP_603:
401 case POWERPC_EXCP_603E:
402 case POWERPC_EXCP_G2:
403 goto tlb_miss_tgpr;
404 case POWERPC_EXCP_7x5:
405 goto tlb_miss;
406 case POWERPC_EXCP_74xx:
407 goto tlb_miss_74xx;
408 default:
409 cpu_abort(env, "Invalid instruction TLB miss exception\n");
410 break;
412 break;
413 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
414 if (lpes1 == 0) { /* XXX: check this */
415 new_msr |= (target_ulong)MSR_HVB;
417 switch (excp_model) {
418 case POWERPC_EXCP_602:
419 case POWERPC_EXCP_603:
420 case POWERPC_EXCP_603E:
421 case POWERPC_EXCP_G2:
422 goto tlb_miss_tgpr;
423 case POWERPC_EXCP_7x5:
424 goto tlb_miss;
425 case POWERPC_EXCP_74xx:
426 goto tlb_miss_74xx;
427 default:
428 cpu_abort(env, "Invalid data load TLB miss exception\n");
429 break;
431 break;
432 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
433 if (lpes1 == 0) { /* XXX: check this */
434 new_msr |= (target_ulong)MSR_HVB;
436 switch (excp_model) {
437 case POWERPC_EXCP_602:
438 case POWERPC_EXCP_603:
439 case POWERPC_EXCP_603E:
440 case POWERPC_EXCP_G2:
441 tlb_miss_tgpr:
442 /* Swap temporary saved registers with GPRs */
443 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
444 new_msr |= (target_ulong)1 << MSR_TGPR;
445 hreg_swap_gpr_tgpr(env);
447 goto tlb_miss;
448 case POWERPC_EXCP_7x5:
449 tlb_miss:
450 #if defined(DEBUG_SOFTWARE_TLB)
451 if (qemu_log_enabled()) {
452 const char *es;
453 target_ulong *miss, *cmp;
454 int en;
456 if (excp == POWERPC_EXCP_IFTLB) {
457 es = "I";
458 en = 'I';
459 miss = &env->spr[SPR_IMISS];
460 cmp = &env->spr[SPR_ICMP];
461 } else {
462 if (excp == POWERPC_EXCP_DLTLB) {
463 es = "DL";
464 } else {
465 es = "DS";
467 en = 'D';
468 miss = &env->spr[SPR_DMISS];
469 cmp = &env->spr[SPR_DCMP];
471 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
472 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
473 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
474 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
475 env->error_code);
477 #endif
478 msr |= env->crf[0] << 28;
479 msr |= env->error_code; /* key, D/I, S/L bits */
480 /* Set way using a LRU mechanism */
481 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
482 break;
483 case POWERPC_EXCP_74xx:
484 tlb_miss_74xx:
485 #if defined(DEBUG_SOFTWARE_TLB)
486 if (qemu_log_enabled()) {
487 const char *es;
488 target_ulong *miss, *cmp;
489 int en;
491 if (excp == POWERPC_EXCP_IFTLB) {
492 es = "I";
493 en = 'I';
494 miss = &env->spr[SPR_TLBMISS];
495 cmp = &env->spr[SPR_PTEHI];
496 } else {
497 if (excp == POWERPC_EXCP_DLTLB) {
498 es = "DL";
499 } else {
500 es = "DS";
502 en = 'D';
503 miss = &env->spr[SPR_TLBMISS];
504 cmp = &env->spr[SPR_PTEHI];
506 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
507 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
508 env->error_code);
510 #endif
511 msr |= env->error_code; /* key bit */
512 break;
513 default:
514 cpu_abort(env, "Invalid data store TLB miss exception\n");
515 break;
517 goto store_next;
518 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
519 /* XXX: TODO */
520 cpu_abort(env, "Floating point assist exception "
521 "is not implemented yet !\n");
522 goto store_next;
523 case POWERPC_EXCP_DABR: /* Data address breakpoint */
524 /* XXX: TODO */
525 cpu_abort(env, "DABR exception is not implemented yet !\n");
526 goto store_next;
527 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
528 /* XXX: TODO */
529 cpu_abort(env, "IABR exception is not implemented yet !\n");
530 goto store_next;
531 case POWERPC_EXCP_SMI: /* System management interrupt */
532 /* XXX: TODO */
533 cpu_abort(env, "SMI exception is not implemented yet !\n");
534 goto store_next;
535 case POWERPC_EXCP_THERM: /* Thermal interrupt */
536 /* XXX: TODO */
537 cpu_abort(env, "Thermal management exception "
538 "is not implemented yet !\n");
539 goto store_next;
540 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
541 if (lpes1 == 0) {
542 new_msr |= (target_ulong)MSR_HVB;
544 /* XXX: TODO */
545 cpu_abort(env,
546 "Performance counter exception is not implemented yet !\n");
547 goto store_next;
548 case POWERPC_EXCP_VPUA: /* Vector assist exception */
549 /* XXX: TODO */
550 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
551 goto store_next;
552 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
553 /* XXX: TODO */
554 cpu_abort(env,
555 "970 soft-patch exception is not implemented yet !\n");
556 goto store_next;
557 case POWERPC_EXCP_MAINT: /* Maintenance exception */
558 /* XXX: TODO */
559 cpu_abort(env,
560 "970 maintenance exception is not implemented yet !\n");
561 goto store_next;
562 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
563 /* XXX: TODO */
564 cpu_abort(env, "Maskable external exception "
565 "is not implemented yet !\n");
566 goto store_next;
567 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
568 /* XXX: TODO */
569 cpu_abort(env, "Non maskable external exception "
570 "is not implemented yet !\n");
571 goto store_next;
572 default:
573 excp_invalid:
574 cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
575 break;
576 store_current:
577 /* save current instruction location */
578 env->spr[srr0] = env->nip - 4;
579 break;
580 store_next:
581 /* save next instruction location */
582 env->spr[srr0] = env->nip;
583 break;
585 /* Save MSR */
586 env->spr[srr1] = msr;
587 /* If any alternate SRR register are defined, duplicate saved values */
588 if (asrr0 != -1) {
589 env->spr[asrr0] = env->spr[srr0];
591 if (asrr1 != -1) {
592 env->spr[asrr1] = env->spr[srr1];
594 /* If we disactivated any translation, flush TLBs */
595 if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
596 tlb_flush(env, 1);
599 if (msr_ile) {
600 new_msr |= (target_ulong)1 << MSR_LE;
603 /* Jump to handler */
604 vector = env->excp_vectors[excp];
605 if (vector == (target_ulong)-1ULL) {
606 cpu_abort(env, "Raised an exception without defined vector %d\n",
607 excp);
609 vector |= env->excp_prefix;
610 #if defined(TARGET_PPC64)
611 if (excp_model == POWERPC_EXCP_BOOKE) {
612 if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
613 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
614 new_msr |= (target_ulong)1 << MSR_CM;
615 } else {
616 vector = (uint32_t)vector;
618 } else {
619 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
620 vector = (uint32_t)vector;
621 } else {
622 new_msr |= (target_ulong)1 << MSR_SF;
625 #endif
626 /* XXX: we don't use hreg_store_msr here as already have treated
627 * any special case that could occur. Just store MSR and update hflags
629 env->msr = new_msr & env->msr_mask;
630 hreg_compute_hflags(env);
631 env->nip = vector;
632 /* Reset exception state */
633 env->exception_index = POWERPC_EXCP_NONE;
634 env->error_code = 0;
636 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
637 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
638 /* XXX: The BookE changes address space when switching modes,
639 we should probably implement that as different MMU indexes,
640 but for the moment we do it the slow way and flush all. */
641 tlb_flush(env, 1);
645 void do_interrupt(CPUPPCState *env)
647 PowerPCCPU *cpu = ppc_env_get_cpu(env);
649 powerpc_excp(cpu, env->excp_model, env->exception_index);
652 void ppc_hw_interrupt(CPUPPCState *env)
654 PowerPCCPU *cpu = ppc_env_get_cpu(env);
655 int hdice;
657 #if 0
658 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
659 __func__, env, env->pending_interrupts,
660 env->interrupt_request, (int)msr_me, (int)msr_ee);
661 #endif
662 /* External reset */
663 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
664 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
665 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
666 return;
668 /* Machine check exception */
669 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
670 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
671 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
672 return;
674 #if 0 /* TODO */
675 /* External debug exception */
676 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
677 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
678 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
679 return;
681 #endif
682 if (0) {
683 /* XXX: find a suitable condition to enable the hypervisor mode */
684 hdice = env->spr[SPR_LPCR] & 1;
685 } else {
686 hdice = 0;
688 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
689 /* Hypervisor decrementer exception */
690 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
691 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
692 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
693 return;
696 if (msr_ce != 0) {
697 /* External critical interrupt */
698 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
699 /* Taking a critical external interrupt does not clear the external
700 * critical interrupt status
702 #if 0
703 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
704 #endif
705 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
706 return;
709 if (msr_ee != 0) {
710 /* Watchdog timer on embedded PowerPC */
711 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
712 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
713 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
714 return;
716 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
717 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
718 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
719 return;
721 /* Fixed interval timer on embedded PowerPC */
722 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
723 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
724 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
725 return;
727 /* Programmable interval timer on embedded PowerPC */
728 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
729 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
730 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
731 return;
733 /* Decrementer exception */
734 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
735 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
736 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
737 return;
739 /* External interrupt */
740 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
741 /* Taking an external interrupt does not clear the external
742 * interrupt status
744 #if 0
745 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
746 #endif
747 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
748 return;
750 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
751 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
752 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
753 return;
755 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
756 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
757 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
758 return;
760 /* Thermal interrupt */
761 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
762 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
763 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
764 return;
768 #endif /* !CONFIG_USER_ONLY */
770 #if defined(DEBUG_OP)
771 static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
773 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
774 TARGET_FMT_lx "\n", RA, msr);
776 #endif
778 /*****************************************************************************/
779 /* Exceptions processing helpers */
781 void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
782 uint32_t error_code)
784 #if 0
785 printf("Raise exception %3x code : %d\n", exception, error_code);
786 #endif
787 env->exception_index = exception;
788 env->error_code = error_code;
789 cpu_loop_exit(env);
792 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
794 helper_raise_exception_err(env, exception, 0);
797 #if !defined(CONFIG_USER_ONLY)
798 void helper_store_msr(CPUPPCState *env, target_ulong val)
800 val = hreg_store_msr(env, val, 0);
801 if (val != 0) {
802 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
803 helper_raise_exception(env, val);
807 static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
808 target_ulong msrm, int keep_msrh)
810 #if defined(TARGET_PPC64)
811 if (msr_is_64bit(env, msr)) {
812 nip = (uint64_t)nip;
813 msr &= (uint64_t)msrm;
814 } else {
815 nip = (uint32_t)nip;
816 msr = (uint32_t)(msr & msrm);
817 if (keep_msrh) {
818 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
821 #else
822 nip = (uint32_t)nip;
823 msr &= (uint32_t)msrm;
824 #endif
825 /* XXX: beware: this is false if VLE is supported */
826 env->nip = nip & ~((target_ulong)0x00000003);
827 hreg_store_msr(env, msr, 1);
828 #if defined(DEBUG_OP)
829 cpu_dump_rfi(env->nip, env->msr);
830 #endif
831 /* No need to raise an exception here,
832 * as rfi is always the last insn of a TB
834 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
837 void helper_rfi(CPUPPCState *env)
839 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
840 ~((target_ulong)0x783F0000), 1);
843 #if defined(TARGET_PPC64)
844 void helper_rfid(CPUPPCState *env)
846 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
847 ~((target_ulong)0x783F0000), 0);
850 void helper_hrfid(CPUPPCState *env)
852 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
853 ~((target_ulong)0x783F0000), 0);
855 #endif
857 /*****************************************************************************/
858 /* Embedded PowerPC specific helpers */
859 void helper_40x_rfci(CPUPPCState *env)
861 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
862 ~((target_ulong)0xFFFF0000), 0);
865 void helper_rfci(CPUPPCState *env)
867 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
868 ~((target_ulong)0x3FFF0000), 0);
871 void helper_rfdi(CPUPPCState *env)
873 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
874 ~((target_ulong)0x3FFF0000), 0);
877 void helper_rfmci(CPUPPCState *env)
879 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
880 ~((target_ulong)0x3FFF0000), 0);
882 #endif
884 void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
885 uint32_t flags)
887 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
888 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
889 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
890 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
891 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
892 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
893 POWERPC_EXCP_TRAP);
897 #if defined(TARGET_PPC64)
898 void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
899 uint32_t flags)
901 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
902 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
903 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
904 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
905 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
906 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
907 POWERPC_EXCP_TRAP);
910 #endif
912 #if !defined(CONFIG_USER_ONLY)
913 /*****************************************************************************/
914 /* PowerPC 601 specific instructions (POWER bridge) */
916 void helper_rfsvc(CPUPPCState *env)
918 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
921 /* Embedded.Processor Control */
922 static int dbell2irq(target_ulong rb)
924 int msg = rb & DBELL_TYPE_MASK;
925 int irq = -1;
927 switch (msg) {
928 case DBELL_TYPE_DBELL:
929 irq = PPC_INTERRUPT_DOORBELL;
930 break;
931 case DBELL_TYPE_DBELL_CRIT:
932 irq = PPC_INTERRUPT_CDOORBELL;
933 break;
934 case DBELL_TYPE_G_DBELL:
935 case DBELL_TYPE_G_DBELL_CRIT:
936 case DBELL_TYPE_G_DBELL_MC:
937 /* XXX implement */
938 default:
939 break;
942 return irq;
945 void helper_msgclr(CPUPPCState *env, target_ulong rb)
947 int irq = dbell2irq(rb);
949 if (irq < 0) {
950 return;
953 env->pending_interrupts &= ~(1 << irq);
956 void helper_msgsnd(target_ulong rb)
958 int irq = dbell2irq(rb);
959 int pir = rb & DBELL_PIRTAG_MASK;
960 CPUPPCState *cenv;
962 if (irq < 0) {
963 return;
966 for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
967 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
968 cenv->pending_interrupts |= 1 << irq;
969 cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
973 #endif