diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2017-11-02 11:21:14 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2017-11-02 11:28:25 -0400 |
commit | 488e1c3fef2e789d38a5190baae977131a911fa7 (patch) | |
tree | 46846492609a01d9b86f3dddcf478e808c2e1ea4 /src/hw/timer.c | |
parent | cd47172a673762a05a0c7bd27df6e3cc8febe8d6 (diff) | |
download | seabios-hppa-488e1c3fef2e789d38a5190baae977131a911fa7.zip seabios-hppa-488e1c3fef2e789d38a5190baae977131a911fa7.tar.gz seabios-hppa-488e1c3fef2e789d38a5190baae977131a911fa7.tar.bz2 |
timer: Avoid integer overflows in usec and nsec calculations
When timer_calc_usec() is used with large timeout values, such as 60s,
the integer math can overflow and produce different results than when
using timer_calc(time / 1000) for the same timeout.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/hw/timer.c')
-rw-r--r-- | src/hw/timer.c | 55 |
1 files changed, 31 insertions, 24 deletions
diff --git a/src/hw/timer.c b/src/hw/timer.c index 03d22b2..bdcb3bf 100644 --- a/src/hw/timer.c +++ b/src/hw/timer.c @@ -159,6 +159,29 @@ timer_read(void) return timer_adjust_bits(v, 0xffff); } +// Return the TSC value that is 'msecs' time in the future. +u32 +timer_calc(u32 msecs) +{ + return timer_read() + (GET_GLOBAL(TimerKHz) * msecs); +} +u32 +timer_calc_usec(u32 usecs) +{ + u32 cur = timer_read(), khz = GET_GLOBAL(TimerKHz); + if (usecs > 500000) + return cur + DIV_ROUND_UP(usecs, 1000) * khz; + return cur + DIV_ROUND_UP(usecs * khz, 1000); +} +static u32 +timer_calc_nsec(u32 nsecs) +{ + u32 cur = timer_read(), khz = GET_GLOBAL(TimerKHz); + if (nsecs > 500000) + return cur + DIV_ROUND_UP(nsecs, 1000000) * khz; + return cur + DIV_ROUND_UP(nsecs * khz, 1000000); +} + // Check if the current time is past a previously calculated end time. int timer_check(u32 end) @@ -167,53 +190,37 @@ timer_check(u32 end) } static void -timer_delay(u32 diff) +timer_delay(u32 end) { - u32 start = timer_read(); - u32 end = start + diff; while (!timer_check(end)) cpu_relax(); } static void -timer_sleep(u32 diff) +timer_sleep(u32 end) { - u32 start = timer_read(); - u32 end = start + diff; while (!timer_check(end)) yield(); } void ndelay(u32 count) { - timer_delay(DIV_ROUND_UP(count * GET_GLOBAL(TimerKHz), 1000000)); + timer_delay(timer_calc_nsec(count)); } void udelay(u32 count) { - timer_delay(DIV_ROUND_UP(count * GET_GLOBAL(TimerKHz), 1000)); + timer_delay(timer_calc_usec(count)); } void mdelay(u32 count) { - timer_delay(count * GET_GLOBAL(TimerKHz)); + timer_delay(timer_calc(count)); } void nsleep(u32 count) { - timer_sleep(DIV_ROUND_UP(count * GET_GLOBAL(TimerKHz), 1000000)); + timer_sleep(timer_calc_nsec(count)); } void usleep(u32 count) { - timer_sleep(DIV_ROUND_UP(count * GET_GLOBAL(TimerKHz), 1000)); + timer_sleep(timer_calc_usec(count)); } void msleep(u32 count) { - timer_sleep(count * GET_GLOBAL(TimerKHz)); -} - -// Return the TSC value that is 'msecs' time in the future. -u32 -timer_calc(u32 msecs) -{ - return timer_read() + (GET_GLOBAL(TimerKHz) * msecs); -} -u32 -timer_calc_usec(u32 usecs) -{ - return timer_read() + DIV_ROUND_UP(GET_GLOBAL(TimerKHz) * usecs, 1000); + timer_sleep(timer_calc(count)); } |