202 lines
4.6 KiB
C
202 lines
4.6 KiB
C
/*
|
|
* AsterOS Kernel
|
|
* Autor: Pavel Kalaš
|
|
* Rok: 2026
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Tento architekturalni modul inicializuje GDT, IDT a remapuje PIC.
|
|
* Obsahuje centralni vstup pro obsluhu vyjimek, hardwarovych preruseni
|
|
* i syscall vektoru, vcetne predani rizeni scheduleru pri timer IRQ.
|
|
*/
|
|
|
|
#include "cpu.h"
|
|
#include "panic.h"
|
|
#include "printk.h"
|
|
#include "scheduler.h"
|
|
#include "syscall.h"
|
|
#include "timer.h"
|
|
#include "types.h"
|
|
|
|
extern void arch_load_gdt(void *ptr);
|
|
extern void arch_reload_segments(void);
|
|
extern void arch_load_idt(void *ptr);
|
|
extern void *isr_stub_table[];
|
|
|
|
#define IDT_ENTRIES 256
|
|
|
|
static inline void outb(u16 port, u8 value) {
|
|
__asm__ volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
|
|
}
|
|
|
|
static inline void io_wait(void) {
|
|
__asm__ volatile ("outb %%al, $0x80" : : "a"(0));
|
|
}
|
|
|
|
struct __attribute__((packed)) gdt_ptr {
|
|
u16 limit;
|
|
u64 base;
|
|
};
|
|
|
|
struct __attribute__((packed)) idt_entry {
|
|
u16 offset_low;
|
|
u16 selector;
|
|
u8 ist;
|
|
u8 type_attr;
|
|
u16 offset_mid;
|
|
u32 offset_high;
|
|
u32 zero;
|
|
};
|
|
|
|
struct __attribute__((packed)) idt_ptr {
|
|
u16 limit;
|
|
u64 base;
|
|
};
|
|
|
|
static u64 gdt_table[3];
|
|
static struct idt_entry idt[IDT_ENTRIES];
|
|
|
|
static void set_idt_gate(u8 vec, void *isr, u8 flags) {
|
|
u64 addr = (u64)isr;
|
|
idt[vec].offset_low = (u16)(addr & 0xFFFF);
|
|
idt[vec].selector = 0x08;
|
|
idt[vec].ist = 0;
|
|
idt[vec].type_attr = flags;
|
|
idt[vec].offset_mid = (u16)((addr >> 16) & 0xFFFF);
|
|
idt[vec].offset_high = (u32)((addr >> 32) & 0xFFFFFFFF);
|
|
idt[vec].zero = 0;
|
|
}
|
|
|
|
static void pic_remap(void) {
|
|
outb(0x20, 0x11);
|
|
io_wait();
|
|
outb(0xA0, 0x11);
|
|
io_wait();
|
|
|
|
outb(0x21, 0x20);
|
|
io_wait();
|
|
outb(0xA1, 0x28);
|
|
io_wait();
|
|
|
|
outb(0x21, 0x04);
|
|
io_wait();
|
|
outb(0xA1, 0x02);
|
|
io_wait();
|
|
|
|
outb(0x21, 0x01);
|
|
io_wait();
|
|
outb(0xA1, 0x01);
|
|
io_wait();
|
|
|
|
/* Unmask IRQ0(timer), IRQ1(keyboard), IRQ2(cascade); keep the rest masked. */
|
|
outb(0x21, 0xF8);
|
|
outb(0xA1, 0xFF);
|
|
}
|
|
|
|
static inline u64 read_cr2(void) {
|
|
u64 value;
|
|
__asm__ volatile ("mov %%cr2, %0" : "=r"(value));
|
|
return value;
|
|
}
|
|
|
|
static void pic_send_eoi(u64 vector) {
|
|
if (vector >= 40) {
|
|
outb(0xA0, 0x20);
|
|
}
|
|
outb(0x20, 0x20);
|
|
}
|
|
|
|
static const char *exception_name(u64 vector) {
|
|
switch (vector) {
|
|
case 8:
|
|
return "Double Fault";
|
|
case 13:
|
|
return "General Protection Fault";
|
|
case 14:
|
|
return "Page Fault";
|
|
default:
|
|
return "CPU Exception";
|
|
}
|
|
}
|
|
|
|
static void dump_frame(interrupt_frame_t *f) {
|
|
printk("[EXC] %s (vector=%u error=%x)\n", exception_name(f->vector), (u32)f->vector, (u32)f->error);
|
|
printk("[EXC] RIP=%p CS=%p RFLAGS=%p RSP=%p SS=%p\n", (void *)f->rip, (void *)f->cs, (void *)f->rflags, (void *)f->rsp, (void *)f->ss);
|
|
printk("[EXC] RAX=%p RBX=%p RCX=%p RDX=%p\n", (void *)f->rax, (void *)f->rbx, (void *)f->rcx, (void *)f->rdx);
|
|
printk("[EXC] RSI=%p RDI=%p RBP=%p\n", (void *)f->rsi, (void *)f->rdi, (void *)f->rbp);
|
|
printk("[EXC] R8 =%p R9 =%p R10=%p R11=%p\n", (void *)f->r8, (void *)f->r9, (void *)f->r10, (void *)f->r11);
|
|
printk("[EXC] R12=%p R13=%p R14=%p R15=%p\n", (void *)f->r12, (void *)f->r13, (void *)f->r14, (void *)f->r15);
|
|
|
|
if (f->vector == 14) {
|
|
printk("[EXC] CR2(fault addr)=%p\n", (void *)read_cr2());
|
|
}
|
|
}
|
|
|
|
void cpu_init(void) {
|
|
struct gdt_ptr gp;
|
|
|
|
gdt_table[0] = 0x0000000000000000ULL;
|
|
gdt_table[1] = 0x00AF9A000000FFFFULL;
|
|
gdt_table[2] = 0x00CF92000000FFFFULL;
|
|
|
|
gp.limit = sizeof(gdt_table) - 1;
|
|
gp.base = (u64)&gdt_table[0];
|
|
|
|
arch_load_gdt(&gp);
|
|
arch_reload_segments();
|
|
}
|
|
|
|
void interrupts_init(void) {
|
|
struct idt_ptr ip;
|
|
u32 i;
|
|
|
|
for (i = 0; i < IDT_ENTRIES; ++i) {
|
|
set_idt_gate((u8)i, isr_stub_table[0], 0x8E);
|
|
}
|
|
|
|
for (i = 0; i < 34; ++i) {
|
|
set_idt_gate((u8)i, isr_stub_table[i], 0x8E);
|
|
}
|
|
|
|
set_idt_gate(128, isr_stub_table[34], 0xEE);
|
|
|
|
ip.limit = sizeof(idt) - 1;
|
|
ip.base = (u64)&idt[0];
|
|
|
|
arch_load_idt(&ip);
|
|
pic_remap();
|
|
|
|
__asm__ volatile ("sti");
|
|
}
|
|
|
|
void interrupt_dispatch(interrupt_frame_t *frame) {
|
|
if (frame->vector < 32) {
|
|
dump_frame(frame);
|
|
panic("CPU exception");
|
|
}
|
|
|
|
if (frame->vector == 32) {
|
|
scheduler_tick();
|
|
pic_send_eoi(frame->vector);
|
|
return;
|
|
}
|
|
|
|
if (frame->vector == 33) {
|
|
pic_send_eoi(frame->vector);
|
|
return;
|
|
}
|
|
|
|
if (frame->vector == 128) {
|
|
frame->rax = syscall_dispatch(frame->rax, frame->rbx, frame->rcx, frame->rdx, frame->rsi);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void cpu_halt(void) {
|
|
__asm__ volatile ("cli");
|
|
for (;;) {
|
|
__asm__ volatile ("hlt");
|
|
}
|
|
}
|