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