]>
git.ipfire.org Git - thirdparty/qemu.git/blob - target-ppc/excp_helper.c
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
;
70 target_ulong msr
, new_msr
, vector
;
71 int srr0
, srr1
, asrr0
, asrr1
;
72 int lpes0
, lpes1
, lev
;
75 /* XXX: find a suitable condition to enable the hypervisor mode */
76 lpes0
= (env
->spr
[SPR_LPCR
] >> 1) & 1;
77 lpes1
= (env
->spr
[SPR_LPCR
] >> 2) & 1;
79 /* Those values ensure we won't enter the hypervisor mode */
84 qemu_log_mask(CPU_LOG_INT
, "Raise exception at " TARGET_FMT_lx
85 " => %08x (%02x)\n", env
->nip
, excp
, env
->error_code
);
87 /* new srr1 value excluding must-be-zero bits */
88 if (excp_model
== POWERPC_EXCP_BOOKE
) {
91 msr
= env
->msr
& ~0x783f0000ULL
;
94 /* new interrupt handler msr */
95 new_msr
= env
->msr
& ((target_ulong
)1 << MSR_ME
);
97 /* target registers */
104 case POWERPC_EXCP_NONE
:
105 /* Should never happen */
107 case POWERPC_EXCP_CRITICAL
: /* Critical input */
108 switch (excp_model
) {
109 case POWERPC_EXCP_40x
:
113 case POWERPC_EXCP_BOOKE
:
114 srr0
= SPR_BOOKE_CSRR0
;
115 srr1
= SPR_BOOKE_CSRR1
;
117 case POWERPC_EXCP_G2
:
123 case POWERPC_EXCP_MCHECK
: /* Machine check exception */
125 /* Machine check exception is not enabled.
126 * Enter checkstop state.
128 if (qemu_log_enabled()) {
129 qemu_log("Machine check while not allowed. "
130 "Entering checkstop state\n");
132 fprintf(stderr
, "Machine check while not allowed. "
133 "Entering checkstop state\n");
137 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
140 /* XXX: find a suitable condition to enable the hypervisor mode */
141 new_msr
|= (target_ulong
)MSR_HVB
;
144 /* machine check exceptions don't have ME set */
145 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
147 /* XXX: should also have something loaded in DAR / DSISR */
148 switch (excp_model
) {
149 case POWERPC_EXCP_40x
:
153 case POWERPC_EXCP_BOOKE
:
154 /* FIXME: choose one or the other based on CPU type */
155 srr0
= SPR_BOOKE_MCSRR0
;
156 srr1
= SPR_BOOKE_MCSRR1
;
157 asrr0
= SPR_BOOKE_CSRR0
;
158 asrr1
= SPR_BOOKE_CSRR1
;
164 case POWERPC_EXCP_DSI
: /* Data storage exception */
165 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx
" DAR=" TARGET_FMT_lx
166 "\n", env
->spr
[SPR_DSISR
], env
->spr
[SPR_DAR
]);
168 new_msr
|= (target_ulong
)MSR_HVB
;
171 case POWERPC_EXCP_ISI
: /* Instruction storage exception */
172 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx
", nip=" TARGET_FMT_lx
173 "\n", msr
, env
->nip
);
175 new_msr
|= (target_ulong
)MSR_HVB
;
177 msr
|= env
->error_code
;
179 case POWERPC_EXCP_EXTERNAL
: /* External input */
181 new_msr
|= (target_ulong
)MSR_HVB
;
183 if (env
->mpic_proxy
) {
184 /* IACK the IRQ on delivery */
185 env
->spr
[SPR_BOOKE_EPR
] = ldl_phys(env
->mpic_iack
);
188 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
190 new_msr
|= (target_ulong
)MSR_HVB
;
192 /* XXX: this is false */
193 /* Get rS/rD and rA from faulting opcode */
194 env
->spr
[SPR_DSISR
] |= (cpu_ldl_code(env
, (env
->nip
- 4))
197 case POWERPC_EXCP_PROGRAM
: /* Program exception */
198 switch (env
->error_code
& ~0xF) {
199 case POWERPC_EXCP_FP
:
200 if ((msr_fe0
== 0 && msr_fe1
== 0) || msr_fp
== 0) {
201 LOG_EXCP("Ignore floating point exception\n");
202 env
->exception_index
= POWERPC_EXCP_NONE
;
207 new_msr
|= (target_ulong
)MSR_HVB
;
210 if (msr_fe0
== msr_fe1
) {
215 case POWERPC_EXCP_INVAL
:
216 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx
"\n", env
->nip
);
218 new_msr
|= (target_ulong
)MSR_HVB
;
221 env
->spr
[SPR_BOOKE_ESR
] = ESR_PIL
;
223 case POWERPC_EXCP_PRIV
:
225 new_msr
|= (target_ulong
)MSR_HVB
;
228 env
->spr
[SPR_BOOKE_ESR
] = ESR_PPR
;
230 case POWERPC_EXCP_TRAP
:
232 new_msr
|= (target_ulong
)MSR_HVB
;
235 env
->spr
[SPR_BOOKE_ESR
] = ESR_PTR
;
238 /* Should never occur */
239 cpu_abort(env
, "Invalid program exception %d. Aborting\n",
244 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
246 new_msr
|= (target_ulong
)MSR_HVB
;
249 case POWERPC_EXCP_SYSCALL
: /* System call exception */
251 lev
= env
->error_code
;
252 if ((lev
== 1) && cpu_ppc_hypercall
) {
253 cpu_ppc_hypercall(cpu
);
256 if (lev
== 1 || (lpes0
== 0 && lpes1
== 0)) {
257 new_msr
|= (target_ulong
)MSR_HVB
;
260 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
262 case POWERPC_EXCP_DECR
: /* Decrementer exception */
264 new_msr
|= (target_ulong
)MSR_HVB
;
267 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
269 LOG_EXCP("FIT exception\n");
271 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
272 LOG_EXCP("WDT exception\n");
273 switch (excp_model
) {
274 case POWERPC_EXCP_BOOKE
:
275 srr0
= SPR_BOOKE_CSRR0
;
276 srr1
= SPR_BOOKE_CSRR1
;
282 case POWERPC_EXCP_DTLB
: /* Data TLB error */
284 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
286 case POWERPC_EXCP_DEBUG
: /* Debug interrupt */
287 switch (excp_model
) {
288 case POWERPC_EXCP_BOOKE
:
289 /* FIXME: choose one or the other based on CPU type */
290 srr0
= SPR_BOOKE_DSRR0
;
291 srr1
= SPR_BOOKE_DSRR1
;
292 asrr0
= SPR_BOOKE_CSRR0
;
293 asrr1
= SPR_BOOKE_CSRR1
;
299 cpu_abort(env
, "Debug exception is not implemented yet !\n");
301 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavailable */
302 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
304 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data interrupt */
306 cpu_abort(env
, "Embedded floating point data exception "
307 "is not implemented yet !\n");
308 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
310 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round interrupt */
312 cpu_abort(env
, "Embedded floating point round exception "
313 "is not implemented yet !\n");
314 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
316 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor interrupt */
319 "Performance counter exception is not implemented yet !\n");
321 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
323 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
324 srr0
= SPR_BOOKE_CSRR0
;
325 srr1
= SPR_BOOKE_CSRR1
;
327 case POWERPC_EXCP_RESET
: /* System reset exception */
329 /* indicate that we resumed from power save mode */
332 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
336 /* XXX: find a suitable condition to enable the hypervisor mode */
337 new_msr
|= (target_ulong
)MSR_HVB
;
340 case POWERPC_EXCP_DSEG
: /* Data segment exception */
342 new_msr
|= (target_ulong
)MSR_HVB
;
345 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
347 new_msr
|= (target_ulong
)MSR_HVB
;
350 case POWERPC_EXCP_HDECR
: /* Hypervisor decrementer exception */
353 new_msr
|= (target_ulong
)MSR_HVB
;
354 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
356 case POWERPC_EXCP_TRACE
: /* Trace exception */
358 new_msr
|= (target_ulong
)MSR_HVB
;
361 case POWERPC_EXCP_HDSI
: /* Hypervisor data storage exception */
364 new_msr
|= (target_ulong
)MSR_HVB
;
365 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
367 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage exception */
370 new_msr
|= (target_ulong
)MSR_HVB
;
371 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
373 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
376 new_msr
|= (target_ulong
)MSR_HVB
;
377 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
379 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment exception */
382 new_msr
|= (target_ulong
)MSR_HVB
;
383 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
385 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
387 new_msr
|= (target_ulong
)MSR_HVB
;
390 case POWERPC_EXCP_PIT
: /* Programmable interval timer interrupt */
391 LOG_EXCP("PIT exception\n");
393 case POWERPC_EXCP_IO
: /* IO error exception */
395 cpu_abort(env
, "601 IO error exception is not implemented yet !\n");
397 case POWERPC_EXCP_RUNM
: /* Run mode exception */
399 cpu_abort(env
, "601 run mode exception is not implemented yet !\n");
401 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
403 cpu_abort(env
, "602 emulation trap exception "
404 "is not implemented yet !\n");
406 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
407 if (lpes1
== 0) { /* XXX: check this */
408 new_msr
|= (target_ulong
)MSR_HVB
;
410 switch (excp_model
) {
411 case POWERPC_EXCP_602
:
412 case POWERPC_EXCP_603
:
413 case POWERPC_EXCP_603E
:
414 case POWERPC_EXCP_G2
:
416 case POWERPC_EXCP_7x5
:
418 case POWERPC_EXCP_74xx
:
421 cpu_abort(env
, "Invalid instruction TLB miss exception\n");
425 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
426 if (lpes1
== 0) { /* XXX: check this */
427 new_msr
|= (target_ulong
)MSR_HVB
;
429 switch (excp_model
) {
430 case POWERPC_EXCP_602
:
431 case POWERPC_EXCP_603
:
432 case POWERPC_EXCP_603E
:
433 case POWERPC_EXCP_G2
:
435 case POWERPC_EXCP_7x5
:
437 case POWERPC_EXCP_74xx
:
440 cpu_abort(env
, "Invalid data load TLB miss exception\n");
444 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
445 if (lpes1
== 0) { /* XXX: check this */
446 new_msr
|= (target_ulong
)MSR_HVB
;
448 switch (excp_model
) {
449 case POWERPC_EXCP_602
:
450 case POWERPC_EXCP_603
:
451 case POWERPC_EXCP_603E
:
452 case POWERPC_EXCP_G2
:
454 /* Swap temporary saved registers with GPRs */
455 if (!(new_msr
& ((target_ulong
)1 << MSR_TGPR
))) {
456 new_msr
|= (target_ulong
)1 << MSR_TGPR
;
457 hreg_swap_gpr_tgpr(env
);
460 case POWERPC_EXCP_7x5
:
462 #if defined(DEBUG_SOFTWARE_TLB)
463 if (qemu_log_enabled()) {
465 target_ulong
*miss
, *cmp
;
468 if (excp
== POWERPC_EXCP_IFTLB
) {
471 miss
= &env
->spr
[SPR_IMISS
];
472 cmp
= &env
->spr
[SPR_ICMP
];
474 if (excp
== POWERPC_EXCP_DLTLB
) {
480 miss
= &env
->spr
[SPR_DMISS
];
481 cmp
= &env
->spr
[SPR_DCMP
];
483 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
484 TARGET_FMT_lx
" H1 " TARGET_FMT_lx
" H2 "
485 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
486 env
->spr
[SPR_HASH1
], env
->spr
[SPR_HASH2
],
490 msr
|= env
->crf
[0] << 28;
491 msr
|= env
->error_code
; /* key, D/I, S/L bits */
492 /* Set way using a LRU mechanism */
493 msr
|= ((env
->last_way
+ 1) & (env
->nb_ways
- 1)) << 17;
495 case POWERPC_EXCP_74xx
:
497 #if defined(DEBUG_SOFTWARE_TLB)
498 if (qemu_log_enabled()) {
500 target_ulong
*miss
, *cmp
;
503 if (excp
== POWERPC_EXCP_IFTLB
) {
506 miss
= &env
->spr
[SPR_TLBMISS
];
507 cmp
= &env
->spr
[SPR_PTEHI
];
509 if (excp
== POWERPC_EXCP_DLTLB
) {
515 miss
= &env
->spr
[SPR_TLBMISS
];
516 cmp
= &env
->spr
[SPR_PTEHI
];
518 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
519 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
523 msr
|= env
->error_code
; /* key bit */
526 cpu_abort(env
, "Invalid data store TLB miss exception\n");
530 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
532 cpu_abort(env
, "Floating point assist exception "
533 "is not implemented yet !\n");
535 case POWERPC_EXCP_DABR
: /* Data address breakpoint */
537 cpu_abort(env
, "DABR exception is not implemented yet !\n");
539 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
541 cpu_abort(env
, "IABR exception is not implemented yet !\n");
543 case POWERPC_EXCP_SMI
: /* System management interrupt */
545 cpu_abort(env
, "SMI exception is not implemented yet !\n");
547 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
549 cpu_abort(env
, "Thermal management exception "
550 "is not implemented yet !\n");
552 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor interrupt */
554 new_msr
|= (target_ulong
)MSR_HVB
;
558 "Performance counter exception is not implemented yet !\n");
560 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
562 cpu_abort(env
, "VPU assist exception is not implemented yet !\n");
564 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
567 "970 soft-patch exception is not implemented yet !\n");
569 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
572 "970 maintenance exception is not implemented yet !\n");
574 case POWERPC_EXCP_MEXTBR
: /* Maskable external breakpoint */
576 cpu_abort(env
, "Maskable external exception "
577 "is not implemented yet !\n");
579 case POWERPC_EXCP_NMEXTBR
: /* Non maskable external breakpoint */
581 cpu_abort(env
, "Non maskable external exception "
582 "is not implemented yet !\n");
586 cpu_abort(env
, "Invalid PowerPC exception %d. Aborting\n", excp
);
589 /* save current instruction location */
590 env
->spr
[srr0
] = env
->nip
- 4;
593 /* save next instruction location */
594 env
->spr
[srr0
] = env
->nip
;
598 env
->spr
[srr1
] = msr
;
599 /* If any alternate SRR register are defined, duplicate saved values */
601 env
->spr
[asrr0
] = env
->spr
[srr0
];
604 env
->spr
[asrr1
] = env
->spr
[srr1
];
606 /* If we disactivated any translation, flush TLBs */
607 if (msr
& ((1 << MSR_IR
) | (1 << MSR_DR
))) {
612 new_msr
|= (target_ulong
)1 << MSR_LE
;
615 /* Jump to handler */
616 vector
= env
->excp_vectors
[excp
];
617 if (vector
== (target_ulong
)-1ULL) {
618 cpu_abort(env
, "Raised an exception without defined vector %d\n",
621 vector
|= env
->excp_prefix
;
622 #if defined(TARGET_PPC64)
623 if (excp_model
== POWERPC_EXCP_BOOKE
) {
624 if (env
->spr
[SPR_BOOKE_EPCR
] & EPCR_ICM
) {
625 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
626 new_msr
|= (target_ulong
)1 << MSR_CM
;
628 vector
= (uint32_t)vector
;
631 if (!msr_isf
&& !(env
->mmu_model
& POWERPC_MMU_64
)) {
632 vector
= (uint32_t)vector
;
634 new_msr
|= (target_ulong
)1 << MSR_SF
;
638 /* XXX: we don't use hreg_store_msr here as already have treated
639 * any special case that could occur. Just store MSR and update hflags
641 env
->msr
= new_msr
& env
->msr_mask
;
642 hreg_compute_hflags(env
);
644 /* Reset exception state */
645 env
->exception_index
= POWERPC_EXCP_NONE
;
648 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
649 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
650 /* XXX: The BookE changes address space when switching modes,
651 we should probably implement that as different MMU indexes,
652 but for the moment we do it the slow way and flush all. */
657 void do_interrupt(CPUPPCState
*env
)
659 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
661 powerpc_excp(cpu
, env
->excp_model
, env
->exception_index
);
664 void ppc_hw_interrupt(CPUPPCState
*env
)
666 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
669 CPUState
*cs
= CPU(cpu
);
671 qemu_log_mask(CPU_LOG_INT
, "%s: %p pending %08x req %08x me %d ee %d\n",
672 __func__
, env
, env
->pending_interrupts
,
673 cs
->interrupt_request
, (int)msr_me
, (int)msr_ee
);
676 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_RESET
)) {
677 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_RESET
);
678 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_RESET
);
681 /* Machine check exception */
682 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_MCK
)) {
683 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_MCK
);
684 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_MCHECK
);
688 /* External debug exception */
689 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DEBUG
)) {
690 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DEBUG
);
691 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DEBUG
);
696 /* XXX: find a suitable condition to enable the hypervisor mode */
697 hdice
= env
->spr
[SPR_LPCR
] & 1;
701 if ((msr_ee
!= 0 || msr_hv
== 0 || msr_pr
!= 0) && hdice
!= 0) {
702 /* Hypervisor decrementer exception */
703 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_HDECR
)) {
704 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_HDECR
);
705 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_HDECR
);
710 /* External critical interrupt */
711 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CEXT
)) {
712 /* Taking a critical external interrupt does not clear the external
713 * critical interrupt status
716 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CEXT
);
718 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_CRITICAL
);
723 /* Watchdog timer on embedded PowerPC */
724 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_WDT
)) {
725 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_WDT
);
726 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_WDT
);
729 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CDOORBELL
)) {
730 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CDOORBELL
);
731 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORCI
);
734 /* Fixed interval timer on embedded PowerPC */
735 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_FIT
)) {
736 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_FIT
);
737 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_FIT
);
740 /* Programmable interval timer on embedded PowerPC */
741 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PIT
)) {
742 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PIT
);
743 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PIT
);
746 /* Decrementer exception */
747 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DECR
)) {
748 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DECR
);
749 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DECR
);
752 /* External interrupt */
753 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_EXT
)) {
754 /* Taking an external interrupt does not clear the external
758 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_EXT
);
760 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_EXTERNAL
);
763 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DOORBELL
)) {
764 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DOORBELL
);
765 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORI
);
768 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PERFM
)) {
769 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PERFM
);
770 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PERFM
);
773 /* Thermal interrupt */
774 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_THERM
)) {
775 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_THERM
);
776 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_THERM
);
781 #endif /* !CONFIG_USER_ONLY */
783 #if defined(DEBUG_OP)
784 static void cpu_dump_rfi(target_ulong RA
, target_ulong msr
)
786 qemu_log("Return from exception at " TARGET_FMT_lx
" with flags "
787 TARGET_FMT_lx
"\n", RA
, msr
);
791 /*****************************************************************************/
792 /* Exceptions processing helpers */
794 void helper_raise_exception_err(CPUPPCState
*env
, uint32_t exception
,
798 printf("Raise exception %3x code : %d\n", exception
, error_code
);
800 env
->exception_index
= exception
;
801 env
->error_code
= error_code
;
805 void helper_raise_exception(CPUPPCState
*env
, uint32_t exception
)
807 helper_raise_exception_err(env
, exception
, 0);
810 #if !defined(CONFIG_USER_ONLY)
811 void helper_store_msr(CPUPPCState
*env
, target_ulong val
)
815 val
= hreg_store_msr(env
, val
, 0);
817 cs
= CPU(ppc_env_get_cpu(env
));
818 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
819 helper_raise_exception(env
, val
);
823 static inline void do_rfi(CPUPPCState
*env
, target_ulong nip
, target_ulong msr
,
824 target_ulong msrm
, int keep_msrh
)
826 CPUState
*cs
= CPU(ppc_env_get_cpu(env
));
828 #if defined(TARGET_PPC64)
829 if (msr_is_64bit(env
, msr
)) {
831 msr
&= (uint64_t)msrm
;
834 msr
= (uint32_t)(msr
& msrm
);
836 msr
|= env
->msr
& ~((uint64_t)0xFFFFFFFF);
841 msr
&= (uint32_t)msrm
;
843 /* XXX: beware: this is false if VLE is supported */
844 env
->nip
= nip
& ~((target_ulong
)0x00000003);
845 hreg_store_msr(env
, msr
, 1);
846 #if defined(DEBUG_OP)
847 cpu_dump_rfi(env
->nip
, env
->msr
);
849 /* No need to raise an exception here,
850 * as rfi is always the last insn of a TB
852 cs
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
855 void helper_rfi(CPUPPCState
*env
)
857 if (env
->excp_model
== POWERPC_EXCP_BOOKE
) {
858 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
859 ~((target_ulong
)0), 0);
861 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
862 ~((target_ulong
)0x783F0000), 1);
866 #if defined(TARGET_PPC64)
867 void helper_rfid(CPUPPCState
*env
)
869 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
870 ~((target_ulong
)0x783F0000), 0);
873 void helper_hrfid(CPUPPCState
*env
)
875 do_rfi(env
, env
->spr
[SPR_HSRR0
], env
->spr
[SPR_HSRR1
],
876 ~((target_ulong
)0x783F0000), 0);
880 /*****************************************************************************/
881 /* Embedded PowerPC specific helpers */
882 void helper_40x_rfci(CPUPPCState
*env
)
884 do_rfi(env
, env
->spr
[SPR_40x_SRR2
], env
->spr
[SPR_40x_SRR3
],
885 ~((target_ulong
)0xFFFF0000), 0);
888 void helper_rfci(CPUPPCState
*env
)
890 do_rfi(env
, env
->spr
[SPR_BOOKE_CSRR0
], env
->spr
[SPR_BOOKE_CSRR1
],
891 ~((target_ulong
)0), 0);
894 void helper_rfdi(CPUPPCState
*env
)
896 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
897 do_rfi(env
, env
->spr
[SPR_BOOKE_DSRR0
], env
->spr
[SPR_BOOKE_DSRR1
],
898 ~((target_ulong
)0), 0);
901 void helper_rfmci(CPUPPCState
*env
)
903 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
904 do_rfi(env
, env
->spr
[SPR_BOOKE_MCSRR0
], env
->spr
[SPR_BOOKE_MCSRR1
],
905 ~((target_ulong
)0), 0);
909 void helper_tw(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
912 if (!likely(!(((int32_t)arg1
< (int32_t)arg2
&& (flags
& 0x10)) ||
913 ((int32_t)arg1
> (int32_t)arg2
&& (flags
& 0x08)) ||
914 ((int32_t)arg1
== (int32_t)arg2
&& (flags
& 0x04)) ||
915 ((uint32_t)arg1
< (uint32_t)arg2
&& (flags
& 0x02)) ||
916 ((uint32_t)arg1
> (uint32_t)arg2
&& (flags
& 0x01))))) {
917 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
922 #if defined(TARGET_PPC64)
923 void helper_td(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
926 if (!likely(!(((int64_t)arg1
< (int64_t)arg2
&& (flags
& 0x10)) ||
927 ((int64_t)arg1
> (int64_t)arg2
&& (flags
& 0x08)) ||
928 ((int64_t)arg1
== (int64_t)arg2
&& (flags
& 0x04)) ||
929 ((uint64_t)arg1
< (uint64_t)arg2
&& (flags
& 0x02)) ||
930 ((uint64_t)arg1
> (uint64_t)arg2
&& (flags
& 0x01))))) {
931 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
937 #if !defined(CONFIG_USER_ONLY)
938 /*****************************************************************************/
939 /* PowerPC 601 specific instructions (POWER bridge) */
941 void helper_rfsvc(CPUPPCState
*env
)
943 do_rfi(env
, env
->lr
, env
->ctr
, 0x0000FFFF, 0);
946 /* Embedded.Processor Control */
947 static int dbell2irq(target_ulong rb
)
949 int msg
= rb
& DBELL_TYPE_MASK
;
953 case DBELL_TYPE_DBELL
:
954 irq
= PPC_INTERRUPT_DOORBELL
;
956 case DBELL_TYPE_DBELL_CRIT
:
957 irq
= PPC_INTERRUPT_CDOORBELL
;
959 case DBELL_TYPE_G_DBELL
:
960 case DBELL_TYPE_G_DBELL_CRIT
:
961 case DBELL_TYPE_G_DBELL_MC
:
970 void helper_msgclr(CPUPPCState
*env
, target_ulong rb
)
972 int irq
= dbell2irq(rb
);
978 env
->pending_interrupts
&= ~(1 << irq
);
981 void helper_msgsnd(target_ulong rb
)
983 int irq
= dbell2irq(rb
);
984 int pir
= rb
& DBELL_PIRTAG_MASK
;
991 for (cenv
= first_cpu
; cenv
!= NULL
; cenv
= cenv
->next_cpu
) {
992 if ((rb
& DBELL_BRDCAST
) || (cenv
->spr
[SPR_BOOKE_PIR
] == pir
)) {
993 cenv
->pending_interrupts
|= 1 << irq
;
994 cpu_interrupt(cenv
, CPU_INTERRUPT_HARD
);