[SOLVED] Timer interuupt handler doesn't get called

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
ruisleipa
Member
Member
Posts: 46
Joined: Wed Sep 10, 2008 8:39 am
Location: Finland

[SOLVED] Timer interuupt handler doesn't get called

Post by ruisleipa »

I am doing a floppy disk driver. In the floppy disk driver there are some delays (timer_wait(milliseconds)). When I call timer_wait(), the clock interrupt handler doesn't seem to be called at all.

What might be the cause of the problem?

I have already tried using the volatile keyword but it didn't help for some reason.

And yes, the clock interrupt handler does get called when I don't call timer_wait().

My timer.c:

Code: Select all

#include <irq.h>
#include <system.h>
#include <trace.h>

#define TIMER_TICKS_PER_SEC 100

/* This will keep track of how many ticks that the system
*  has been running for */
static volatile int timer_ticks=0;
static volatile int seconds=0;

void timer_handler(struct regs *r)
{
	timer_ticks++;/*TRACE;*/
	puts("time: ");putnum(timer_ticks);putch('\n');
	
	if (timer_ticks%TIMER_TICKS_PER_SEC==0)
	{
		seconds++;
	}
}


void timer_install()
{
	int divisor=1193180/TIMER_TICKS_PER_SEC;   /* Calculate our divisor */
	outportb(0x43,0x36); /* Set our command byte 0x36 */
	outportb(0x40,divisor&0xFF);   /* Set low byte of divisor */
	outportb(0x40,divisor>>8); /* Set high byte of divisor */
	
	puts("\tFrequency: ");
	putnum(TIMER_TICKS_PER_SEC);
	puts(" hz\n");

	irq_install_handler(0, timer_handler);
}

void timer_wait(int ticks)
{
	unsigned long eticks;

	eticks = timer_ticks + ticks/(1000/TIMER_TICKS_PER_SEC);
	while(timer_ticks <= eticks)
	{
		puts("time: ");putnum(timer_ticks);puts(" eticks: ");putnum(eticks);putch('\n');
	}
}

int timer_get_ticks()
{
	return timer_ticks*(1000/TIMER_TICKS_PER_SEC);
}
My irq.asm

Code: Select all

global irq0
global irq1
global irq2
global irq3
global irq4
global irq5
global irq6
global irq7
global irq8
global irq9
global irq10
global irq11
global irq12
global irq13
global irq14
global irq15

; 32: IRQ0
irq0:
	cli
	push byte 0
	push byte 32
	jmp irq_common_stub

; 33: IRQ1
irq1:
	cli
	push byte 0
	push byte 33
	 
	jmp irq_common_stub

--snip--

; 47: IRQ15
irq15:
	cli
	push byte 0
	push byte 47
	 
	jmp irq_common_stub

extern irq_handler

irq_common_stub:

	pusha
	push ds
	push es
	push fs
	push gs

	mov ax, 0x10
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov eax, esp

	push eax
	mov eax, irq_handler
	call eax
	pop eax

	pop gs
	pop fs
	pop es
	pop ds
	popa
	add esp, 8
   
	iret
Thanks in advance.
Last edited by ruisleipa on Wed Sep 17, 2008 8:45 am, edited 1 time in total.
http://code.google.com/p/rmmtos/ - Real Mode MultiTasking Operating System
ru2aqare
Member
Member
Posts: 342
Joined: Fri Jul 11, 2008 5:15 am
Location: Hungary

Re: Timer interuupt handler doesn't get called when sleep()ing

Post by ru2aqare »

Where do you acknowledge the interrupt to the PIC? I don't see anything resembling

Code: Select all

  mov al, 20h
  out 20h,al
ruisleipa
Member
Member
Posts: 46
Joined: Wed Sep 10, 2008 8:39 am
Location: Finland

Re: Timer interuupt handler doesn't get called when sleep()ing

Post by ruisleipa »

Oh. There is my irq.c:

Code: Select all

#include <system.h>

/* These are own ISRs that point to our special IRQ handler
*  instead of the regular 'fault_handler' function */
extern void irq0();
extern void irq1();
extern void irq2();
extern void irq3();
extern void irq4();
extern void irq5();
extern void irq6();
extern void irq7();
extern void irq8();
extern void irq9();
extern void irq10();
extern void irq11();
extern void irq12();
extern void irq13();
extern void irq14();
extern void irq15();

/* This array is actually an array of function pointers. We use
*  this to handle custom IRQ handlers for a given IRQ */
void *irq_routines[16] =
{
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0
};

/* This installs a custom IRQ handler for the given IRQ */
void irq_install_handler(int irq, void (*handler)(struct regs *r))
{
	irq_routines[irq] = handler;
}

/* This clears the handler for a given IRQ */
void irq_uninstall_handler(int irq)
{
	irq_routines[irq] = 0;
}

/* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This
*  is a problem in protected mode, because IDT entry 8 is a
*  Double Fault! Without remapping, every time IRQ0 fires,
*  you get a Double Fault Exception, which is NOT actually
*  what's happening. We send commands to the Programmable
*  Interrupt Controller (PICs - also called the 8259's) in
*  order to make IRQ0 to 15 be remapped to IDT entries 32 to
*  47 */
void irq_remap(void)
{
	outportb(0x20, 0x11);
	outportb(0xA0, 0x11);
	outportb(0x21, 0x20);
	outportb(0xA1, 0x28);
	outportb(0x21, 0x04);
	outportb(0xA1, 0x02);
	outportb(0x21, 0x01);
	outportb(0xA1, 0x01);
	outportb(0x21, 0x0);
	outportb(0xA1, 0x0);
}

/* We first remap the interrupt controllers, and then we install
*  the appropriate ISRs to the correct entries in the IDT. This
*  is just like installing the exception handlers */
void irq_install()
{
    irq_remap();

    idt_set_gate(32, (unsigned)irq0, 0x08, 0x8E);
    idt_set_gate(33, (unsigned)irq1, 0x08, 0x8E);
    idt_set_gate(34, (unsigned)irq2, 0x08, 0x8E);
    idt_set_gate(35, (unsigned)irq3, 0x08, 0x8E);
    idt_set_gate(36, (unsigned)irq4, 0x08, 0x8E);
    idt_set_gate(37, (unsigned)irq5, 0x08, 0x8E);
    idt_set_gate(38, (unsigned)irq6, 0x08, 0x8E);
    idt_set_gate(39, (unsigned)irq7, 0x08, 0x8E);
    idt_set_gate(40, (unsigned)irq8, 0x08, 0x8E);
    idt_set_gate(41, (unsigned)irq9, 0x08, 0x8E);
    idt_set_gate(42, (unsigned)irq10, 0x08, 0x8E);
    idt_set_gate(43, (unsigned)irq11, 0x08, 0x8E);
    idt_set_gate(44, (unsigned)irq12, 0x08, 0x8E);
    idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E);
    idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E);
    idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E);
}

/* Each of the IRQ ISRs point to this function, rather than
*  the 'fault_handler' in 'isrs.c'. The IRQ Controllers need
*  to be told when you are done servicing them, so you need
*  to send them an "End of Interrupt" command (0x20). There
*  are two 8259 chips: The first exists at 0x20, the second
*  exists at 0xA0. If the second controller (an IRQ from 8 to
*  15) gets an interrupt, you need to acknowledge the
*  interrupt at BOTH controllers, otherwise, you only send
*  an EOI command to the first controller. If you don't send
*  an EOI, you won't raise any more IRQs */
void irq_handler(struct regs *r)
{
	/* This is a blank function pointer */
	void (*handler)(struct regs *r);
	/* Find out if we have a custom handler to run for this
	*  IRQ, and then finally, run it */
	handler = irq_routines[r->int_no - 32];
	if (handler)
	{
		handler(r);
	}
	/* If the IDT entry that was invoked was greater than 40
	*  (meaning IRQ8 - 15), then we need to send an EOI to
	*  the slave controller */
	if (r->int_no >= 40)
	{
		outportb(0xA0, 0x20);
	}
	/* In either case, we need to send an EOI to the master
	*  interrupt controller too */
	outportb(0x20, 0x20);
}

Interrupts do actually work when I remove the timer_wait():s from the code. When I do an timer_wait() interrupts just stop working. No PIT interrupts, no keyboard interrupts, no any interrupts at all.
http://code.google.com/p/rmmtos/ - Real Mode MultiTasking Operating System
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Timer interuupt handler doesn't get called when sleep()ing

Post by pcmattman »

I haven't actually looked at your code (in a rush), but are you missing a volatile keyword in timer_wait() perhaps?
ruisleipa
Member
Member
Posts: 46
Joined: Wed Sep 10, 2008 8:39 am
Location: Finland

Re: Timer interuupt handler doesn't get called when sleep()ing

Post by ruisleipa »

The problem is solved!

I was so stupid that I put routines that need interrupts before the set interrupts line, effectively stopping all interrupts.
http://code.google.com/p/rmmtos/ - Real Mode MultiTasking Operating System
Post Reply