Nucleus
Barry Kernel threads + threads share address space 6217f0d (3 years, 1 month ago)
/*
* This file deals with the Interrupt Descriptor Table. It creates a simple
* IDT, with hard-coded handler functions. It is these handler functions that
* can run custom handlers, registered at runtime. This file does not deal with
* dispatching messages/signals to processes on an interrupt.
*/
#include <stdint.h>
#include <nucleus/cpu.h>
#include <nucleus/io.h>
#include <nucleus/kernel.h>
#include <nucleus/lib.h>
#include <nucleus/memory.h>
#include <nucleus/task.h>
#include "desc.h"
/* Structure for an IDT Entry */
static struct IDTEntry {
uint16_t offsetLower, selector;
uint8_t zero, typeAttr;
uint16_t offsetHigher;
} __attribute__((packed)) *IDT;
void (**interrupts)(struct InterruptFrame *);
/* Install an IDT Entry */
static void
install_idt_entry(uint8_t num, void *addr)
{
uint8_t type = 0x8E; /* Interrupt gate */
if (num < 32)
type = 0x8F; /* Trap gate for exceptions */
if (num == 0x80)
type |= 3 << 5; /* Allowed from ring 3 */
IDT[num].offsetLower = (uintptr_t) addr & 0xFFFF;
IDT[num].selector = 0x08;
IDT[num].zero = 0;
IDT[num].typeAttr = type;
IDT[num].offsetHigher = (uintptr_t) addr >> 16;
}
/* Generic ISR handler */
void
isr_handler(struct InterruptFrame frame)
{
if (!interrupts[frame.intnum] && frame.intnum < 32)
panic("Failed to handle exception %d (%#.8x) @ %#.8x",
frame.intnum, frame.err, frame.eip);
/* Send EOI */
if (frame.intnum >= 40 && frame.intnum < 48)
outb(0xA0, 0x20);
if (frame.intnum >= 32 && frame.intnum < 48)
outb(0x20, 0x20);
/* Send APIC EOI */
if (apic)
LAPIC(0xB0) = 0;
/* Run registered handler */
int_handler_t handler = interrupts[frame.intnum];
struct InterruptFrame *oldFrame;
if (handler) {
oldFrame = cpu->frame;
cpu->frame = &frame;
handler(&frame);
cpu->frame = oldFrame;
}
}
/* Register an exception handler */
void
register_exception(uint8_t num, int_handler_t addr)
{
interrupts[num] = addr;
}
/* Register an interrupt handler */
void
register_interrupt(uint8_t num, int_handler_t addr)
{
if (num >= 0 && num < 16)
register_exception(num + 32, addr);
}
/* Register an IPI handler */
void
register_ipi(uint8_t num, int_handler_t addr)
{
if (num >= 0 && num < 16)
register_exception(num + 48, addr);
}
/* Exceptions */
extern char exc0[], exc1[], exc2[], exc3[], exc4[], exc5[], exc6[],
exc7[], exc8[], exc9[], exc10[], exc11[], exc12[], exc13[],
exc14[], exc15[], exc16[], exc17[], exc18[], exc19[], exc20[],
exc30[];
/* Interrutps */
extern char exc32[], exc33[], exc34[], exc35[], exc36[], exc37[], exc38[],
exc39[], exc40[], exc41[], exc42[], exc43[], exc44[], exc45[],
exc46[], exc47[];
/* IPIs */
extern char exc48[], exc49[], exc50[], exc51[], exc52[], exc53[], exc54[],
exc55[], exc56[], exc57[], exc58[], exc59[], exc60[], exc61[],
exc62[], exc63[];
/* System Call */
extern char exc128[];
/* Initialise the IDT */
void
init_idt(void)
{
IDT = (void *) alloc_frame();
/* Install exceptions */
install_idt_entry(0, exc0);
install_idt_entry(1, exc1);
install_idt_entry(2, exc2);
install_idt_entry(3, exc3);
install_idt_entry(4, exc4);
install_idt_entry(5, exc5);
install_idt_entry(6, exc6);
install_idt_entry(7, exc7);
install_idt_entry(8, exc8);
install_idt_entry(9, exc9);
install_idt_entry(10, exc10);
install_idt_entry(11, exc11);
install_idt_entry(12, exc12);
install_idt_entry(13, exc13);
install_idt_entry(14, exc14);
install_idt_entry(15, exc15);
install_idt_entry(16, exc16);
install_idt_entry(17, exc17);
install_idt_entry(18, exc18);
install_idt_entry(19, exc19);
install_idt_entry(20, exc20);
install_idt_entry(30, exc30);
/* Install interrupts */
install_idt_entry(32, exc32);
install_idt_entry(33, exc33);
install_idt_entry(34, exc34);
install_idt_entry(35, exc35);
install_idt_entry(36, exc36);
install_idt_entry(37, exc37);
install_idt_entry(38, exc38);
install_idt_entry(39, exc39);
install_idt_entry(40, exc40);
install_idt_entry(41, exc41);
install_idt_entry(42, exc42);
install_idt_entry(43, exc43);
install_idt_entry(44, exc44);
install_idt_entry(45, exc45);
install_idt_entry(46, exc46);
install_idt_entry(47, exc47);
/* Install IPIs */
install_idt_entry(48, exc48);
install_idt_entry(49, exc49);
install_idt_entry(50, exc50);
install_idt_entry(51, exc51);
install_idt_entry(52, exc52);
install_idt_entry(53, exc53);
install_idt_entry(54, exc54);
install_idt_entry(55, exc55);
install_idt_entry(56, exc56);
install_idt_entry(57, exc57);
install_idt_entry(58, exc58);
install_idt_entry(59, exc59);
install_idt_entry(60, exc60);
install_idt_entry(61, exc61);
install_idt_entry(62, exc62);
install_idt_entry(63, exc63);
/* Install system call handler */
install_idt_entry(128, exc128);
interrupts = (void *) (IDT + 256);
memset(interrupts, 0, 1024);
}
/* Load the IDT */
void
cpu_load_idt(void)
{
struct DescRecord ptr = {
.limit = sizeof(struct IDTEntry) * 256,
.base = (uintptr_t) IDT,
};
asm volatile("lidt %0" :: "m" (ptr));
}