I need some help with correctly setting up the PIT and I'm hitting my head against this wall since several days now.
I compile my kernel with a gcc cross compiler (i686-elf-gcc) and I'm using the qemu emulator. I used the "Meaty Skeleton" as a starting point.
The Interrupt itself is working correctly. I've added
Code: Select all
__asm__ __volatile__ ("int $0x20");
Here is what I do to set up the timer (all in GNU Assembly dialect):
First (bevor setting up the IDT) I remap the IRQ Ports:
Code: Select all
.global PIC_remap
PIC_remap:
# tell both PIC that a reinit will come now
mov $0x11, %al
outb %al, $0x20
outb %al, $0xA0
# tell both PICs their Interrupt Number Offset
mov $0x20, %al
outb %al, $0x21
mov $0x28, %al
outb %al, $0xA1
# tell Master PIC that there is a slave on port 2 (0000 0100)
mov $0x04, %al
outb %al, $0x21
# tell Slave PIC its cascade identity (0000 0010)
mov $0x02, %al
outb %al, $0xA1
# activate 8086/88 (MCS-80/85) mode on both PIC
mov $0x01, %al
outb %al, $0x21
outb %al, $0xA1
# unmask/activate all IRQs
mov $0x0, %al
outb %al, $0x21
outb %al, $0xA1
Then, I initialize the PIT (partly C, partly Assembly):
Code: Select all
// in irq.c
extern void send_divisior_to_PID(uint32_t);
void init_irq0_timer(uint32_t frequency) {
// The value we send to the PIT is the value to divide it's input clock
// (1193180 Hz) by, to get our required frequency. Important to note is
// that the divisor must be small enough to fit into 16-bits.
uint32_t divisor = 1193180 / frequency;
send_divisior_to_PID(divisor);
}
// in irq_asm.S
.global send_divisior_to_PID
send_divisior_to_PID:
cli
mov $0x34, %al #channel 0, lobyte/hibyte, rate generator
outb %al, $0x43
mov 4(%esp), %eax # set EDA to 1st argument - the divisior
outb %al,$0x40 #Set low byte of PIT reload value
mov %ah,%al #ax = high 8 bits of reload value
outb %al,$0x40 #Set high byte of PIT reload value
# unmask/activate all IRQs
mov $0x0, %al
outb %al, $0x21
outb %al, $0xA1
// in boot.S
...
push $100 # 100Hz, i.e. 100 times per Second or every 10 ms
call init_irq0_timer
add $0x04, %esp # Stack Cleanup
...
However, the interrupt is not called by the timer.
I added
Code: Select all
static uint32_t i = 0;
...
for (;;) {
++i;
if (i == 0)
printf("overflow\n");
}