Hi, Is it bad if the olatch counts up if the host's wall clock is set backward? Or if the olatch makes a big jump for the same reason?
Serious question: I don't have any EPT hardware to test this (sorry). While here, it looks like we can (a) roll the olatch-writing parts of i8253_do_readback into a loop, and (b) use the timespecsub macro from sys/time.h, to make the code briefer. Anyone down to test? -- Scott Cheloha Index: usr.sbin/vmd/i8253.c =================================================================== RCS file: /cvs/src/usr.sbin/vmd/i8253.c,v retrieving revision 1.17 diff -u -p -r1.17 i8253.c --- usr.sbin/vmd/i8253.c 14 Aug 2017 19:46:44 -0000 1.17 +++ usr.sbin/vmd/i8253.c 18 Feb 2018 17:53:48 -0000 @@ -25,6 +25,7 @@ #include <event.h> #include <string.h> #include <stddef.h> +#include <time.h> #include <unistd.h> #include "i8253.h" @@ -53,7 +54,7 @@ void i8253_init(uint32_t vm_id) { memset(&i8253_channel, 0, sizeof(struct i8253_channel)); - gettimeofday(&i8253_channel[0].tv, NULL); + clock_gettime(CLOCK_MONOTONIC, &i8253_channel[0].ts); i8253_channel[0].start = 0xFFFF; i8253_channel[0].mode = TIMER_INTTC; i8253_channel[0].last_r = 1; @@ -86,8 +87,10 @@ i8253_init(uint32_t vm_id) void i8253_do_readback(uint32_t data) { - struct timeval now, delta; + struct timespec now, delta; uint64_t ns, ticks; + int readback_channel[3] = { TIMER_RB_C0, TIMER_RB_C1, TIMER_RB_C2 }; + int i; /* bits are inverted here - !TIMER_RB_STATUS == enable chan readback */ if (data & ~TIMER_RB_STATUS) { @@ -98,73 +101,19 @@ i8253_do_readback(uint32_t data) /* !TIMER_RB_COUNT == enable counter readback */ if (data & ~TIMER_RB_COUNT) { - if (data & TIMER_RB_C0) { - gettimeofday(&now, NULL); - delta.tv_sec = now.tv_sec - i8253_channel[0].tv.tv_sec; - delta.tv_usec = now.tv_usec - - i8253_channel[0].tv.tv_usec; - if (delta.tv_usec < 0) { - delta.tv_sec--; - delta.tv_usec += 1000000; + for (i = 0; i < 3; i++) { + if (data & readback_channel[i]) { + clock_gettime(CLOCK_MONOTONIC, &now); + timespecsub(&now, &i8253_channel[i].ts, &delta); + ns = delta.tv_sec * 1000000000 + delta.tv_nsec; + ticks = ns / NS_PER_TICK; + if (i8253_channel[i].start) + i8253_channel[i].olatch = + i8253_channel[i].start - + ticks % i8253_channel[i].start; + else + i8253_channel[i].olatch = 0; } - if (delta.tv_usec > 1000000) { - delta.tv_sec++; - delta.tv_usec -= 1000000; - } - ns = delta.tv_usec * 1000 + delta.tv_sec * 1000000000; - ticks = ns / NS_PER_TICK; - if (i8253_channel[0].start) - i8253_channel[0].olatch = - i8253_channel[0].start - - ticks % i8253_channel[0].start; - else - i8253_channel[0].olatch = 0; - } - - if (data & TIMER_RB_C1) { - gettimeofday(&now, NULL); - delta.tv_sec = now.tv_sec - i8253_channel[1].tv.tv_sec; - delta.tv_usec = now.tv_usec - - i8253_channel[1].tv.tv_usec; - if (delta.tv_usec < 0) { - delta.tv_sec--; - delta.tv_usec += 1000000; - } - if (delta.tv_usec > 1000000) { - delta.tv_sec++; - delta.tv_usec -= 1000000; - } - ns = delta.tv_usec * 1000 + delta.tv_sec * 1000000000; - ticks = ns / NS_PER_TICK; - if (i8253_channel[1].start) - i8253_channel[1].olatch = - i8253_channel[1].start - - ticks % i8253_channel[1].start; - else - i8253_channel[1].olatch = 0; - } - - if (data & TIMER_RB_C2) { - gettimeofday(&now, NULL); - delta.tv_sec = now.tv_sec - i8253_channel[2].tv.tv_sec; - delta.tv_usec = now.tv_usec - - i8253_channel[2].tv.tv_usec; - if (delta.tv_usec < 0) { - delta.tv_sec--; - delta.tv_usec += 1000000; - } - if (delta.tv_usec > 1000000) { - delta.tv_sec++; - delta.tv_usec -= 1000000; - } - ns = delta.tv_usec * 1000 + delta.tv_sec * 1000000000; - ticks = ns / NS_PER_TICK; - if (i8253_channel[2].start) - i8253_channel[2].olatch = - i8253_channel[2].start - - ticks % i8253_channel[2].start; - else - i8253_channel[2].olatch = 0; } } } @@ -188,7 +137,7 @@ vcpu_exit_i8253(struct vm_run_params *vr uint32_t out_data; uint8_t sel, rw, data, mode; uint64_t ns, ticks; - struct timeval now, delta; + struct timespec now, delta; union vm_exit *vei = vrp->vrp_exit; get_input_data(vei, &out_data); @@ -216,21 +165,9 @@ vcpu_exit_i8253(struct vm_run_params *vr * rate. */ if (rw == TIMER_LATCH) { - gettimeofday(&now, NULL); - delta.tv_sec = now.tv_sec - - i8253_channel[sel].tv.tv_sec; - delta.tv_usec = now.tv_usec - - i8253_channel[sel].tv.tv_usec; - if (delta.tv_usec < 0) { - delta.tv_sec--; - delta.tv_usec += 1000000; - } - if (delta.tv_usec > 1000000) { - delta.tv_sec++; - delta.tv_usec -= 1000000; - } - ns = delta.tv_usec * 1000 + - delta.tv_sec * 1000000000; + clock_gettime(CLOCK_MONOTONIC, &now); + timespecsub(&now, &i8253_channel[sel].ts, &delta); + ns = delta.tv_sec * 1000000000 + delta.tv_nsec; ticks = ns / NS_PER_TICK; if (i8253_channel[sel].start) { i8253_channel[sel].olatch = Index: usr.sbin/vmd/i8253.h =================================================================== RCS file: /cvs/src/usr.sbin/vmd/i8253.h,v retrieving revision 1.7 diff -u -p -r1.7 i8253.h --- usr.sbin/vmd/i8253.h 9 Jul 2017 00:51:40 -0000 1.7 +++ usr.sbin/vmd/i8253.h 18 Feb 2018 17:53:48 -0000 @@ -29,7 +29,7 @@ /* i8253 registers */ struct i8253_channel { - struct timeval tv; /* timer start time */ + struct timespec ts; /* timer start time */ uint16_t start; /* starting value */ uint16_t olatch; /* output latch */ uint16_t ilatch; /* input latch */