Basically, I have a function in a file called VGA.c that puts a character at a certain location on the screen. When I call the function in my timer callback handler, I get a general protection fault.
Code: Select all
/* Called after IRQ0 is raised */
void Timer_callback(registers_t regs) {
VGA_TerminalPutEntryAt('X', VGA_COLOR_WHITE, 2, 2); // This call causes a GPF
}
Code: Select all
void TerminalPutEntryAt(char c, uint8_t color, size_t x, size_t y)
{
const size_t index = y * VGA_WIDTH + x;
terminal_buffer[index] = VGA_Entry(c, color); // Put the character and color byte in the VGA memory map, which starts at 0xC00B8000
}
void Timer_callback(registers_t regs) {
TerminalPutEntryAt('X', VGA_COLOR_WHITE, 2, 2); // This call does not
}
Any time an IRQ is raised, I have the IDT point to a stub defined in assembly. This pushes the IRQ and ISR number, and then calls a more general IRQ stub, which calls a dispatch, which calls the actual callback function.
Code: Select all
global irq0
; ...
irq0:
cli
push byte 0
push byte 32
jmp irq_common_stub
; ...
; Called by IRQ stubs below
irq_common_stub:
pusha
mov ax, ds
push eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
call Interrupt_IRQHandler ; Different than the ISR code
pop ebx ; Different than the ISR code
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa
add esp, 0x8
sti
iret
Code: Select all
/* Called by irq_common_stub, sends acknowledge to PIC, and then calls IRQ handler */
void Interrupt_IRQHandler(registers_t r) {
// Need to send EOI to PICs or they will not send another interrupt
if (r.int_no >= 40) {
IO_OutByte(0xA0, 0x20); // slave
}
IO_OutByte(0x20, 0x20); // master
// Handle the interrupt in a more modular way
if (interrupt_handlers[r.int_no] != 0) {
isr_t handler = interrupt_handlers[r.int_no];
if(handler) {
handler(r);
}
}
}