aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-06-09 15:43:26 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-06-16 10:17:28 +0100
commitf9d7856dbe85404955aa18e860af3e02473267bb (patch)
tree98d835ad6a2143e0ead97dbbc90f0f48f2885b90
parent3eafeeb4444a4b109a086fc8e4ea168102b8ec1e (diff)
target-arm: Fix errors in writes to generic timer control registers
[Cherry pick of master commit d3afacc7269f.] 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
-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 417161e216..b6f1b21cb9 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1016,16 +1016,16 @@ static void 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));
}
}