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 env
->exception_index
= POWERPC_EXCP_NONE
;
50 void ppc_hw_interrupt(CPUPPCState
*env
)
52 env
->exception_index
= POWERPC_EXCP_NONE
;
55 #else /* defined(CONFIG_USER_ONLY) */
56 static inline void dump_syscall(CPUPPCState
*env
)
58 qemu_log_mask(CPU_LOG_INT
, "syscall r0=%016" PRIx64
" r3=%016" PRIx64
59 " r4=%016" PRIx64
" r5=%016" PRIx64
" r6=%016" PRIx64
60 " nip=" TARGET_FMT_lx
"\n",
61 ppc_dump_gpr(env
, 0), ppc_dump_gpr(env
, 3),
62 ppc_dump_gpr(env
, 4), ppc_dump_gpr(env
, 5),
63 ppc_dump_gpr(env
, 6), env
->nip
);
66 /* Note that this function should be greatly optimized
67 * when called with a constant excp, from ppc_hw_interrupt
69 static inline void powerpc_excp(PowerPCCPU
*cpu
, int excp_model
, int excp
)
71 CPUPPCState
*env
= &cpu
->env
;
73 target_ulong msr
, new_msr
, vector
;
74 int srr0
, srr1
, asrr0
, asrr1
;
75 int lpes0
, lpes1
, lev
;
78 /* XXX: find a suitable condition to enable the hypervisor mode */
79 lpes0
= (env
->spr
[SPR_LPCR
] >> 1) & 1;
80 lpes1
= (env
->spr
[SPR_LPCR
] >> 2) & 1;
82 /* Those values ensure we won't enter the hypervisor mode */
87 qemu_log_mask(CPU_LOG_INT
, "Raise exception at " TARGET_FMT_lx
88 " => %08x (%02x)\n", env
->nip
, excp
, env
->error_code
);
90 /* new srr1 value excluding must-be-zero bits */
91 if (excp_model
== POWERPC_EXCP_BOOKE
) {
94 msr
= env
->msr
& ~0x783f0000ULL
;
97 /* new interrupt handler msr */
98 new_msr
= env
->msr
& ((target_ulong
)1 << MSR_ME
);
100 /* target registers */
107 case POWERPC_EXCP_NONE
:
108 /* Should never happen */
110 case POWERPC_EXCP_CRITICAL
: /* Critical input */
111 switch (excp_model
) {
112 case POWERPC_EXCP_40x
:
116 case POWERPC_EXCP_BOOKE
:
117 srr0
= SPR_BOOKE_CSRR0
;
118 srr1
= SPR_BOOKE_CSRR1
;
120 case POWERPC_EXCP_G2
:
126 case POWERPC_EXCP_MCHECK
: /* Machine check exception */
128 /* Machine check exception is not enabled.
129 * Enter checkstop state.
131 if (qemu_log_enabled()) {
132 qemu_log("Machine check while not allowed. "
133 "Entering checkstop state\n");
135 fprintf(stderr
, "Machine check while not allowed. "
136 "Entering checkstop state\n");
140 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
143 /* XXX: find a suitable condition to enable the hypervisor mode */
144 new_msr
|= (target_ulong
)MSR_HVB
;
147 /* machine check exceptions don't have ME set */
148 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
150 /* XXX: should also have something loaded in DAR / DSISR */
151 switch (excp_model
) {
152 case POWERPC_EXCP_40x
:
156 case POWERPC_EXCP_BOOKE
:
157 /* FIXME: choose one or the other based on CPU type */
158 srr0
= SPR_BOOKE_MCSRR0
;
159 srr1
= SPR_BOOKE_MCSRR1
;
160 asrr0
= SPR_BOOKE_CSRR0
;
161 asrr1
= SPR_BOOKE_CSRR1
;
167 case POWERPC_EXCP_DSI
: /* Data storage exception */
168 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx
" DAR=" TARGET_FMT_lx
169 "\n", env
->spr
[SPR_DSISR
], env
->spr
[SPR_DAR
]);
171 new_msr
|= (target_ulong
)MSR_HVB
;
174 case POWERPC_EXCP_ISI
: /* Instruction storage exception */
175 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx
", nip=" TARGET_FMT_lx
176 "\n", msr
, env
->nip
);
178 new_msr
|= (target_ulong
)MSR_HVB
;
180 msr
|= env
->error_code
;
182 case POWERPC_EXCP_EXTERNAL
: /* External input */
184 new_msr
|= (target_ulong
)MSR_HVB
;
186 if (env
->mpic_proxy
) {
187 /* IACK the IRQ on delivery */
188 env
->spr
[SPR_BOOKE_EPR
] = ldl_phys(env
->mpic_iack
);
191 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
193 new_msr
|= (target_ulong
)MSR_HVB
;
195 /* XXX: this is false */
196 /* Get rS/rD and rA from faulting opcode */
197 env
->spr
[SPR_DSISR
] |= (cpu_ldl_code(env
, (env
->nip
- 4))
200 case POWERPC_EXCP_PROGRAM
: /* Program exception */
201 switch (env
->error_code
& ~0xF) {
202 case POWERPC_EXCP_FP
:
203 if ((msr_fe0
== 0 && msr_fe1
== 0) || msr_fp
== 0) {
204 LOG_EXCP("Ignore floating point exception\n");
205 env
->exception_index
= POWERPC_EXCP_NONE
;
210 new_msr
|= (target_ulong
)MSR_HVB
;
213 if (msr_fe0
== msr_fe1
) {
218 case POWERPC_EXCP_INVAL
:
219 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx
"\n", env
->nip
);
221 new_msr
|= (target_ulong
)MSR_HVB
;
224 env
->spr
[SPR_BOOKE_ESR
] = ESR_PIL
;
226 case POWERPC_EXCP_PRIV
:
228 new_msr
|= (target_ulong
)MSR_HVB
;
231 env
->spr
[SPR_BOOKE_ESR
] = ESR_PPR
;
233 case POWERPC_EXCP_TRAP
:
235 new_msr
|= (target_ulong
)MSR_HVB
;
238 env
->spr
[SPR_BOOKE_ESR
] = ESR_PTR
;
241 /* Should never occur */
242 cpu_abort(env
, "Invalid program exception %d. Aborting\n",
247 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
249 new_msr
|= (target_ulong
)MSR_HVB
;
252 case POWERPC_EXCP_SYSCALL
: /* System call exception */
254 lev
= env
->error_code
;
255 if ((lev
== 1) && cpu_ppc_hypercall
) {
256 cpu_ppc_hypercall(cpu
);
259 if (lev
== 1 || (lpes0
== 0 && lpes1
== 0)) {
260 new_msr
|= (target_ulong
)MSR_HVB
;
263 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
265 case POWERPC_EXCP_DECR
: /* Decrementer exception */
267 new_msr
|= (target_ulong
)MSR_HVB
;
270 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
272 LOG_EXCP("FIT exception\n");
274 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
275 LOG_EXCP("WDT exception\n");
276 switch (excp_model
) {
277 case POWERPC_EXCP_BOOKE
:
278 srr0
= SPR_BOOKE_CSRR0
;
279 srr1
= SPR_BOOKE_CSRR1
;
285 case POWERPC_EXCP_DTLB
: /* Data TLB error */
287 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
289 case POWERPC_EXCP_DEBUG
: /* Debug interrupt */
290 switch (excp_model
) {
291 case POWERPC_EXCP_BOOKE
:
292 /* FIXME: choose one or the other based on CPU type */
293 srr0
= SPR_BOOKE_DSRR0
;
294 srr1
= SPR_BOOKE_DSRR1
;
295 asrr0
= SPR_BOOKE_CSRR0
;
296 asrr1
= SPR_BOOKE_CSRR1
;
302 cpu_abort(env
, "Debug exception is not implemented yet !\n");
304 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavailable */
305 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
307 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data interrupt */
309 cpu_abort(env
, "Embedded floating point data exception "
310 "is not implemented yet !\n");
311 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
313 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round interrupt */
315 cpu_abort(env
, "Embedded floating point round exception "
316 "is not implemented yet !\n");
317 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
319 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor interrupt */
322 "Performance counter exception is not implemented yet !\n");
324 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
326 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
327 srr0
= SPR_BOOKE_CSRR0
;
328 srr1
= SPR_BOOKE_CSRR1
;
330 case POWERPC_EXCP_RESET
: /* System reset exception */
332 /* indicate that we resumed from power save mode */
335 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
339 /* XXX: find a suitable condition to enable the hypervisor mode */
340 new_msr
|= (target_ulong
)MSR_HVB
;
343 case POWERPC_EXCP_DSEG
: /* Data segment exception */
345 new_msr
|= (target_ulong
)MSR_HVB
;
348 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
350 new_msr
|= (target_ulong
)MSR_HVB
;
353 case POWERPC_EXCP_HDECR
: /* Hypervisor decrementer exception */
356 new_msr
|= (target_ulong
)MSR_HVB
;
357 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
359 case POWERPC_EXCP_TRACE
: /* Trace exception */
361 new_msr
|= (target_ulong
)MSR_HVB
;
364 case POWERPC_EXCP_HDSI
: /* Hypervisor data storage exception */
367 new_msr
|= (target_ulong
)MSR_HVB
;
368 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
370 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage exception */
373 new_msr
|= (target_ulong
)MSR_HVB
;
374 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
376 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
379 new_msr
|= (target_ulong
)MSR_HVB
;
380 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
382 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment exception */
385 new_msr
|= (target_ulong
)MSR_HVB
;
386 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
388 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
390 new_msr
|= (target_ulong
)MSR_HVB
;
393 case POWERPC_EXCP_PIT
: /* Programmable interval timer interrupt */
394 LOG_EXCP("PIT exception\n");
396 case POWERPC_EXCP_IO
: /* IO error exception */
398 cpu_abort(env
, "601 IO error exception is not implemented yet !\n");
400 case POWERPC_EXCP_RUNM
: /* Run mode exception */
402 cpu_abort(env
, "601 run mode exception is not implemented yet !\n");
404 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
406 cpu_abort(env
, "602 emulation trap exception "
407 "is not implemented yet !\n");
409 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
410 if (lpes1
== 0) { /* XXX: check this */
411 new_msr
|= (target_ulong
)MSR_HVB
;
413 switch (excp_model
) {
414 case POWERPC_EXCP_602
:
415 case POWERPC_EXCP_603
:
416 case POWERPC_EXCP_603E
:
417 case POWERPC_EXCP_G2
:
419 case POWERPC_EXCP_7x5
:
421 case POWERPC_EXCP_74xx
:
424 cpu_abort(env
, "Invalid instruction TLB miss exception\n");
428 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
429 if (lpes1
== 0) { /* XXX: check this */
430 new_msr
|= (target_ulong
)MSR_HVB
;
432 switch (excp_model
) {
433 case POWERPC_EXCP_602
:
434 case POWERPC_EXCP_603
:
435 case POWERPC_EXCP_603E
:
436 case POWERPC_EXCP_G2
:
438 case POWERPC_EXCP_7x5
:
440 case POWERPC_EXCP_74xx
:
443 cpu_abort(env
, "Invalid data load TLB miss exception\n");
447 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
448 if (lpes1
== 0) { /* XXX: check this */
449 new_msr
|= (target_ulong
)MSR_HVB
;
451 switch (excp_model
) {
452 case POWERPC_EXCP_602
:
453 case POWERPC_EXCP_603
:
454 case POWERPC_EXCP_603E
:
455 case POWERPC_EXCP_G2
:
457 /* Swap temporary saved registers with GPRs */
458 if (!(new_msr
& ((target_ulong
)1 << MSR_TGPR
))) {
459 new_msr
|= (target_ulong
)1 << MSR_TGPR
;
460 hreg_swap_gpr_tgpr(env
);
463 case POWERPC_EXCP_7x5
:
465 #if defined(DEBUG_SOFTWARE_TLB)
466 if (qemu_log_enabled()) {
468 target_ulong
*miss
, *cmp
;
471 if (excp
== POWERPC_EXCP_IFTLB
) {
474 miss
= &env
->spr
[SPR_IMISS
];
475 cmp
= &env
->spr
[SPR_ICMP
];
477 if (excp
== POWERPC_EXCP_DLTLB
) {
483 miss
= &env
->spr
[SPR_DMISS
];
484 cmp
= &env
->spr
[SPR_DCMP
];
486 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
487 TARGET_FMT_lx
" H1 " TARGET_FMT_lx
" H2 "
488 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
489 env
->spr
[SPR_HASH1
], env
->spr
[SPR_HASH2
],
493 msr
|= env
->crf
[0] << 28;
494 msr
|= env
->error_code
; /* key, D/I, S/L bits */
495 /* Set way using a LRU mechanism */
496 msr
|= ((env
->last_way
+ 1) & (env
->nb_ways
- 1)) << 17;
498 case POWERPC_EXCP_74xx
:
500 #if defined(DEBUG_SOFTWARE_TLB)
501 if (qemu_log_enabled()) {
503 target_ulong
*miss
, *cmp
;
506 if (excp
== POWERPC_EXCP_IFTLB
) {
509 miss
= &env
->spr
[SPR_TLBMISS
];
510 cmp
= &env
->spr
[SPR_PTEHI
];
512 if (excp
== POWERPC_EXCP_DLTLB
) {
518 miss
= &env
->spr
[SPR_TLBMISS
];
519 cmp
= &env
->spr
[SPR_PTEHI
];
521 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
522 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
526 msr
|= env
->error_code
; /* key bit */
529 cpu_abort(env
, "Invalid data store TLB miss exception\n");
533 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
535 cpu_abort(env
, "Floating point assist exception "
536 "is not implemented yet !\n");
538 case POWERPC_EXCP_DABR
: /* Data address breakpoint */
540 cpu_abort(env
, "DABR exception is not implemented yet !\n");
542 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
544 cpu_abort(env
, "IABR exception is not implemented yet !\n");
546 case POWERPC_EXCP_SMI
: /* System management interrupt */
548 cpu_abort(env
, "SMI exception is not implemented yet !\n");
550 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
552 cpu_abort(env
, "Thermal management exception "
553 "is not implemented yet !\n");
555 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor interrupt */
557 new_msr
|= (target_ulong
)MSR_HVB
;
561 "Performance counter exception is not implemented yet !\n");
563 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
565 cpu_abort(env
, "VPU assist exception is not implemented yet !\n");
567 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
570 "970 soft-patch exception is not implemented yet !\n");
572 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
575 "970 maintenance exception is not implemented yet !\n");
577 case POWERPC_EXCP_MEXTBR
: /* Maskable external breakpoint */
579 cpu_abort(env
, "Maskable external exception "
580 "is not implemented yet !\n");
582 case POWERPC_EXCP_NMEXTBR
: /* Non maskable external breakpoint */
584 cpu_abort(env
, "Non maskable external exception "
585 "is not implemented yet !\n");
589 cpu_abort(env
, "Invalid PowerPC exception %d. Aborting\n", excp
);
592 /* save current instruction location */
593 env
->spr
[srr0
] = env
->nip
- 4;
596 /* save next instruction location */
597 env
->spr
[srr0
] = env
->nip
;
601 env
->spr
[srr1
] = msr
;
602 /* If any alternate SRR register are defined, duplicate saved values */
604 env
->spr
[asrr0
] = env
->spr
[srr0
];
607 env
->spr
[asrr1
] = env
->spr
[srr1
];
609 /* If we disactivated any translation, flush TLBs */
610 if (msr
& ((1 << MSR_IR
) | (1 << MSR_DR
))) {
615 if (excp_model
== POWERPC_EXCP_POWER7
) {
616 if (env
->spr
[SPR_LPCR
] & LPCR_ILE
) {
617 new_msr
|= (target_ulong
)1 << MSR_LE
;
619 } else if (msr_ile
) {
620 new_msr
|= (target_ulong
)1 << MSR_LE
;
624 new_msr
|= (target_ulong
)1 << MSR_LE
;
628 /* Jump to handler */
629 vector
= env
->excp_vectors
[excp
];
630 if (vector
== (target_ulong
)-1ULL) {
631 cpu_abort(env
, "Raised an exception without defined vector %d\n",
634 vector
|= env
->excp_prefix
;
635 #if defined(TARGET_PPC64)
636 if (excp_model
== POWERPC_EXCP_BOOKE
) {
637 if (env
->spr
[SPR_BOOKE_EPCR
] & EPCR_ICM
) {
638 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
639 new_msr
|= (target_ulong
)1 << MSR_CM
;
641 vector
= (uint32_t)vector
;
644 if (!msr_isf
&& !(env
->mmu_model
& POWERPC_MMU_64
)) {
645 vector
= (uint32_t)vector
;
647 new_msr
|= (target_ulong
)1 << MSR_SF
;
651 /* XXX: we don't use hreg_store_msr here as already have treated
652 * any special case that could occur. Just store MSR and update hflags
654 env
->msr
= new_msr
& env
->msr_mask
;
655 hreg_compute_hflags(env
);
657 /* Reset exception state */
658 env
->exception_index
= POWERPC_EXCP_NONE
;
661 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
662 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
663 /* XXX: The BookE changes address space when switching modes,
664 we should probably implement that as different MMU indexes,
665 but for the moment we do it the slow way and flush all. */
670 void ppc_cpu_do_interrupt(CPUState
*cs
)
672 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
673 CPUPPCState
*env
= &cpu
->env
;
675 powerpc_excp(cpu
, env
->excp_model
, env
->exception_index
);
678 void ppc_hw_interrupt(CPUPPCState
*env
)
680 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
683 CPUState
*cs
= CPU(cpu
);
685 qemu_log_mask(CPU_LOG_INT
, "%s: %p pending %08x req %08x me %d ee %d\n",
686 __func__
, env
, env
->pending_interrupts
,
687 cs
->interrupt_request
, (int)msr_me
, (int)msr_ee
);
690 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_RESET
)) {
691 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_RESET
);
692 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_RESET
);
695 /* Machine check exception */
696 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_MCK
)) {
697 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_MCK
);
698 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_MCHECK
);
702 /* External debug exception */
703 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DEBUG
)) {
704 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DEBUG
);
705 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DEBUG
);
710 /* XXX: find a suitable condition to enable the hypervisor mode */
711 hdice
= env
->spr
[SPR_LPCR
] & 1;
715 if ((msr_ee
!= 0 || msr_hv
== 0 || msr_pr
!= 0) && hdice
!= 0) {
716 /* Hypervisor decrementer exception */
717 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_HDECR
)) {
718 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_HDECR
);
719 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_HDECR
);
724 /* External critical interrupt */
725 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CEXT
)) {
726 /* Taking a critical external interrupt does not clear the external
727 * critical interrupt status
730 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CEXT
);
732 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_CRITICAL
);
737 /* Watchdog timer on embedded PowerPC */
738 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_WDT
)) {
739 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_WDT
);
740 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_WDT
);
743 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CDOORBELL
)) {
744 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CDOORBELL
);
745 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORCI
);
748 /* Fixed interval timer on embedded PowerPC */
749 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_FIT
)) {
750 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_FIT
);
751 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_FIT
);
754 /* Programmable interval timer on embedded PowerPC */
755 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PIT
)) {
756 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PIT
);
757 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PIT
);
760 /* Decrementer exception */
761 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DECR
)) {
762 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DECR
);
763 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DECR
);
766 /* External interrupt */
767 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_EXT
)) {
768 /* Taking an external interrupt does not clear the external
772 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_EXT
);
774 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_EXTERNAL
);
777 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DOORBELL
)) {
778 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DOORBELL
);
779 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORI
);
782 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PERFM
)) {
783 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PERFM
);
784 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PERFM
);
787 /* Thermal interrupt */
788 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_THERM
)) {
789 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_THERM
);
790 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_THERM
);
795 #endif /* !CONFIG_USER_ONLY */
797 #if defined(DEBUG_OP)
798 static void cpu_dump_rfi(target_ulong RA
, target_ulong msr
)
800 qemu_log("Return from exception at " TARGET_FMT_lx
" with flags "
801 TARGET_FMT_lx
"\n", RA
, msr
);
805 /*****************************************************************************/
806 /* Exceptions processing helpers */
808 void helper_raise_exception_err(CPUPPCState
*env
, uint32_t exception
,
812 printf("Raise exception %3x code : %d\n", exception
, error_code
);
814 env
->exception_index
= exception
;
815 env
->error_code
= error_code
;
819 void helper_raise_exception(CPUPPCState
*env
, uint32_t exception
)
821 helper_raise_exception_err(env
, exception
, 0);
824 #if !defined(CONFIG_USER_ONLY)
825 void helper_store_msr(CPUPPCState
*env
, target_ulong val
)
829 val
= hreg_store_msr(env
, val
, 0);
831 cs
= CPU(ppc_env_get_cpu(env
));
832 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
833 helper_raise_exception(env
, val
);
837 static inline void do_rfi(CPUPPCState
*env
, target_ulong nip
, target_ulong msr
,
838 target_ulong msrm
, int keep_msrh
)
840 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
842 #if defined(TARGET_PPC64)
843 if (msr_is_64bit(env
, msr
)) {
845 msr
&= (uint64_t)msrm
;
848 msr
= (uint32_t)(msr
& msrm
);
850 msr
|= env
->msr
& ~((uint64_t)0xFFFFFFFF);
855 msr
&= (uint32_t)msrm
;
857 /* XXX: beware: this is false if VLE is supported */
858 env
->nip
= nip
& ~((target_ulong
)0x00000003);
859 hreg_store_msr(env
, msr
, 1);
860 #if defined(DEBUG_OP)
861 cpu_dump_rfi(env
->nip
, env
->msr
);
863 /* No need to raise an exception here,
864 * as rfi is always the last insn of a TB
866 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
869 void helper_rfi(CPUPPCState
*env
)
871 if (env
->excp_model
== POWERPC_EXCP_BOOKE
) {
872 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
873 ~((target_ulong
)0), 0);
875 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
876 ~((target_ulong
)0x783F0000), 1);
880 #if defined(TARGET_PPC64)
881 void helper_rfid(CPUPPCState
*env
)
883 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
884 ~((target_ulong
)0x783F0000), 0);
887 void helper_hrfid(CPUPPCState
*env
)
889 do_rfi(env
, env
->spr
[SPR_HSRR0
], env
->spr
[SPR_HSRR1
],
890 ~((target_ulong
)0x783F0000), 0);
894 /*****************************************************************************/
895 /* Embedded PowerPC specific helpers */
896 void helper_40x_rfci(CPUPPCState
*env
)
898 do_rfi(env
, env
->spr
[SPR_40x_SRR2
], env
->spr
[SPR_40x_SRR3
],
899 ~((target_ulong
)0xFFFF0000), 0);
902 void helper_rfci(CPUPPCState
*env
)
904 do_rfi(env
, env
->spr
[SPR_BOOKE_CSRR0
], env
->spr
[SPR_BOOKE_CSRR1
],
905 ~((target_ulong
)0), 0);
908 void helper_rfdi(CPUPPCState
*env
)
910 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
911 do_rfi(env
, env
->spr
[SPR_BOOKE_DSRR0
], env
->spr
[SPR_BOOKE_DSRR1
],
912 ~((target_ulong
)0), 0);
915 void helper_rfmci(CPUPPCState
*env
)
917 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
918 do_rfi(env
, env
->spr
[SPR_BOOKE_MCSRR0
], env
->spr
[SPR_BOOKE_MCSRR1
],
919 ~((target_ulong
)0), 0);
923 void helper_tw(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
926 if (!likely(!(((int32_t)arg1
< (int32_t)arg2
&& (flags
& 0x10)) ||
927 ((int32_t)arg1
> (int32_t)arg2
&& (flags
& 0x08)) ||
928 ((int32_t)arg1
== (int32_t)arg2
&& (flags
& 0x04)) ||
929 ((uint32_t)arg1
< (uint32_t)arg2
&& (flags
& 0x02)) ||
930 ((uint32_t)arg1
> (uint32_t)arg2
&& (flags
& 0x01))))) {
931 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
936 #if defined(TARGET_PPC64)
937 void helper_td(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
940 if (!likely(!(((int64_t)arg1
< (int64_t)arg2
&& (flags
& 0x10)) ||
941 ((int64_t)arg1
> (int64_t)arg2
&& (flags
& 0x08)) ||
942 ((int64_t)arg1
== (int64_t)arg2
&& (flags
& 0x04)) ||
943 ((uint64_t)arg1
< (uint64_t)arg2
&& (flags
& 0x02)) ||
944 ((uint64_t)arg1
> (uint64_t)arg2
&& (flags
& 0x01))))) {
945 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
951 #if !defined(CONFIG_USER_ONLY)
952 /*****************************************************************************/
953 /* PowerPC 601 specific instructions (POWER bridge) */
955 void helper_rfsvc(CPUPPCState
*env
)
957 do_rfi(env
, env
->lr
, env
->ctr
, 0x0000FFFF, 0);
960 /* Embedded.Processor Control */
961 static int dbell2irq(target_ulong rb
)
963 int msg
= rb
& DBELL_TYPE_MASK
;
967 case DBELL_TYPE_DBELL
:
968 irq
= PPC_INTERRUPT_DOORBELL
;
970 case DBELL_TYPE_DBELL_CRIT
:
971 irq
= PPC_INTERRUPT_CDOORBELL
;
973 case DBELL_TYPE_G_DBELL
:
974 case DBELL_TYPE_G_DBELL_CRIT
:
975 case DBELL_TYPE_G_DBELL_MC
:
984 void helper_msgclr(CPUPPCState
*env
, target_ulong rb
)
986 int irq
= dbell2irq(rb
);
992 env
->pending_interrupts
&= ~(1 << irq
);
995 void helper_msgsnd(target_ulong rb
)
997 int irq
= dbell2irq(rb
);
998 int pir
= rb
& DBELL_PIRTAG_MASK
;
1006 PowerPCCPU
*cpu
= POWERPC_CPU(cs
);
1007 CPUPPCState
*cenv
= &cpu
->env
;
1009 if ((rb
& DBELL_BRDCAST
) || (cenv
->spr
[SPR_BOOKE_PIR
] == pir
)) {
1010 cenv
->pending_interrupts
|= 1 << irq
;
1011 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);