Qemu PIT Broken?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Rudster816
Member
Member
Posts: 141
Joined: Thu Jun 17, 2010 2:36 am

Qemu PIT Broken?

Post 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).
User avatar
brain
Member
Member
Posts: 234
Joined: Thu Nov 05, 2009 5:04 pm
Location: UK
Contact:

Re: Qemu PIT Broken?

Post 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....
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Qemu PIT Broken?

Post 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
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Post Reply