From: Dave Voutila Subject: Re: vmd: set i8253 output latch to 0 in INTTC mode To: tech@openbsd.org Date: Tue, 17 Feb 2026 13:10:07 -0500 hshoexer writes: > Hi, > > On Fri, Feb 13, 2026 at 09:55:17AM -0500, Dave Voutila wrote: >> 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 > > I'm not sure, but is this assumption true? Both [1] and [2] state > that the counter actually wraps and keeps counting after hitting > zero. Ah, yes... definitely seems this thing is supposed to wrap. I guess I can instead detect the wrap. While imperfect, at least should satisfy my need for a cheap interrupt-less timeout. Or I guess I just enable interrupts... > > [1] https://archive.org/details/i8253 p. 3-54 > [2] https://web.archive.org/web/20150603122044/http://download.intel.com/design/archives/periphrl/docs/23124406.pdf p. 14 > > Take care, > HJ. > >> 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); >>