Some IRQ cleanup

This commit is contained in:
Dale Weiler 2015-05-20 19:52:19 -04:00
parent 82d706f453
commit 5ddbbf8199
4 changed files with 104 additions and 161 deletions

View File

@ -2,6 +2,7 @@
* This file is part of ToaruOS and is released under the terms
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2011-2013 Kevin Lange
* Copyright (C) 2015 Dale Weiler
*
* Global Descriptor Tables module
*
@ -10,134 +11,92 @@
#include <logging.h>
#include <tss.h>
static void write_tss(int32_t, uint16_t, uint32_t);
tss_entry_t tss_entry;
/*
* Global Descriptor Table Entry
*/
struct gdt_entry {
typedef struct {
/* Limits */
unsigned short limit_low;
uint16_t limit_low;
/* Segment address */
unsigned short base_low;
unsigned char base_middle;
uint16_t base_low;
uint8_t base_middle;
/* Access modes */
unsigned char access;
unsigned char granularity;
unsigned char base_high;
} __attribute__((packed));
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed)) gdt_entry_t;
/*
* GDT pointer
*/
struct gdt_ptr {
unsigned short limit;
unsigned int base;
} __attribute__((packed));
typedef struct {
uint16_t limit;
uintptr_t base;
} __attribute__((packed)) gdt_pointer_t;
struct gdt_entry gdt[6];
struct gdt_ptr gp;
/* In the future we may need to put a lock on the access of this */
static struct {
gdt_entry_t entries[6];
gdt_pointer_t pointer;
tss_entry_t tss;
} gdt __attribute__((used));
/**
* (ASM) gdt_flush
* Reloads the segment registers
*/
extern void gdt_flush(uintptr_t);
/**
* Set a GDT descriptor
*
* @param num The number for the descriptor to set.
* @param base Base address
* @param limit Limit
* @param access Access permissions
* @param gran Granularity
*/
void
gdt_set_gate(
size_t num,
unsigned long base,
unsigned long limit,
unsigned char access,
unsigned char gran
) {
#define ENTRY(X) (gdt.entries[(X)])
void gdt_set_gate(uint8_t num, uint64_t base, uint64_t limit, uint8_t access, uint8_t gran) {
/* Base Address */
gdt[num].base_low = (base & 0xFFFF);
gdt[num].base_middle = (base >> 16) & 0xFF;
gdt[num].base_high = (base >> 24) & 0xFF;
ENTRY(num).base_low = (base & 0xFFFF);
ENTRY(num).base_middle = (base >> 16) & 0xFF;
ENTRY(num).base_high = (base >> 24) & 0xFF;
/* Limits */
gdt[num].limit_low = (limit & 0xFFFF);
gdt[num].granularity = (limit >> 16) & 0X0F;
ENTRY(num).limit_low = (limit & 0xFFFF);
ENTRY(num).granularity = (limit >> 16) & 0X0F;
/* Granularity */
gdt[num].granularity |= (gran & 0xF0);
ENTRY(num).granularity |= (gran & 0xF0);
/* Access flags */
gdt[num].access = access;
ENTRY(num).access = access;
}
/*
* gdt_install
* Install the kernel's GDTs
*/
void
gdt_install(void) {
/* GDT pointer and limits */
gp.limit = (sizeof(struct gdt_entry) * 6) - 1;
gp.base = (uintptr_t)&gdt;
/* NULL */
gdt_set_gate(0, 0, 0, 0, 0);
/* Code segment */
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
/* Data segment */
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
/* User code */
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);
/* User data */
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
static void write_tss(int32_t num, uint16_t ss0, uint32_t esp0);
void gdt_install(void) {
gdt_pointer_t *gdtp = &gdt.pointer;
gdtp->limit = sizeof gdt.entries - 1;
gdtp->base = (uintptr_t)&ENTRY(0);
gdt_set_gate(0, 0, 0, 0, 0); /* NULL segment */
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Code segment */
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); /* User code */
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); /* User data */
write_tss(5, 0x10, 0x0);
/* Go go go */
gdt_flush((uintptr_t)&gp);
gdt_flush((uintptr_t)gdtp);
tss_flush();
}
/**
* Write a TSS (we only do this once)
*/
static void
write_tss(
int32_t num,
uint16_t ss0,
uint32_t esp0
) {
uintptr_t base = (uintptr_t)&tss_entry;
uintptr_t limit = base + sizeof(tss_entry);
static void write_tss(int32_t num, uint16_t ss0, uint32_t esp0) {
tss_entry_t *tss = &gdt.tss;
uintptr_t base = (uintptr_t)tss;
uintptr_t limit = base + sizeof *tss;
/* Add the TSS descriptor to the GDT */
gdt_set_gate(num, base, limit, 0xE9, 0x00);
memset(&tss_entry, 0x0, sizeof(tss_entry));
memset(tss, 0x0, sizeof *tss);
tss_entry.ss0 = ss0;
tss_entry.esp0 = esp0;
/* Zero out the descriptors */
tss_entry.cs = 0x0b;
tss_entry.ss =
tss_entry.ds =
tss_entry.es =
tss_entry.fs =
tss_entry.gs = 0x13;
tss_entry.iomap_base = sizeof(tss_entry);
tss->ss0 = ss0;
tss->esp0 = esp0;
tss->cs = 0x0b;
tss->ss = 0x13;
tss->ds = 0x13;
tss->es = 0x13;
tss->fs = 0x13;
tss->gs = 0x13;
tss->iomap_base = sizeof *tss;
}
/**
* Set the kernel stack.
*
* @param stack Pointer to a the stack pointer for the kernel.
*/
void
set_kernel_stack(
uintptr_t stack
) {
tss_entry.esp0 = stack;
void set_kernel_stack(uintptr_t stack) {
/* Set the kernel stack */
gdt.tss.esp0 = stack;
}

View File

@ -2,6 +2,7 @@
* This file is part of ToaruOS and is released under the terms
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2011-2014 Kevin Lange
* Copyright (C) 2015 Dale Weiler
*
* Interrupt Requests
*
@ -26,43 +27,41 @@ extern void _irq13(void);
extern void _irq14(void);
extern void _irq15(void);
static irq_handler_chain_t irq_routines[16] = { NULL };
static irq_handler_chain_t irq_routines_a[16] = { NULL };
static irq_handler_chain_t irq_routines_b[16] = { NULL };
static irq_handler_chain_t irq_routines_c[16] = { NULL };
static void (*irqs[])(void) = {
_irq0, _irq1, _irq2, _irq3, _irq4, _irq5, _irq6, _irq7,
_irq8, _irq9, _irq10, _irq11, _irq12, _irq13, _irq14, _irq15
};
#define IRQ_CHAIN_SIZE (sizeof(irqs)/sizeof(*irqs))
#define IRQ_CHAIN_DEPTH 4
#define SYNC_CLI() asm volatile("cli")
#define SYNC_STI() asm volatile("sti")
static irq_handler_chain_t irq_routines[IRQ_CHAIN_SIZE * IRQ_CHAIN_DEPTH] = { NULL };
/*
* Install an interupt handler for a hardware device.
*/
void irq_install_handler(size_t irq, irq_handler_chain_t handler) {
if (irq_routines[irq]) {
if (irq_routines_a[irq]) {
if (irq_routines_b[irq]) {
irq_routines_c[irq] = handler;
return;
}
irq_routines_b[irq] = handler;
return;
}
irq_routines_a[irq] = handler;
return;
/* Disable interrupts when changing handlers */
SYNC_CLI();
for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) {
if (irq_routines[i * IRQ_CHAIN_SIZE + irq])
continue;
irq_routines[i * IRQ_CHAIN_SIZE + irq] = handler;
break;
}
irq_routines[irq] = handler;
SYNC_STI();
}
/*
* Remove an interrupt handler for a hardware device.
*/
void irq_uninstall_handler(size_t irq) {
irq_routines[irq] = NULL;
irq_routines_a[irq] = NULL;
irq_routines_b[irq] = NULL;
irq_routines_c[irq] = NULL;
/* Disable interrupts when changing handlers */
SYNC_CLI();
for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++)
irq_routines[i * IRQ_CHAIN_SIZE + irq] = NULL;
SYNC_STI();
}
/*
* Remap interrupt handlers
*/
void irq_remap(void) {
outportb(0x20, 0x11);
outportb(0xA0, 0x11);
@ -76,34 +75,17 @@ void irq_remap(void) {
outportb(0xA1, 0x0);
}
void irq_gates(void) {
idt_set_gate(32, _irq0, 0x08, 0x8E);
idt_set_gate(33, _irq1, 0x08, 0x8E);
idt_set_gate(34, _irq2, 0x08, 0x8E);
idt_set_gate(35, _irq3, 0x08, 0x8E);
idt_set_gate(36, _irq4, 0x08, 0x8E);
idt_set_gate(37, _irq5, 0x08, 0x8E);
idt_set_gate(38, _irq6, 0x08, 0x8E);
idt_set_gate(39, _irq7, 0x08, 0x8E);
idt_set_gate(40, _irq8, 0x08, 0x8E);
idt_set_gate(41, _irq9, 0x08, 0x8E);
idt_set_gate(42, _irq10, 0x08, 0x8E);
idt_set_gate(43, _irq11, 0x08, 0x8E);
idt_set_gate(44, _irq12, 0x08, 0x8E);
idt_set_gate(45, _irq13, 0x08, 0x8E);
idt_set_gate(46, _irq14, 0x08, 0x8E);
idt_set_gate(47, _irq15, 0x08, 0x8E);
static void irq_setup_gates(void) {
for (size_t i = 0; i < IRQ_CHAIN_SIZE; i++)
idt_set_gate(32 + i, irqs[i], 0x08, 0x8E);
}
/*
* Set up interrupt handler for hardware devices.
*/
void irq_install(void) {
irq_remap();
irq_gates();
IRQ_RES;
irq_setup_gates();
}
/* TODO: Clean up everything below */
void irq_ack(size_t irq_no) {
if (irq_no >= 8) {
outportb(0xA0, 0x20);
@ -117,10 +99,12 @@ void irq_handler(struct regs *r) {
IRQ_RES;
return;
}
if (irq_routines [r->int_no - 32] && irq_routines [r->int_no - 32](r)) goto _done;
if (irq_routines_a[r->int_no - 32] && irq_routines_a[r->int_no - 32](r)) goto _done;
if (irq_routines_b[r->int_no - 32] && irq_routines_b[r->int_no - 32](r)) goto _done;
if (irq_routines_c[r->int_no - 32] && irq_routines_c[r->int_no - 32](r)) goto _done;
for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) {
irq_handler_chain_t handler = irq_routines[i * IRQ_CHAIN_SIZE + (r->int_no - 32)];
if (handler && handler(r)) {
goto _done;
}
}
irq_ack(r->int_no - 32);
_done:
IRQ_RES;

View File

@ -78,12 +78,12 @@ extern uint8_t startswith(const char * str, const char * accept);
/* GDT */
extern void gdt_install(void);
extern void gdt_set_gate(size_t num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran);
extern void gdt_set_gate(uint8_t num, uint64_t base, uint64_t limit, uint8_t access, uint8_t gran);
extern void set_kernel_stack(uintptr_t stack);
/* IDT */
extern void idt_install(void);
extern void idt_set_gate(unsigned char num, void (*base)(void), unsigned short sel, unsigned char flags);
extern void idt_set_gate(uint8_t num, void (*base)(void), uint16_t sel, uint8_t flags);
/* Registers
*

View File

@ -86,7 +86,7 @@ int exec_elf(char * path, fs_node_t * file, int argc, char ** argv, char ** env)
/* Collect arguments */
int envc = 0;
for (envc = 0; env[envc] != NULL; ++envc);
/* Format auxv */
Elf32_auxv auxv[] = {
{256, 0xDEADBEEF},