]>
git.proxmox.com Git - 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
;
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
;
182 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
184 new_msr
|= (target_ulong
)MSR_HVB
;
186 /* XXX: this is false */
187 /* Get rS/rD and rA from faulting opcode */
188 env
->spr
[SPR_DSISR
] |= (cpu_ldl_code(env
, (env
->nip
- 4))
191 case POWERPC_EXCP_PROGRAM
: /* Program exception */
192 switch (env
->error_code
& ~0xF) {
193 case POWERPC_EXCP_FP
:
194 if ((msr_fe0
== 0 && msr_fe1
== 0) || msr_fp
== 0) {
195 LOG_EXCP("Ignore floating point exception\n");
196 env
->exception_index
= POWERPC_EXCP_NONE
;
201 new_msr
|= (target_ulong
)MSR_HVB
;
204 if (msr_fe0
== msr_fe1
) {
209 case POWERPC_EXCP_INVAL
:
210 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx
"\n", env
->nip
);
212 new_msr
|= (target_ulong
)MSR_HVB
;
215 env
->spr
[SPR_BOOKE_ESR
] = ESR_PIL
;
217 case POWERPC_EXCP_PRIV
:
219 new_msr
|= (target_ulong
)MSR_HVB
;
222 env
->spr
[SPR_BOOKE_ESR
] = ESR_PPR
;
224 case POWERPC_EXCP_TRAP
:
226 new_msr
|= (target_ulong
)MSR_HVB
;
229 env
->spr
[SPR_BOOKE_ESR
] = ESR_PTR
;
232 /* Should never occur */
233 cpu_abort(env
, "Invalid program exception %d. Aborting\n",
238 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
240 new_msr
|= (target_ulong
)MSR_HVB
;
243 case POWERPC_EXCP_SYSCALL
: /* System call exception */
245 lev
= env
->error_code
;
246 if ((lev
== 1) && cpu_ppc_hypercall
) {
247 cpu_ppc_hypercall(cpu
);
250 if (lev
== 1 || (lpes0
== 0 && lpes1
== 0)) {
251 new_msr
|= (target_ulong
)MSR_HVB
;
254 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
256 case POWERPC_EXCP_DECR
: /* Decrementer exception */
258 new_msr
|= (target_ulong
)MSR_HVB
;
261 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
263 LOG_EXCP("FIT exception\n");
265 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
266 LOG_EXCP("WDT exception\n");
267 switch (excp_model
) {
268 case POWERPC_EXCP_BOOKE
:
269 srr0
= SPR_BOOKE_CSRR0
;
270 srr1
= SPR_BOOKE_CSRR1
;
276 case POWERPC_EXCP_DTLB
: /* Data TLB error */
278 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
280 case POWERPC_EXCP_DEBUG
: /* Debug interrupt */
281 switch (excp_model
) {
282 case POWERPC_EXCP_BOOKE
:
283 /* FIXME: choose one or the other based on CPU type */
284 srr0
= SPR_BOOKE_DSRR0
;
285 srr1
= SPR_BOOKE_DSRR1
;
286 asrr0
= SPR_BOOKE_CSRR0
;
287 asrr1
= SPR_BOOKE_CSRR1
;
293 cpu_abort(env
, "Debug exception is not implemented yet !\n");
295 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavailable */
296 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
298 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data interrupt */
300 cpu_abort(env
, "Embedded floating point data exception "
301 "is not implemented yet !\n");
302 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
304 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round interrupt */
306 cpu_abort(env
, "Embedded floating point round exception "
307 "is not implemented yet !\n");
308 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
310 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor interrupt */
313 "Performance counter exception is not implemented yet !\n");
315 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
317 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
318 srr0
= SPR_BOOKE_CSRR0
;
319 srr1
= SPR_BOOKE_CSRR1
;
321 case POWERPC_EXCP_RESET
: /* System reset exception */
323 /* indicate that we resumed from power save mode */
326 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
330 /* XXX: find a suitable condition to enable the hypervisor mode */
331 new_msr
|= (target_ulong
)MSR_HVB
;
334 case POWERPC_EXCP_DSEG
: /* Data segment exception */
336 new_msr
|= (target_ulong
)MSR_HVB
;
339 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
341 new_msr
|= (target_ulong
)MSR_HVB
;
344 case POWERPC_EXCP_HDECR
: /* Hypervisor decrementer exception */
347 new_msr
|= (target_ulong
)MSR_HVB
;
348 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
350 case POWERPC_EXCP_TRACE
: /* Trace exception */
352 new_msr
|= (target_ulong
)MSR_HVB
;
355 case POWERPC_EXCP_HDSI
: /* Hypervisor data storage exception */
358 new_msr
|= (target_ulong
)MSR_HVB
;
359 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
361 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage exception */
364 new_msr
|= (target_ulong
)MSR_HVB
;
365 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
367 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
370 new_msr
|= (target_ulong
)MSR_HVB
;
371 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
373 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment exception */
376 new_msr
|= (target_ulong
)MSR_HVB
;
377 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
379 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
381 new_msr
|= (target_ulong
)MSR_HVB
;
384 case POWERPC_EXCP_PIT
: /* Programmable interval timer interrupt */
385 LOG_EXCP("PIT exception\n");
387 case POWERPC_EXCP_IO
: /* IO error exception */
389 cpu_abort(env
, "601 IO error exception is not implemented yet !\n");
391 case POWERPC_EXCP_RUNM
: /* Run mode exception */
393 cpu_abort(env
, "601 run mode exception is not implemented yet !\n");
395 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
397 cpu_abort(env
, "602 emulation trap exception "
398 "is not implemented yet !\n");
400 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
401 if (lpes1
== 0) { /* XXX: check this */
402 new_msr
|= (target_ulong
)MSR_HVB
;
404 switch (excp_model
) {
405 case POWERPC_EXCP_602
:
406 case POWERPC_EXCP_603
:
407 case POWERPC_EXCP_603E
:
408 case POWERPC_EXCP_G2
:
410 case POWERPC_EXCP_7x5
:
412 case POWERPC_EXCP_74xx
:
415 cpu_abort(env
, "Invalid instruction TLB miss exception\n");
419 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
420 if (lpes1
== 0) { /* XXX: check this */
421 new_msr
|= (target_ulong
)MSR_HVB
;
423 switch (excp_model
) {
424 case POWERPC_EXCP_602
:
425 case POWERPC_EXCP_603
:
426 case POWERPC_EXCP_603E
:
427 case POWERPC_EXCP_G2
:
429 case POWERPC_EXCP_7x5
:
431 case POWERPC_EXCP_74xx
:
434 cpu_abort(env
, "Invalid data load TLB miss exception\n");
438 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
439 if (lpes1
== 0) { /* XXX: check this */
440 new_msr
|= (target_ulong
)MSR_HVB
;
442 switch (excp_model
) {
443 case POWERPC_EXCP_602
:
444 case POWERPC_EXCP_603
:
445 case POWERPC_EXCP_603E
:
446 case POWERPC_EXCP_G2
:
448 /* Swap temporary saved registers with GPRs */
449 if (!(new_msr
& ((target_ulong
)1 << MSR_TGPR
))) {
450 new_msr
|= (target_ulong
)1 << MSR_TGPR
;
451 hreg_swap_gpr_tgpr(env
);
454 case POWERPC_EXCP_7x5
:
456 #if defined(DEBUG_SOFTWARE_TLB)
457 if (qemu_log_enabled()) {
459 target_ulong
*miss
, *cmp
;
462 if (excp
== POWERPC_EXCP_IFTLB
) {
465 miss
= &env
->spr
[SPR_IMISS
];
466 cmp
= &env
->spr
[SPR_ICMP
];
468 if (excp
== POWERPC_EXCP_DLTLB
) {
474 miss
= &env
->spr
[SPR_DMISS
];
475 cmp
= &env
->spr
[SPR_DCMP
];
477 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
478 TARGET_FMT_lx
" H1 " TARGET_FMT_lx
" H2 "
479 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
480 env
->spr
[SPR_HASH1
], env
->spr
[SPR_HASH2
],
484 msr
|= env
->crf
[0] << 28;
485 msr
|= env
->error_code
; /* key, D/I, S/L bits */
486 /* Set way using a LRU mechanism */
487 msr
|= ((env
->last_way
+ 1) & (env
->nb_ways
- 1)) << 17;
489 case POWERPC_EXCP_74xx
:
491 #if defined(DEBUG_SOFTWARE_TLB)
492 if (qemu_log_enabled()) {
494 target_ulong
*miss
, *cmp
;
497 if (excp
== POWERPC_EXCP_IFTLB
) {
500 miss
= &env
->spr
[SPR_TLBMISS
];
501 cmp
= &env
->spr
[SPR_PTEHI
];
503 if (excp
== POWERPC_EXCP_DLTLB
) {
509 miss
= &env
->spr
[SPR_TLBMISS
];
510 cmp
= &env
->spr
[SPR_PTEHI
];
512 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
513 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
517 msr
|= env
->error_code
; /* key bit */
520 cpu_abort(env
, "Invalid data store TLB miss exception\n");
524 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
526 cpu_abort(env
, "Floating point assist exception "
527 "is not implemented yet !\n");
529 case POWERPC_EXCP_DABR
: /* Data address breakpoint */
531 cpu_abort(env
, "DABR exception is not implemented yet !\n");
533 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
535 cpu_abort(env
, "IABR exception is not implemented yet !\n");
537 case POWERPC_EXCP_SMI
: /* System management interrupt */
539 cpu_abort(env
, "SMI exception is not implemented yet !\n");
541 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
543 cpu_abort(env
, "Thermal management exception "
544 "is not implemented yet !\n");
546 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor interrupt */
548 new_msr
|= (target_ulong
)MSR_HVB
;
552 "Performance counter exception is not implemented yet !\n");
554 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
556 cpu_abort(env
, "VPU assist exception is not implemented yet !\n");
558 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
561 "970 soft-patch exception is not implemented yet !\n");
563 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
566 "970 maintenance exception is not implemented yet !\n");
568 case POWERPC_EXCP_MEXTBR
: /* Maskable external breakpoint */
570 cpu_abort(env
, "Maskable external exception "
571 "is not implemented yet !\n");
573 case POWERPC_EXCP_NMEXTBR
: /* Non maskable external breakpoint */
575 cpu_abort(env
, "Non maskable external exception "
576 "is not implemented yet !\n");
580 cpu_abort(env
, "Invalid PowerPC exception %d. Aborting\n", excp
);
583 /* save current instruction location */
584 env
->spr
[srr0
] = env
->nip
- 4;
587 /* save next instruction location */
588 env
->spr
[srr0
] = env
->nip
;
592 env
->spr
[srr1
] = msr
;
593 /* If any alternate SRR register are defined, duplicate saved values */
595 env
->spr
[asrr0
] = env
->spr
[srr0
];
598 env
->spr
[asrr1
] = env
->spr
[srr1
];
600 /* If we disactivated any translation, flush TLBs */
601 if (msr
& ((1 << MSR_IR
) | (1 << MSR_DR
))) {
606 new_msr
|= (target_ulong
)1 << MSR_LE
;
609 /* Jump to handler */
610 vector
= env
->excp_vectors
[excp
];
611 if (vector
== (target_ulong
)-1ULL) {
612 cpu_abort(env
, "Raised an exception without defined vector %d\n",
615 vector
|= env
->excp_prefix
;
616 #if defined(TARGET_PPC64)
617 if (excp_model
== POWERPC_EXCP_BOOKE
) {
618 if (env
->spr
[SPR_BOOKE_EPCR
] & EPCR_ICM
) {
619 /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
620 new_msr
|= (target_ulong
)1 << MSR_CM
;
622 vector
= (uint32_t)vector
;
625 if (!msr_isf
&& !(env
->mmu_model
& POWERPC_MMU_64
)) {
626 vector
= (uint32_t)vector
;
628 new_msr
|= (target_ulong
)1 << MSR_SF
;
632 /* XXX: we don't use hreg_store_msr here as already have treated
633 * any special case that could occur. Just store MSR and update hflags
635 env
->msr
= new_msr
& env
->msr_mask
;
636 hreg_compute_hflags(env
);
638 /* Reset exception state */
639 env
->exception_index
= POWERPC_EXCP_NONE
;
642 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
643 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
644 /* XXX: The BookE changes address space when switching modes,
645 we should probably implement that as different MMU indexes,
646 but for the moment we do it the slow way and flush all. */
651 void do_interrupt(CPUPPCState
*env
)
653 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
655 powerpc_excp(cpu
, env
->excp_model
, env
->exception_index
);
658 void ppc_hw_interrupt(CPUPPCState
*env
)
660 PowerPCCPU
*cpu
= ppc_env_get_cpu(env
);
664 qemu_log_mask(CPU_LOG_INT
, "%s: %p pending %08x req %08x me %d ee %d\n",
665 __func__
, env
, env
->pending_interrupts
,
666 env
->interrupt_request
, (int)msr_me
, (int)msr_ee
);
669 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_RESET
)) {
670 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_RESET
);
671 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_RESET
);
674 /* Machine check exception */
675 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_MCK
)) {
676 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_MCK
);
677 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_MCHECK
);
681 /* External debug exception */
682 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DEBUG
)) {
683 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DEBUG
);
684 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DEBUG
);
689 /* XXX: find a suitable condition to enable the hypervisor mode */
690 hdice
= env
->spr
[SPR_LPCR
] & 1;
694 if ((msr_ee
!= 0 || msr_hv
== 0 || msr_pr
!= 0) && hdice
!= 0) {
695 /* Hypervisor decrementer exception */
696 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_HDECR
)) {
697 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_HDECR
);
698 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_HDECR
);
703 /* External critical interrupt */
704 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CEXT
)) {
705 /* Taking a critical external interrupt does not clear the external
706 * critical interrupt status
709 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CEXT
);
711 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_CRITICAL
);
716 /* Watchdog timer on embedded PowerPC */
717 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_WDT
)) {
718 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_WDT
);
719 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_WDT
);
722 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CDOORBELL
)) {
723 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CDOORBELL
);
724 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORCI
);
727 /* Fixed interval timer on embedded PowerPC */
728 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_FIT
)) {
729 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_FIT
);
730 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_FIT
);
733 /* Programmable interval timer on embedded PowerPC */
734 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PIT
)) {
735 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PIT
);
736 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PIT
);
739 /* Decrementer exception */
740 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DECR
)) {
741 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DECR
);
742 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DECR
);
745 /* External interrupt */
746 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_EXT
)) {
747 /* Taking an external interrupt does not clear the external
751 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_EXT
);
753 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_EXTERNAL
);
756 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DOORBELL
)) {
757 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DOORBELL
);
758 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_DOORI
);
761 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PERFM
)) {
762 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PERFM
);
763 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_PERFM
);
766 /* Thermal interrupt */
767 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_THERM
)) {
768 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_THERM
);
769 powerpc_excp(cpu
, env
->excp_model
, POWERPC_EXCP_THERM
);
774 #endif /* !CONFIG_USER_ONLY */
776 #if defined(DEBUG_OP)
777 static void cpu_dump_rfi(target_ulong RA
, target_ulong msr
)
779 qemu_log("Return from exception at " TARGET_FMT_lx
" with flags "
780 TARGET_FMT_lx
"\n", RA
, msr
);
784 /*****************************************************************************/
785 /* Exceptions processing helpers */
787 void helper_raise_exception_err(CPUPPCState
*env
, uint32_t exception
,
791 printf("Raise exception %3x code : %d\n", exception
, error_code
);
793 env
->exception_index
= exception
;
794 env
->error_code
= error_code
;
798 void helper_raise_exception(CPUPPCState
*env
, uint32_t exception
)
800 helper_raise_exception_err(env
, exception
, 0);
803 #if !defined(CONFIG_USER_ONLY)
804 void helper_store_msr(CPUPPCState
*env
, target_ulong val
)
806 val
= hreg_store_msr(env
, val
, 0);
808 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
809 helper_raise_exception(env
, val
);
813 static inline void do_rfi(CPUPPCState
*env
, target_ulong nip
, target_ulong msr
,
814 target_ulong msrm
, int keep_msrh
)
816 #if defined(TARGET_PPC64)
817 if (msr_is_64bit(env
, msr
)) {
819 msr
&= (uint64_t)msrm
;
822 msr
= (uint32_t)(msr
& msrm
);
824 msr
|= env
->msr
& ~((uint64_t)0xFFFFFFFF);
829 msr
&= (uint32_t)msrm
;
831 /* XXX: beware: this is false if VLE is supported */
832 env
->nip
= nip
& ~((target_ulong
)0x00000003);
833 hreg_store_msr(env
, msr
, 1);
834 #if defined(DEBUG_OP)
835 cpu_dump_rfi(env
->nip
, env
->msr
);
837 /* No need to raise an exception here,
838 * as rfi is always the last insn of a TB
840 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
843 void helper_rfi(CPUPPCState
*env
)
845 if (env
->excp_model
== POWERPC_EXCP_BOOKE
) {
846 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
847 ~((target_ulong
)0), 0);
849 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
850 ~((target_ulong
)0x783F0000), 1);
854 #if defined(TARGET_PPC64)
855 void helper_rfid(CPUPPCState
*env
)
857 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
858 ~((target_ulong
)0x783F0000), 0);
861 void helper_hrfid(CPUPPCState
*env
)
863 do_rfi(env
, env
->spr
[SPR_HSRR0
], env
->spr
[SPR_HSRR1
],
864 ~((target_ulong
)0x783F0000), 0);
868 /*****************************************************************************/
869 /* Embedded PowerPC specific helpers */
870 void helper_40x_rfci(CPUPPCState
*env
)
872 do_rfi(env
, env
->spr
[SPR_40x_SRR2
], env
->spr
[SPR_40x_SRR3
],
873 ~((target_ulong
)0xFFFF0000), 0);
876 void helper_rfci(CPUPPCState
*env
)
878 do_rfi(env
, env
->spr
[SPR_BOOKE_CSRR0
], env
->spr
[SPR_BOOKE_CSRR1
],
879 ~((target_ulong
)0), 0);
882 void helper_rfdi(CPUPPCState
*env
)
884 /* FIXME: choose CSRR1 or DSRR1 based on cpu type */
885 do_rfi(env
, env
->spr
[SPR_BOOKE_DSRR0
], env
->spr
[SPR_BOOKE_DSRR1
],
886 ~((target_ulong
)0), 0);
889 void helper_rfmci(CPUPPCState
*env
)
891 /* FIXME: choose CSRR1 or MCSRR1 based on cpu type */
892 do_rfi(env
, env
->spr
[SPR_BOOKE_MCSRR0
], env
->spr
[SPR_BOOKE_MCSRR1
],
893 ~((target_ulong
)0), 0);
897 void helper_tw(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
900 if (!likely(!(((int32_t)arg1
< (int32_t)arg2
&& (flags
& 0x10)) ||
901 ((int32_t)arg1
> (int32_t)arg2
&& (flags
& 0x08)) ||
902 ((int32_t)arg1
== (int32_t)arg2
&& (flags
& 0x04)) ||
903 ((uint32_t)arg1
< (uint32_t)arg2
&& (flags
& 0x02)) ||
904 ((uint32_t)arg1
> (uint32_t)arg2
&& (flags
& 0x01))))) {
905 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
910 #if defined(TARGET_PPC64)
911 void helper_td(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
914 if (!likely(!(((int64_t)arg1
< (int64_t)arg2
&& (flags
& 0x10)) ||
915 ((int64_t)arg1
> (int64_t)arg2
&& (flags
& 0x08)) ||
916 ((int64_t)arg1
== (int64_t)arg2
&& (flags
& 0x04)) ||
917 ((uint64_t)arg1
< (uint64_t)arg2
&& (flags
& 0x02)) ||
918 ((uint64_t)arg1
> (uint64_t)arg2
&& (flags
& 0x01))))) {
919 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
925 #if !defined(CONFIG_USER_ONLY)
926 /*****************************************************************************/
927 /* PowerPC 601 specific instructions (POWER bridge) */
929 void helper_rfsvc(CPUPPCState
*env
)
931 do_rfi(env
, env
->lr
, env
->ctr
, 0x0000FFFF, 0);
934 /* Embedded.Processor Control */
935 static int dbell2irq(target_ulong rb
)
937 int msg
= rb
& DBELL_TYPE_MASK
;
941 case DBELL_TYPE_DBELL
:
942 irq
= PPC_INTERRUPT_DOORBELL
;
944 case DBELL_TYPE_DBELL_CRIT
:
945 irq
= PPC_INTERRUPT_CDOORBELL
;
947 case DBELL_TYPE_G_DBELL
:
948 case DBELL_TYPE_G_DBELL_CRIT
:
949 case DBELL_TYPE_G_DBELL_MC
:
958 void helper_msgclr(CPUPPCState
*env
, target_ulong rb
)
960 int irq
= dbell2irq(rb
);
966 env
->pending_interrupts
&= ~(1 << irq
);
969 void helper_msgsnd(target_ulong rb
)
971 int irq
= dbell2irq(rb
);
972 int pir
= rb
& DBELL_PIRTAG_MASK
;
979 for (cenv
= first_cpu
; cenv
!= NULL
; cenv
= cenv
->next_cpu
) {
980 if ((rb
& DBELL_BRDCAST
) || (cenv
->spr
[SPR_BOOKE_PIR
] == pir
)) {
981 cenv
->pending_interrupts
|= 1 << irq
;
982 cpu_interrupt(cenv
, CPU_INTERRUPT_HARD
);