Skip to content
  • Peter Maydell's avatar
    d2f9a79a
    hw/timer/nrf51_timer: Don't lose time when timer is queried in tight loop · d2f9a79a
    Peter Maydell authored
    
    
    The nrf51_timer has a free-running counter which we implement using
    the pattern of using two fields (update_counter_ns, counter) to track
    the last point at which we calculated the counter value, and the
    counter value at that time.  Then we can find the current counter
    value by converting the difference in wall-clock time between then
    and now to a tick count that we need to add to the counter value.
    
    Unfortunately the nrf51_timer's implementation of this has a bug
    which means it loses time every time update_counter() is called.
    After updating s->counter it always sets s->update_counter_ns to
    'now', even though the actual point when s->counter hit the new value
    will be some point in the past (half a tick, say).  In the worst case
    (guest code in a tight loop reading the counter, icount mode) the
    counter is continually queried less than a tick after it was last
    read, so s->counter never advances but s->update_counter_ns does, and
    the guest never makes forward progress.
    
    The fix for this is to only advance update_counter_ns to the
    timestamp of the last tick, not all the way to 'now'.  (This is the
    pattern used in hw/misc/mps2-fpgaio.c's counter.)
    
    Cc: qemu-stable@nongnu.org
    Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
    Reviewed-by: default avatarJoel Stanley <joel@jms.id.au>
    Message-id: 20230606134917.3782215-1-peter.maydell@linaro.org
    d2f9a79a
    hw/timer/nrf51_timer: Don't lose time when timer is queried in tight loop
    Peter Maydell authored
    
    
    The nrf51_timer has a free-running counter which we implement using
    the pattern of using two fields (update_counter_ns, counter) to track
    the last point at which we calculated the counter value, and the
    counter value at that time.  Then we can find the current counter
    value by converting the difference in wall-clock time between then
    and now to a tick count that we need to add to the counter value.
    
    Unfortunately the nrf51_timer's implementation of this has a bug
    which means it loses time every time update_counter() is called.
    After updating s->counter it always sets s->update_counter_ns to
    'now', even though the actual point when s->counter hit the new value
    will be some point in the past (half a tick, say).  In the worst case
    (guest code in a tight loop reading the counter, icount mode) the
    counter is continually queried less than a tick after it was last
    read, so s->counter never advances but s->update_counter_ns does, and
    the guest never makes forward progress.
    
    The fix for this is to only advance update_counter_ns to the
    timestamp of the last tick, not all the way to 'now'.  (This is the
    pattern used in hw/misc/mps2-fpgaio.c's counter.)
    
    Cc: qemu-stable@nongnu.org
    Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
    Reviewed-by: default avatarJoel Stanley <joel@jms.id.au>
    Message-id: 20230606134917.3782215-1-peter.maydell@linaro.org
Loading