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).