summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-06-09 15:43:26 +0100
committerMichael Roth <mdroth@linux.vnet.ibm.com>2014-07-03 16:31:30 -0500
commitf784615221c6018896d985101edc7e6de3cc9119 (patch)
treeec8a3362496e9e309bcc5fbd23741a15f136d1f1
parente34feec2641228394cafd8a7559f463cf4091138 (diff)
downloadqemu-f784615221c6018896d985101edc7e6de3cc9119.tar.gz
target-arm: Fix errors in writes to generic timer control registers
The code for handling writes to the generic timer control registers had several bugs: * ISTATUS (bit 2) is read-only but we forced it to zero on any write * the check for "was IMASK (bit 1) toggled?" incorrectly used '&' where it should be '^' * the handling of IMASK was inverted: we should set the IRQ if ISTATUS is set and IMASK is clear, not if both are set The combination of these bugs meant that when running a Linux guest that uses the generic timers we would fairly quickly end up either forgetting that the timer output should be asserted, or failing to set the IRQ when the timer was unmasked. The result is that the guest never gets any more timer interrupts. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Message-id: 1401803208-1281-1-git-send-email-peter.maydell@linaro.org Cc: qemu-stable@nongnu.org (cherry picked from commit d3afacc7269fee45d54d1501a46b51f12ea7bb15) Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
-rw-r--r--target-arm/helper.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/target-arm/helper.c b/target-arm/helper.c
index c3e491006f..6e67317811 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -859,16 +859,16 @@ static int gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
int timeridx = ri->crm & 1;
uint32_t oldval = env->cp15.c14_timer[timeridx].ctl;
- env->cp15.c14_timer[timeridx].ctl = value & 3;
+ env->cp15.c14_timer[timeridx].ctl = deposit64(oldval, 0, 2, value);
if ((oldval ^ value) & 1) {
/* Enable toggled */
gt_recalc_timer(cpu, timeridx);
- } else if ((oldval & value) & 2) {
+ } else if ((oldval ^ value) & 2) {
/* IMASK toggled: don't need to recalculate,
* just set the interrupt line based on ISTATUS
*/
qemu_set_irq(cpu->gt_timer_outputs[timeridx],
- (oldval & 4) && (value & 2));
+ (oldval & 4) && !(value & 2));
}
return 0;
}