From: Dave Voutila Subject: vmd: set i8253 output latch to 0 in INTTC mode To: tech@openbsd.org Date: Fri, 13 Feb 2026 09:55:17 -0500 So found this while building a toy firmware for vmd. We don't fully emulate all the nuances of a i8253 PIT, which is generally fine. However, I needed a way to measure a fixed passage of time without interrupts, so was trying to use the "interrupt on terminal count" mode of the PIT and polling for it to output zero. In INTTC mode, the output latch value should not wrap around when hitting zero, but vmd isn't distinguishing this mode from the others and will never precisely hit or stop at zero. Our PIT isn't super accurate, but the way it works in this case is when the timer event we set with libevent fires, .state toggles from 0 (counting) to 1 (fired) IFF we're in INTTC mode on that channel. I'm no PIT expert...so other eyeballs welcome! Otherwise, ok? -dv diff refs/heads/master refs/heads/codex-vmd-i8253-oneshot commit - 7d8bc7d2b639aaf8b2bb352eaf8db563407cf7d0 commit + dc390c186d477b8b873ab66acb0855cb4fd56f23 blob - 9e32d9382b6aa5b340402e487c577e0702f22ca9 blob + 2bcd52417ec4e3d20d6435647cfe474ab6ea20b6 --- usr.sbin/vmd/i8253.c +++ usr.sbin/vmd/i8253.c @@ -135,6 +135,13 @@ i8253_do_readback(uint32_t data) clock_gettime(CLOCK_MONOTONIC, &now); for (i = 0; i < 3; i++) { if (data & readback_channel[i]) { + if (i8253_channel[i].mode == + TIMER_INTTC && + i8253_channel[i].state) { + /* mode 0: latch 0 after fire */ + i8253_channel[i].olatch = 0; + continue; + } timespecsub(&now, &i8253_channel[i].ts, &delta); ns = delta.tv_sec * 1000000000 + delta.tv_nsec; ticks = ns / NS_PER_TICK; @@ -251,6 +258,13 @@ vcpu_exit_i8253(struct vm_run_params *vrp) * rate. */ if (rw == TIMER_LATCH) { + if (i8253_channel[sel].mode == + TIMER_INTTC && + i8253_channel[sel].state) { + /* mode 0: latch 0 after fire */ + i8253_channel[sel].olatch = 0; + goto ret; + } clock_gettime(CLOCK_MONOTONIC, &now); timespecsub(&now, &i8253_channel[sel].ts, &delta);