2 * PowerPC exception emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 #include "helper_regs.h"
25 //#define DEBUG_EXCEPTIONS
27 #ifdef DEBUG_EXCEPTIONS
28 # define LOG_EXCP(...) qemu_log(__VA_ARGS__)
30 # define LOG_EXCP(...) do { } while (0)
33 /*****************************************************************************/
34 /* PowerPC Hypercall emulation */
36 void (*cpu_ppc_hypercall
)(PowerPCCPU
*);
38 /*****************************************************************************/
39 /* Exception processing */
40 #if defined(CONFIG_USER_ONLY)
41 void ppc_cpu_do_interrupt(CPUState
*cs
)
43 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
44 CPUPPCState
*env
= &cpu
->env
;
46 cs
->exception_index
= POWERPC_EXCP_NONE
;
50 void ppc_hw_interrupt(CPUPPCState
*env
)
52 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
54 cs
->exception_index
= POWERPC_EXCP_NONE
;
57 #else /* defined(CONFIG_USER_ONLY) */
58 static inline void dump_syscall(CPUPPCState
*env
)
60 qemu_log_mask(CPU_LOG_INT
, "syscall r0=%016" PRIx64
" r3=%016" PRIx64
61 " r4=%016" PRIx64
" r5=%016" PRIx64
" r6=%016" PRIx64
62 " nip=" TARGET_FMT_lx
"\n",
63 ppc_dump_gpr(env
, 0), ppc_dump_gpr(env
, 3),
64 ppc_dump_gpr(env
, 4), ppc_dump_gpr(env
, 5),
65 ppc_dump_gpr(env
, 6), env
->nip
);
68 /* Note that this function should be greatly optimized
69 * when called with a constant excp, from ppc_hw_interrupt
71 static inline void powerpc_excp(PowerPCCPU
*cpu
, int excp_model
, int excp
)
73 CPUState
*cs
= CPU(cpu
);
74 CPUPPCState
*env
= &cpu
->env
;
75 target_ulong msr
, new_msr
, vector
;
76 int srr0
, srr1
, asrr0
, asrr1
;
77 int lpes0
, lpes1
, lev
;
80 /* XXX: find a suitable condition to enable the hypervisor mode */
81 lpes0
= (env
->spr
[SPR_LPCR
] >> 1) & 1;
82 lpes1
= (env
->spr
[SPR_LPCR
] >> 2) & 1;
84 /* Those values ensure we won't enter the hypervisor mode */
89 qemu_log_mask(CPU_LOG_INT
, "Raise exception at " TARGET_FMT_lx
90 " => %08x (%02x)\n", env
->nip
, excp
, env
->error_code
);
92 /* new srr1 value excluding must-be-zero bits */
93 if (excp_model
== POWERPC_EXCP_BOOKE
) {
96 msr
= env
->msr
& ~0x783f0000ULL
;
99 /* new interrupt handler msr */
100 new_msr
= env
->msr
& ((target_ulong
)1 << MSR_ME
);
102 /* target registers */
109 case POWERPC_EXCP_NONE
:
110 /* Should never happen */
112 case POWERPC_EXCP_CRITICAL
: /* Critical input */
113 switch (excp_model
) {
114 case POWERPC_EXCP_40x
:
118 case POWERPC_EXCP_BOOKE
:
119 srr0
= SPR_BOOKE_CSRR0
;
120 srr1
= SPR_BOOKE_CSRR1
;
122 case POWERPC_EXCP_G2
:
128 case POWERPC_EXCP_MCHECK
: /* Machine check exception */
130 /* Machine check exception is not enabled.
131 * Enter checkstop state.
133 if (qemu_log_enabled()) {
134 qemu_log("Machine check while not allowed. "
135 "Entering checkstop state\n");
137 fprintf(stderr
, "Machine check while not allowed. "
138 "Entering checkstop state\n");
141 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
144 /* XXX: find a suitable condition to enable the hypervisor mode */
145 new_msr
|= (target_ulong
)MSR_HVB
;
148 /* machine check exceptions don't have ME set */
149 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
151 /* XXX: should also have something loaded in DAR / DSISR */
152 switch (excp_model
) {
153 case POWERPC_EXCP_40x
:
157 case POWERPC_EXCP_BOOKE
:
158 /* FIXME: choose one or the other based on CPU type */
159 srr0
= SPR_BOOKE_MCSRR0
;
160 srr1
= SPR_BOOKE_MCSRR1
;
161 asrr0
= SPR_BOOKE_CSRR0
;
162 asrr1
= SPR_BOOKE_CSRR1
;
168 case POWERPC_EXCP_DSI
: /* Data storage exception */
169 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx
" DAR=" TARGET_FMT_lx
170 "\n", env
->spr
[SPR_DSISR
], env
->spr
[SPR_DAR
]);
172 new_msr
|= (target_ulong
)MSR_HVB
;
175 case POWERPC_EXCP_ISI
: /* Instruction storage exception */
176 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx
", nip=" TARGET_FMT_lx
177 "\n", msr
, env
->nip
);
179 new_msr
|= (target_ulong
)MSR_HVB
;
181 msr
|= env
->error_code
;
183 case POWERPC_EXCP_EXTERNAL
: /* External input */
187 new_msr
|= (target_ulong
)MSR_HVB
;
189 if (env
->mpic_proxy
) {
190 /* IACK the IRQ on delivery */
191 env
->spr
[SPR_BOOKE_EPR
] = ldl_phys(cs
->as
, env
->mpic_iack
);
194 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
196 new_msr
|= (target_ulong
)MSR_HVB
;
198 /* XXX: this is false */
199 /* Get rS/rD and rA from faulting opcode */
200 env
->spr
[SPR_DSISR
] |= (cpu_ldl_code(env
, (env
->nip
- 4))
203 case POWERPC_EXCP_PROGRAM
: /* Program exception */
204 switch (env
->error_code
& ~0xF) {
205 case POWERPC_EXCP_FP
:
206 if ((msr_fe0
== 0 && msr_fe1
== 0) || msr_fp
== 0) {
207 LOG_EXCP("Ignore floating point exception\n");
208 cs
->exception_index
= POWERPC_EXCP_NONE
;
213 new_msr
|= (target_ulong
)MSR_HVB
;
216 if (msr_fe0
== msr_fe1
) {
221 case POWERPC_EXCP_INVAL
:
222 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx
"\n", env
->nip
);
224 new_msr
|= (target_ulong
)MSR_HVB
;
227 env
->spr
[SPR_BOOKE_ESR
] = ESR_PIL
;
229 case POWERPC_EXCP_PRIV
:
231 new_msr
|= (target_ulong
)MSR_HVB
;
234 env
->spr
[SPR_BOOKE_ESR
] = ESR_PPR
;
236 case POWERPC_EXCP_TRAP
:
238 new_msr
|= (target_ulong
)MSR_HVB
;
241 env
->spr
[SPR_BOOKE_ESR
] = ESR_PTR
;
244 /* Should never occur */
245 cpu_abort(cs
, "Invalid program exception %d. Aborting\n",
250 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
252 new_msr
|= (target_ulong
)MSR_HVB
;
255 case POWERPC_EXCP_SYSCALL
: /* System call exception */
257 lev
= env
->error_code
;
258 if ((lev
== 1) && cpu_ppc_hypercall
) {
259 cpu_ppc_hypercall(cpu
);
262 if (lev
== 1 || (lpes0
== 0 && lpes1
== 0)) {
263 new_msr
|= (target_ulong
)MSR_HVB
;
266 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
268 case POWERPC_EXCP_DECR
: /* Decrementer exception */
270 new_msr
|= (target_ulong
)MSR_HVB
;
273 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
275 LOG_EXCP("FIT exception\n");
277 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
278 LOG_EXCP("WDT exception\n");
279 switch (excp_model
) {
280 case POWERPC_EXCP_BOOKE
:
281 srr0
= SPR_BOOKE_CSRR0
;
282 srr1
= SPR_BOOKE_CSRR1
;
288 case POWERPC_EXCP_DTLB
: /* Data TLB error */
290 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
292 case POWERPC_EXCP_DEBUG
: /* Debug interrupt */
293 switch (excp_model
) {
294 case POWERPC_EXCP_BOOKE
:
295 /* FIXME: choose one or the other based on CPU type */
296 srr0
= SPR_BOOKE_DSRR0
;
297 srr1
= SPR_BOOKE_DSRR1
;
298 asrr0
= SPR_BOOKE_CSRR0
;
299 asrr1
= SPR_BOOKE_CSRR1
;
305 cpu_abort(cs
, "Debug exception is not implemented yet !\n");
307 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavailable */
308 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
310 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data interrupt */
312 cpu_abort(cs
, "Embedded floating point data exception "
313 "is not implemented yet !\n");
314 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
316 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round interrupt */
318 cpu_abort(cs
, "Embedded floating point round exception "
319 "is not implemented yet !\n");
320 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
322 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor interrupt */
325 "Performance counter exception is not implemented yet !\n");
327 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
329 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
330 srr0
= SPR_BOOKE_CSRR0
;
331 srr1
= SPR_BOOKE_CSRR1
;
333 case POWERPC_EXCP_RESET
: /* System reset exception */
335 /* indicate that we resumed from power save mode */
338 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
342 /* XXX: find a suitable condition to enable the hypervisor mode */
343 new_msr
|= (target_ulong
)MSR_HVB
;
346 case POWERPC_EXCP_DSEG
: /* Data segment exception */
348 new_msr
|= (target_ulong
)MSR_HVB
;
351 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
353 new_msr
|= (target_ulong
)MSR_HVB
;
356 case POWERPC_EXCP_HDECR
: /* Hypervisor decrementer exception */
359 new_msr
|= (target_ulong
)MSR_HVB
;
360 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
362 case POWERPC_EXCP_TRACE
: /* Trace exception */
364 new_msr
|= (target_ulong
)MSR_HVB
;
367 case POWERPC_EXCP_HDSI
: /* Hypervisor data storage exception */
370 new_msr
|= (target_ulong
)MSR_HVB
;
371 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
373 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage exception */
376 new_msr
|= (target_ulong
)MSR_HVB
;
377 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
379 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
382 new_msr
|= (target_ulong
)MSR_HVB
;
383 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
385 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment exception */
388 new_msr
|= (target_ulong
)MSR_HVB
;
389 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
391 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
393 new_msr
|= (target_ulong
)MSR_HVB
;
396 case POWERPC_EXCP_VSXU
: /* VSX unavailable exception */
398 new_msr
|= (target_ulong
)MSR_HVB
;
401 case POWERPC_EXCP_PIT
: /* Programmable interval timer interrupt */
402 LOG_EXCP("PIT exception\n");
404 case POWERPC_EXCP_IO
: /* IO error exception */
406 cpu_abort(cs
, "601 IO error exception is not implemented yet !\n");
408 case POWERPC_EXCP_RUNM
: /* Run mode exception */
410 cpu_abort(cs
, "601 run mode exception is not implemented yet !\n");
412 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
414 cpu_abort(cs
, "602 emulation trap exception "
415 "is not implemented yet !\n");
417 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
418 if (lpes1
== 0) { /* XXX: check this */
419 new_msr
|= (target_ulong
)MSR_HVB
;
421 switch (excp_model
) {
422 case POWERPC_EXCP_602
:
423 case POWERPC_EXCP_603
:
424 case POWERPC_EXCP_603E
:
425 case POWERPC_EXCP_G2
:
427 case POWERPC_EXCP_7x5
:
429 case POWERPC_EXCP_74xx
:
432 cpu_abort(cs
, "Invalid instruction TLB miss exception\n");
436 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
437 if (lpes1
== 0) { /* XXX: check this */
438 new_msr
|= (target_ulong
)MSR_HVB
;
440 switch (excp_model
) {
441 case POWERPC_EXCP_602
:
442 case POWERPC_EXCP_603
:
443 case POWERPC_EXCP_603E
:
444 case POWERPC_EXCP_G2
:
446 case POWERPC_EXCP_7x5
:
448 case POWERPC_EXCP_74xx
:
451 cpu_abort(cs
, "Invalid data load TLB miss exception\n");
455 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
456 if (lpes1
== 0) { /* XXX: check this */
457 new_msr
|= (target_ulong
)MSR_HVB
;
459 switch (excp_model
) {
460 case POWERPC_EXCP_602
:
461 case POWERPC_EXCP_603
:
462 case POWERPC_EXCP_603E
:
463 case POWERPC_EXCP_G2
:
465 /* Swap temporary saved registers with GPRs */
466 if (!(new_msr
& ((target_ulong
)1 << MSR_TGPR
))) {
467 new_msr
|= (target_ulong
)1 << MSR_TGPR
;
468 hreg_swap_gpr_tgpr(env
);
471 case POWERPC_EXCP_7x5
:
473 #if defined(DEBUG_SOFTWARE_TLB)
474 if (qemu_log_enabled()) {
476 target_ulong
*miss
, *cmp
;
479 if (excp
== POWERPC_EXCP_IFTLB
) {
482 miss
= &env
->spr
[SPR_IMISS
];
483 cmp
= &env
->spr
[SPR_ICMP
];
485 if (excp
== POWERPC_EXCP_DLTLB
) {
491 miss
= &env
->spr
[SPR_DMISS
];
492 cmp
= &env
->spr
[SPR_DCMP
];
494 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
495 TARGET_FMT_lx
" H1 " TARGET_FMT_lx
" H2 "
496 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
497 env
->spr
[SPR_HASH1
], env
->spr
[SPR_HASH2
],
501 msr
|= env
->crf
[0] << 28;
502 msr
|= env
->error_code
; /* key, D/I, S/L bits */
503 /* Set way using a LRU mechanism */
504 msr
|= ((env
->last_way
+ 1) & (env
->nb_ways
- 1)) << 17;
506 case POWERPC_EXCP_74xx
:
508 #if defined(DEBUG_SOFTWARE_TLB)
509 if (qemu_log_enabled()) {
511 target_ulong
*miss
, *cmp
;
514 if (excp
== POWERPC_EXCP_IFTLB
) {
517 miss
= &env
->spr
[SPR_TLBMISS
];
518 cmp
= &env
->spr
[SPR_PTEHI
];
520 if (excp
== POWERPC_EXCP_DLTLB
) {
526 miss
= &env
->spr
[SPR_TLBMISS
];
527 cmp
= &env
->spr
[SPR_PTEHI
];
529 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
530 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
534 msr
|= env
->error_code
; /* key bit */
537 cpu_abort(cs
, "Invalid data store TLB miss exception\n");
541 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
543 cpu_abort(cs
, "Floating point assist exception "
544 "is not implemented yet !\n");
546 case POWERPC_EXCP_DABR
: /* Data address breakpoint */
548 cpu_abort(cs
, "DABR exception is not implemented yet !\n");
550 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
552 cpu_abort(cs
, "IABR exception is not implemented yet !\n");
554 case POWERPC_EXCP_SMI
: /* System management interrupt */
556 cpu_abort(cs
, "SMI exception is not implemented yet !\n");
558 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
560 cpu_abort(cs
, "Thermal management exception "
561 "is not implemented yet !\n");
563 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor interrupt */
565 new_msr
|= (target_ulong
)MSR_HVB
;
569 "Performance counter exception is not implemented yet !\n");
571 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
573 cpu_abort(cs
, "VPU assist exception is not implemented yet !\n");
575 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
578 "970 soft-patch exception is not implemented yet !\n");
580 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
583 "970 maintenance exception is not implemented yet !\n");
585 case POWERPC_EXCP_MEXTBR
: /* Maskable external breakpoint */
587 cpu_abort(cs
, "Maskable external exception "
588 "is not implemented yet !\n");
590 case POWERPC_EXCP_NMEXTBR
: /* Non maskable external breakpoint */
592 cpu_abort(cs
, "Non maskable external exception "
593 "is not implemented yet !\n");
597 cpu_abort(cs
, "Invalid PowerPC exception %d. Aborting\n", excp
);
600 /* save current instruction location */
601 env
->spr
[srr0
] = env
->nip
- 4;
604 /* save next instruction location */
605 env
->spr
[srr0
] = env
->nip
;
609 env
->spr
[srr1
] = msr
;
610 /* If any alternate SRR register are defined, duplicate saved values */
612 env
->spr
[asrr0
] = env
->spr
[srr0
];
615 env
->spr
[asrr1
] = env
->spr
[srr1
];
617 /* If we disactivated any translation, flush TLBs */
618 if (msr
& ((1 << MSR_IR
) | (1 << MSR_DR
))) {
623 if (excp_model
== POWERPC_EXCP_POWER7
) {
624 if (env
->spr
[SPR_LPCR
] & LPCR_ILE
) {
625 new_msr
|= (target_ulong
)1 << MSR_LE
;
627 } else if (msr_ile
) {
628 new_msr
|= (target_ulong
)1 << MSR_LE
;
632 new_msr
|= (target_ulong
)1 << MSR_LE
;
636 /* Jump to handler */
637 vector
= env
->excp_vectors
[excp
];
638 if (vector
== (target_ulong
)-1ULL) {
639 cpu_abort(cs
, "Raised an exception without defined vector %d\n",
642 vector
|= env
->excp_prefix
;
643 #if defined(TARGET_PPC64)
644 if (excp_model
== POWERPC_EXCP_BOOKE
) {
645 if (env
->spr
[SPR_BOOKE_EPCR
] & EPCR_ICM
) {
646 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
647 new_msr
|= (target_ulong
)1 << MSR_CM
;
649 vector
= (uint32_t)vector
;
652 if (!msr_isf
&& !(env
->mmu_model
& POWERPC_MMU_64
)) {
653 vector
= (uint32_t)vector
;
655 new_msr
|= (target_ulong
)1 << MSR_SF
;
659 /* XXX: we don't use hreg_store_msr here as already have treated
660 * any special case that could occur. Just store MSR and update hflags
662 env
->msr
= new_msr
& env
->msr_mask
;
663 hreg_compute_hflags(env
);
665 /* Reset exception state */
666 cs
->exception_index
= POWERPC_EXCP_NONE
;
669 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
670 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
671 /* XXX: The BookE changes address space when switching modes,
672 we should probably implement that as different MMU indexes,
673 but for the moment we do it the slow way and flush all. */
678 void ppc_cpu_do_interrupt(CPUState
*cs
)
680 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
681 CPUPPCState
*env
= &cpu
->env
;
683 powerpc_excp(cpu
, env
->excp_model
, cs
->exception_index
);
686 void ppc_hw_interrupt(CPUPPCState
*env
)
688 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
691 CPUState
*cs
= CPU(cpu
);
693 qemu_log_mask(CPU_LOG_INT
, "%s: %p pending %08x req %08x me %d ee %d\n",
694 __func__
, env
, env
->pending_interrupts
,
695 cs
->interrupt_request
, (int)msr_me
, (int)msr_ee
);
698 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_RESET
)) {
699 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_RESET
);
700 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_RESET
);
703 /* Machine check exception */
704 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_MCK
)) {
705 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_MCK
);
706 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_MCHECK
);
710 /* External debug exception */
711 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DEBUG
)) {
712 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DEBUG
);
713 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DEBUG
);
718 /* XXX: find a suitable condition to enable the hypervisor mode */
719 hdice
= env
->spr
[SPR_LPCR
] & 1;
723 if ((msr_ee
!= 0 || msr_hv
== 0 || msr_pr
!= 0) && hdice
!= 0) {
724 /* Hypervisor decrementer exception */
725 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_HDECR
)) {
726 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_HDECR
);
731 /* External critical interrupt */
732 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CEXT
)) {
733 /* Taking a critical external interrupt does not clear the external
734 * critical interrupt status
737 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CEXT
);
739 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_CRITICAL
);
744 /* Watchdog timer on embedded PowerPC */
745 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_WDT
)) {
746 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_WDT
);
747 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_WDT
);
750 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CDOORBELL
)) {
751 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CDOORBELL
);
752 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORCI
);
755 /* Fixed interval timer on embedded PowerPC */
756 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_FIT
)) {
757 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_FIT
);
758 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_FIT
);
761 /* Programmable interval timer on embedded PowerPC */
762 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PIT
)) {
763 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PIT
);
764 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PIT
);
767 /* Decrementer exception */
768 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DECR
)) {
769 if (ppc_decr_clear_on_delivery(env
)) {
770 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DECR
);
772 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DECR
);
775 /* External interrupt */
776 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_EXT
)) {
777 /* Taking an external interrupt does not clear the external
781 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_EXT
);
783 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_EXTERNAL
);
786 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DOORBELL
)) {
787 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DOORBELL
);
788 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORI
);
791 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PERFM
)) {
792 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PERFM
);
793 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PERFM
);
796 /* Thermal interrupt */
797 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_THERM
)) {
798 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_THERM
);
799 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_THERM
);
804 #endif /* !CONFIG_USER_ONLY */
806 #if defined(DEBUG_OP)
807 static void cpu_dump_rfi(target_ulong RA
, target_ulong msr
)
809 qemu_log("Return from exception at " TARGET_FMT_lx
" with flags "
810 TARGET_FMT_lx
"\n", RA
, msr
);
814 /*****************************************************************************/
815 /* Exceptions processing helpers */
817 void helper_raise_exception_err(CPUPPCState
*env
, uint32_t exception
,
820 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
823 printf("Raise exception %3x code : %d\n", exception
, error_code
);
825 cs
->exception_index
= exception
;
826 env
->error_code
= error_code
;
830 void helper_raise_exception(CPUPPCState
*env
, uint32_t exception
)
832 helper_raise_exception_err(env
, exception
, 0);
835 #if !defined(CONFIG_USER_ONLY)
836 void helper_store_msr(CPUPPCState
*env
, target_ulong val
)
840 val
= hreg_store_msr(env
, val
, 0);
842 cs
= CPU(ppc_env_get_cpu(env
));
843 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
844 helper_raise_exception(env
, val
);
848 static inline void do_rfi(CPUPPCState
*env
, target_ulong nip
, target_ulong msr
,
849 target_ulong msrm
, int keep_msrh
)
851 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
853 #if defined(TARGET_PPC64)
854 if (msr_is_64bit(env
, msr
)) {
856 msr
&= (uint64_t)msrm
;
859 msr
= (uint32_t)(msr
& msrm
);
861 msr
|= env
->msr
& ~((uint64_t)0xFFFFFFFF);
866 msr
&= (uint32_t)msrm
;
868 /* XXX: beware: this is false if VLE is supported */
869 env
->nip
= nip
& ~((target_ulong
)0x00000003);
870 hreg_store_msr(env
, msr
, 1);
871 #if defined(DEBUG_OP)
872 cpu_dump_rfi(env
->nip
, env
->msr
);
874 /* No need to raise an exception here,
875 * as rfi is always the last insn of a TB
877 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
880 void helper_rfi(CPUPPCState
*env
)
882 if (env
->excp_model
== POWERPC_EXCP_BOOKE
) {
883 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
884 ~((target_ulong
)0), 0);
886 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
887 ~((target_ulong
)0x783F0000), 1);
891 #if defined(TARGET_PPC64)
892 void helper_rfid(CPUPPCState
*env
)
894 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
895 ~((target_ulong
)0x783F0000), 0);
898 void helper_hrfid(CPUPPCState
*env
)
900 do_rfi(env
, env
->spr
[SPR_HSRR0
], env
->spr
[SPR_HSRR1
],
901 ~((target_ulong
)0x783F0000), 0);
905 /*****************************************************************************/
906 /* Embedded PowerPC specific helpers */
907 void helper_40x_rfci(CPUPPCState
*env
)
909 do_rfi(env
, env
->spr
[SPR_40x_SRR2
], env
->spr
[SPR_40x_SRR3
],
910 ~((target_ulong
)0xFFFF0000), 0);
913 void helper_rfci(CPUPPCState
*env
)
915 do_rfi(env
, env
->spr
[SPR_BOOKE_CSRR0
], env
->spr
[SPR_BOOKE_CSRR1
],
916 ~((target_ulong
)0), 0);
919 void helper_rfdi(CPUPPCState
*env
)
921 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
922 do_rfi(env
, env
->spr
[SPR_BOOKE_DSRR0
], env
->spr
[SPR_BOOKE_DSRR1
],
923 ~((target_ulong
)0), 0);
926 void helper_rfmci(CPUPPCState
*env
)
928 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
929 do_rfi(env
, env
->spr
[SPR_BOOKE_MCSRR0
], env
->spr
[SPR_BOOKE_MCSRR1
],
930 ~((target_ulong
)0), 0);
934 void helper_tw(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
937 if (!likely(!(((int32_t)arg1
< (int32_t)arg2
&& (flags
& 0x10)) ||
938 ((int32_t)arg1
> (int32_t)arg2
&& (flags
& 0x08)) ||
939 ((int32_t)arg1
== (int32_t)arg2
&& (flags
& 0x04)) ||
940 ((uint32_t)arg1
< (uint32_t)arg2
&& (flags
& 0x02)) ||
941 ((uint32_t)arg1
> (uint32_t)arg2
&& (flags
& 0x01))))) {
942 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
947 #if defined(TARGET_PPC64)
948 void helper_td(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
951 if (!likely(!(((int64_t)arg1
< (int64_t)arg2
&& (flags
& 0x10)) ||
952 ((int64_t)arg1
> (int64_t)arg2
&& (flags
& 0x08)) ||
953 ((int64_t)arg1
== (int64_t)arg2
&& (flags
& 0x04)) ||
954 ((uint64_t)arg1
< (uint64_t)arg2
&& (flags
& 0x02)) ||
955 ((uint64_t)arg1
> (uint64_t)arg2
&& (flags
& 0x01))))) {
956 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
962 #if !defined(CONFIG_USER_ONLY)
963 /*****************************************************************************/
964 /* PowerPC 601 specific instructions (POWER bridge) */
966 void helper_rfsvc(CPUPPCState
*env
)
968 do_rfi(env
, env
->lr
, env
->ctr
, 0x0000FFFF, 0);
971 /* Embedded.Processor Control */
972 static int dbell2irq(target_ulong rb
)
974 int msg
= rb
& DBELL_TYPE_MASK
;
978 case DBELL_TYPE_DBELL
:
979 irq
= PPC_INTERRUPT_DOORBELL
;
981 case DBELL_TYPE_DBELL_CRIT
:
982 irq
= PPC_INTERRUPT_CDOORBELL
;
984 case DBELL_TYPE_G_DBELL
:
985 case DBELL_TYPE_G_DBELL_CRIT
:
986 case DBELL_TYPE_G_DBELL_MC
:
995 void helper_msgclr(CPUPPCState
*env
, target_ulong rb
)
997 int irq
= dbell2irq(rb
);
1003 env
->pending_interrupts
&= ~(1 << irq
);
1006 void helper_msgsnd(target_ulong rb
)
1008 int irq
= dbell2irq(rb
);
1009 int pir
= rb
& DBELL_PIRTAG_MASK
;
1017 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
1018 CPUPPCState
*cenv
= &cpu
->env
;
1020 if ((rb
& DBELL_BRDCAST
) || (cenv
->spr
[SPR_BOOKE_PIR
] == pir
)) {
1021 cenv
->pending_interrupts
|= 1 << irq
;
1022 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);