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