openbmc / qemu

Official QEMU mirror
Other
20 stars 22 forks source link

Timer register corruption when kexec'ing #16

Open shenki opened 6 years ago

shenki commented 6 years ago

EDIT: Not memory corruption, but I guess some signness and things getting negative where they where thought to be that they wouldn't.

What I'm observing is the following:

  1. Kexec'd linux kernel writes 0x10 = 0, setting status of timer2 to 0.
  2. This results in a negative delta, and muldiv64 is only capable of operating on unsigned numbers.
  3. This results in a bogus value like 0xaaaaa...

This is my home-made dump of the action:

!! TIMER_REG_STATUS for timer 1:                                                 
 now: 3e37c1a3e, value: 0, ticks: eb85f3d5                                       
 delta: ffffffff147a0c2b, rate: 16e3600, t->start: aaaaaa84e37c1a66

I patched my local qemu with this:

diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 9acd1de485..1a54d85e9d 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -253,7 +253,7 @@ static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
             int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
             uint32_t rate = calculate_rate(t);

-            t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
+            t->start = (int64_t)t->start + ((__int128_t)delta * NANOSECONDS_PER_SECOND / rate);
             aspeed_timer_mod(t);
         }
         break;

And now Linux boots :-)

Originally posted by @bluecmd in https://github.com/openbmc/qemu/issues/14#issuecomment-437692215

shenki commented 6 years ago

https://patchwork.ozlabs.org/patch/996449/