]>
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
)(CPUPPCState
*);
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(CPUPPCState
*env
, int excp_model
, int excp
)
68 target_ulong msr
, new_msr
, vector
;
69 int srr0
, srr1
, asrr0
, asrr1
;
70 int lpes0
, lpes1
, lev
;
73 /* XXX: find a suitable condition to enable the hypervisor mode */
74 lpes0
= (env
->spr
[SPR_LPCR
] >> 1) & 1;
75 lpes1
= (env
->spr
[SPR_LPCR
] >> 2) & 1;
77 /* Those values ensure we won't enter the hypervisor mode */
82 qemu_log_mask(CPU_LOG_INT
, "Raise exception at " TARGET_FMT_lx
83 " => %08x (%02x)\n", env
->nip
, excp
, env
->error_code
);
85 /* new srr1 value excluding must-be-zero bits */
86 msr
= env
->msr
& ~0x783f0000ULL
;
88 /* new interrupt handler msr */
89 new_msr
= env
->msr
& ((target_ulong
)1 << MSR_ME
);
91 /* target registers */
98 case POWERPC_EXCP_NONE
:
99 /* Should never happen */
101 case POWERPC_EXCP_CRITICAL
: /* Critical input */
102 switch (excp_model
) {
103 case POWERPC_EXCP_40x
:
107 case POWERPC_EXCP_BOOKE
:
108 srr0
= SPR_BOOKE_CSRR0
;
109 srr1
= SPR_BOOKE_CSRR1
;
111 case POWERPC_EXCP_G2
:
117 case POWERPC_EXCP_MCHECK
: /* Machine check exception */
119 /* Machine check exception is not enabled.
120 * Enter checkstop state.
122 if (qemu_log_enabled()) {
123 qemu_log("Machine check while not allowed. "
124 "Entering checkstop state\n");
126 fprintf(stderr
, "Machine check while not allowed. "
127 "Entering checkstop state\n");
130 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
133 /* XXX: find a suitable condition to enable the hypervisor mode */
134 new_msr
|= (target_ulong
)MSR_HVB
;
137 /* machine check exceptions don't have ME set */
138 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
140 /* XXX: should also have something loaded in DAR / DSISR */
141 switch (excp_model
) {
142 case POWERPC_EXCP_40x
:
146 case POWERPC_EXCP_BOOKE
:
147 srr0
= SPR_BOOKE_MCSRR0
;
148 srr1
= SPR_BOOKE_MCSRR1
;
149 asrr0
= SPR_BOOKE_CSRR0
;
150 asrr1
= SPR_BOOKE_CSRR1
;
156 case POWERPC_EXCP_DSI
: /* Data storage exception */
157 LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx
" DAR=" TARGET_FMT_lx
158 "\n", env
->spr
[SPR_DSISR
], env
->spr
[SPR_DAR
]);
160 new_msr
|= (target_ulong
)MSR_HVB
;
163 case POWERPC_EXCP_ISI
: /* Instruction storage exception */
164 LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx
", nip=" TARGET_FMT_lx
165 "\n", msr
, env
->nip
);
167 new_msr
|= (target_ulong
)MSR_HVB
;
169 msr
|= env
->error_code
;
171 case POWERPC_EXCP_EXTERNAL
: /* External input */
173 new_msr
|= (target_ulong
)MSR_HVB
;
176 case POWERPC_EXCP_ALIGN
: /* Alignment exception */
178 new_msr
|= (target_ulong
)MSR_HVB
;
180 /* XXX: this is false */
181 /* Get rS/rD and rA from faulting opcode */
182 env
->spr
[SPR_DSISR
] |= (ldl_code((env
->nip
- 4)) & 0x03FF0000) >> 16;
184 case POWERPC_EXCP_PROGRAM
: /* Program exception */
185 switch (env
->error_code
& ~0xF) {
186 case POWERPC_EXCP_FP
:
187 if ((msr_fe0
== 0 && msr_fe1
== 0) || msr_fp
== 0) {
188 LOG_EXCP("Ignore floating point exception\n");
189 env
->exception_index
= POWERPC_EXCP_NONE
;
194 new_msr
|= (target_ulong
)MSR_HVB
;
197 if (msr_fe0
== msr_fe1
) {
202 case POWERPC_EXCP_INVAL
:
203 LOG_EXCP("Invalid instruction at " TARGET_FMT_lx
"\n", env
->nip
);
205 new_msr
|= (target_ulong
)MSR_HVB
;
208 env
->spr
[SPR_BOOKE_ESR
] = ESR_PIL
;
210 case POWERPC_EXCP_PRIV
:
212 new_msr
|= (target_ulong
)MSR_HVB
;
215 env
->spr
[SPR_BOOKE_ESR
] = ESR_PPR
;
217 case POWERPC_EXCP_TRAP
:
219 new_msr
|= (target_ulong
)MSR_HVB
;
222 env
->spr
[SPR_BOOKE_ESR
] = ESR_PTR
;
225 /* Should never occur */
226 cpu_abort(env
, "Invalid program exception %d. Aborting\n",
231 case POWERPC_EXCP_FPU
: /* Floating-point unavailable exception */
233 new_msr
|= (target_ulong
)MSR_HVB
;
236 case POWERPC_EXCP_SYSCALL
: /* System call exception */
238 lev
= env
->error_code
;
239 if ((lev
== 1) && cpu_ppc_hypercall
) {
240 cpu_ppc_hypercall(env
);
243 if (lev
== 1 || (lpes0
== 0 && lpes1
== 0)) {
244 new_msr
|= (target_ulong
)MSR_HVB
;
247 case POWERPC_EXCP_APU
: /* Auxiliary processor unavailable */
249 case POWERPC_EXCP_DECR
: /* Decrementer exception */
251 new_msr
|= (target_ulong
)MSR_HVB
;
254 case POWERPC_EXCP_FIT
: /* Fixed-interval timer interrupt */
256 LOG_EXCP("FIT exception\n");
258 case POWERPC_EXCP_WDT
: /* Watchdog timer interrupt */
259 LOG_EXCP("WDT exception\n");
260 switch (excp_model
) {
261 case POWERPC_EXCP_BOOKE
:
262 srr0
= SPR_BOOKE_CSRR0
;
263 srr1
= SPR_BOOKE_CSRR1
;
269 case POWERPC_EXCP_DTLB
: /* Data TLB error */
271 case POWERPC_EXCP_ITLB
: /* Instruction TLB error */
273 case POWERPC_EXCP_DEBUG
: /* Debug interrupt */
274 switch (excp_model
) {
275 case POWERPC_EXCP_BOOKE
:
276 srr0
= SPR_BOOKE_DSRR0
;
277 srr1
= SPR_BOOKE_DSRR1
;
278 asrr0
= SPR_BOOKE_CSRR0
;
279 asrr1
= SPR_BOOKE_CSRR1
;
285 cpu_abort(env
, "Debug exception is not implemented yet !\n");
287 case POWERPC_EXCP_SPEU
: /* SPE/embedded floating-point unavailable */
288 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
290 case POWERPC_EXCP_EFPDI
: /* Embedded floating-point data interrupt */
292 cpu_abort(env
, "Embedded floating point data exception "
293 "is not implemented yet !\n");
294 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
296 case POWERPC_EXCP_EFPRI
: /* Embedded floating-point round interrupt */
298 cpu_abort(env
, "Embedded floating point round exception "
299 "is not implemented yet !\n");
300 env
->spr
[SPR_BOOKE_ESR
] = ESR_SPV
;
302 case POWERPC_EXCP_EPERFM
: /* Embedded performance monitor interrupt */
305 "Performance counter exception is not implemented yet !\n");
307 case POWERPC_EXCP_DOORI
: /* Embedded doorbell interrupt */
309 case POWERPC_EXCP_DOORCI
: /* Embedded doorbell critical interrupt */
310 srr0
= SPR_BOOKE_CSRR0
;
311 srr1
= SPR_BOOKE_CSRR1
;
313 case POWERPC_EXCP_RESET
: /* System reset exception */
315 /* indicate that we resumed from power save mode */
318 new_msr
&= ~((target_ulong
)1 << MSR_ME
);
322 /* XXX: find a suitable condition to enable the hypervisor mode */
323 new_msr
|= (target_ulong
)MSR_HVB
;
326 case POWERPC_EXCP_DSEG
: /* Data segment exception */
328 new_msr
|= (target_ulong
)MSR_HVB
;
331 case POWERPC_EXCP_ISEG
: /* Instruction segment exception */
333 new_msr
|= (target_ulong
)MSR_HVB
;
336 case POWERPC_EXCP_HDECR
: /* Hypervisor decrementer exception */
339 new_msr
|= (target_ulong
)MSR_HVB
;
340 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
342 case POWERPC_EXCP_TRACE
: /* Trace exception */
344 new_msr
|= (target_ulong
)MSR_HVB
;
347 case POWERPC_EXCP_HDSI
: /* Hypervisor data storage exception */
350 new_msr
|= (target_ulong
)MSR_HVB
;
351 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
353 case POWERPC_EXCP_HISI
: /* Hypervisor instruction storage exception */
356 new_msr
|= (target_ulong
)MSR_HVB
;
357 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
359 case POWERPC_EXCP_HDSEG
: /* Hypervisor data segment exception */
362 new_msr
|= (target_ulong
)MSR_HVB
;
363 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
365 case POWERPC_EXCP_HISEG
: /* Hypervisor instruction segment exception */
368 new_msr
|= (target_ulong
)MSR_HVB
;
369 new_msr
|= env
->msr
& ((target_ulong
)1 << MSR_RI
);
371 case POWERPC_EXCP_VPU
: /* Vector unavailable exception */
373 new_msr
|= (target_ulong
)MSR_HVB
;
376 case POWERPC_EXCP_PIT
: /* Programmable interval timer interrupt */
377 LOG_EXCP("PIT exception\n");
379 case POWERPC_EXCP_IO
: /* IO error exception */
381 cpu_abort(env
, "601 IO error exception is not implemented yet !\n");
383 case POWERPC_EXCP_RUNM
: /* Run mode exception */
385 cpu_abort(env
, "601 run mode exception is not implemented yet !\n");
387 case POWERPC_EXCP_EMUL
: /* Emulation trap exception */
389 cpu_abort(env
, "602 emulation trap exception "
390 "is not implemented yet !\n");
392 case POWERPC_EXCP_IFTLB
: /* Instruction fetch TLB error */
393 if (lpes1
== 0) { /* XXX: check this */
394 new_msr
|= (target_ulong
)MSR_HVB
;
396 switch (excp_model
) {
397 case POWERPC_EXCP_602
:
398 case POWERPC_EXCP_603
:
399 case POWERPC_EXCP_603E
:
400 case POWERPC_EXCP_G2
:
402 case POWERPC_EXCP_7x5
:
404 case POWERPC_EXCP_74xx
:
407 cpu_abort(env
, "Invalid instruction TLB miss exception\n");
411 case POWERPC_EXCP_DLTLB
: /* Data load TLB miss */
412 if (lpes1
== 0) { /* XXX: check this */
413 new_msr
|= (target_ulong
)MSR_HVB
;
415 switch (excp_model
) {
416 case POWERPC_EXCP_602
:
417 case POWERPC_EXCP_603
:
418 case POWERPC_EXCP_603E
:
419 case POWERPC_EXCP_G2
:
421 case POWERPC_EXCP_7x5
:
423 case POWERPC_EXCP_74xx
:
426 cpu_abort(env
, "Invalid data load TLB miss exception\n");
430 case POWERPC_EXCP_DSTLB
: /* Data store TLB miss */
431 if (lpes1
== 0) { /* XXX: check this */
432 new_msr
|= (target_ulong
)MSR_HVB
;
434 switch (excp_model
) {
435 case POWERPC_EXCP_602
:
436 case POWERPC_EXCP_603
:
437 case POWERPC_EXCP_603E
:
438 case POWERPC_EXCP_G2
:
440 /* Swap temporary saved registers with GPRs */
441 if (!(new_msr
& ((target_ulong
)1 << MSR_TGPR
))) {
442 new_msr
|= (target_ulong
)1 << MSR_TGPR
;
443 hreg_swap_gpr_tgpr(env
);
446 case POWERPC_EXCP_7x5
:
448 #if defined(DEBUG_SOFTWARE_TLB)
449 if (qemu_log_enabled()) {
451 target_ulong
*miss
, *cmp
;
454 if (excp
== POWERPC_EXCP_IFTLB
) {
457 miss
= &env
->spr
[SPR_IMISS
];
458 cmp
= &env
->spr
[SPR_ICMP
];
460 if (excp
== POWERPC_EXCP_DLTLB
) {
466 miss
= &env
->spr
[SPR_DMISS
];
467 cmp
= &env
->spr
[SPR_DCMP
];
469 qemu_log("6xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
470 TARGET_FMT_lx
" H1 " TARGET_FMT_lx
" H2 "
471 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
472 env
->spr
[SPR_HASH1
], env
->spr
[SPR_HASH2
],
476 msr
|= env
->crf
[0] << 28;
477 msr
|= env
->error_code
; /* key, D/I, S/L bits */
478 /* Set way using a LRU mechanism */
479 msr
|= ((env
->last_way
+ 1) & (env
->nb_ways
- 1)) << 17;
481 case POWERPC_EXCP_74xx
:
483 #if defined(DEBUG_SOFTWARE_TLB)
484 if (qemu_log_enabled()) {
486 target_ulong
*miss
, *cmp
;
489 if (excp
== POWERPC_EXCP_IFTLB
) {
492 miss
= &env
->spr
[SPR_TLBMISS
];
493 cmp
= &env
->spr
[SPR_PTEHI
];
495 if (excp
== POWERPC_EXCP_DLTLB
) {
501 miss
= &env
->spr
[SPR_TLBMISS
];
502 cmp
= &env
->spr
[SPR_PTEHI
];
504 qemu_log("74xx %sTLB miss: %cM " TARGET_FMT_lx
" %cC "
505 TARGET_FMT_lx
" %08x\n", es
, en
, *miss
, en
, *cmp
,
509 msr
|= env
->error_code
; /* key bit */
512 cpu_abort(env
, "Invalid data store TLB miss exception\n");
516 case POWERPC_EXCP_FPA
: /* Floating-point assist exception */
518 cpu_abort(env
, "Floating point assist exception "
519 "is not implemented yet !\n");
521 case POWERPC_EXCP_DABR
: /* Data address breakpoint */
523 cpu_abort(env
, "DABR exception is not implemented yet !\n");
525 case POWERPC_EXCP_IABR
: /* Instruction address breakpoint */
527 cpu_abort(env
, "IABR exception is not implemented yet !\n");
529 case POWERPC_EXCP_SMI
: /* System management interrupt */
531 cpu_abort(env
, "SMI exception is not implemented yet !\n");
533 case POWERPC_EXCP_THERM
: /* Thermal interrupt */
535 cpu_abort(env
, "Thermal management exception "
536 "is not implemented yet !\n");
538 case POWERPC_EXCP_PERFM
: /* Embedded performance monitor interrupt */
540 new_msr
|= (target_ulong
)MSR_HVB
;
544 "Performance counter exception is not implemented yet !\n");
546 case POWERPC_EXCP_VPUA
: /* Vector assist exception */
548 cpu_abort(env
, "VPU assist exception is not implemented yet !\n");
550 case POWERPC_EXCP_SOFTP
: /* Soft patch exception */
553 "970 soft-patch exception is not implemented yet !\n");
555 case POWERPC_EXCP_MAINT
: /* Maintenance exception */
558 "970 maintenance exception is not implemented yet !\n");
560 case POWERPC_EXCP_MEXTBR
: /* Maskable external breakpoint */
562 cpu_abort(env
, "Maskable external exception "
563 "is not implemented yet !\n");
565 case POWERPC_EXCP_NMEXTBR
: /* Non maskable external breakpoint */
567 cpu_abort(env
, "Non maskable external exception "
568 "is not implemented yet !\n");
572 cpu_abort(env
, "Invalid PowerPC exception %d. Aborting\n", excp
);
575 /* save current instruction location */
576 env
->spr
[srr0
] = env
->nip
- 4;
579 /* save next instruction location */
580 env
->spr
[srr0
] = env
->nip
;
584 env
->spr
[srr1
] = msr
;
585 /* If any alternate SRR register are defined, duplicate saved values */
587 env
->spr
[asrr0
] = env
->spr
[srr0
];
590 env
->spr
[asrr1
] = env
->spr
[srr1
];
592 /* If we disactivated any translation, flush TLBs */
593 if (msr
& ((1 << MSR_IR
) | (1 << MSR_DR
))) {
598 new_msr
|= (target_ulong
)1 << MSR_LE
;
601 /* Jump to handler */
602 vector
= env
->excp_vectors
[excp
];
603 if (vector
== (target_ulong
)-1ULL) {
604 cpu_abort(env
, "Raised an exception without defined vector %d\n",
607 vector
|= env
->excp_prefix
;
608 #if defined(TARGET_PPC64)
609 if (excp_model
== POWERPC_EXCP_BOOKE
) {
611 vector
= (uint32_t)vector
;
613 new_msr
|= (target_ulong
)1 << MSR_CM
;
616 if (!msr_isf
&& !(env
->mmu_model
& POWERPC_MMU_64
)) {
617 vector
= (uint32_t)vector
;
619 new_msr
|= (target_ulong
)1 << MSR_SF
;
623 /* XXX: we don't use hreg_store_msr here as already have treated
624 * any special case that could occur. Just store MSR and update hflags
626 env
->msr
= new_msr
& env
->msr_mask
;
627 hreg_compute_hflags(env
);
629 /* Reset exception state */
630 env
->exception_index
= POWERPC_EXCP_NONE
;
633 if ((env
->mmu_model
== POWERPC_MMU_BOOKE
) ||
634 (env
->mmu_model
== POWERPC_MMU_BOOKE206
)) {
635 /* XXX: The BookE changes address space when switching modes,
636 we should probably implement that as different MMU indexes,
637 but for the moment we do it the slow way and flush all. */
642 void do_interrupt(CPUPPCState
*env
)
644 powerpc_excp(env
, env
->excp_model
, env
->exception_index
);
647 void ppc_hw_interrupt(CPUPPCState
*env
)
652 qemu_log_mask(CPU_LOG_INT
, "%s: %p pending %08x req %08x me %d ee %d\n",
653 __func__
, env
, env
->pending_interrupts
,
654 env
->interrupt_request
, (int)msr_me
, (int)msr_ee
);
657 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_RESET
)) {
658 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_RESET
);
659 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_RESET
);
662 /* Machine check exception */
663 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_MCK
)) {
664 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_MCK
);
665 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_MCHECK
);
669 /* External debug exception */
670 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DEBUG
)) {
671 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DEBUG
);
672 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_DEBUG
);
677 /* XXX: find a suitable condition to enable the hypervisor mode */
678 hdice
= env
->spr
[SPR_LPCR
] & 1;
682 if ((msr_ee
!= 0 || msr_hv
== 0 || msr_pr
!= 0) && hdice
!= 0) {
683 /* Hypervisor decrementer exception */
684 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_HDECR
)) {
685 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_HDECR
);
686 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_HDECR
);
691 /* External critical interrupt */
692 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CEXT
)) {
693 /* Taking a critical external interrupt does not clear the external
694 * critical interrupt status
697 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CEXT
);
699 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_CRITICAL
);
704 /* Watchdog timer on embedded PowerPC */
705 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_WDT
)) {
706 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_WDT
);
707 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_WDT
);
710 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_CDOORBELL
)) {
711 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_CDOORBELL
);
712 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_DOORCI
);
715 /* Fixed interval timer on embedded PowerPC */
716 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_FIT
)) {
717 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_FIT
);
718 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_FIT
);
721 /* Programmable interval timer on embedded PowerPC */
722 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PIT
)) {
723 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PIT
);
724 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_PIT
);
727 /* Decrementer exception */
728 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DECR
)) {
729 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DECR
);
730 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_DECR
);
733 /* External interrupt */
734 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_EXT
)) {
735 /* Taking an external interrupt does not clear the external
739 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_EXT
);
741 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_EXTERNAL
);
744 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_DOORBELL
)) {
745 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_DOORBELL
);
746 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_DOORI
);
749 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_PERFM
)) {
750 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_PERFM
);
751 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_PERFM
);
754 /* Thermal interrupt */
755 if (env
->pending_interrupts
& (1 << PPC_INTERRUPT_THERM
)) {
756 env
->pending_interrupts
&= ~(1 << PPC_INTERRUPT_THERM
);
757 powerpc_excp(env
, env
->excp_model
, POWERPC_EXCP_THERM
);
762 #endif /* !CONFIG_USER_ONLY */
764 #if defined(DEBUG_OP)
765 static void cpu_dump_rfi(target_ulong RA
, target_ulong msr
)
767 qemu_log("Return from exception at " TARGET_FMT_lx
" with flags "
768 TARGET_FMT_lx
"\n", RA
, msr
);
772 /*****************************************************************************/
773 /* Exceptions processing helpers */
775 void helper_raise_exception_err(CPUPPCState
*env
, uint32_t exception
,
779 printf("Raise exception %3x code : %d\n", exception
, error_code
);
781 env
->exception_index
= exception
;
782 env
->error_code
= error_code
;
786 void helper_raise_exception(CPUPPCState
*env
, uint32_t exception
)
788 helper_raise_exception_err(env
, exception
, 0);
791 #if !defined(CONFIG_USER_ONLY)
792 void helper_store_msr(CPUPPCState
*env
, target_ulong val
)
794 val
= hreg_store_msr(env
, val
, 0);
796 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
797 helper_raise_exception(env
, val
);
801 static inline void do_rfi(CPUPPCState
*env
, target_ulong nip
, target_ulong msr
,
802 target_ulong msrm
, int keep_msrh
)
804 #if defined(TARGET_PPC64)
805 if (msr
& (1ULL << MSR_SF
)) {
807 msr
&= (uint64_t)msrm
;
810 msr
= (uint32_t)(msr
& msrm
);
812 msr
|= env
->msr
& ~((uint64_t)0xFFFFFFFF);
817 msr
&= (uint32_t)msrm
;
819 /* XXX: beware: this is false if VLE is supported */
820 env
->nip
= nip
& ~((target_ulong
)0x00000003);
821 hreg_store_msr(env
, msr
, 1);
822 #if defined(DEBUG_OP)
823 cpu_dump_rfi(env
->nip
, env
->msr
);
825 /* No need to raise an exception here,
826 * as rfi is always the last insn of a TB
828 env
->interrupt_request
|= CPU_INTERRUPT_EXITTB
;
831 void helper_rfi(CPUPPCState
*env
)
833 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
834 ~((target_ulong
)0x783F0000), 1);
837 #if defined(TARGET_PPC64)
838 void helper_rfid(CPUPPCState
*env
)
840 do_rfi(env
, env
->spr
[SPR_SRR0
], env
->spr
[SPR_SRR1
],
841 ~((target_ulong
)0x783F0000), 0);
844 void helper_hrfid(CPUPPCState
*env
)
846 do_rfi(env
, env
->spr
[SPR_HSRR0
], env
->spr
[SPR_HSRR1
],
847 ~((target_ulong
)0x783F0000), 0);
851 /*****************************************************************************/
852 /* Embedded PowerPC specific helpers */
853 void helper_40x_rfci(CPUPPCState
*env
)
855 do_rfi(env
, env
->spr
[SPR_40x_SRR2
], env
->spr
[SPR_40x_SRR3
],
856 ~((target_ulong
)0xFFFF0000), 0);
859 void helper_rfci(CPUPPCState
*env
)
861 do_rfi(env
, env
->spr
[SPR_BOOKE_CSRR0
], SPR_BOOKE_CSRR1
,
862 ~((target_ulong
)0x3FFF0000), 0);
865 void helper_rfdi(CPUPPCState
*env
)
867 do_rfi(env
, env
->spr
[SPR_BOOKE_DSRR0
], SPR_BOOKE_DSRR1
,
868 ~((target_ulong
)0x3FFF0000), 0);
871 void helper_rfmci(CPUPPCState
*env
)
873 do_rfi(env
, env
->spr
[SPR_BOOKE_MCSRR0
], SPR_BOOKE_MCSRR1
,
874 ~((target_ulong
)0x3FFF0000), 0);
878 void helper_tw(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
881 if (!likely(!(((int32_t)arg1
< (int32_t)arg2
&& (flags
& 0x10)) ||
882 ((int32_t)arg1
> (int32_t)arg2
&& (flags
& 0x08)) ||
883 ((int32_t)arg1
== (int32_t)arg2
&& (flags
& 0x04)) ||
884 ((uint32_t)arg1
< (uint32_t)arg2
&& (flags
& 0x02)) ||
885 ((uint32_t)arg1
> (uint32_t)arg2
&& (flags
& 0x01))))) {
886 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
891 #if defined(TARGET_PPC64)
892 void helper_td(CPUPPCState
*env
, target_ulong arg1
, target_ulong arg2
,
895 if (!likely(!(((int64_t)arg1
< (int64_t)arg2
&& (flags
& 0x10)) ||
896 ((int64_t)arg1
> (int64_t)arg2
&& (flags
& 0x08)) ||
897 ((int64_t)arg1
== (int64_t)arg2
&& (flags
& 0x04)) ||
898 ((uint64_t)arg1
< (uint64_t)arg2
&& (flags
& 0x02)) ||
899 ((uint64_t)arg1
> (uint64_t)arg2
&& (flags
& 0x01))))) {
900 helper_raise_exception_err(env
, POWERPC_EXCP_PROGRAM
,
906 #if !defined(CONFIG_USER_ONLY)
907 /*****************************************************************************/
908 /* PowerPC 601 specific instructions (POWER bridge) */
910 void helper_rfsvc(CPUPPCState
*env
)
912 do_rfi(env
, env
->lr
, env
->ctr
, 0x0000FFFF, 0);
915 /* Embedded.Processor Control */
916 static int dbell2irq(target_ulong rb
)
918 int msg
= rb
& DBELL_TYPE_MASK
;
922 case DBELL_TYPE_DBELL
:
923 irq
= PPC_INTERRUPT_DOORBELL
;
925 case DBELL_TYPE_DBELL_CRIT
:
926 irq
= PPC_INTERRUPT_CDOORBELL
;
928 case DBELL_TYPE_G_DBELL
:
929 case DBELL_TYPE_G_DBELL_CRIT
:
930 case DBELL_TYPE_G_DBELL_MC
:
939 void helper_msgclr(CPUPPCState
*env
, target_ulong rb
)
941 int irq
= dbell2irq(rb
);
947 env
->pending_interrupts
&= ~(1 << irq
);
950 void helper_msgsnd(target_ulong rb
)
952 int irq
= dbell2irq(rb
);
953 int pir
= rb
& DBELL_PIRTAG_MASK
;
960 for (cenv
= first_cpu
; cenv
!= NULL
; cenv
= cenv
->next_cpu
) {
961 if ((rb
& DBELL_BRDCAST
) || (cenv
->spr
[SPR_BOOKE_PIR
] == pir
)) {
962 cenv
->pending_interrupts
|= 1 << irq
;
963 cpu_interrupt(cenv
, CPU_INTERRUPT_HARD
);