Download raw body.
vmd: set i8253 output latch to 0 in INTTC mode
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);
>
vmd: set i8253 output latch to 0 in INTTC mode