diff options
Diffstat (limited to 'target-ppc/helper.c')
-rw-r--r-- | target-ppc/helper.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/target-ppc/helper.c b/target-ppc/helper.c index b86f8234e6..4356edc36c 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 */ |