memory: unfold memory_region_test_and_clear()
[qemu/ar7.git] / target-ppc / excp_helper.c
blob26c57d9a3421a89dfdb82b31cdfe04f6ef4ef1ca
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 ppc_cpu_do_interrupt(CPUState *cs)
43 PowerPCCPU *cpu = POWERPC_CPU(cs);
44 CPUPPCState *env = &cpu->env;
46 env->exception_index = POWERPC_EXCP_NONE;
47 env->error_code = 0;
50 void ppc_hw_interrupt(CPUPPCState *env)
52 env->exception_index = POWERPC_EXCP_NONE;
53 env->error_code = 0;
55 #else /* defined(CONFIG_USER_ONLY) */
56 static inline void dump_syscall(CPUPPCState *env)
58 qemu_log_mask(CPU_LOG_INT, "syscall r0=%016" PRIx64 " r3=%016" PRIx64
59 " r4=%016" PRIx64 " r5=%016" PRIx64 " r6=%016" PRIx64
60 " nip=" TARGET_FMT_lx "\n",
61 ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3),
62 ppc_dump_gpr(env, 4), ppc_dump_gpr(env, 5),
63 ppc_dump_gpr(env, 6), env->nip);
66 /* Note that this function should be greatly optimized
67 * when called with a constant excp, from ppc_hw_interrupt
69 static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
71 CPUPPCState *env = &cpu->env;
72 CPUState *cs;
73 target_ulong msr, new_msr, vector;
74 int srr0, srr1, asrr0, asrr1;
75 int lpes0, lpes1, lev;
77 if (0) {
78 /* XXX: find a suitable condition to enable the hypervisor mode */
79 lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
80 lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
81 } else {
82 /* Those values ensure we won't enter the hypervisor mode */
83 lpes0 = 0;
84 lpes1 = 1;
87 qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
88 " => %08x (%02x)\n", env->nip, excp, env->error_code);
90 /* new srr1 value excluding must-be-zero bits */
91 if (excp_model == POWERPC_EXCP_BOOKE) {
92 msr = env->msr;
93 } else {
94 msr = env->msr & ~0x783f0000ULL;
97 /* new interrupt handler msr */
98 new_msr = env->msr & ((target_ulong)1 << MSR_ME);
100 /* target registers */
101 srr0 = SPR_SRR0;
102 srr1 = SPR_SRR1;
103 asrr0 = -1;
104 asrr1 = -1;
106 switch (excp) {
107 case POWERPC_EXCP_NONE:
108 /* Should never happen */
109 return;
110 case POWERPC_EXCP_CRITICAL: /* Critical input */
111 switch (excp_model) {
112 case POWERPC_EXCP_40x:
113 srr0 = SPR_40x_SRR2;
114 srr1 = SPR_40x_SRR3;
115 break;
116 case POWERPC_EXCP_BOOKE:
117 srr0 = SPR_BOOKE_CSRR0;
118 srr1 = SPR_BOOKE_CSRR1;
119 break;
120 case POWERPC_EXCP_G2:
121 break;
122 default:
123 goto excp_invalid;
125 goto store_next;
126 case POWERPC_EXCP_MCHECK: /* Machine check exception */
127 if (msr_me == 0) {
128 /* Machine check exception is not enabled.
129 * Enter checkstop state.
131 if (qemu_log_enabled()) {
132 qemu_log("Machine check while not allowed. "
133 "Entering checkstop state\n");
134 } else {
135 fprintf(stderr, "Machine check while not allowed. "
136 "Entering checkstop state\n");
138 cs = CPU(cpu);
139 cs->halted = 1;
140 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
142 if (0) {
143 /* XXX: find a suitable condition to enable the hypervisor mode */
144 new_msr |= (target_ulong)MSR_HVB;
147 /* machine check exceptions don't have ME set */
148 new_msr &= ~((target_ulong)1 << MSR_ME);
150 /* XXX: should also have something loaded in DAR / DSISR */
151 switch (excp_model) {
152 case POWERPC_EXCP_40x:
153 srr0 = SPR_40x_SRR2;
154 srr1 = SPR_40x_SRR3;
155 break;
156 case POWERPC_EXCP_BOOKE:
157 /* FIXME: choose one or the other based on CPU type */
158 srr0 = SPR_BOOKE_MCSRR0;
159 srr1 = SPR_BOOKE_MCSRR1;
160 asrr0 = SPR_BOOKE_CSRR0;
161 asrr1 = SPR_BOOKE_CSRR1;
162 break;
163 default:
164 break;
166 goto store_next;
167 case POWERPC_EXCP_DSI: /* Data storage exception */
168 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
169 "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
170 if (lpes1 == 0) {
171 new_msr |= (target_ulong)MSR_HVB;
173 goto store_next;
174 case POWERPC_EXCP_ISI: /* Instruction storage exception */
175 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
176 "\n", msr, env->nip);
177 if (lpes1 == 0) {
178 new_msr |= (target_ulong)MSR_HVB;
180 msr |= env->error_code;
181 goto store_next;
182 case POWERPC_EXCP_EXTERNAL: /* External input */
183 if (lpes0 == 1) {
184 new_msr |= (target_ulong)MSR_HVB;
186 if (env->mpic_proxy) {
187 /* IACK the IRQ on delivery */
188 env->spr[SPR_BOOKE_EPR] = ldl_phys(env->mpic_iack);
190 goto store_next;
191 case POWERPC_EXCP_ALIGN: /* Alignment exception */
192 if (lpes1 == 0) {
193 new_msr |= (target_ulong)MSR_HVB;
195 /* XXX: this is false */
196 /* Get rS/rD and rA from faulting opcode */
197 env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
198 & 0x03FF0000) >> 16;
199 goto store_current;
200 case POWERPC_EXCP_PROGRAM: /* Program exception */
201 switch (env->error_code & ~0xF) {
202 case POWERPC_EXCP_FP:
203 if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
204 LOG_EXCP("Ignore floating point exception\n");
205 env->exception_index = POWERPC_EXCP_NONE;
206 env->error_code = 0;
207 return;
209 if (lpes1 == 0) {
210 new_msr |= (target_ulong)MSR_HVB;
212 msr |= 0x00100000;
213 if (msr_fe0 == msr_fe1) {
214 goto store_next;
216 msr |= 0x00010000;
217 break;
218 case POWERPC_EXCP_INVAL:
219 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
220 if (lpes1 == 0) {
221 new_msr |= (target_ulong)MSR_HVB;
223 msr |= 0x00080000;
224 env->spr[SPR_BOOKE_ESR] = ESR_PIL;
225 break;
226 case POWERPC_EXCP_PRIV:
227 if (lpes1 == 0) {
228 new_msr |= (target_ulong)MSR_HVB;
230 msr |= 0x00040000;
231 env->spr[SPR_BOOKE_ESR] = ESR_PPR;
232 break;
233 case POWERPC_EXCP_TRAP:
234 if (lpes1 == 0) {
235 new_msr |= (target_ulong)MSR_HVB;
237 msr |= 0x00020000;
238 env->spr[SPR_BOOKE_ESR] = ESR_PTR;
239 break;
240 default:
241 /* Should never occur */
242 cpu_abort(env, "Invalid program exception %d. Aborting\n",
243 env->error_code);
244 break;
246 goto store_current;
247 case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
248 if (lpes1 == 0) {
249 new_msr |= (target_ulong)MSR_HVB;
251 goto store_current;
252 case POWERPC_EXCP_SYSCALL: /* System call exception */
253 dump_syscall(env);
254 lev = env->error_code;
255 if ((lev == 1) && cpu_ppc_hypercall) {
256 cpu_ppc_hypercall(cpu);
257 return;
259 if (lev == 1 || (lpes0 == 0 && lpes1 == 0)) {
260 new_msr |= (target_ulong)MSR_HVB;
262 goto store_next;
263 case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
264 goto store_current;
265 case POWERPC_EXCP_DECR: /* Decrementer exception */
266 if (lpes1 == 0) {
267 new_msr |= (target_ulong)MSR_HVB;
269 goto store_next;
270 case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
271 /* FIT on 4xx */
272 LOG_EXCP("FIT exception\n");
273 goto store_next;
274 case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
275 LOG_EXCP("WDT exception\n");
276 switch (excp_model) {
277 case POWERPC_EXCP_BOOKE:
278 srr0 = SPR_BOOKE_CSRR0;
279 srr1 = SPR_BOOKE_CSRR1;
280 break;
281 default:
282 break;
284 goto store_next;
285 case POWERPC_EXCP_DTLB: /* Data TLB error */
286 goto store_next;
287 case POWERPC_EXCP_ITLB: /* Instruction TLB error */
288 goto store_next;
289 case POWERPC_EXCP_DEBUG: /* Debug interrupt */
290 switch (excp_model) {
291 case POWERPC_EXCP_BOOKE:
292 /* FIXME: choose one or the other based on CPU type */
293 srr0 = SPR_BOOKE_DSRR0;
294 srr1 = SPR_BOOKE_DSRR1;
295 asrr0 = SPR_BOOKE_CSRR0;
296 asrr1 = SPR_BOOKE_CSRR1;
297 break;
298 default:
299 break;
301 /* XXX: TODO */
302 cpu_abort(env, "Debug exception is not implemented yet !\n");
303 goto store_next;
304 case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
305 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
306 goto store_current;
307 case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
308 /* XXX: TODO */
309 cpu_abort(env, "Embedded floating point data exception "
310 "is not implemented yet !\n");
311 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
312 goto store_next;
313 case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
314 /* XXX: TODO */
315 cpu_abort(env, "Embedded floating point round exception "
316 "is not implemented yet !\n");
317 env->spr[SPR_BOOKE_ESR] = ESR_SPV;
318 goto store_next;
319 case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
320 /* XXX: TODO */
321 cpu_abort(env,
322 "Performance counter exception is not implemented yet !\n");
323 goto store_next;
324 case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
325 goto store_next;
326 case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
327 srr0 = SPR_BOOKE_CSRR0;
328 srr1 = SPR_BOOKE_CSRR1;
329 goto store_next;
330 case POWERPC_EXCP_RESET: /* System reset exception */
331 if (msr_pow) {
332 /* indicate that we resumed from power save mode */
333 msr |= 0x10000;
334 } else {
335 new_msr &= ~((target_ulong)1 << MSR_ME);
338 if (0) {
339 /* XXX: find a suitable condition to enable the hypervisor mode */
340 new_msr |= (target_ulong)MSR_HVB;
342 goto store_next;
343 case POWERPC_EXCP_DSEG: /* Data segment exception */
344 if (lpes1 == 0) {
345 new_msr |= (target_ulong)MSR_HVB;
347 goto store_next;
348 case POWERPC_EXCP_ISEG: /* Instruction segment exception */
349 if (lpes1 == 0) {
350 new_msr |= (target_ulong)MSR_HVB;
352 goto store_next;
353 case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
354 srr0 = SPR_HSRR0;
355 srr1 = SPR_HSRR1;
356 new_msr |= (target_ulong)MSR_HVB;
357 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
358 goto store_next;
359 case POWERPC_EXCP_TRACE: /* Trace exception */
360 if (lpes1 == 0) {
361 new_msr |= (target_ulong)MSR_HVB;
363 goto store_next;
364 case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
365 srr0 = SPR_HSRR0;
366 srr1 = SPR_HSRR1;
367 new_msr |= (target_ulong)MSR_HVB;
368 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
369 goto store_next;
370 case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
371 srr0 = SPR_HSRR0;
372 srr1 = SPR_HSRR1;
373 new_msr |= (target_ulong)MSR_HVB;
374 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
375 goto store_next;
376 case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
377 srr0 = SPR_HSRR0;
378 srr1 = SPR_HSRR1;
379 new_msr |= (target_ulong)MSR_HVB;
380 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
381 goto store_next;
382 case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
383 srr0 = SPR_HSRR0;
384 srr1 = SPR_HSRR1;
385 new_msr |= (target_ulong)MSR_HVB;
386 new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
387 goto store_next;
388 case POWERPC_EXCP_VPU: /* Vector unavailable exception */
389 if (lpes1 == 0) {
390 new_msr |= (target_ulong)MSR_HVB;
392 goto store_current;
393 case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
394 if (lpes1 == 0) {
395 new_msr |= (target_ulong)MSR_HVB;
397 goto store_current;
398 case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
399 LOG_EXCP("PIT exception\n");
400 goto store_next;
401 case POWERPC_EXCP_IO: /* IO error exception */
402 /* XXX: TODO */
403 cpu_abort(env, "601 IO error exception is not implemented yet !\n");
404 goto store_next;
405 case POWERPC_EXCP_RUNM: /* Run mode exception */
406 /* XXX: TODO */
407 cpu_abort(env, "601 run mode exception is not implemented yet !\n");
408 goto store_next;
409 case POWERPC_EXCP_EMUL: /* Emulation trap exception */
410 /* XXX: TODO */
411 cpu_abort(env, "602 emulation trap exception "
412 "is not implemented yet !\n");
413 goto store_next;
414 case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
415 if (lpes1 == 0) { /* XXX: check this */
416 new_msr |= (target_ulong)MSR_HVB;
418 switch (excp_model) {
419 case POWERPC_EXCP_602:
420 case POWERPC_EXCP_603:
421 case POWERPC_EXCP_603E:
422 case POWERPC_EXCP_G2:
423 goto tlb_miss_tgpr;
424 case POWERPC_EXCP_7x5:
425 goto tlb_miss;
426 case POWERPC_EXCP_74xx:
427 goto tlb_miss_74xx;
428 default:
429 cpu_abort(env, "Invalid instruction TLB miss exception\n");
430 break;
432 break;
433 case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
434 if (lpes1 == 0) { /* XXX: check this */
435 new_msr |= (target_ulong)MSR_HVB;
437 switch (excp_model) {
438 case POWERPC_EXCP_602:
439 case POWERPC_EXCP_603:
440 case POWERPC_EXCP_603E:
441 case POWERPC_EXCP_G2:
442 goto tlb_miss_tgpr;
443 case POWERPC_EXCP_7x5:
444 goto tlb_miss;
445 case POWERPC_EXCP_74xx:
446 goto tlb_miss_74xx;
447 default:
448 cpu_abort(env, "Invalid data load TLB miss exception\n");
449 break;
451 break;
452 case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
453 if (lpes1 == 0) { /* XXX: check this */
454 new_msr |= (target_ulong)MSR_HVB;
456 switch (excp_model) {
457 case POWERPC_EXCP_602:
458 case POWERPC_EXCP_603:
459 case POWERPC_EXCP_603E:
460 case POWERPC_EXCP_G2:
461 tlb_miss_tgpr:
462 /* Swap temporary saved registers with GPRs */
463 if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
464 new_msr |= (target_ulong)1 << MSR_TGPR;
465 hreg_swap_gpr_tgpr(env);
467 goto tlb_miss;
468 case POWERPC_EXCP_7x5:
469 tlb_miss:
470 #if defined(DEBUG_SOFTWARE_TLB)
471 if (qemu_log_enabled()) {
472 const char *es;
473 target_ulong *miss, *cmp;
474 int en;
476 if (excp == POWERPC_EXCP_IFTLB) {
477 es = "I";
478 en = 'I';
479 miss = &env->spr[SPR_IMISS];
480 cmp = &env->spr[SPR_ICMP];
481 } else {
482 if (excp == POWERPC_EXCP_DLTLB) {
483 es = "DL";
484 } else {
485 es = "DS";
487 en = 'D';
488 miss = &env->spr[SPR_DMISS];
489 cmp = &env->spr[SPR_DCMP];
491 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
492 TARGET_FMT_lx " H1 " TARGET_FMT_lx " H2 "
493 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
494 env->spr[SPR_HASH1], env->spr[SPR_HASH2],
495 env->error_code);
497 #endif
498 msr |= env->crf[0] << 28;
499 msr |= env->error_code; /* key, D/I, S/L bits */
500 /* Set way using a LRU mechanism */
501 msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
502 break;
503 case POWERPC_EXCP_74xx:
504 tlb_miss_74xx:
505 #if defined(DEBUG_SOFTWARE_TLB)
506 if (qemu_log_enabled()) {
507 const char *es;
508 target_ulong *miss, *cmp;
509 int en;
511 if (excp == POWERPC_EXCP_IFTLB) {
512 es = "I";
513 en = 'I';
514 miss = &env->spr[SPR_TLBMISS];
515 cmp = &env->spr[SPR_PTEHI];
516 } else {
517 if (excp == POWERPC_EXCP_DLTLB) {
518 es = "DL";
519 } else {
520 es = "DS";
522 en = 'D';
523 miss = &env->spr[SPR_TLBMISS];
524 cmp = &env->spr[SPR_PTEHI];
526 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx " %cC "
527 TARGET_FMT_lx " %08x\n", es, en, *miss, en, *cmp,
528 env->error_code);
530 #endif
531 msr |= env->error_code; /* key bit */
532 break;
533 default:
534 cpu_abort(env, "Invalid data store TLB miss exception\n");
535 break;
537 goto store_next;
538 case POWERPC_EXCP_FPA: /* Floating-point assist exception */
539 /* XXX: TODO */
540 cpu_abort(env, "Floating point assist exception "
541 "is not implemented yet !\n");
542 goto store_next;
543 case POWERPC_EXCP_DABR: /* Data address breakpoint */
544 /* XXX: TODO */
545 cpu_abort(env, "DABR exception is not implemented yet !\n");
546 goto store_next;
547 case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
548 /* XXX: TODO */
549 cpu_abort(env, "IABR exception is not implemented yet !\n");
550 goto store_next;
551 case POWERPC_EXCP_SMI: /* System management interrupt */
552 /* XXX: TODO */
553 cpu_abort(env, "SMI exception is not implemented yet !\n");
554 goto store_next;
555 case POWERPC_EXCP_THERM: /* Thermal interrupt */
556 /* XXX: TODO */
557 cpu_abort(env, "Thermal management exception "
558 "is not implemented yet !\n");
559 goto store_next;
560 case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
561 if (lpes1 == 0) {
562 new_msr |= (target_ulong)MSR_HVB;
564 /* XXX: TODO */
565 cpu_abort(env,
566 "Performance counter exception is not implemented yet !\n");
567 goto store_next;
568 case POWERPC_EXCP_VPUA: /* Vector assist exception */
569 /* XXX: TODO */
570 cpu_abort(env, "VPU assist exception is not implemented yet !\n");
571 goto store_next;
572 case POWERPC_EXCP_SOFTP: /* Soft patch exception */
573 /* XXX: TODO */
574 cpu_abort(env,
575 "970 soft-patch exception is not implemented yet !\n");
576 goto store_next;
577 case POWERPC_EXCP_MAINT: /* Maintenance exception */
578 /* XXX: TODO */
579 cpu_abort(env,
580 "970 maintenance exception is not implemented yet !\n");
581 goto store_next;
582 case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
583 /* XXX: TODO */
584 cpu_abort(env, "Maskable external exception "
585 "is not implemented yet !\n");
586 goto store_next;
587 case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
588 /* XXX: TODO */
589 cpu_abort(env, "Non maskable external exception "
590 "is not implemented yet !\n");
591 goto store_next;
592 default:
593 excp_invalid:
594 cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
595 break;
596 store_current:
597 /* save current instruction location */
598 env->spr[srr0] = env->nip - 4;
599 break;
600 store_next:
601 /* save next instruction location */
602 env->spr[srr0] = env->nip;
603 break;
605 /* Save MSR */
606 env->spr[srr1] = msr;
607 /* If any alternate SRR register are defined, duplicate saved values */
608 if (asrr0 != -1) {
609 env->spr[asrr0] = env->spr[srr0];
611 if (asrr1 != -1) {
612 env->spr[asrr1] = env->spr[srr1];
614 /* If we disactivated any translation, flush TLBs */
615 if (msr & ((1 << MSR_IR) | (1 << MSR_DR))) {
616 tlb_flush(env, 1);
619 #ifdef TARGET_PPC64
620 if (excp_model == POWERPC_EXCP_POWER7) {
621 if (env->spr[SPR_LPCR] & LPCR_ILE) {
622 new_msr |= (target_ulong)1 << MSR_LE;
624 } else if (msr_ile) {
625 new_msr |= (target_ulong)1 << MSR_LE;
627 #else
628 if (msr_ile) {
629 new_msr |= (target_ulong)1 << MSR_LE;
631 #endif
633 /* Jump to handler */
634 vector = env->excp_vectors[excp];
635 if (vector == (target_ulong)-1ULL) {
636 cpu_abort(env, "Raised an exception without defined vector %d\n",
637 excp);
639 vector |= env->excp_prefix;
640 #if defined(TARGET_PPC64)
641 if (excp_model == POWERPC_EXCP_BOOKE) {
642 if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
643 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
644 new_msr |= (target_ulong)1 << MSR_CM;
645 } else {
646 vector = (uint32_t)vector;
648 } else {
649 if (!msr_isf && !(env->mmu_model & POWERPC_MMU_64)) {
650 vector = (uint32_t)vector;
651 } else {
652 new_msr |= (target_ulong)1 << MSR_SF;
655 #endif
656 /* XXX: we don't use hreg_store_msr here as already have treated
657 * any special case that could occur. Just store MSR and update hflags
659 env->msr = new_msr & env->msr_mask;
660 hreg_compute_hflags(env);
661 env->nip = vector;
662 /* Reset exception state */
663 env->exception_index = POWERPC_EXCP_NONE;
664 env->error_code = 0;
666 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
667 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
668 /* XXX: The BookE changes address space when switching modes,
669 we should probably implement that as different MMU indexes,
670 but for the moment we do it the slow way and flush all. */
671 tlb_flush(env, 1);
675 void ppc_cpu_do_interrupt(CPUState *cs)
677 PowerPCCPU *cpu = POWERPC_CPU(cs);
678 CPUPPCState *env = &cpu->env;
680 powerpc_excp(cpu, env->excp_model, env->exception_index);
683 void ppc_hw_interrupt(CPUPPCState *env)
685 PowerPCCPU *cpu = ppc_env_get_cpu(env);
686 int hdice;
687 #if 0
688 CPUState *cs = CPU(cpu);
690 qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
691 __func__, env, env->pending_interrupts,
692 cs->interrupt_request, (int)msr_me, (int)msr_ee);
693 #endif
694 /* External reset */
695 if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
696 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
697 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_RESET);
698 return;
700 /* Machine check exception */
701 if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
702 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
703 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_MCHECK);
704 return;
706 #if 0 /* TODO */
707 /* External debug exception */
708 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
709 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
710 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DEBUG);
711 return;
713 #endif
714 if (0) {
715 /* XXX: find a suitable condition to enable the hypervisor mode */
716 hdice = env->spr[SPR_LPCR] & 1;
717 } else {
718 hdice = 0;
720 if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
721 /* Hypervisor decrementer exception */
722 if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
723 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
724 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
725 return;
728 if (msr_ce != 0) {
729 /* External critical interrupt */
730 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
731 /* Taking a critical external interrupt does not clear the external
732 * critical interrupt status
734 #if 0
735 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
736 #endif
737 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_CRITICAL);
738 return;
741 if (msr_ee != 0) {
742 /* Watchdog timer on embedded PowerPC */
743 if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
744 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
745 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_WDT);
746 return;
748 if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
749 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
750 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORCI);
751 return;
753 /* Fixed interval timer on embedded PowerPC */
754 if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
755 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
756 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_FIT);
757 return;
759 /* Programmable interval timer on embedded PowerPC */
760 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
761 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
762 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PIT);
763 return;
765 /* Decrementer exception */
766 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
767 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
768 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
769 return;
771 /* External interrupt */
772 if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
773 /* Taking an external interrupt does not clear the external
774 * interrupt status
776 #if 0
777 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
778 #endif
779 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_EXTERNAL);
780 return;
782 if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
783 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
784 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DOORI);
785 return;
787 if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
788 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
789 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_PERFM);
790 return;
792 /* Thermal interrupt */
793 if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
794 env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
795 powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_THERM);
796 return;
800 #endif /* !CONFIG_USER_ONLY */
802 #if defined(DEBUG_OP)
803 static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
805 qemu_log("Return from exception at " TARGET_FMT_lx " with flags "
806 TARGET_FMT_lx "\n", RA, msr);
808 #endif
810 /*****************************************************************************/
811 /* Exceptions processing helpers */
813 void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
814 uint32_t error_code)
816 #if 0
817 printf("Raise exception %3x code : %d\n", exception, error_code);
818 #endif
819 env->exception_index = exception;
820 env->error_code = error_code;
821 cpu_loop_exit(env);
824 void helper_raise_exception(CPUPPCState *env, uint32_t exception)
826 helper_raise_exception_err(env, exception, 0);
829 #if !defined(CONFIG_USER_ONLY)
830 void helper_store_msr(CPUPPCState *env, target_ulong val)
832 CPUState *cs;
834 val = hreg_store_msr(env, val, 0);
835 if (val != 0) {
836 cs = CPU(ppc_env_get_cpu(env));
837 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
838 helper_raise_exception(env, val);
842 static inline void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr,
843 target_ulong msrm, int keep_msrh)
845 CPUState *cs = CPU(ppc_env_get_cpu(env));
847 #if defined(TARGET_PPC64)
848 if (msr_is_64bit(env, msr)) {
849 nip = (uint64_t)nip;
850 msr &= (uint64_t)msrm;
851 } else {
852 nip = (uint32_t)nip;
853 msr = (uint32_t)(msr & msrm);
854 if (keep_msrh) {
855 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
858 #else
859 nip = (uint32_t)nip;
860 msr &= (uint32_t)msrm;
861 #endif
862 /* XXX: beware: this is false if VLE is supported */
863 env->nip = nip & ~((target_ulong)0x00000003);
864 hreg_store_msr(env, msr, 1);
865 #if defined(DEBUG_OP)
866 cpu_dump_rfi(env->nip, env->msr);
867 #endif
868 /* No need to raise an exception here,
869 * as rfi is always the last insn of a TB
871 cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
874 void helper_rfi(CPUPPCState *env)
876 if (env->excp_model == POWERPC_EXCP_BOOKE) {
877 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
878 ~((target_ulong)0), 0);
879 } else {
880 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
881 ~((target_ulong)0x783F0000), 1);
885 #if defined(TARGET_PPC64)
886 void helper_rfid(CPUPPCState *env)
888 do_rfi(env, env->spr[SPR_SRR0], env->spr[SPR_SRR1],
889 ~((target_ulong)0x783F0000), 0);
892 void helper_hrfid(CPUPPCState *env)
894 do_rfi(env, env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
895 ~((target_ulong)0x783F0000), 0);
897 #endif
899 /*****************************************************************************/
900 /* Embedded PowerPC specific helpers */
901 void helper_40x_rfci(CPUPPCState *env)
903 do_rfi(env, env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
904 ~((target_ulong)0xFFFF0000), 0);
907 void helper_rfci(CPUPPCState *env)
909 do_rfi(env, env->spr[SPR_BOOKE_CSRR0], env->spr[SPR_BOOKE_CSRR1],
910 ~((target_ulong)0), 0);
913 void helper_rfdi(CPUPPCState *env)
915 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
916 do_rfi(env, env->spr[SPR_BOOKE_DSRR0], env->spr[SPR_BOOKE_DSRR1],
917 ~((target_ulong)0), 0);
920 void helper_rfmci(CPUPPCState *env)
922 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
923 do_rfi(env, env->spr[SPR_BOOKE_MCSRR0], env->spr[SPR_BOOKE_MCSRR1],
924 ~((target_ulong)0), 0);
926 #endif
928 void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
929 uint32_t flags)
931 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
932 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
933 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
934 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
935 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
936 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
937 POWERPC_EXCP_TRAP);
941 #if defined(TARGET_PPC64)
942 void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
943 uint32_t flags)
945 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
946 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
947 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
948 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
949 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
950 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
951 POWERPC_EXCP_TRAP);
954 #endif
956 #if !defined(CONFIG_USER_ONLY)
957 /*****************************************************************************/
958 /* PowerPC 601 specific instructions (POWER bridge) */
960 void helper_rfsvc(CPUPPCState *env)
962 do_rfi(env, env->lr, env->ctr, 0x0000FFFF, 0);
965 /* Embedded.Processor Control */
966 static int dbell2irq(target_ulong rb)
968 int msg = rb & DBELL_TYPE_MASK;
969 int irq = -1;
971 switch (msg) {
972 case DBELL_TYPE_DBELL:
973 irq = PPC_INTERRUPT_DOORBELL;
974 break;
975 case DBELL_TYPE_DBELL_CRIT:
976 irq = PPC_INTERRUPT_CDOORBELL;
977 break;
978 case DBELL_TYPE_G_DBELL:
979 case DBELL_TYPE_G_DBELL_CRIT:
980 case DBELL_TYPE_G_DBELL_MC:
981 /* XXX implement */
982 default:
983 break;
986 return irq;
989 void helper_msgclr(CPUPPCState *env, target_ulong rb)
991 int irq = dbell2irq(rb);
993 if (irq < 0) {
994 return;
997 env->pending_interrupts &= ~(1 << irq);
1000 void helper_msgsnd(target_ulong rb)
1002 int irq = dbell2irq(rb);
1003 int pir = rb & DBELL_PIRTAG_MASK;
1004 CPUState *cs;
1006 if (irq < 0) {
1007 return;
1010 CPU_FOREACH(cs) {
1011 PowerPCCPU *cpu = POWERPC_CPU(cs);
1012 CPUPPCState *cenv = &cpu->env;
1014 if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
1015 cenv->pending_interrupts |= 1 << irq;
1016 cpu_interrupt(cs, CPU_INTERRUPT_HARD);
1020 #endif