PIT & JamesM tutorial
Posted: Wed Mar 13, 2013 8:41 am
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
isr.c
isr.h
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);
}
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);
}
}
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);