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 msr
= env
->msr
& ~0x783f0000ULL
;
89 /* new interrupt handler msr */
90 new_msr
= env
->msr
& ((target_ulong
)1 << MSR_ME
);
92 /* target registers */
99 case POWERPC_EXCP_NONE
:
100 /* Should never happen */
102 case POWERPC_EXCP_CRITICAL
: /* Critical input */
103 switch (excp_model
) {
104 case POWERPC_EXCP_40x
:
108 case POWERPC_EXCP_BOOKE
:
109 srr0
= SPR_BOOKE_CSRR0
;
110 srr1
= SPR_BOOKE_CSRR1
;
112 case POWERPC_EXCP_G2
:
118 case POWERPC_EXCP_MCHECK
: /* Machine check exception */
120 /* Machine check exception is not enabled.
121 * Enter checkstop state.
123 if (qemu_log_enabled()) {
124 qemu_log("Machine check while not allowed. "
125 "Entering checkstop state\n");
127 fprintf(stderr
, "Machine check while not allowed. "
128 "Entering checkstop state\n");
131 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
134 /* XXX: find a suitable condition to enable the hypervisor mode */
135 new_msr
|= (target_ulong
)MSR_HVB
;
138 /* machine check exceptions don't have ME set */
139 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
141 /* XXX: should also have something loaded in DAR / DSISR */
142 switch (excp_model
) {
143 case POWERPC_EXCP_40x
:
147 case POWERPC_EXCP_BOOKE
:
148 srr0
= SPR_BOOKE_MCSRR0
;
149 srr1
= SPR_BOOKE_MCSRR1
;
150 asrr0
= SPR_BOOKE_CSRR0
;
151 asrr1
= SPR_BOOKE_CSRR1
;
157 case POWERPC_EXCP_DSI
: /* Data storage exception */
158 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx
" DAR=" TARGET_FMT_lx
159 "\n", env
->spr
[SPR_DSISR
], env
->spr
[SPR_DAR
]);
161 new_msr
|= (target_ulong
)MSR_HVB
;
164 case POWERPC_EXCP_ISI
: /* Instruction storage exception */
165 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx
", nip=" TARGET_FMT_lx
166 "\n", msr
, env
->nip
);
168 new_msr
|= (target_ulong
)MSR_HVB
;
170 msr
|= env
->error_code
;
172 case POWERPC_EXCP_EXTERNAL
: /* External input */
174 new_msr
|= (target_ulong
)MSR_HVB
;
177 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
179 new_msr
|= (target_ulong
)MSR_HVB
;
181 /* XXX: this is false */
182 /* Get rS/rD and rA from faulting opcode */
183 env
->spr
[SPR_DSISR
] |= (cpu_ldl_code(env
, (env
->nip
- 4))
186 case POWERPC_EXCP_PROGRAM
: /* Program exception */
187 switch (env
->error_code
& ~0xF) {
188 case POWERPC_EXCP_FP
:
189 if ((msr_fe0
== 0 && msr_fe1
== 0) || msr_fp
== 0) {
190 LOG_EXCP("Ignore floating point exception\n");
191 env
->exception_index
= POWERPC_EXCP_NONE
;
196 new_msr
|= (target_ulong
)MSR_HVB
;
199 if (msr_fe0
== msr_fe1
) {
204 case POWERPC_EXCP_INVAL
:
205 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx
"\n", env
->nip
);
207 new_msr
|= (target_ulong
)MSR_HVB
;
210 env
->spr
[SPR_BOOKE_ESR
] = ESR_PIL
;
212 case POWERPC_EXCP_PRIV
:
214 new_msr
|= (target_ulong
)MSR_HVB
;
217 env
->spr
[SPR_BOOKE_ESR
] = ESR_PPR
;
219 case POWERPC_EXCP_TRAP
:
221 new_msr
|= (target_ulong
)MSR_HVB
;
224 env
->spr
[SPR_BOOKE_ESR
] = ESR_PTR
;
227 /* Should never occur */
228 cpu_abort(env
, "Invalid program exception %d. Aborting\n",
233 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
235 new_msr
|= (target_ulong
)MSR_HVB
;
238 case POWERPC_EXCP_SYSCALL
: /* System call exception */
240 lev
= env
->error_code
;
241 if ((lev
== 1) && cpu_ppc_hypercall
) {
242 cpu_ppc_hypercall(cpu
);
245 if (lev
== 1 || (lpes0
== 0 && lpes1
== 0)) {
246 new_msr
|= (target_ulong
)MSR_HVB
;
249 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
251 case POWERPC_EXCP_DECR
: /* Decrementer exception */
253 new_msr
|= (target_ulong
)MSR_HVB
;
256 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
258 LOG_EXCP("FIT exception\n");
260 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
261 LOG_EXCP("WDT exception\n");
262 switch (excp_model
) {
263 case POWERPC_EXCP_BOOKE
:
264 srr0
= SPR_BOOKE_CSRR0
;
265 srr1
= SPR_BOOKE_CSRR1
;
271 case POWERPC_EXCP_DTLB
: /* Data TLB error */
273 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
275 case POWERPC_EXCP_DEBUG
: /* Debug interrupt */
276 switch (excp_model
) {
277 case POWERPC_EXCP_BOOKE
:
278 srr0
= SPR_BOOKE_DSRR0
;
279 srr1
= SPR_BOOKE_DSRR1
;
280 asrr0
= SPR_BOOKE_CSRR0
;
281 asrr1
= SPR_BOOKE_CSRR1
;
287 cpu_abort(env
, "Debug exception is not implemented yet !\n");
289 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavailable */
290 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
292 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data interrupt */
294 cpu_abort(env
, "Embedded floating point data exception "
295 "is not implemented yet !\n");
296 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
298 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round interrupt */
300 cpu_abort(env
, "Embedded floating point round exception "
301 "is not implemented yet !\n");
302 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
304 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor interrupt */
307 "Performance counter exception is not implemented yet !\n");
309 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
311 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
312 srr0
= SPR_BOOKE_CSRR0
;
313 srr1
= SPR_BOOKE_CSRR1
;
315 case POWERPC_EXCP_RESET
: /* System reset exception */
317 /* indicate that we resumed from power save mode */
320 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
324 /* XXX: find a suitable condition to enable the hypervisor mode */
325 new_msr
|= (target_ulong
)MSR_HVB
;
328 case POWERPC_EXCP_DSEG
: /* Data segment exception */
330 new_msr
|= (target_ulong
)MSR_HVB
;
333 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
335 new_msr
|= (target_ulong
)MSR_HVB
;
338 case POWERPC_EXCP_HDECR
: /* Hypervisor decrementer exception */
341 new_msr
|= (target_ulong
)MSR_HVB
;
342 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
344 case POWERPC_EXCP_TRACE
: /* Trace exception */
346 new_msr
|= (target_ulong
)MSR_HVB
;
349 case POWERPC_EXCP_HDSI
: /* Hypervisor data storage exception */
352 new_msr
|= (target_ulong
)MSR_HVB
;
353 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
355 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage exception */
358 new_msr
|= (target_ulong
)MSR_HVB
;
359 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
361 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
364 new_msr
|= (target_ulong
)MSR_HVB
;
365 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
367 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment exception */
370 new_msr
|= (target_ulong
)MSR_HVB
;
371 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
373 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
375 new_msr
|= (target_ulong
)MSR_HVB
;
378 case POWERPC_EXCP_PIT
: /* Programmable interval timer interrupt */
379 LOG_EXCP("PIT exception\n");
381 case POWERPC_EXCP_IO
: /* IO error exception */
383 cpu_abort(env
, "601 IO error exception is not implemented yet !\n");
385 case POWERPC_EXCP_RUNM
: /* Run mode exception */
387 cpu_abort(env
, "601 run mode exception is not implemented yet !\n");
389 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
391 cpu_abort(env
, "602 emulation trap exception "
392 "is not implemented yet !\n");
394 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
395 if (lpes1
== 0) { /* XXX: check this */
396 new_msr
|= (target_ulong
)MSR_HVB
;
398 switch (excp_model
) {
399 case POWERPC_EXCP_602
:
400 case POWERPC_EXCP_603
:
401 case POWERPC_EXCP_603E
:
402 case POWERPC_EXCP_G2
:
404 case POWERPC_EXCP_7x5
:
406 case POWERPC_EXCP_74xx
:
409 cpu_abort(env
, "Invalid instruction TLB miss exception\n");
413 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
414 if (lpes1
== 0) { /* XXX: check this */
415 new_msr
|= (target_ulong
)MSR_HVB
;
417 switch (excp_model
) {
418 case POWERPC_EXCP_602
:
419 case POWERPC_EXCP_603
:
420 case POWERPC_EXCP_603E
:
421 case POWERPC_EXCP_G2
:
423 case POWERPC_EXCP_7x5
:
425 case POWERPC_EXCP_74xx
:
428 cpu_abort(env
, "Invalid data load TLB miss exception\n");
432 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
433 if (lpes1
== 0) { /* XXX: check this */
434 new_msr
|= (target_ulong
)MSR_HVB
;
436 switch (excp_model
) {
437 case POWERPC_EXCP_602
:
438 case POWERPC_EXCP_603
:
439 case POWERPC_EXCP_603E
:
440 case POWERPC_EXCP_G2
:
442 /* Swap temporary saved registers with GPRs */
443 if (!(new_msr
& ((target_ulong
)1 << MSR_TGPR
))) {
444 new_msr
|= (target_ulong
)1 << MSR_TGPR
;
445 hreg_swap_gpr_tgpr(env
);
448 case POWERPC_EXCP_7x5
:
450 #if defined(DEBUG_SOFTWARE_TLB)
451 if (qemu_log_enabled()) {
453 target_ulong
*miss
, *cmp
;
456 if (excp
== POWERPC_EXCP_IFTLB
) {
459 miss
= &env
->spr
[SPR_IMISS
];
460 cmp
= &env
->spr
[SPR_ICMP
];
462 if (excp
== POWERPC_EXCP_DLTLB
) {
468 miss
= &env
->spr
[SPR_DMISS
];
469 cmp
= &env
->spr
[SPR_DCMP
];
471 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
472 TARGET_FMT_lx
" H1 " TARGET_FMT_lx
" H2 "
473 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
474 env
->spr
[SPR_HASH1
], env
->spr
[SPR_HASH2
],
478 msr
|= env
->crf
[0] << 28;
479 msr
|= env
->error_code
; /* key, D/I, S/L bits */
480 /* Set way using a LRU mechanism */
481 msr
|= ((env
->last_way
+ 1) & (env
->nb_ways
- 1)) << 17;
483 case POWERPC_EXCP_74xx
:
485 #if defined(DEBUG_SOFTWARE_TLB)
486 if (qemu_log_enabled()) {
488 target_ulong
*miss
, *cmp
;
491 if (excp
== POWERPC_EXCP_IFTLB
) {
494 miss
= &env
->spr
[SPR_TLBMISS
];
495 cmp
= &env
->spr
[SPR_PTEHI
];
497 if (excp
== POWERPC_EXCP_DLTLB
) {
503 miss
= &env
->spr
[SPR_TLBMISS
];
504 cmp
= &env
->spr
[SPR_PTEHI
];
506 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
507 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
511 msr
|= env
->error_code
; /* key bit */
514 cpu_abort(env
, "Invalid data store TLB miss exception\n");
518 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
520 cpu_abort(env
, "Floating point assist exception "
521 "is not implemented yet !\n");
523 case POWERPC_EXCP_DABR
: /* Data address breakpoint */
525 cpu_abort(env
, "DABR exception is not implemented yet !\n");
527 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
529 cpu_abort(env
, "IABR exception is not implemented yet !\n");
531 case POWERPC_EXCP_SMI
: /* System management interrupt */
533 cpu_abort(env
, "SMI exception is not implemented yet !\n");
535 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
537 cpu_abort(env
, "Thermal management exception "
538 "is not implemented yet !\n");
540 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor interrupt */
542 new_msr
|= (target_ulong
)MSR_HVB
;
546 "Performance counter exception is not implemented yet !\n");
548 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
550 cpu_abort(env
, "VPU assist exception is not implemented yet !\n");
552 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
555 "970 soft-patch exception is not implemented yet !\n");
557 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
560 "970 maintenance exception is not implemented yet !\n");
562 case POWERPC_EXCP_MEXTBR
: /* Maskable external breakpoint */
564 cpu_abort(env
, "Maskable external exception "
565 "is not implemented yet !\n");
567 case POWERPC_EXCP_NMEXTBR
: /* Non maskable external breakpoint */
569 cpu_abort(env
, "Non maskable external exception "
570 "is not implemented yet !\n");
574 cpu_abort(env
, "Invalid PowerPC exception %d. Aborting\n", excp
);
577 /* save current instruction location */
578 env
->spr
[srr0
] = env
->nip
- 4;
581 /* save next instruction location */
582 env
->spr
[srr0
] = env
->nip
;
586 env
->spr
[srr1
] = msr
;
587 /* If any alternate SRR register are defined, duplicate saved values */
589 env
->spr
[asrr0
] = env
->spr
[srr0
];
592 env
->spr
[asrr1
] = env
->spr
[srr1
];
594 /* If we disactivated any translation, flush TLBs */
595 if (msr
& ((1 << MSR_IR
) | (1 << MSR_DR
))) {
600 new_msr
|= (target_ulong
)1 << MSR_LE
;
603 /* Jump to handler */
604 vector
= env
->excp_vectors
[excp
];
605 if (vector
== (target_ulong
)-1ULL) {
606 cpu_abort(env
, "Raised an exception without defined vector %d\n",
609 vector
|= env
->excp_prefix
;
610 #if defined(TARGET_PPC64)
611 if (excp_model
== POWERPC_EXCP_BOOKE
) {
612 if (env
->spr
[SPR_BOOKE_EPCR
] & EPCR_ICM
) {
613 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
614 new_msr
|= (target_ulong
)1 << MSR_CM
;
616 vector
= (uint32_t)vector
;
619 if (!msr_isf
&& !(env
->mmu_model
& POWERPC_MMU_64
)) {
620 vector
= (uint32_t)vector
;
622 new_msr
|= (target_ulong
)1 << MSR_SF
;
626 /* XXX: we don't use hreg_store_msr here as already have treated
627 * any special case that could occur. Just store MSR and update hflags
629 env
->msr
= new_msr
& env
->msr_mask
;
630 hreg_compute_hflags(env
);
632 /* Reset exception state */
633 env
->exception_index
= POWERPC_EXCP_NONE
;
636 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
637 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
638 /* XXX: The BookE changes address space when switching modes,
639 we should probably implement that as different MMU indexes,
640 but for the moment we do it the slow way and flush all. */
645 void do_interrupt(CPUPPCState
*env
)
647 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
649 powerpc_excp(cpu
, env
->excp_model
, env
->exception_index
);
652 void ppc_hw_interrupt(CPUPPCState
*env
)
654 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
658 qemu_log_mask(CPU_LOG_INT
, "%s: %p pending %08x req %08x me %d ee %d\n",
659 __func__
, env
, env
->pending_interrupts
,
660 env
->interrupt_request
, (int)msr_me
, (int)msr_ee
);
663 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_RESET
)) {
664 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_RESET
);
665 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_RESET
);
668 /* Machine check exception */
669 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_MCK
)) {
670 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_MCK
);
671 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_MCHECK
);
675 /* External debug exception */
676 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DEBUG
)) {
677 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DEBUG
);
678 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DEBUG
);
683 /* XXX: find a suitable condition to enable the hypervisor mode */
684 hdice
= env
->spr
[SPR_LPCR
] & 1;
688 if ((msr_ee
!= 0 || msr_hv
== 0 || msr_pr
!= 0) && hdice
!= 0) {
689 /* Hypervisor decrementer exception */
690 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_HDECR
)) {
691 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_HDECR
);
692 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_HDECR
);
697 /* External critical interrupt */
698 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CEXT
)) {
699 /* Taking a critical external interrupt does not clear the external
700 * critical interrupt status
703 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CEXT
);
705 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_CRITICAL
);
710 /* Watchdog timer on embedded PowerPC */
711 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_WDT
)) {
712 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_WDT
);
713 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_WDT
);
716 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CDOORBELL
)) {
717 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CDOORBELL
);
718 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORCI
);
721 /* Fixed interval timer on embedded PowerPC */
722 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_FIT
)) {
723 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_FIT
);
724 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_FIT
);
727 /* Programmable interval timer on embedded PowerPC */
728 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PIT
)) {
729 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PIT
);
730 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PIT
);
733 /* Decrementer exception */
734 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DECR
)) {
735 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DECR
);
736 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DECR
);
739 /* External interrupt */
740 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_EXT
)) {
741 /* Taking an external interrupt does not clear the external
745 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_EXT
);
747 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_EXTERNAL
);
750 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DOORBELL
)) {
751 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DOORBELL
);
752 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORI
);
755 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PERFM
)) {
756 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PERFM
);
757 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PERFM
);
760 /* Thermal interrupt */
761 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_THERM
)) {
762 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_THERM
);
763 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_THERM
);
768 #endif /* !CONFIG_USER_ONLY */
770 #if defined(DEBUG_OP)
771 static void cpu_dump_rfi(target_ulong RA
, target_ulong msr
)
773 qemu_log("Return from exception at " TARGET_FMT_lx
" with flags "
774 TARGET_FMT_lx
"\n", RA
, msr
);
778 /*****************************************************************************/
779 /* Exceptions processing helpers */
781 void helper_raise_exception_err(CPUPPCState
*env
, uint32_t exception
,
785 printf("Raise exception %3x code : %d\n", exception
, error_code
);
787 env
->exception_index
= exception
;
788 env
->error_code
= error_code
;
792 void helper_raise_exception(CPUPPCState
*env
, uint32_t exception
)
794 helper_raise_exception_err(env
, exception
, 0);
797 #if !defined(CONFIG_USER_ONLY)
798 void helper_store_msr(CPUPPCState
*env
, target_ulong val
)
800 val
= hreg_store_msr(env
, val
, 0);
802 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
803 helper_raise_exception(env
, val
);
807 static inline void do_rfi(CPUPPCState
*env
, target_ulong nip
, target_ulong msr
,
808 target_ulong msrm
, int keep_msrh
)
810 #if defined(TARGET_PPC64)
811 if (msr_is_64bit(env
, msr
)) {
813 msr
&= (uint64_t)msrm
;
816 msr
= (uint32_t)(msr
& msrm
);
818 msr
|= env
->msr
& ~((uint64_t)0xFFFFFFFF);
823 msr
&= (uint32_t)msrm
;
825 /* XXX: beware: this is false if VLE is supported */
826 env
->nip
= nip
& ~((target_ulong
)0x00000003);
827 hreg_store_msr(env
, msr
, 1);
828 #if defined(DEBUG_OP)
829 cpu_dump_rfi(env
->nip
, env
->msr
);
831 /* No need to raise an exception here,
832 * as rfi is always the last insn of a TB
834 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
837 void helper_rfi(CPUPPCState
*env
)
839 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
840 ~((target_ulong
)0x783F0000), 1);
843 #if defined(TARGET_PPC64)
844 void helper_rfid(CPUPPCState
*env
)
846 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
847 ~((target_ulong
)0x783F0000), 0);
850 void helper_hrfid(CPUPPCState
*env
)
852 do_rfi(env
, env
->spr
[SPR_HSRR0
], env
->spr
[SPR_HSRR1
],
853 ~((target_ulong
)0x783F0000), 0);
857 /*****************************************************************************/
858 /* Embedded PowerPC specific helpers */
859 void helper_40x_rfci(CPUPPCState
*env
)
861 do_rfi(env
, env
->spr
[SPR_40x_SRR2
], env
->spr
[SPR_40x_SRR3
],
862 ~((target_ulong
)0xFFFF0000), 0);
865 void helper_rfci(CPUPPCState
*env
)
867 do_rfi(env
, env
->spr
[SPR_BOOKE_CSRR0
], SPR_BOOKE_CSRR1
,
868 ~((target_ulong
)0x3FFF0000), 0);
871 void helper_rfdi(CPUPPCState
*env
)
873 do_rfi(env
, env
->spr
[SPR_BOOKE_DSRR0
], SPR_BOOKE_DSRR1
,
874 ~((target_ulong
)0x3FFF0000), 0);
877 void helper_rfmci(CPUPPCState
*env
)
879 do_rfi(env
, env
->spr
[SPR_BOOKE_MCSRR0
], SPR_BOOKE_MCSRR1
,
880 ~((target_ulong
)0x3FFF0000), 0);
884 void helper_tw(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
887 if (!likely(!(((int32_t)arg1
< (int32_t)arg2
&& (flags
& 0x10)) ||
888 ((int32_t)arg1
> (int32_t)arg2
&& (flags
& 0x08)) ||
889 ((int32_t)arg1
== (int32_t)arg2
&& (flags
& 0x04)) ||
890 ((uint32_t)arg1
< (uint32_t)arg2
&& (flags
& 0x02)) ||
891 ((uint32_t)arg1
> (uint32_t)arg2
&& (flags
& 0x01))))) {
892 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
897 #if defined(TARGET_PPC64)
898 void helper_td(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
901 if (!likely(!(((int64_t)arg1
< (int64_t)arg2
&& (flags
& 0x10)) ||
902 ((int64_t)arg1
> (int64_t)arg2
&& (flags
& 0x08)) ||
903 ((int64_t)arg1
== (int64_t)arg2
&& (flags
& 0x04)) ||
904 ((uint64_t)arg1
< (uint64_t)arg2
&& (flags
& 0x02)) ||
905 ((uint64_t)arg1
> (uint64_t)arg2
&& (flags
& 0x01))))) {
906 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
912 #if !defined(CONFIG_USER_ONLY)
913 /*****************************************************************************/
914 /* PowerPC 601 specific instructions (POWER bridge) */
916 void helper_rfsvc(CPUPPCState
*env
)
918 do_rfi(env
, env
->lr
, env
->ctr
, 0x0000FFFF, 0);
921 /* Embedded.Processor Control */
922 static int dbell2irq(target_ulong rb
)
924 int msg
= rb
& DBELL_TYPE_MASK
;
928 case DBELL_TYPE_DBELL
:
929 irq
= PPC_INTERRUPT_DOORBELL
;
931 case DBELL_TYPE_DBELL_CRIT
:
932 irq
= PPC_INTERRUPT_CDOORBELL
;
934 case DBELL_TYPE_G_DBELL
:
935 case DBELL_TYPE_G_DBELL_CRIT
:
936 case DBELL_TYPE_G_DBELL_MC
:
945 void helper_msgclr(CPUPPCState
*env
, target_ulong rb
)
947 int irq
= dbell2irq(rb
);
953 env
->pending_interrupts
&= ~(1 << irq
);
956 void helper_msgsnd(target_ulong rb
)
958 int irq
= dbell2irq(rb
);
959 int pir
= rb
& DBELL_PIRTAG_MASK
;
966 for (cenv
= first_cpu
; cenv
!= NULL
; cenv
= cenv
->next_cpu
) {
967 if ((rb
& DBELL_BRDCAST
) || (cenv
->spr
[SPR_BOOKE_PIR
] == pir
)) {
968 cenv
->pending_interrupts
|= 1 << irq
;
969 cpu_interrupt(cenv
, CPU_INTERRUPT_HARD
);