Page 1 of 1

Qemu PIT Broken?

Posted: Tue Mar 20, 2012 11:52 pm
by Rudster816
Is it me, or is Qemu's PIT very dodgy? I'm trying to use the PIT to create consistent delays for MP startup, but it seems that Qemu does not handle the PIT very well at all.

I'm testing it like so:

Code: Select all

PRIVATE u64 ticks = 0;
void pit_tick()
{
	ticks++;
	if (!(ticks % 16))
	{
		kprintf_cls();
		kprintf("Ticks: %X", ticks);
	}
	outb(MASTER_PIC_COMMAND, 0x20);
}


PRIVATE void pit_init()
{
	/* First setup the PIC */

	outb(MASTER_PIC_COMMAND, ICW1_INIT + ICW1_ICW4);
	outb(SLAVE_PIC_COMMAND, ICW1_INIT + ICW1_ICW4);
	outb(MASTER_PIC_DATA, 0x20);
	outb(SLAVE_PIC_DATA, 0x28);
	outb(MASTER_PIC_DATA, 4);
	outb(SLAVE_PIC_DATA, 2);
	outb(MASTER_PIC_DATA, ICW4_8086);
	outb(SLAVE_PIC_DATA, ICW4_8086);
	/* Mask all interrupts besides IRQ 0 (the PIT) */
	outb(MASTER_PIC_DATA, 0xFE);
	outb(SLAVE_PIC_DATA, 0xFF);

	outb(PIT_COMMAND, 0x34); // Channel 0, Mode 2, Lo\Hi bytes access mode
	outb(PIT0_DATA, 0x05);
	outb(PIT0_DATA, 0x00);

	set_isr(32, (unsigned long)pit_tick, 0x8, 0x8E00);
	enable_interrupts();
	for(;;);	
}

The problem is that the rate at which Qemu generates the interrupts is very inconsistent. When I run the above code, I get ~20 interrupts a second, which is same is what I get without changing the reload value (which I assume is set to 65535\65536 by the BIOS) which is what you would expect by default, but not with a reload value of just 5.

Other values I've tested:
Low: 0x10 High: 0x00
I get a steady stream of interrupts, about very roughly 4096 every ~10 seconds
Low: 0xF0 High: 0x00
I get about twice as many interrupts as above
Low: 0xF0 High: 0xF0
I'm back to the ~20 interrupts a second routine.

I understand that Qemu cant emulate the PIT to a degree anywhere close to what the real deal can, but obviously this isn't right. Am I doing something wrong? Everything seems to work just fine in Virtualbox (changing the (ticks % 16) to a much higher value or nothing is ever really seen with low reloads, as one would expect).

I've used the old binaries included with Qemu Manager 7 and recent ones found below with the same results.
http://lassauge.free.fr/qemu/
(I tried to compile the git repo, but it's giving me grief on Cygwin).

Re: Qemu PIT Broken?

Posted: Wed Mar 21, 2012 2:55 pm
by brain
You're right that qemu can't emulate the pit accurately, is it possible that your emulator ia slowing down and speeding up based on activity in the pc running it? To be honest I have learned that no timing at all can really be trusted in an emulator, not just the pit as getting all sorts of interrupts etc accurate is a proper pain for emulator developers....

Re: Qemu PIT Broken?

Posted: Thu Mar 22, 2012 1:12 am
by Brendan
Hi,

To summerize results so far:

Count = 5, expected = 238636.333 Hz, actual = 20 IRQs per second, difference = 11932 times slower than expected.
Probably faster than real hardware can handle, even without a massive overhead of "kprintf_cls();" in the middle of the IRQ handler. You probably miss most of the IRQs that the PIT is generating due to spending far too long in the IRQ handler. Qemu is probably also having a seizure trying to keep up with emulating the PIT's hardware.

Count = 16, expected = 74573.854166 Hz, actual = 409.6 IRQs per second, difference = 182 times slower than expected.
Similar problems as above, but a lot closer because count is a lot less insane.

Count = 250, expected = 4772.72666 Hz, actual = 819.2 IRQs per second, difference = 5.83 times slower than expected.
Count is much closer to sane, and coincidentally actual frequency is much closer to expected frequency.

Count = 61680, expected = 19.3447 Hz, actual = 20 IRQs per second, difference = probably nothing.
Works.

Where's the problem? ;)

Note: I'm guessing that if you set the count to 600 (low = 0x58, high = 0x02) and got rid of the "kprintf_cls();", it'd work perfectly (expected = 1988.636 Hz, actual = about 1988 IRQs per second).


Cheers,

Brendan