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
)(CPUPPCState
*);
38 /*****************************************************************************/
39 /* Exception processing */
40 #if defined(CONFIG_USER_ONLY)
41 void do_interrupt(CPUPPCState
*env
)
43 env
->exception_index
= POWERPC_EXCP_NONE
;
47 void ppc_hw_interrupt(CPUPPCState
*env
)
49 env
->exception_index
= POWERPC_EXCP_NONE
;
52 #else /* defined(CONFIG_USER_ONLY) */
53 static inline void dump_syscall(CPUPPCState
*env
)
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
);
63 /* Note that this function should be greatly optimized
64 * when called with a constant excp, from ppc_hw_interrupt
66 static inline void powerpc_excp(CPUPPCState
*env
, int excp_model
, int excp
)
68 target_ulong msr
, new_msr
, vector
;
69 int srr0
, srr1
, asrr0
, asrr1
;
70 int lpes0
, lpes1
, lev
;
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;
77 /* Those values ensure we won't enter the hypervisor mode */
82 qemu_log_mask(CPU_LOG_INT
, "Raise exception at " TARGET_FMT_lx
83 " => %08x (%02x)\n", env
->nip
, excp
, env
->error_code
);
85 /* new srr1 value excluding must-be-zero bits */
86 msr
= env
->msr
& ~0x783f0000ULL
;
88 /* new interrupt handler msr */
89 new_msr
= env
->msr
& ((target_ulong
)1 << MSR_ME
);
91 /* target registers */
98 case POWERPC_EXCP_NONE
:
99 /* Should never happen */
101 case POWERPC_EXCP_CRITICAL
: /* Critical input */
102 switch (excp_model
) {
103 case POWERPC_EXCP_40x
:
107 case POWERPC_EXCP_BOOKE
:
108 srr0
= SPR_BOOKE_CSRR0
;
109 srr1
= SPR_BOOKE_CSRR1
;
111 case POWERPC_EXCP_G2
:
117 case POWERPC_EXCP_MCHECK
: /* Machine check exception */
119 /* Machine check exception is not enabled.
120 * Enter checkstop state.
122 if (qemu_log_enabled()) {
123 qemu_log("Machine check while not allowed. "
124 "Entering checkstop state\n");
126 fprintf(stderr
, "Machine check while not allowed. "
127 "Entering checkstop state\n");
130 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
133 /* XXX: find a suitable condition to enable the hypervisor mode */
134 new_msr
|= (target_ulong
)MSR_HVB
;
137 /* machine check exceptions don't have ME set */
138 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
140 /* XXX: should also have something loaded in DAR / DSISR */
141 switch (excp_model
) {
142 case POWERPC_EXCP_40x
:
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
;
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
]);
160 new_msr
|= (target_ulong
)MSR_HVB
;
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
);
167 new_msr
|= (target_ulong
)MSR_HVB
;
169 msr
|= env
->error_code
;
171 case POWERPC_EXCP_EXTERNAL
: /* External input */
173 new_msr
|= (target_ulong
)MSR_HVB
;
176 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
178 new_msr
|= (target_ulong
)MSR_HVB
;
180 /* XXX: this is false */
181 /* Get rS/rD and rA from faulting opcode */
182 env
->spr
[SPR_DSISR
] |= (cpu_ldl_code(env
, (env
->nip
- 4))
185 case POWERPC_EXCP_PROGRAM
: /* Program exception */
186 switch (env
->error_code
& ~0xF) {
187 case POWERPC_EXCP_FP
:
188 if ((msr_fe0
== 0 && msr_fe1
== 0) || msr_fp
== 0) {
189 LOG_EXCP("Ignore floating point exception\n");
190 env
->exception_index
= POWERPC_EXCP_NONE
;
195 new_msr
|= (target_ulong
)MSR_HVB
;
198 if (msr_fe0
== msr_fe1
) {
203 case POWERPC_EXCP_INVAL
:
204 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx
"\n", env
->nip
);
206 new_msr
|= (target_ulong
)MSR_HVB
;
209 env
->spr
[SPR_BOOKE_ESR
] = ESR_PIL
;
211 case POWERPC_EXCP_PRIV
:
213 new_msr
|= (target_ulong
)MSR_HVB
;
216 env
->spr
[SPR_BOOKE_ESR
] = ESR_PPR
;
218 case POWERPC_EXCP_TRAP
:
220 new_msr
|= (target_ulong
)MSR_HVB
;
223 env
->spr
[SPR_BOOKE_ESR
] = ESR_PTR
;
226 /* Should never occur */
227 cpu_abort(env
, "Invalid program exception %d. Aborting\n",
232 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
234 new_msr
|= (target_ulong
)MSR_HVB
;
237 case POWERPC_EXCP_SYSCALL
: /* System call exception */
239 lev
= env
->error_code
;
240 if ((lev
== 1) && cpu_ppc_hypercall
) {
241 cpu_ppc_hypercall(env
);
244 if (lev
== 1 || (lpes0
== 0 && lpes1
== 0)) {
245 new_msr
|= (target_ulong
)MSR_HVB
;
248 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
250 case POWERPC_EXCP_DECR
: /* Decrementer exception */
252 new_msr
|= (target_ulong
)MSR_HVB
;
255 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
257 LOG_EXCP("FIT exception\n");
259 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
260 LOG_EXCP("WDT exception\n");
261 switch (excp_model
) {
262 case POWERPC_EXCP_BOOKE
:
263 srr0
= SPR_BOOKE_CSRR0
;
264 srr1
= SPR_BOOKE_CSRR1
;
270 case POWERPC_EXCP_DTLB
: /* Data TLB error */
272 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
274 case POWERPC_EXCP_DEBUG
: /* Debug interrupt */
275 switch (excp_model
) {
276 case POWERPC_EXCP_BOOKE
:
277 srr0
= SPR_BOOKE_DSRR0
;
278 srr1
= SPR_BOOKE_DSRR1
;
279 asrr0
= SPR_BOOKE_CSRR0
;
280 asrr1
= SPR_BOOKE_CSRR1
;
286 cpu_abort(env
, "Debug exception is not implemented yet !\n");
288 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavailable */
289 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
291 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data interrupt */
293 cpu_abort(env
, "Embedded floating point data exception "
294 "is not implemented yet !\n");
295 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
297 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round interrupt */
299 cpu_abort(env
, "Embedded floating point round exception "
300 "is not implemented yet !\n");
301 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
303 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor interrupt */
306 "Performance counter exception is not implemented yet !\n");
308 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
310 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
311 srr0
= SPR_BOOKE_CSRR0
;
312 srr1
= SPR_BOOKE_CSRR1
;
314 case POWERPC_EXCP_RESET
: /* System reset exception */
316 /* indicate that we resumed from power save mode */
319 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
323 /* XXX: find a suitable condition to enable the hypervisor mode */
324 new_msr
|= (target_ulong
)MSR_HVB
;
327 case POWERPC_EXCP_DSEG
: /* Data segment exception */
329 new_msr
|= (target_ulong
)MSR_HVB
;
332 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
334 new_msr
|= (target_ulong
)MSR_HVB
;
337 case POWERPC_EXCP_HDECR
: /* Hypervisor decrementer exception */
340 new_msr
|= (target_ulong
)MSR_HVB
;
341 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
343 case POWERPC_EXCP_TRACE
: /* Trace exception */
345 new_msr
|= (target_ulong
)MSR_HVB
;
348 case POWERPC_EXCP_HDSI
: /* Hypervisor data storage exception */
351 new_msr
|= (target_ulong
)MSR_HVB
;
352 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
354 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage exception */
357 new_msr
|= (target_ulong
)MSR_HVB
;
358 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
360 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
363 new_msr
|= (target_ulong
)MSR_HVB
;
364 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
366 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment exception */
369 new_msr
|= (target_ulong
)MSR_HVB
;
370 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
372 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
374 new_msr
|= (target_ulong
)MSR_HVB
;
377 case POWERPC_EXCP_PIT
: /* Programmable interval timer interrupt */
378 LOG_EXCP("PIT exception\n");
380 case POWERPC_EXCP_IO
: /* IO error exception */
382 cpu_abort(env
, "601 IO error exception is not implemented yet !\n");
384 case POWERPC_EXCP_RUNM
: /* Run mode exception */
386 cpu_abort(env
, "601 run mode exception is not implemented yet !\n");
388 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
390 cpu_abort(env
, "602 emulation trap exception "
391 "is not implemented yet !\n");
393 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
394 if (lpes1
== 0) { /* XXX: check this */
395 new_msr
|= (target_ulong
)MSR_HVB
;
397 switch (excp_model
) {
398 case POWERPC_EXCP_602
:
399 case POWERPC_EXCP_603
:
400 case POWERPC_EXCP_603E
:
401 case POWERPC_EXCP_G2
:
403 case POWERPC_EXCP_7x5
:
405 case POWERPC_EXCP_74xx
:
408 cpu_abort(env
, "Invalid instruction TLB miss exception\n");
412 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
413 if (lpes1
== 0) { /* XXX: check this */
414 new_msr
|= (target_ulong
)MSR_HVB
;
416 switch (excp_model
) {
417 case POWERPC_EXCP_602
:
418 case POWERPC_EXCP_603
:
419 case POWERPC_EXCP_603E
:
420 case POWERPC_EXCP_G2
:
422 case POWERPC_EXCP_7x5
:
424 case POWERPC_EXCP_74xx
:
427 cpu_abort(env
, "Invalid data load TLB miss exception\n");
431 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
432 if (lpes1
== 0) { /* XXX: check this */
433 new_msr
|= (target_ulong
)MSR_HVB
;
435 switch (excp_model
) {
436 case POWERPC_EXCP_602
:
437 case POWERPC_EXCP_603
:
438 case POWERPC_EXCP_603E
:
439 case POWERPC_EXCP_G2
:
441 /* Swap temporary saved registers with GPRs */
442 if (!(new_msr
& ((target_ulong
)1 << MSR_TGPR
))) {
443 new_msr
|= (target_ulong
)1 << MSR_TGPR
;
444 hreg_swap_gpr_tgpr(env
);
447 case POWERPC_EXCP_7x5
:
449 #if defined(DEBUG_SOFTWARE_TLB)
450 if (qemu_log_enabled()) {
452 target_ulong
*miss
, *cmp
;
455 if (excp
== POWERPC_EXCP_IFTLB
) {
458 miss
= &env
->spr
[SPR_IMISS
];
459 cmp
= &env
->spr
[SPR_ICMP
];
461 if (excp
== POWERPC_EXCP_DLTLB
) {
467 miss
= &env
->spr
[SPR_DMISS
];
468 cmp
= &env
->spr
[SPR_DCMP
];
470 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
471 TARGET_FMT_lx
" H1 " TARGET_FMT_lx
" H2 "
472 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
473 env
->spr
[SPR_HASH1
], env
->spr
[SPR_HASH2
],
477 msr
|= env
->crf
[0] << 28;
478 msr
|= env
->error_code
; /* key, D/I, S/L bits */
479 /* Set way using a LRU mechanism */
480 msr
|= ((env
->last_way
+ 1) & (env
->nb_ways
- 1)) << 17;
482 case POWERPC_EXCP_74xx
:
484 #if defined(DEBUG_SOFTWARE_TLB)
485 if (qemu_log_enabled()) {
487 target_ulong
*miss
, *cmp
;
490 if (excp
== POWERPC_EXCP_IFTLB
) {
493 miss
= &env
->spr
[SPR_TLBMISS
];
494 cmp
= &env
->spr
[SPR_PTEHI
];
496 if (excp
== POWERPC_EXCP_DLTLB
) {
502 miss
= &env
->spr
[SPR_TLBMISS
];
503 cmp
= &env
->spr
[SPR_PTEHI
];
505 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
506 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
510 msr
|= env
->error_code
; /* key bit */
513 cpu_abort(env
, "Invalid data store TLB miss exception\n");
517 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
519 cpu_abort(env
, "Floating point assist exception "
520 "is not implemented yet !\n");
522 case POWERPC_EXCP_DABR
: /* Data address breakpoint */
524 cpu_abort(env
, "DABR exception is not implemented yet !\n");
526 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
528 cpu_abort(env
, "IABR exception is not implemented yet !\n");
530 case POWERPC_EXCP_SMI
: /* System management interrupt */
532 cpu_abort(env
, "SMI exception is not implemented yet !\n");
534 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
536 cpu_abort(env
, "Thermal management exception "
537 "is not implemented yet !\n");
539 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor interrupt */
541 new_msr
|= (target_ulong
)MSR_HVB
;
545 "Performance counter exception is not implemented yet !\n");
547 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
549 cpu_abort(env
, "VPU assist exception is not implemented yet !\n");
551 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
554 "970 soft-patch exception is not implemented yet !\n");
556 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
559 "970 maintenance exception is not implemented yet !\n");
561 case POWERPC_EXCP_MEXTBR
: /* Maskable external breakpoint */
563 cpu_abort(env
, "Maskable external exception "
564 "is not implemented yet !\n");
566 case POWERPC_EXCP_NMEXTBR
: /* Non maskable external breakpoint */
568 cpu_abort(env
, "Non maskable external exception "
569 "is not implemented yet !\n");
573 cpu_abort(env
, "Invalid PowerPC exception %d. Aborting\n", excp
);
576 /* save current instruction location */
577 env
->spr
[srr0
] = env
->nip
- 4;
580 /* save next instruction location */
581 env
->spr
[srr0
] = env
->nip
;
585 env
->spr
[srr1
] = msr
;
586 /* If any alternate SRR register are defined, duplicate saved values */
588 env
->spr
[asrr0
] = env
->spr
[srr0
];
591 env
->spr
[asrr1
] = env
->spr
[srr1
];
593 /* If we disactivated any translation, flush TLBs */
594 if (msr
& ((1 << MSR_IR
) | (1 << MSR_DR
))) {
599 new_msr
|= (target_ulong
)1 << MSR_LE
;
602 /* Jump to handler */
603 vector
= env
->excp_vectors
[excp
];
604 if (vector
== (target_ulong
)-1ULL) {
605 cpu_abort(env
, "Raised an exception without defined vector %d\n",
608 vector
|= env
->excp_prefix
;
609 #if defined(TARGET_PPC64)
610 if (excp_model
== POWERPC_EXCP_BOOKE
) {
611 if (env
->spr
[SPR_BOOKE_EPCR
] & EPCR_ICM
) {
612 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
613 new_msr
|= (target_ulong
)1 << MSR_CM
;
615 vector
= (uint32_t)vector
;
618 if (!msr_isf
&& !(env
->mmu_model
& POWERPC_MMU_64
)) {
619 vector
= (uint32_t)vector
;
621 new_msr
|= (target_ulong
)1 << MSR_SF
;
625 /* XXX: we don't use hreg_store_msr here as already have treated
626 * any special case that could occur. Just store MSR and update hflags
628 env
->msr
= new_msr
& env
->msr_mask
;
629 hreg_compute_hflags(env
);
631 /* Reset exception state */
632 env
->exception_index
= POWERPC_EXCP_NONE
;
635 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
636 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
637 /* XXX: The BookE changes address space when switching modes,
638 we should probably implement that as different MMU indexes,
639 but for the moment we do it the slow way and flush all. */
644 void do_interrupt(CPUPPCState
*env
)
646 powerpc_excp(env
, env
->excp_model
, env
->exception_index
);
649 void ppc_hw_interrupt(CPUPPCState
*env
)
654 qemu_log_mask(CPU_LOG_INT
, "%s: %p pending %08x req %08x me %d ee %d\n",
655 __func__
, env
, env
->pending_interrupts
,
656 env
->interrupt_request
, (int)msr_me
, (int)msr_ee
);
659 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_RESET
)) {
660 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_RESET
);
661 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_RESET
);
664 /* Machine check exception */
665 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_MCK
)) {
666 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_MCK
);
667 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_MCHECK
);
671 /* External debug exception */
672 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DEBUG
)) {
673 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DEBUG
);
674 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_DEBUG
);
679 /* XXX: find a suitable condition to enable the hypervisor mode */
680 hdice
= env
->spr
[SPR_LPCR
] & 1;
684 if ((msr_ee
!= 0 || msr_hv
== 0 || msr_pr
!= 0) && hdice
!= 0) {
685 /* Hypervisor decrementer exception */
686 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_HDECR
)) {
687 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_HDECR
);
688 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_HDECR
);
693 /* External critical interrupt */
694 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CEXT
)) {
695 /* Taking a critical external interrupt does not clear the external
696 * critical interrupt status
699 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CEXT
);
701 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_CRITICAL
);
706 /* Watchdog timer on embedded PowerPC */
707 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_WDT
)) {
708 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_WDT
);
709 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_WDT
);
712 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CDOORBELL
)) {
713 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CDOORBELL
);
714 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_DOORCI
);
717 /* Fixed interval timer on embedded PowerPC */
718 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_FIT
)) {
719 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_FIT
);
720 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_FIT
);
723 /* Programmable interval timer on embedded PowerPC */
724 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PIT
)) {
725 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PIT
);
726 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_PIT
);
729 /* Decrementer exception */
730 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DECR
)) {
731 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DECR
);
732 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_DECR
);
735 /* External interrupt */
736 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_EXT
)) {
737 /* Taking an external interrupt does not clear the external
741 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_EXT
);
743 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_EXTERNAL
);
746 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DOORBELL
)) {
747 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DOORBELL
);
748 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_DOORI
);
751 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PERFM
)) {
752 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PERFM
);
753 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_PERFM
);
756 /* Thermal interrupt */
757 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_THERM
)) {
758 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_THERM
);
759 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_THERM
);
764 #endif /* !CONFIG_USER_ONLY */
766 #if defined(DEBUG_OP)
767 static void cpu_dump_rfi(target_ulong RA
, target_ulong msr
)
769 qemu_log("Return from exception at " TARGET_FMT_lx
" with flags "
770 TARGET_FMT_lx
"\n", RA
, msr
);
774 /*****************************************************************************/
775 /* Exceptions processing helpers */
777 void helper_raise_exception_err(CPUPPCState
*env
, uint32_t exception
,
781 printf("Raise exception %3x code : %d\n", exception
, error_code
);
783 env
->exception_index
= exception
;
784 env
->error_code
= error_code
;
788 void helper_raise_exception(CPUPPCState
*env
, uint32_t exception
)
790 helper_raise_exception_err(env
, exception
, 0);
793 #if !defined(CONFIG_USER_ONLY)
794 void helper_store_msr(CPUPPCState
*env
, target_ulong val
)
796 val
= hreg_store_msr(env
, val
, 0);
798 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
799 helper_raise_exception(env
, val
);
803 static inline void do_rfi(CPUPPCState
*env
, target_ulong nip
, target_ulong msr
,
804 target_ulong msrm
, int keep_msrh
)
806 #if defined(TARGET_PPC64)
807 if (msr_is_64bit(env
, msr
)) {
809 msr
&= (uint64_t)msrm
;
812 msr
= (uint32_t)(msr
& msrm
);
814 msr
|= env
->msr
& ~((uint64_t)0xFFFFFFFF);
819 msr
&= (uint32_t)msrm
;
821 /* XXX: beware: this is false if VLE is supported */
822 env
->nip
= nip
& ~((target_ulong
)0x00000003);
823 hreg_store_msr(env
, msr
, 1);
824 #if defined(DEBUG_OP)
825 cpu_dump_rfi(env
->nip
, env
->msr
);
827 /* No need to raise an exception here,
828 * as rfi is always the last insn of a TB
830 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
833 void helper_rfi(CPUPPCState
*env
)
835 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
836 ~((target_ulong
)0x783F0000), 1);
839 #if defined(TARGET_PPC64)
840 void helper_rfid(CPUPPCState
*env
)
842 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
843 ~((target_ulong
)0x783F0000), 0);
846 void helper_hrfid(CPUPPCState
*env
)
848 do_rfi(env
, env
->spr
[SPR_HSRR0
], env
->spr
[SPR_HSRR1
],
849 ~((target_ulong
)0x783F0000), 0);
853 /*****************************************************************************/
854 /* Embedded PowerPC specific helpers */
855 void helper_40x_rfci(CPUPPCState
*env
)
857 do_rfi(env
, env
->spr
[SPR_40x_SRR2
], env
->spr
[SPR_40x_SRR3
],
858 ~((target_ulong
)0xFFFF0000), 0);
861 void helper_rfci(CPUPPCState
*env
)
863 do_rfi(env
, env
->spr
[SPR_BOOKE_CSRR0
], SPR_BOOKE_CSRR1
,
864 ~((target_ulong
)0x3FFF0000), 0);
867 void helper_rfdi(CPUPPCState
*env
)
869 do_rfi(env
, env
->spr
[SPR_BOOKE_DSRR0
], SPR_BOOKE_DSRR1
,
870 ~((target_ulong
)0x3FFF0000), 0);
873 void helper_rfmci(CPUPPCState
*env
)
875 do_rfi(env
, env
->spr
[SPR_BOOKE_MCSRR0
], SPR_BOOKE_MCSRR1
,
876 ~((target_ulong
)0x3FFF0000), 0);
880 void helper_tw(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
883 if (!likely(!(((int32_t)arg1
< (int32_t)arg2
&& (flags
& 0x10)) ||
884 ((int32_t)arg1
> (int32_t)arg2
&& (flags
& 0x08)) ||
885 ((int32_t)arg1
== (int32_t)arg2
&& (flags
& 0x04)) ||
886 ((uint32_t)arg1
< (uint32_t)arg2
&& (flags
& 0x02)) ||
887 ((uint32_t)arg1
> (uint32_t)arg2
&& (flags
& 0x01))))) {
888 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
893 #if defined(TARGET_PPC64)
894 void helper_td(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
897 if (!likely(!(((int64_t)arg1
< (int64_t)arg2
&& (flags
& 0x10)) ||
898 ((int64_t)arg1
> (int64_t)arg2
&& (flags
& 0x08)) ||
899 ((int64_t)arg1
== (int64_t)arg2
&& (flags
& 0x04)) ||
900 ((uint64_t)arg1
< (uint64_t)arg2
&& (flags
& 0x02)) ||
901 ((uint64_t)arg1
> (uint64_t)arg2
&& (flags
& 0x01))))) {
902 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
908 #if !defined(CONFIG_USER_ONLY)
909 /*****************************************************************************/
910 /* PowerPC 601 specific instructions (POWER bridge) */
912 void helper_rfsvc(CPUPPCState
*env
)
914 do_rfi(env
, env
->lr
, env
->ctr
, 0x0000FFFF, 0);
917 /* Embedded.Processor Control */
918 static int dbell2irq(target_ulong rb
)
920 int msg
= rb
& DBELL_TYPE_MASK
;
924 case DBELL_TYPE_DBELL
:
925 irq
= PPC_INTERRUPT_DOORBELL
;
927 case DBELL_TYPE_DBELL_CRIT
:
928 irq
= PPC_INTERRUPT_CDOORBELL
;
930 case DBELL_TYPE_G_DBELL
:
931 case DBELL_TYPE_G_DBELL_CRIT
:
932 case DBELL_TYPE_G_DBELL_MC
:
941 void helper_msgclr(CPUPPCState
*env
, target_ulong rb
)
943 int irq
= dbell2irq(rb
);
949 env
->pending_interrupts
&= ~(1 << irq
);
952 void helper_msgsnd(target_ulong rb
)
954 int irq
= dbell2irq(rb
);
955 int pir
= rb
& DBELL_PIRTAG_MASK
;
962 for (cenv
= first_cpu
; cenv
!= NULL
; cenv
= cenv
->next_cpu
) {
963 if ((rb
& DBELL_BRDCAST
) || (cenv
->spr
[SPR_BOOKE_PIR
] == pir
)) {
964 cenv
->pending_interrupts
|= 1 << irq
;
965 cpu_interrupt(cenv
, CPU_INTERRUPT_HARD
);