summaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2014-04-06 01:32:06 +0200
committerAlexander Graf <agraf@suse.de>2014-04-08 11:20:04 +0200
commite81a982aa5398269a2cc344091ffa4930bdd242f (patch)
tree5d09772f11575fffff75613be0dea2b7899c362f /target-ppc
parent6cd7db3d92d44344d75feb432e3ece8587e1afd4 (diff)
PPC: Clean up DECR implementation
There are 3 different variants of the decrementor for BookE and BookS. The BookE variant sets TSR[DIS] to 1 when the DEC value becomes 1 or 0. TSR[DIS] is then the indicator whether the decrementor interrupt line is asserted or not. The old BookS variant treats DEC as an edge interrupt that gets triggered when the DEC value's top bit turns 1 from 0. The new BookS variant maintains the assertion bit inside DEC itself. Whenever the DEC value becomes negative (top bit set) the DEC interrupt line is asserted. So far we implemented mostly the old BookS variant. Let's do them all properly. This fixes booting pseries ppc64 guest images in TCG mode for me. Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/cpu.h1
-rw-r--r--target-ppc/excp_helper.c5
2 files changed, 4 insertions, 2 deletions
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2719c08323..d4983405a2 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1133,6 +1133,7 @@ uint64_t cpu_ppc_load_atbl (CPUPPCState *env);
uint32_t cpu_ppc_load_atbu (CPUPPCState *env);
void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value);
void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value);
+bool ppc_decr_clear_on_delivery(CPUPPCState *env);
uint32_t cpu_ppc_load_decr (CPUPPCState *env);
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
uint32_t cpu_ppc_load_hdecr (CPUPPCState *env);
diff --git a/target-ppc/excp_helper.c b/target-ppc/excp_helper.c
index 19bc6b66ba..4fa297d7dd 100644
--- a/target-ppc/excp_helper.c
+++ b/target-ppc/excp_helper.c
@@ -723,7 +723,6 @@ void ppc_hw_interrupt(CPUPPCState *env)
if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
/* Hypervisor decrementer exception */
if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HDECR);
return;
}
@@ -767,7 +766,9 @@ void ppc_hw_interrupt(CPUPPCState *env)
}
/* Decrementer exception */
if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
- env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+ if (ppc_decr_clear_on_delivery(env)) {
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+ }
powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_DECR);
return;
}