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 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(PowerPCCPU
*cpu
, int excp_model
, int excp
)
68 CPUPPCState
*env
= &cpu
->env
;
69 target_ulong msr
, new_msr
, vector
;
70 int srr0
, srr1
, asrr0
, asrr1
;
71 int lpes0
, lpes1
, lev
;
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;
78 /* Those values ensure we won't enter the hypervisor mode */
83 qemu_log_mask(CPU_LOG_INT
, "Raise exception at " TARGET_FMT_lx
84 " => %08x (%02x)\n", env
->nip
, excp
, env
->error_code
);
86 /* new srr1 value excluding must-be-zero bits */
87 if (excp_model
== POWERPC_EXCP_BOOKE
) {
90 msr
= env
->msr
& ~0x783f0000ULL
;
93 /* new interrupt handler msr */
94 new_msr
= env
->msr
& ((target_ulong
)1 << MSR_ME
);
96 /* target registers */
103 case POWERPC_EXCP_NONE
:
104 /* Should never happen */
106 case POWERPC_EXCP_CRITICAL
: /* Critical input */
107 switch (excp_model
) {
108 case POWERPC_EXCP_40x
:
112 case POWERPC_EXCP_BOOKE
:
113 srr0
= SPR_BOOKE_CSRR0
;
114 srr1
= SPR_BOOKE_CSRR1
;
116 case POWERPC_EXCP_G2
:
122 case POWERPC_EXCP_MCHECK
: /* Machine check exception */
124 /* Machine check exception is not enabled.
125 * Enter checkstop state.
127 if (qemu_log_enabled()) {
128 qemu_log("Machine check while not allowed. "
129 "Entering checkstop state\n");
131 fprintf(stderr
, "Machine check while not allowed. "
132 "Entering checkstop state\n");
135 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
138 /* XXX: find a suitable condition to enable the hypervisor mode */
139 new_msr
|= (target_ulong
)MSR_HVB
;
142 /* machine check exceptions don't have ME set */
143 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
145 /* XXX: should also have something loaded in DAR / DSISR */
146 switch (excp_model
) {
147 case POWERPC_EXCP_40x
:
151 case POWERPC_EXCP_BOOKE
:
152 /* FIXME: choose one or the other based on CPU type */
153 srr0
= SPR_BOOKE_MCSRR0
;
154 srr1
= SPR_BOOKE_MCSRR1
;
155 asrr0
= SPR_BOOKE_CSRR0
;
156 asrr1
= SPR_BOOKE_CSRR1
;
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
]);
166 new_msr
|= (target_ulong
)MSR_HVB
;
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
);
173 new_msr
|= (target_ulong
)MSR_HVB
;
175 msr
|= env
->error_code
;
177 case POWERPC_EXCP_EXTERNAL
: /* External input */
179 new_msr
|= (target_ulong
)MSR_HVB
;
181 if (env
->mpic_proxy
) {
182 /* IACK the IRQ on delivery */
183 env
->spr
[SPR_BOOKE_EPR
] = ldl_phys(env
->mpic_iack
);
186 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
188 new_msr
|= (target_ulong
)MSR_HVB
;
190 /* XXX: this is false */
191 /* Get rS/rD and rA from faulting opcode */
192 env
->spr
[SPR_DSISR
] |= (cpu_ldl_code(env
, (env
->nip
- 4))
195 case POWERPC_EXCP_PROGRAM
: /* Program exception */
196 switch (env
->error_code
& ~0xF) {
197 case POWERPC_EXCP_FP
:
198 if ((msr_fe0
== 0 && msr_fe1
== 0) || msr_fp
== 0) {
199 LOG_EXCP("Ignore floating point exception\n");
200 env
->exception_index
= POWERPC_EXCP_NONE
;
205 new_msr
|= (target_ulong
)MSR_HVB
;
208 if (msr_fe0
== msr_fe1
) {
213 case POWERPC_EXCP_INVAL
:
214 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx
"\n", env
->nip
);
216 new_msr
|= (target_ulong
)MSR_HVB
;
219 env
->spr
[SPR_BOOKE_ESR
] = ESR_PIL
;
221 case POWERPC_EXCP_PRIV
:
223 new_msr
|= (target_ulong
)MSR_HVB
;
226 env
->spr
[SPR_BOOKE_ESR
] = ESR_PPR
;
228 case POWERPC_EXCP_TRAP
:
230 new_msr
|= (target_ulong
)MSR_HVB
;
233 env
->spr
[SPR_BOOKE_ESR
] = ESR_PTR
;
236 /* Should never occur */
237 cpu_abort(env
, "Invalid program exception %d. Aborting\n",
242 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
244 new_msr
|= (target_ulong
)MSR_HVB
;
247 case POWERPC_EXCP_SYSCALL
: /* System call exception */
249 lev
= env
->error_code
;
250 if ((lev
== 1) && cpu_ppc_hypercall
) {
251 cpu_ppc_hypercall(cpu
);
254 if (lev
== 1 || (lpes0
== 0 && lpes1
== 0)) {
255 new_msr
|= (target_ulong
)MSR_HVB
;
258 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
260 case POWERPC_EXCP_DECR
: /* Decrementer exception */
262 new_msr
|= (target_ulong
)MSR_HVB
;
265 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
267 LOG_EXCP("FIT exception\n");
269 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
270 LOG_EXCP("WDT exception\n");
271 switch (excp_model
) {
272 case POWERPC_EXCP_BOOKE
:
273 srr0
= SPR_BOOKE_CSRR0
;
274 srr1
= SPR_BOOKE_CSRR1
;
280 case POWERPC_EXCP_DTLB
: /* Data TLB error */
282 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
284 case POWERPC_EXCP_DEBUG
: /* Debug interrupt */
285 switch (excp_model
) {
286 case POWERPC_EXCP_BOOKE
:
287 /* FIXME: choose one or the other based on CPU type */
288 srr0
= SPR_BOOKE_DSRR0
;
289 srr1
= SPR_BOOKE_DSRR1
;
290 asrr0
= SPR_BOOKE_CSRR0
;
291 asrr1
= SPR_BOOKE_CSRR1
;
297 cpu_abort(env
, "Debug exception is not implemented yet !\n");
299 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavailable */
300 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
302 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data interrupt */
304 cpu_abort(env
, "Embedded floating point data exception "
305 "is not implemented yet !\n");
306 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
308 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round interrupt */
310 cpu_abort(env
, "Embedded floating point round exception "
311 "is not implemented yet !\n");
312 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
314 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor interrupt */
317 "Performance counter exception is not implemented yet !\n");
319 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
321 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
322 srr0
= SPR_BOOKE_CSRR0
;
323 srr1
= SPR_BOOKE_CSRR1
;
325 case POWERPC_EXCP_RESET
: /* System reset exception */
327 /* indicate that we resumed from power save mode */
330 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
334 /* XXX: find a suitable condition to enable the hypervisor mode */
335 new_msr
|= (target_ulong
)MSR_HVB
;
338 case POWERPC_EXCP_DSEG
: /* Data segment exception */
340 new_msr
|= (target_ulong
)MSR_HVB
;
343 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
345 new_msr
|= (target_ulong
)MSR_HVB
;
348 case POWERPC_EXCP_HDECR
: /* Hypervisor decrementer exception */
351 new_msr
|= (target_ulong
)MSR_HVB
;
352 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
354 case POWERPC_EXCP_TRACE
: /* Trace exception */
356 new_msr
|= (target_ulong
)MSR_HVB
;
359 case POWERPC_EXCP_HDSI
: /* Hypervisor data storage exception */
362 new_msr
|= (target_ulong
)MSR_HVB
;
363 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
365 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage exception */
368 new_msr
|= (target_ulong
)MSR_HVB
;
369 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
371 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
374 new_msr
|= (target_ulong
)MSR_HVB
;
375 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
377 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment exception */
380 new_msr
|= (target_ulong
)MSR_HVB
;
381 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
383 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
385 new_msr
|= (target_ulong
)MSR_HVB
;
388 case POWERPC_EXCP_PIT
: /* Programmable interval timer interrupt */
389 LOG_EXCP("PIT exception\n");
391 case POWERPC_EXCP_IO
: /* IO error exception */
393 cpu_abort(env
, "601 IO error exception is not implemented yet !\n");
395 case POWERPC_EXCP_RUNM
: /* Run mode exception */
397 cpu_abort(env
, "601 run mode exception is not implemented yet !\n");
399 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
401 cpu_abort(env
, "602 emulation trap exception "
402 "is not implemented yet !\n");
404 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
405 if (lpes1
== 0) { /* XXX: check this */
406 new_msr
|= (target_ulong
)MSR_HVB
;
408 switch (excp_model
) {
409 case POWERPC_EXCP_602
:
410 case POWERPC_EXCP_603
:
411 case POWERPC_EXCP_603E
:
412 case POWERPC_EXCP_G2
:
414 case POWERPC_EXCP_7x5
:
416 case POWERPC_EXCP_74xx
:
419 cpu_abort(env
, "Invalid instruction TLB miss exception\n");
423 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
424 if (lpes1
== 0) { /* XXX: check this */
425 new_msr
|= (target_ulong
)MSR_HVB
;
427 switch (excp_model
) {
428 case POWERPC_EXCP_602
:
429 case POWERPC_EXCP_603
:
430 case POWERPC_EXCP_603E
:
431 case POWERPC_EXCP_G2
:
433 case POWERPC_EXCP_7x5
:
435 case POWERPC_EXCP_74xx
:
438 cpu_abort(env
, "Invalid data load TLB miss exception\n");
442 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
443 if (lpes1
== 0) { /* XXX: check this */
444 new_msr
|= (target_ulong
)MSR_HVB
;
446 switch (excp_model
) {
447 case POWERPC_EXCP_602
:
448 case POWERPC_EXCP_603
:
449 case POWERPC_EXCP_603E
:
450 case POWERPC_EXCP_G2
:
452 /* Swap temporary saved registers with GPRs */
453 if (!(new_msr
& ((target_ulong
)1 << MSR_TGPR
))) {
454 new_msr
|= (target_ulong
)1 << MSR_TGPR
;
455 hreg_swap_gpr_tgpr(env
);
458 case POWERPC_EXCP_7x5
:
460 #if defined(DEBUG_SOFTWARE_TLB)
461 if (qemu_log_enabled()) {
463 target_ulong
*miss
, *cmp
;
466 if (excp
== POWERPC_EXCP_IFTLB
) {
469 miss
= &env
->spr
[SPR_IMISS
];
470 cmp
= &env
->spr
[SPR_ICMP
];
472 if (excp
== POWERPC_EXCP_DLTLB
) {
478 miss
= &env
->spr
[SPR_DMISS
];
479 cmp
= &env
->spr
[SPR_DCMP
];
481 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
482 TARGET_FMT_lx
" H1 " TARGET_FMT_lx
" H2 "
483 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
484 env
->spr
[SPR_HASH1
], env
->spr
[SPR_HASH2
],
488 msr
|= env
->crf
[0] << 28;
489 msr
|= env
->error_code
; /* key, D/I, S/L bits */
490 /* Set way using a LRU mechanism */
491 msr
|= ((env
->last_way
+ 1) & (env
->nb_ways
- 1)) << 17;
493 case POWERPC_EXCP_74xx
:
495 #if defined(DEBUG_SOFTWARE_TLB)
496 if (qemu_log_enabled()) {
498 target_ulong
*miss
, *cmp
;
501 if (excp
== POWERPC_EXCP_IFTLB
) {
504 miss
= &env
->spr
[SPR_TLBMISS
];
505 cmp
= &env
->spr
[SPR_PTEHI
];
507 if (excp
== POWERPC_EXCP_DLTLB
) {
513 miss
= &env
->spr
[SPR_TLBMISS
];
514 cmp
= &env
->spr
[SPR_PTEHI
];
516 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
517 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
521 msr
|= env
->error_code
; /* key bit */
524 cpu_abort(env
, "Invalid data store TLB miss exception\n");
528 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
530 cpu_abort(env
, "Floating point assist exception "
531 "is not implemented yet !\n");
533 case POWERPC_EXCP_DABR
: /* Data address breakpoint */
535 cpu_abort(env
, "DABR exception is not implemented yet !\n");
537 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
539 cpu_abort(env
, "IABR exception is not implemented yet !\n");
541 case POWERPC_EXCP_SMI
: /* System management interrupt */
543 cpu_abort(env
, "SMI exception is not implemented yet !\n");
545 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
547 cpu_abort(env
, "Thermal management exception "
548 "is not implemented yet !\n");
550 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor interrupt */
552 new_msr
|= (target_ulong
)MSR_HVB
;
556 "Performance counter exception is not implemented yet !\n");
558 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
560 cpu_abort(env
, "VPU assist exception is not implemented yet !\n");
562 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
565 "970 soft-patch exception is not implemented yet !\n");
567 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
570 "970 maintenance exception is not implemented yet !\n");
572 case POWERPC_EXCP_MEXTBR
: /* Maskable external breakpoint */
574 cpu_abort(env
, "Maskable external exception "
575 "is not implemented yet !\n");
577 case POWERPC_EXCP_NMEXTBR
: /* Non maskable external breakpoint */
579 cpu_abort(env
, "Non maskable external exception "
580 "is not implemented yet !\n");
584 cpu_abort(env
, "Invalid PowerPC exception %d. Aborting\n", excp
);
587 /* save current instruction location */
588 env
->spr
[srr0
] = env
->nip
- 4;
591 /* save next instruction location */
592 env
->spr
[srr0
] = env
->nip
;
596 env
->spr
[srr1
] = msr
;
597 /* If any alternate SRR register are defined, duplicate saved values */
599 env
->spr
[asrr0
] = env
->spr
[srr0
];
602 env
->spr
[asrr1
] = env
->spr
[srr1
];
604 /* If we disactivated any translation, flush TLBs */
605 if (msr
& ((1 << MSR_IR
) | (1 << MSR_DR
))) {
610 new_msr
|= (target_ulong
)1 << MSR_LE
;
613 /* Jump to handler */
614 vector
= env
->excp_vectors
[excp
];
615 if (vector
== (target_ulong
)-1ULL) {
616 cpu_abort(env
, "Raised an exception without defined vector %d\n",
619 vector
|= env
->excp_prefix
;
620 #if defined(TARGET_PPC64)
621 if (excp_model
== POWERPC_EXCP_BOOKE
) {
622 if (env
->spr
[SPR_BOOKE_EPCR
] & EPCR_ICM
) {
623 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
624 new_msr
|= (target_ulong
)1 << MSR_CM
;
626 vector
= (uint32_t)vector
;
629 if (!msr_isf
&& !(env
->mmu_model
& POWERPC_MMU_64
)) {
630 vector
= (uint32_t)vector
;
632 new_msr
|= (target_ulong
)1 << MSR_SF
;
636 /* XXX: we don't use hreg_store_msr here as already have treated
637 * any special case that could occur. Just store MSR and update hflags
639 env
->msr
= new_msr
& env
->msr_mask
;
640 hreg_compute_hflags(env
);
642 /* Reset exception state */
643 env
->exception_index
= POWERPC_EXCP_NONE
;
646 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
647 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
648 /* XXX: The BookE changes address space when switching modes,
649 we should probably implement that as different MMU indexes,
650 but for the moment we do it the slow way and flush all. */
655 void do_interrupt(CPUPPCState
*env
)
657 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
659 powerpc_excp(cpu
, env
->excp_model
, env
->exception_index
);
662 void ppc_hw_interrupt(CPUPPCState
*env
)
664 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
668 qemu_log_mask(CPU_LOG_INT
, "%s: %p pending %08x req %08x me %d ee %d\n",
669 __func__
, env
, env
->pending_interrupts
,
670 env
->interrupt_request
, (int)msr_me
, (int)msr_ee
);
673 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_RESET
)) {
674 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_RESET
);
675 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_RESET
);
678 /* Machine check exception */
679 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_MCK
)) {
680 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_MCK
);
681 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_MCHECK
);
685 /* External debug exception */
686 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DEBUG
)) {
687 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DEBUG
);
688 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DEBUG
);
693 /* XXX: find a suitable condition to enable the hypervisor mode */
694 hdice
= env
->spr
[SPR_LPCR
] & 1;
698 if ((msr_ee
!= 0 || msr_hv
== 0 || msr_pr
!= 0) && hdice
!= 0) {
699 /* Hypervisor decrementer exception */
700 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_HDECR
)) {
701 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_HDECR
);
702 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_HDECR
);
707 /* External critical interrupt */
708 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CEXT
)) {
709 /* Taking a critical external interrupt does not clear the external
710 * critical interrupt status
713 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CEXT
);
715 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_CRITICAL
);
720 /* Watchdog timer on embedded PowerPC */
721 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_WDT
)) {
722 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_WDT
);
723 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_WDT
);
726 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CDOORBELL
)) {
727 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CDOORBELL
);
728 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORCI
);
731 /* Fixed interval timer on embedded PowerPC */
732 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_FIT
)) {
733 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_FIT
);
734 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_FIT
);
737 /* Programmable interval timer on embedded PowerPC */
738 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PIT
)) {
739 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PIT
);
740 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PIT
);
743 /* Decrementer exception */
744 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DECR
)) {
745 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DECR
);
746 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DECR
);
749 /* External interrupt */
750 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_EXT
)) {
751 /* Taking an external interrupt does not clear the external
755 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_EXT
);
757 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_EXTERNAL
);
760 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DOORBELL
)) {
761 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DOORBELL
);
762 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORI
);
765 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PERFM
)) {
766 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PERFM
);
767 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PERFM
);
770 /* Thermal interrupt */
771 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_THERM
)) {
772 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_THERM
);
773 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_THERM
);
778 #endif /* !CONFIG_USER_ONLY */
780 #if defined(DEBUG_OP)
781 static void cpu_dump_rfi(target_ulong RA
, target_ulong msr
)
783 qemu_log("Return from exception at " TARGET_FMT_lx
" with flags "
784 TARGET_FMT_lx
"\n", RA
, msr
);
788 /*****************************************************************************/
789 /* Exceptions processing helpers */
791 void helper_raise_exception_err(CPUPPCState
*env
, uint32_t exception
,
795 printf("Raise exception %3x code : %d\n", exception
, error_code
);
797 env
->exception_index
= exception
;
798 env
->error_code
= error_code
;
802 void helper_raise_exception(CPUPPCState
*env
, uint32_t exception
)
804 helper_raise_exception_err(env
, exception
, 0);
807 #if !defined(CONFIG_USER_ONLY)
808 void helper_store_msr(CPUPPCState
*env
, target_ulong val
)
810 val
= hreg_store_msr(env
, val
, 0);
812 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
813 helper_raise_exception(env
, val
);
817 static inline void do_rfi(CPUPPCState
*env
, target_ulong nip
, target_ulong msr
,
818 target_ulong msrm
, int keep_msrh
)
820 #if defined(TARGET_PPC64)
821 if (msr_is_64bit(env
, msr
)) {
823 msr
&= (uint64_t)msrm
;
826 msr
= (uint32_t)(msr
& msrm
);
828 msr
|= env
->msr
& ~((uint64_t)0xFFFFFFFF);
833 msr
&= (uint32_t)msrm
;
835 /* XXX: beware: this is false if VLE is supported */
836 env
->nip
= nip
& ~((target_ulong
)0x00000003);
837 hreg_store_msr(env
, msr
, 1);
838 #if defined(DEBUG_OP)
839 cpu_dump_rfi(env
->nip
, env
->msr
);
841 /* No need to raise an exception here,
842 * as rfi is always the last insn of a TB
844 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
847 void helper_rfi(CPUPPCState
*env
)
849 if (env
->excp_model
== POWERPC_EXCP_BOOKE
) {
850 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
851 ~((target_ulong
)0), 0);
853 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
854 ~((target_ulong
)0x783F0000), 1);
858 #if defined(TARGET_PPC64)
859 void helper_rfid(CPUPPCState
*env
)
861 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
862 ~((target_ulong
)0x783F0000), 0);
865 void helper_hrfid(CPUPPCState
*env
)
867 do_rfi(env
, env
->spr
[SPR_HSRR0
], env
->spr
[SPR_HSRR1
],
868 ~((target_ulong
)0x783F0000), 0);
872 /*****************************************************************************/
873 /* Embedded PowerPC specific helpers */
874 void helper_40x_rfci(CPUPPCState
*env
)
876 do_rfi(env
, env
->spr
[SPR_40x_SRR2
], env
->spr
[SPR_40x_SRR3
],
877 ~((target_ulong
)0xFFFF0000), 0);
880 void helper_rfci(CPUPPCState
*env
)
882 do_rfi(env
, env
->spr
[SPR_BOOKE_CSRR0
], env
->spr
[SPR_BOOKE_CSRR1
],
883 ~((target_ulong
)0), 0);
886 void helper_rfdi(CPUPPCState
*env
)
888 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
889 do_rfi(env
, env
->spr
[SPR_BOOKE_DSRR0
], env
->spr
[SPR_BOOKE_DSRR1
],
890 ~((target_ulong
)0), 0);
893 void helper_rfmci(CPUPPCState
*env
)
895 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
896 do_rfi(env
, env
->spr
[SPR_BOOKE_MCSRR0
], env
->spr
[SPR_BOOKE_MCSRR1
],
897 ~((target_ulong
)0), 0);
901 void helper_tw(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
904 if (!likely(!(((int32_t)arg1
< (int32_t)arg2
&& (flags
& 0x10)) ||
905 ((int32_t)arg1
> (int32_t)arg2
&& (flags
& 0x08)) ||
906 ((int32_t)arg1
== (int32_t)arg2
&& (flags
& 0x04)) ||
907 ((uint32_t)arg1
< (uint32_t)arg2
&& (flags
& 0x02)) ||
908 ((uint32_t)arg1
> (uint32_t)arg2
&& (flags
& 0x01))))) {
909 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
914 #if defined(TARGET_PPC64)
915 void helper_td(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
918 if (!likely(!(((int64_t)arg1
< (int64_t)arg2
&& (flags
& 0x10)) ||
919 ((int64_t)arg1
> (int64_t)arg2
&& (flags
& 0x08)) ||
920 ((int64_t)arg1
== (int64_t)arg2
&& (flags
& 0x04)) ||
921 ((uint64_t)arg1
< (uint64_t)arg2
&& (flags
& 0x02)) ||
922 ((uint64_t)arg1
> (uint64_t)arg2
&& (flags
& 0x01))))) {
923 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
929 #if !defined(CONFIG_USER_ONLY)
930 /*****************************************************************************/
931 /* PowerPC 601 specific instructions (POWER bridge) */
933 void helper_rfsvc(CPUPPCState
*env
)
935 do_rfi(env
, env
->lr
, env
->ctr
, 0x0000FFFF, 0);
938 /* Embedded.Processor Control */
939 static int dbell2irq(target_ulong rb
)
941 int msg
= rb
& DBELL_TYPE_MASK
;
945 case DBELL_TYPE_DBELL
:
946 irq
= PPC_INTERRUPT_DOORBELL
;
948 case DBELL_TYPE_DBELL_CRIT
:
949 irq
= PPC_INTERRUPT_CDOORBELL
;
951 case DBELL_TYPE_G_DBELL
:
952 case DBELL_TYPE_G_DBELL_CRIT
:
953 case DBELL_TYPE_G_DBELL_MC
:
962 void helper_msgclr(CPUPPCState
*env
, target_ulong rb
)
964 int irq
= dbell2irq(rb
);
970 env
->pending_interrupts
&= ~(1 << irq
);
973 void helper_msgsnd(target_ulong rb
)
975 int irq
= dbell2irq(rb
);
976 int pir
= rb
& DBELL_PIRTAG_MASK
;
983 for (cenv
= first_cpu
; cenv
!= NULL
; cenv
= cenv
->next_cpu
) {
984 if ((rb
& DBELL_BRDCAST
) || (cenv
->spr
[SPR_BOOKE_PIR
] == pir
)) {
985 cenv
->pending_interrupts
|= 1 << irq
;
986 cpu_interrupt(cenv
, CPU_INTERRUPT_HARD
);