PIT does not call IRQ Routine

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
micheben
Posts: 2
Joined: Mon Dec 28, 2020 2:41 pm

PIT does not call IRQ Routine

Post by micheben »

Hey,

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");
in my kernel_main to test it.

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
As I understood it, this should map IRQ0 (i.e. the PIT) to ISR32 (or ISR 0x20).

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
...
My Plan was to use a simplified version of https://wiki.osdev.org/Programmable_Interval_Timer (partly inspired by James Molloy's Tutorial).

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");
	}
at the end of my current kernel main to ensure that my kernel is actually still running...
xeyes
Member
Member
Posts: 212
Joined: Mon Dec 07, 2020 8:09 am

Re: PIT does not call IRQ Routine

Post by xeyes »

code seems all right

Have you tried to:

run with qemu -d int to observe interrupt delivery to the CPU (only need to look at the first part, <counter>: v=<vector>)

install a catch all handler on all vectors just in case? or better yet different handlers on each one.

lastly, you didn't forget to unmask interrupts on the CPU (sti) right?
micheben
Posts: 2
Joined: Mon Dec 28, 2020 2:41 pm

Re: PIT does not call IRQ Routine

Post by micheben »

Thanks for your help.

It was actually a series of errors:

Previously, I missed a

Code: Select all

0x
at the IDT Setup, but i found that error while going through my code. I also added a

Code: Select all

cli
inside the PIT Setup at the same instance (found it on the osdev wiki example), and my

Code: Select all

sti
was to early after that change.

PS: I actually thought that "manual" interrupts (i.e.

Code: Select all

int $0x20
) only works, if interrupts are enabled, so I didn't think about checking this flag again.
Post Reply