summaryrefslogtreecommitdiffstats
path: root/target-ppc
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/cpu.h16
-rw-r--r--target-ppc/helper.c83
2 files changed, 99 insertions, 0 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index b21d6b1..ef02f10 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -740,6 +740,7 @@ struct CPUPPCState {
int exception_index;
int error_code;
int interrupt_request;
+ uint32_t pending_interrupts;
/* Those resources are used only during code translation */
/* Next instruction pointer */
@@ -1267,6 +1268,21 @@ enum {
EXCP_TRAP = 0x40,
};
+/* Hardware interruption sources:
+ * all those exception can be raised simulteaneously
+ */
+enum {
+ PPC_INTERRUPT_RESET = 0, /* Reset / critical input */
+ PPC_INTERRUPT_MCK = 1, /* Machine check exception */
+ PPC_INTERRUPT_EXT = 2, /* External interrupt */
+ PPC_INTERRUPT_DECR = 3, /* Decrementer exception */
+ PPC_INTERRUPT_HDECR = 4, /* Hypervisor decrementer exception */
+ PPC_INTERRUPT_PIT = 5, /* Programmable inteval timer interrupt */
+ PPC_INTERRUPT_FIT = 6, /* Fixed interval timer interrupt */
+ PPC_INTERRUPT_WDT = 7, /* Watchdog timer interrupt */
+ PPC_INTERRUPT_DEBUG = 8, /* External debug exception */
+};
+
/*****************************************************************************/
#endif /* !defined (__CPU_PPC_H__) */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index b86f823..4356edc 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1229,6 +1229,13 @@ void do_interrupt (CPUState *env)
{
env->exception_index = -1;
}
+
+int ppc_hw_interrupt (CPUState *env)
+{
+ env->exception_index = -1;
+
+ return 0;
+}
#else /* defined (CONFIG_USER_ONLY) */
static void dump_syscall(CPUState *env)
{
@@ -1753,4 +1760,80 @@ void do_interrupt (CPUState *env)
env->nip = excp;
env->exception_index = EXCP_NONE;
}
+
+int ppc_hw_interrupt (CPUState *env)
+{
+ int raised = 0;
+
+#if 0
+ printf("%s: %p pending %08x req %08x %08x me %d ee %d\n",
+ __func__, env, env->pending_interrupts,
+ env->interrupt_request, interrupt_request,
+ msr_me, msr_ee);
+#endif
+ /* Raise it */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
+ /* External reset / critical input */
+ env->exception_index = EXCP_RESET;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
+ raised = 1;
+ }
+ if (raised == 0 && msr_me != 0) {
+ /* Machine check exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
+ env->exception_index = EXCP_MACHINE_CHECK;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
+ raised = 1;
+ }
+ }
+ if (raised == 0 && msr_ee != 0) {
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+ /* Hypervisor decrementer exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
+ env->exception_index = EXCP_HDECR;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
+ raised = 1;
+ } else
+#endif
+ /* Decrementer exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
+ env->exception_index = EXCP_DECR;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+ raised = 1;
+ /* Programmable interval timer on embedded PowerPC */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
+ env->exception_index = EXCP_40x_PIT;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
+ raised = 1;
+ /* Fixed interval timer on embedded PowerPC */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
+ env->exception_index = EXCP_40x_FIT;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
+ raised = 1;
+ /* Watchdog timer on embedded PowerPC */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
+ env->exception_index = EXCP_40x_WATCHDOG;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
+ raised = 1;
+ /* External interrupt */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
+ env->exception_index = EXCP_EXTERNAL;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
+ raised = 1;
+ }
+#if 0 // TODO
+ /* External debug exception */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
+ env->exception_index = EXCP_xxx;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
+ raised = 1;
+#endif
+ }
+ if (raised != 0) {
+ env->error_code = 0;
+ do_interrupt(env);
+ }
+
+ return raised;
+}
#endif /* !CONFIG_USER_ONLY */
OpenPOWER on IntegriCloud