diff options
author | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
---|---|---|
committer | Anton Kling <anton@kling.gg> | 2023-10-22 19:50:38 +0200 |
commit | 4e09bca9e34c226b6d7e34b4fa11248405fd988e (patch) | |
tree | 80f156b7940d9d19971395f335530170c69516c7 /cpu/idt.c |
Move everything into a new repo.
Diffstat (limited to 'cpu/idt.c')
-rw-r--r-- | cpu/idt.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/cpu/idt.c b/cpu/idt.c new file mode 100644 index 0000000..832162c --- /dev/null +++ b/cpu/idt.c @@ -0,0 +1,265 @@ +#include <cpu/idt.h> +#include <sched/scheduler.h> +#include <stdio.h> + +#define MASTER_PIC_COMMAND_PORT 0x20 +#define MASTER_PIC_DATA_PORT 0x21 +#define SLAVE_PIC_COMMAND_PORT 0xA0 +#define SLAVE_PIC_DATA_PORT 0xA1 +#define KEYBOARD_DATA_PORT 0x60 +#define KEYBOARD_STATUS_PORT 0x64 +#define KERNEL_CODE_SEGMENT_OFFSET GDT_ENTRY_SIZE *GDT_KERNEL_CODE_SEGMENT + +#define IDT_MAX_ENTRY 256 + +struct IDT_Descriptor { + uint16_t low_offset; + uint16_t code_segment_selector; + uint8_t zero; // Always should be zero + uint8_t type_attribute; + uint16_t high_offset; +} __attribute__((packed)) __attribute__((aligned(4))); + +struct IDT_Pointer { + uint16_t size; + struct IDT_Descriptor **interrupt_table; +} __attribute__((packed)); + +struct IDT_Descriptor IDT_Entry[IDT_MAX_ENTRY]; +struct IDT_Pointer idtr; + +extern void load_idtr(void *idtr); + +void format_descriptor(uint32_t offset, uint16_t code_segment, + uint8_t type_attribute, + struct IDT_Descriptor *descriptor) { + descriptor->low_offset = offset & 0xFFFF; + descriptor->high_offset = offset >> 16; + descriptor->type_attribute = type_attribute; + descriptor->code_segment_selector = code_segment; + descriptor->zero = 0; +} + +void install_handler(void (*handler_function)(), uint16_t type_attribute, + uint8_t entry) { + format_descriptor((uint32_t)handler_function, KERNEL_CODE_SEGMENT_OFFSET, + type_attribute, &IDT_Entry[entry]); +} + +__attribute__((no_caller_saved_registers)) void EOI(uint8_t irq) { + if (irq > 7) + outb(SLAVE_PIC_COMMAND_PORT, 0x20); + + outb(MASTER_PIC_COMMAND_PORT, 0x20); +} + +__attribute__((interrupt)) void +kernel_general_protection_fault(kernel_registers_t *regs) { + asm("cli"); + klog("General Protetion Fault", 0x1); + kprintf(" Error Code: %x\n", regs->error_code); + kprintf("Instruction Pointer: %x\n", regs->eip); + dump_backtrace(12); + for (;;) + ; + EOI(0xD - 8); +} + +__attribute__((interrupt)) void general_protection_fault(registers_t *regs) { + kprintf("\n"); + klog("KERNEL General Protetion Fault", 0x1); + kprintf(" Error Code: %x\n", regs->error_code); +#define EXTERNAL_TO_PROCESSOR (1 << 0) + +#define WAS(_b) if (regs->error_code & (_b)) + if (0 == regs->error_code) { + kprintf("This exception is not segment related."); + } else { + WAS(EXTERNAL_TO_PROCESSOR) { + kprintf("Exception originated externally to the processor."); + } + kprintf("Index references: "); + switch ((regs->error_code >> 1) & 0x3) { + case 0: + kprintf("GDT"); + break; + case 3: + case 1: + kprintf("IDT"); + break; + case 2: + kprintf("LDT"); + break; + } + kprintf("\n"); + kprintf("Segmenet index: %x\n", regs->error_code >> 15); + } + /* kprintf(" Page protection violation: %x\n", regs->error_code & 0x1); + kprintf(" Write access: %x\n", (regs->error_code & (0x1<<1)) >> 1); + kprintf(" No privilege violation: %x\n", (regs->error_code & (0x1<<2)) + >> 2); kprintf(" Instruction fetch: %x\n", (regs->error_code & (0x1<<4)) >> + 4); kprintf(" Shadow stack access: %x\n", (regs->error_code & (0x1<<6)) >> + 6);*/ + kprintf("Instruction Pointer: %x\n", regs->eip); + asm("hlt"); + EOI(0xD - 8); +} + +__attribute__((interrupt)) void double_fault(registers_t *regs) { + (void)regs; + klog("DOUBLE FAULT, THIS IS REALLY BAD", LOG_ERROR); + asm("hlt"); + for (;;) + ; +} +__attribute__((interrupt)) void page_fault(registers_t *regs) { + asm("cli"); + klog("Page Fault", LOG_ERROR); + if (get_current_task()) { + kprintf(" PID: %x\n", get_current_task()->pid); + kprintf(" Name: %s\n", get_current_task()->program_name); + } + kprintf(" Error Code: %x\n", regs->error_code); + kprintf(" Interrupt Number: %x\n", regs->interrupt_number); + kprintf(" Instruction Pointer: %x\n", regs->eip); + dump_backtrace(14); + asm("hlt"); + for (;;) + ; +} + +/* +__attribute__((interrupt)) void page_fault(registers_t *regs) { + asm("cli"); + klog("Page Fault", LOG_ERROR); + if (get_current_task()) { + kprintf(" PID: %x\n", get_current_task()->pid); + kprintf(" Name: %s\n", get_current_task()->program_name); + } + kprintf(" Error Code: %x\n", regs->error_code); + kprintf(" Interrupt Number: %x\n", regs->interrupt_number); +#define PAGE_PRESENT (1 << 0) +#define WRITE_ATTEMPT (1 << 1) +#define USER_LEVEL (1 << 2) +#define RESERVED_WRITE (1 << 3) +#define INSTRUCTION_FETCH (1 << 4) +#define PROTECTION_KEY_VIOLATION (1 << 5) +#define SHADOW_STACK_ACCESS (1 << 6) + +#define WAS(_b) if (regs->error_code & (_b)) + + WAS(PAGE_PRESENT) { kprintf(" Page was present.\n"); } + else { + kprintf(" Page is not present.\n"); + } + + WAS(WRITE_ATTEMPT) { kprintf(" Write attempt.\n"); } + else { + kprintf(" Read attempt.\n"); + } + + WAS(USER_LEVEL) { + get_current_task()->dead = 1; + kprintf(" Page fault in ring 3.\n"); + } + else { + kprintf(" Page fault in ring 0-2.\n"); + } + + WAS(INSTRUCTION_FETCH) { kprintf(" Attempted instruction fetch.\n"); } + + WAS(SHADOW_STACK_ACCESS) { kprintf(" Attempted shadow stack access.\n"); } + + kprintf(" Instruction Pointer: %x\n", regs->eip); + dump_backtrace(12); + asm("hlt"); + for (;;) + ; + EOI(0xE - 8); +}*/ + +static inline void io_wait(void) { outb(0x80, 0); } + +#define ICW1_ICW4 0x01 /* ICW4 (not) needed */ +#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ +#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ +#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ +#define ICW1_INIT 0x10 /* Initialization - required! */ + +#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ +#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ +#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ +#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ +#define ICW4_SFNM 0x10 /* Special fully nested (not) */ + +void PIC_remap(int offset) { + unsigned char a1, a2; + a1 = inb(MASTER_PIC_DATA_PORT); + a2 = inb(SLAVE_PIC_DATA_PORT); + + // Send ICW1 and tell the PIC that we will issue a ICW4 + // Since there is no ICW1_SINGLE sent to indicate it is cascaded + // it means we will issue a ICW3. + outb(MASTER_PIC_COMMAND_PORT, ICW1_INIT | ICW1_ICW4); + io_wait(); + outb(SLAVE_PIC_COMMAND_PORT, ICW1_INIT | ICW1_ICW4); + io_wait(); + + // As a part of ICW2 this sends the offsets(the position to put IRQ0) of the + // vector tables. + outb(MASTER_PIC_DATA_PORT, offset); + io_wait(); + outb(SLAVE_PIC_DATA_PORT, offset + 0x8); + io_wait(); + + // This tells the master on which lines it is having slaves + outb(MASTER_PIC_DATA_PORT, 4); + io_wait(); + // This tells the slave the cascading identity. + outb(SLAVE_PIC_DATA_PORT, 2); + io_wait(); + + outb(MASTER_PIC_DATA_PORT, ICW4_8086); + io_wait(); + outb(SLAVE_PIC_DATA_PORT, ICW4_8086); + io_wait(); + + outb(MASTER_PIC_DATA_PORT, a1); + outb(SLAVE_PIC_DATA_PORT, a2); +} + +void IRQ_set_mask(unsigned char IRQline) { + uint16_t port; + uint8_t value; + port = (IRQline < 8) ? MASTER_PIC_DATA_PORT : SLAVE_PIC_DATA_PORT; + if (IRQline >= 8) + IRQline -= 8; + value = inb(port) | (1 << IRQline); + outb(port, value); +} + +void IRQ_clear_mask(unsigned char IRQline) { + uint16_t port; + uint8_t value; + port = (IRQline < 8) ? MASTER_PIC_DATA_PORT : SLAVE_PIC_DATA_PORT; + if (IRQline >= 8) { + IRQline -= 8; + } + value = inb(port) & ~(1 << IRQline); + outb(port, value); +} + +void idt_init(void) { + install_handler(page_fault, INT_32_TRAP_GATE(0x3), 0xE); + install_handler(double_fault, INT_32_TRAP_GATE(0x0), 0x8); + install_handler(kernel_general_protection_fault, INT_32_TRAP_GATE(0x0), 0xD); + + PIC_remap(0x20); + // IRQ_set_mask(0xc); + IRQ_set_mask(0xe); + IRQ_clear_mask(2); + + idtr.interrupt_table = (struct IDT_Descriptor **)&IDT_Entry; + idtr.size = (sizeof(struct IDT_Descriptor) * IDT_MAX_ENTRY) - 1; + load_idtr(&idtr); +} |