BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / blob / master / kernel / idt.c

// Related

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));
}