Index | Thread | Search

From:
hshoexer <hshoexer@yerbouti.franken.de>
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

Download raw body.

Thread
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);
>