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