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