Page 1 of 1

PIT & JamesM tutorial

Posted: Wed Mar 13, 2013 8:41 am
by Knyght
I've been working through the JamesM tutorial (http://www.jamesmolloy.co.uk/tutorial_h ... 20PIT.html) and in order to understand the code rather than just copy/paste I've been writing it up and trying to understand what everything does and make some minor modifications here and there. It was all going so well until I got to the PIT.

It seems like the interrupts are working since least I get the messages that interrupts are received. Bit I don't get any of the clock ticks. Not even the Tick: gets written to the screen so I'm not sure the callback is working. I compiled the JamesM code on my own machine and that runs fine in Bochs. I've compared the code and can't find the problem... though there obviously is one. So I would be very happy if someone could trawl through my code and spot the problem that is probably obvious to everyone except me at this point. I guess the cause is likely to be in one of these files:

timer.c

Code: Select all

#include "timer.h"
#include "isr.h"
#include "screen.h"

u32int tick = 0;

static void timer_callback(registers_t regs) {
    tick++;
    write("Tick: ");
    write_dec(tick);
    write("\n");
}

void init_timer(u32int frequency) {
    // Firstly, register our timer callback.
    register_interrupt_handler(IRQ0, &timer_callback);

    // 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.
    u32int divisor = 1193180 / frequency;

    // Send the command byte.
    outb(0x43, 0x36);

    // Divisor has to be sent byte-wise, so split here into upper/lower bytes.
    u8int l = (u8int)(divisor & 0xFF);
    u8int h = (u8int)((divisor>>8) & 0xFF);

    // Send the frequency divisor.
    outb(0x40, l);
    outb(0x40, h);
}
isr.c

Code: Select all

#include "common.h"
#include "isr.h"
#include "screen.h"

void isr_handler(registers_t regs);
void irq_handler(registers_t regs);

isr_t interrupt_handlers[256];

void register_interrupt_handler(u8int n, isr_t handler) {
    interrupt_handlers[n] = handler;
}

// This gets called from our ASM interrupt handler stub.
void isr_handler(registers_t regs) {
    write("received interrupt: ");
    write_dec(regs.int_no);
    putchar('\n', DEFAULT_BG, DEFAULT_FG);

    if (interrupt_handlers[regs.int_no] != 0) {
        isr_t handler = interrupt_handlers[regs.int_no];
        handler(regs);
    }
}

// This gets called from our ASM interrupt handler stub.
void irq_handler(registers_t regs) {
    // Send an EOI (end of interrupt) signal to the PICs.
    // If this interrupt involved the slave.
    if (regs.int_no >= 40) {
        // Send reset signal to slave.
        outb(0xA0, 0x20);
    }
    // Send reset signal to master. (As well as slave, if necessary).
    outb(0x20, 0x20);

    if (interrupt_handlers[regs.int_no] != 0) {
        isr_t handler = interrupt_handlers[regs.int_no];
        handler(regs);
    }
}
isr.h

Code: Select all

#include "common.h"

static const u8int IRQ0  = 32;
static const u8int IRQ1  = 33;
static const u8int IRQ2  = 34;
static const u8int IRQ3  = 35;
static const u8int IRQ4  = 36;
static const u8int IRQ5  = 37;
static const u8int IRQ6  = 38;
static const u8int IRQ7  = 39;
static const u8int IRQ8  = 40;
static const u8int IRQ9  = 41;
static const u8int IRQ10 = 42;
static const u8int IRQ11 = 43;
static const u8int IRQ12 = 44;
static const u8int IRQ13 = 45;
static const u8int IRQ14 = 46;
static const u8int IRQ15 = 47;

typedef struct registers {
    u32int ds;                                      // Data segment selector.
    u32int edi, esi, ebp, esp, ebx, edx, ecx, eax;  // Pushed by pusha.
    u32int int_no, err_code;                        // Interrupt number and error code.
    u32int eip, cs, eflags, useresp, ss;            // Pushed by the processor automatically.
} registers_t;

// Enables registration of callbacks for interrupts or IRQs.
// For IRQs, to ease confusion, use the variables above as the
// first parameter.
typedef void (*isr_t)(registers_t);
void register_interrupt_handler(u8int n, isr_t handler);

Re: PIT & JamesM tutorial

Posted: Wed Mar 13, 2013 8:54 am
by Combuster
Did you read the FAQ? I Cant Get Interrupts Working

Re: PIT & JamesM tutorial

Posted: Wed Mar 13, 2013 10:12 am
by Knyght
Yeah. It seems that ISR handlers work just fine, seems like the problem is just with IRQ, but not sure why.

Re: PIT & JamesM tutorial

Posted: Wed Mar 13, 2013 1:38 pm
by bewing
"&timer_callback"? Do you need the &? Function pointers are the least pretty part of C, but I don't recall ever using ampersands. (Of course, if the compiler is happy, who am I to quibble?)

Re: PIT & JamesM tutorial

Posted: Wed Mar 13, 2013 7:29 pm
by Knyght
Ah, okay. My code there was fine, it just seems that I set up the IDT wrong for the IRQs. Woops. But yes, I think that ampersand is extraneous.