mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
258 lines
8 KiB
C
258 lines
8 KiB
C
// Copyright (c) 2023-2026 Chris (boreddevnl)
|
|
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
|
|
// This header needs to maintain in any file it is present in, as per the GPL license terms.
|
|
#include "idt.h"
|
|
#include "io.h"
|
|
#include "kutils.h"
|
|
|
|
extern void serial_write(const char *str);
|
|
|
|
#include "process.h"
|
|
#include "cmd.h"
|
|
|
|
|
|
void kernel_panic(registers_t *regs, const char *error_name);
|
|
|
|
static const char *exception_messages[] = {
|
|
"Division By Zero",
|
|
"Debug",
|
|
"Non-Maskable Interrupt",
|
|
"Breakpoint",
|
|
"Into Detected Overflow",
|
|
"Out of Bounds",
|
|
"Invalid Opcode",
|
|
"No Coprocessor",
|
|
"Double Fault",
|
|
"Coprocessor Segment Overrun",
|
|
"Bad TSS",
|
|
"Segment Not Present",
|
|
"Stack Fault",
|
|
"General Protection Fault",
|
|
"Page Fault",
|
|
"Unknown Interrupt",
|
|
"Coprocessor Fault",
|
|
"Alignment Check",
|
|
"Machine Check",
|
|
"SIMD Floating-Point Exception",
|
|
"Virtualization Exception",
|
|
"Control Protection Exception",
|
|
"Reserved",
|
|
"Reserved",
|
|
"Reserved",
|
|
"Reserved",
|
|
"Reserved",
|
|
"Reserved",
|
|
"Hypervisor Injection Exception",
|
|
"VMM Communication Exception",
|
|
"Security Exception",
|
|
"Reserved"
|
|
};
|
|
|
|
uint64_t exception_handler_c(registers_t *regs) {
|
|
uint64_t vector = regs->int_no;
|
|
char buf[17];
|
|
|
|
// Serial Mirror
|
|
serial_write("\n*** EXCEPTION ***\nVector: ");
|
|
k_itoa_hex(vector, buf);
|
|
serial_write("0x");
|
|
serial_write(buf);
|
|
|
|
if ((regs->cs & 0x3) != 0) {
|
|
serial_write("\n*** USER MODE EXCEPTION ***\nVector: 0x");
|
|
k_itoa_hex(vector, buf);
|
|
serial_write(buf);
|
|
serial_write("\nRIP: 0x");
|
|
k_itoa_hex(regs->rip, buf);
|
|
serial_write(buf);
|
|
serial_write("\nError Code: 0x");
|
|
k_itoa_hex(regs->err_code, buf);
|
|
serial_write(buf);
|
|
serial_write("\nTerminating process.\n");
|
|
|
|
if (cmd_get_cursor_col() != 0) cmd_write("\n");
|
|
cmd_write("*** USER EXCEPTION ***\nVector: "); cmd_write_hex(vector);
|
|
cmd_write("\nRIP: "); cmd_write_hex(regs->rip);
|
|
cmd_write("\nTerminating process.\n");
|
|
return process_terminate_current();
|
|
}
|
|
|
|
// Kernel mode exception
|
|
const char *name = (vector < 32) ? exception_messages[vector] : "Unknown Kernel Exception";
|
|
kernel_panic(regs, name);
|
|
|
|
return (uint64_t)regs; // Unreachable
|
|
}
|
|
|
|
#define IDT_ENTRIES 256
|
|
|
|
struct idt_entry {
|
|
uint16_t isr_low;
|
|
uint16_t kernel_cs;
|
|
uint8_t ist;
|
|
uint8_t attributes;
|
|
uint16_t isr_mid;
|
|
uint32_t isr_high;
|
|
uint32_t reserved;
|
|
} __attribute__((packed));
|
|
|
|
struct idt_ptr {
|
|
uint16_t limit;
|
|
uint64_t base;
|
|
} __attribute__((packed));
|
|
|
|
static struct idt_entry idt[IDT_ENTRIES];
|
|
static struct idt_ptr idtr;
|
|
|
|
void idt_set_gate(uint8_t vector, void *isr, uint16_t cs, uint8_t flags) {
|
|
uint64_t addr = (uint64_t)isr;
|
|
idt[vector].isr_low = addr & 0xFFFF;
|
|
idt[vector].kernel_cs = cs;
|
|
idt[vector].ist = 0;
|
|
idt[vector].attributes = flags;
|
|
idt[vector].isr_mid = (addr >> 16) & 0xFFFF;
|
|
idt[vector].isr_high = (addr >> 32) & 0xFFFFFFFF;
|
|
idt[vector].reserved = 0;
|
|
}
|
|
|
|
// Remap PIC
|
|
static void pic_remap(void) {
|
|
uint8_t a1, a2;
|
|
a1 = inb(0x21);
|
|
a2 = inb(0xA1);
|
|
|
|
outb(0x20, 0x11); io_wait();
|
|
outb(0xA0, 0x11); io_wait();
|
|
outb(0x21, 0x20); io_wait(); // Master offset 0x20 (32)
|
|
outb(0xA1, 0x28); io_wait(); // Slave offset 0x28 (40)
|
|
outb(0x21, 0x04); io_wait();
|
|
outb(0xA1, 0x02); io_wait();
|
|
outb(0x21, 0x01); io_wait();
|
|
outb(0xA1, 0x01); io_wait();
|
|
|
|
// 0xEF = 1110 1111 (IRQ 12 (4 on slave) unmasked)
|
|
|
|
outb(0x21, 0xF9); // Unmask Keyboard (IRQ1) and Cascade (IRQ2)
|
|
outb(0xA1, 0xEF); // Unmask Mouse (IRQ12)
|
|
}
|
|
|
|
// Set up PIT (Programmable Interval Timer) for ~60Hz (16.67ms intervals)
|
|
static void pit_setup(void) {
|
|
uint16_t divisor = 1193182 / 60; // ~60Hz
|
|
|
|
// Send command byte
|
|
outb(0x43, 0x36); // Channel 0, lobyte/hibyte, mode 3 (square wave), binary
|
|
|
|
// Send divisor
|
|
outb(0x40, divisor & 0xFF);
|
|
outb(0x40, (divisor >> 8) & 0xFF);
|
|
}
|
|
|
|
void idt_init(void) {
|
|
uint16_t cs;
|
|
asm volatile ("mov %%cs, %0" : "=r"(cs));
|
|
|
|
for (int i = 0; i < IDT_ENTRIES; i++) {
|
|
idt[i] = (struct idt_entry){0};
|
|
}
|
|
|
|
pic_remap();
|
|
|
|
// Unmask IRQ 0 (Timer) in addition to IRQ 1 and 12
|
|
outb(0x21, 0xF8); // Unmask Timer (IRQ0), Keyboard (IRQ1) and Cascade (IRQ2)
|
|
outb(0xA1, 0xEF); // Unmask Mouse (IRQ12)
|
|
|
|
pit_setup();
|
|
}
|
|
|
|
void idt_register_interrupts(void) {
|
|
uint16_t cs;
|
|
asm volatile ("mov %%cs, %0" : "=r"(cs));
|
|
|
|
idt_set_gate(32, isr0_wrapper, cs, 0x8E); // Timer (IRQ 0)
|
|
idt_set_gate(33, isr1_wrapper, cs, 0x8E); // Keyboard (IRQ 1)
|
|
idt_set_gate(44, isr12_wrapper, cs, 0x8E); // Mouse (IRQ 12)
|
|
|
|
// Exceptions
|
|
extern void exc0_wrapper(void);
|
|
extern void exc1_wrapper(void);
|
|
extern void exc2_wrapper(void);
|
|
extern void exc3_wrapper(void);
|
|
extern void exc4_wrapper(void);
|
|
extern void exc5_wrapper(void);
|
|
extern void exc6_wrapper(void);
|
|
extern void exc7_wrapper(void);
|
|
extern void exc8_wrapper(void);
|
|
extern void exc9_wrapper(void);
|
|
extern void exc10_wrapper(void);
|
|
extern void exc11_wrapper(void);
|
|
extern void exc12_wrapper(void);
|
|
extern void exc13_wrapper(void);
|
|
extern void exc14_wrapper(void);
|
|
extern void exc15_wrapper(void);
|
|
extern void exc16_wrapper(void);
|
|
extern void exc17_wrapper(void);
|
|
extern void exc18_wrapper(void);
|
|
extern void exc19_wrapper(void);
|
|
extern void exc20_wrapper(void);
|
|
extern void exc21_wrapper(void);
|
|
extern void exc22_wrapper(void);
|
|
extern void exc23_wrapper(void);
|
|
extern void exc24_wrapper(void);
|
|
extern void exc25_wrapper(void);
|
|
extern void exc26_wrapper(void);
|
|
extern void exc27_wrapper(void);
|
|
extern void exc28_wrapper(void);
|
|
extern void exc29_wrapper(void);
|
|
extern void exc30_wrapper(void);
|
|
extern void exc31_wrapper(void);
|
|
|
|
idt_set_gate(0, exc0_wrapper, cs, 0x8E);
|
|
idt_set_gate(1, exc1_wrapper, cs, 0x8E);
|
|
idt_set_gate(2, exc2_wrapper, cs, 0x8E);
|
|
idt_set_gate(3, exc3_wrapper, cs, 0x8E);
|
|
idt_set_gate(4, exc4_wrapper, cs, 0x8E);
|
|
idt_set_gate(5, exc5_wrapper, cs, 0x8E);
|
|
idt_set_gate(6, exc6_wrapper, cs, 0x8E);
|
|
idt_set_gate(7, exc7_wrapper, cs, 0x8E);
|
|
idt_set_gate(8, exc8_wrapper, cs, 0x8E);
|
|
idt_set_gate(9, exc9_wrapper, cs, 0x8E);
|
|
idt_set_gate(10, exc10_wrapper, cs, 0x8E);
|
|
idt_set_gate(11, exc11_wrapper, cs, 0x8E);
|
|
idt_set_gate(12, exc12_wrapper, cs, 0x8E);
|
|
idt_set_gate(13, exc13_wrapper, cs, 0x8E);
|
|
idt_set_gate(14, exc14_wrapper, cs, 0x8E);
|
|
idt_set_gate(15, exc15_wrapper, cs, 0x8E);
|
|
idt_set_gate(16, exc16_wrapper, cs, 0x8E);
|
|
idt_set_gate(17, exc17_wrapper, cs, 0x8E);
|
|
idt_set_gate(18, exc18_wrapper, cs, 0x8E);
|
|
idt_set_gate(19, exc19_wrapper, cs, 0x8E);
|
|
idt_set_gate(20, exc20_wrapper, cs, 0x8E);
|
|
idt_set_gate(21, exc21_wrapper, cs, 0x8E);
|
|
idt_set_gate(22, exc22_wrapper, cs, 0x8E);
|
|
idt_set_gate(23, exc23_wrapper, cs, 0x8E);
|
|
idt_set_gate(24, exc24_wrapper, cs, 0x8E);
|
|
idt_set_gate(25, exc25_wrapper, cs, 0x8E);
|
|
idt_set_gate(26, exc26_wrapper, cs, 0x8E);
|
|
idt_set_gate(27, exc27_wrapper, cs, 0x8E);
|
|
idt_set_gate(28, exc28_wrapper, cs, 0x8E);
|
|
idt_set_gate(29, exc29_wrapper, cs, 0x8E);
|
|
idt_set_gate(30, exc30_wrapper, cs, 0x8E);
|
|
idt_set_gate(31, exc31_wrapper, cs, 0x8E);
|
|
|
|
// SMP: Scheduling IPI for AP cores (vector 0x41 = 65)
|
|
extern void isr_sched_ipi_wrapper(void);
|
|
idt_set_gate(0x41, isr_sched_ipi_wrapper, cs, 0x8E);
|
|
|
|
// Syscall Handler (vector 128) - DPL 3 for user access
|
|
extern void isr128_wrapper(void);
|
|
idt_set_gate(128, isr128_wrapper, cs, 0xEE);
|
|
}
|
|
|
|
void idt_load(void) {
|
|
idtr.base = (uint64_t)&idt;
|
|
idtr.limit = sizeof(struct idt_entry) * IDT_ENTRIES - 1;
|
|
asm volatile ("lidt %0" : : "m"(idtr));
|
|
// Do not sti here! The OS must decide when to enable interrupts
|
|
// after all subsystems (WM, PS/2) are initialized!
|
|
}
|