188 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <kernel/gdt.h>
 | 
						|
#include <kernel/tty.h>
 | 
						|
#include <debugging.h>
 | 
						|
#include "interrupt.h"
 | 
						|
#include <stdint.h>
 | 
						|
#include <stddef.h>
 | 
						|
#include "../io.h"
 | 
						|
 | 
						|
#define IRQ0 0x20
 | 
						|
#define IRQ1 (IRQ0 + 1)
 | 
						|
#define IRQ2 (IRQ0 + 2)
 | 
						|
#define IRQ3 (IRQ0 + 3)
 | 
						|
#define IRQ4 (IRQ0 + 4)
 | 
						|
#define IRQ5 (IRQ0 + 5)
 | 
						|
#define IRQ6 (IRQ0 + 6)
 | 
						|
#define IRQ7 (IRQ0 + 7)
 | 
						|
 | 
						|
#define IRQ8 0x28
 | 
						|
#define IRQ9  (IRQ8 + 1)
 | 
						|
#define IRQ10 (IRQ8 + 2)
 | 
						|
#define IRQ11 (IRQ8 + 3)
 | 
						|
#define IRQ12 (IRQ8 + 4)
 | 
						|
#define IRQ13 (IRQ8 + 5)
 | 
						|
#define IRQ14 (IRQ8 + 6)
 | 
						|
#define IRQ15 (IRQ8 + 7)
 | 
						|
 | 
						|
#define NUM_ENTRIES 0x100
 | 
						|
 | 
						|
struct InterruptDescriptor {
 | 
						|
    uint32_t offset;
 | 
						|
    uint32_t selector;
 | 
						|
    uint8_t gate_type;
 | 
						|
    uint8_t ring;
 | 
						|
    bool present;
 | 
						|
};
 | 
						|
 | 
						|
struct IDT {
 | 
						|
    uint16_t size;
 | 
						|
    uint64_t* base;
 | 
						|
} __attribute__((packed));
 | 
						|
 | 
						|
static uint64_t entries[NUM_ENTRIES];
 | 
						|
struct IDT idt;
 | 
						|
 | 
						|
enum EntryTypes {
 | 
						|
    DivisionByZero = 0x00,
 | 
						|
    _Reserved0     = 0x01,
 | 
						|
    NMIInterrupt   = 0x02,
 | 
						|
    Breakpoint     = 0x03,
 | 
						|
    Overflow       = 0x04,
 | 
						|
    BoundsExceeded = 0x05,
 | 
						|
    InvalidOpcode  = 0x06,
 | 
						|
    DeviceNotAvail = 0x07,
 | 
						|
    DoubleFault    = 0x08,
 | 
						|
    CoprocSegORun  = 0x09,
 | 
						|
    InvalidTSS     = 0x0A,
 | 
						|
    SegNotPresent  = 0x0B,
 | 
						|
    StackSegFault  = 0x0C,
 | 
						|
    GenerProtFault = 0x0D,
 | 
						|
    PageFault      = 0x0E,
 | 
						|
    _Reserved1     = 0x0F,
 | 
						|
    x87FPUError    = 0x10,
 | 
						|
    AlignmentCheck = 0x11,
 | 
						|
    MachineCheck   = 0x12,
 | 
						|
    SIMDFloatExcep = 0x13,
 | 
						|
};
 | 
						|
 | 
						|
static void encodeIdtEntry(uint8_t *target, struct InterruptDescriptor source)
 | 
						|
{
 | 
						|
    // Encode the present bit
 | 
						|
    if (source.present) {
 | 
						|
        target[5] |= 0x80;
 | 
						|
    } else {
 | 
						|
        // Not present, return
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Encode the offset 
 | 
						|
    target[0] = (source.offset >> 0x00) & 0xFF;
 | 
						|
    target[1] = (source.offset >> 0x08) & 0xFF;
 | 
						|
    target[6] = (source.offset >> 0x10) & 0xFF;
 | 
						|
    target[7] = (source.offset >> 0x18) & 0xFF;
 | 
						|
    
 | 
						|
    // Encode the base
 | 
						|
    target[2] = (source.selector >> 0x00) & 0xFF;
 | 
						|
    target[3] = (source.selector >> 0x08) & 0xFF;
 | 
						|
    
 | 
						|
    // Encode the gate type
 | 
						|
    target[5] |= source.gate_type;
 | 
						|
    
 | 
						|
    // Encode the DPL
 | 
						|
    target[5] |= (source.ring << 5);
 | 
						|
}
 | 
						|
 | 
						|
static void add_entry(struct InterruptDescriptor entry, uint8_t index)
 | 
						|
{
 | 
						|
    uint64_t descriptor = 0;
 | 
						|
    encodeIdtEntry((uint8_t*) &descriptor, entry);
 | 
						|
 | 
						|
    entries[index] = descriptor;
 | 
						|
}
 | 
						|
 | 
						|
static void load_idt() 
 | 
						|
{
 | 
						|
    idt.size = NUM_ENTRIES * 8 - 1;
 | 
						|
    idt.base = entries;
 | 
						|
 | 
						|
    asm ( "lidt %0" : : "m"(idt) );
 | 
						|
}
 | 
						|
 | 
						|
static struct InterruptDescriptor generate_entry(bool present, void isr(struct interrupt_frame*), uint8_t gate_type, uint8_t ring, uint8_t selector)
 | 
						|
{
 | 
						|
    struct InterruptDescriptor entry;
 | 
						|
    entry.present = present;
 | 
						|
    entry.offset = (size_t)isr;
 | 
						|
    entry.gate_type = gate_type;
 | 
						|
    entry.ring = ring;
 | 
						|
    entry.selector = selector;
 | 
						|
    return entry;
 | 
						|
}
 | 
						|
 | 
						|
static void add_exceptions() 
 | 
						|
{
 | 
						|
    struct InterruptDescriptor entry;
 | 
						|
 | 
						|
    entry = generate_entry(true, exception, 0xF, 0, 0x8);
 | 
						|
    for (int i = 0; i < 0x20; i++)
 | 
						|
    {
 | 
						|
        add_entry(entry, i);
 | 
						|
    }
 | 
						|
 | 
						|
    entry = generate_entry(true, divide_by_zero, 0xF, 0, 0x8);
 | 
						|
    add_entry(entry, DivisionByZero);
 | 
						|
 | 
						|
    entry = generate_entry(true, page_fault, 0xF, 0, 0x8);
 | 
						|
    add_entry(entry, PageFault);
 | 
						|
 | 
						|
    entry = generate_entry(true, general_protection_fault, 0xF, 0, 0x8);
 | 
						|
    add_entry(entry, GenerProtFault);
 | 
						|
 | 
						|
    entry = generate_entry(true, double_fault, 0xF, 0, 0x8);
 | 
						|
    add_entry(entry, DoubleFault);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
static void add_irqs()
 | 
						|
{
 | 
						|
    struct InterruptDescriptor entry;
 | 
						|
    entry = generate_entry(true, irq_1, 0xE, 0, 0x8);
 | 
						|
    for (int i = IRQ0; i <= IRQ7; i++)
 | 
						|
    {
 | 
						|
        add_entry(entry, i);
 | 
						|
    }
 | 
						|
 | 
						|
    entry = generate_entry(true, irq_2, 0xE, 0, 0x8);
 | 
						|
    for (int i = IRQ8; i <= IRQ15; i++)
 | 
						|
    {
 | 
						|
        add_entry(entry, i);
 | 
						|
    }
 | 
						|
 | 
						|
    entry = generate_entry(true, irq0, 0xE, 0x3, 0x8);
 | 
						|
    add_entry(entry, IRQ0);
 | 
						|
 | 
						|
    entry = generate_entry(true, keyboard_interrupt, 0xE, 0, 0x8);
 | 
						|
    add_entry(entry, IRQ1);
 | 
						|
}
 | 
						|
 | 
						|
static void add_syscall()
 | 
						|
{
 | 
						|
    struct InterruptDescriptor syscall_entry;
 | 
						|
    syscall_entry.present = true;
 | 
						|
    syscall_entry.offset = (size_t)syscall;
 | 
						|
    syscall_entry.gate_type = 0xE;
 | 
						|
    syscall_entry.ring = 3;
 | 
						|
    syscall_entry.selector = 0x8;
 | 
						|
 | 
						|
    add_entry(syscall_entry, 0x80);
 | 
						|
}
 | 
						|
 | 
						|
void idt_init()
 | 
						|
{
 | 
						|
    add_exceptions();
 | 
						|
    add_irqs();
 | 
						|
    add_syscall();
 | 
						|
 | 
						|
    load_idt();
 | 
						|
}
 |