Some IRQ cleanup
This commit is contained in:
parent
82d706f453
commit
5ddbbf8199
165
kernel/cpu/gdt.c
165
kernel/cpu/gdt.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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},
|
||||
|
Loading…
Reference in New Issue
Block a user