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