From: hshoexer Subject: Re: vmd: set i8253 output latch to 0 in INTTC mode To: tech@openbsd.org Cc: hshoexer@yerbouti.franken.de Date: Tue, 17 Feb 2026 18:00:54 +0100 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. [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); >