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