diff options
30 files changed, 764 insertions, 749 deletions
@@ -3,27 +3,32 @@ # All preprocessor flags - enable using the custom config group below ALL_PREPROCESSOR_FLAGS = \ DEBUG_ALLOC \ + DEBUG_SYSCALLS \ DEBUG_SCHEDULER # All config options ALL_CONFIGS = \ + CONFIG_STRIP \ CONFIG_CACHE \ CONFIG_EXTRA_CFLAGS \ CONFIG_USER_PIE +# Set ccache globally +CONFIG_CACHE ?= ccache + # Specific config groups ifeq ($(CONFIG), debug) CONFIG_OPTIMIZATION ?= -Ofast CONFIG_EXTRA_CFLAGS ?= -Wno-error -ggdb3 -s -fsanitize=undefined -fstack-protector-all - CONFIG_CACHE ?= ccache else ifeq ($(CONFIG), dev) CONFIG_OPTIMIZATION ?= -finline -finline-functions -Ofast - CONFIG_CACHE ?= ccache else ifeq ($(CONFIG), release) CONFIG_OPTIMIZATION ?= -finline -finline-functions -Ofast CONFIG_STRIP ?= true - CONFIG_CACHE ?= ccache +else ifeq ($(CONFIG), experimental) + CONFIG_USER_PIE ?= true else ifeq ($(CONFIG), custom) DEBUG_ALLOC ?= true + DEBUG_SYSCALLS ?= true DEBUG_SCHEDULER ?= true endif diff --git a/kernel/Makefile b/kernel/Makefile index 263f08b..7107e14 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -3,8 +3,9 @@ COBJS = entry_asm.o \ main.o \ multiboot.o \ - drivers/interrupts.o \ - drivers/interrupts_asm.o \ + drivers/int.o \ + drivers/int_asm.o \ + drivers/pic.o \ drivers/gdt.o \ drivers/cpu.o \ drivers/serial.o \ diff --git a/kernel/drivers/cpu.c b/kernel/drivers/cpu.c index 8694fc2..44091a3 100644 --- a/kernel/drivers/cpu.c +++ b/kernel/drivers/cpu.c @@ -7,6 +7,10 @@ #include <mem.h> #include <print.h> +/** + * Serial in/out + */ + u8 inb(u16 port) { u8 value; @@ -43,6 +47,10 @@ void outl(u16 port, u32 data) __asm__ volatile("outl %0, %1" ::"a"(data), "Nd"(port)); } +/** + * Special register manipulation + */ + CLEAR u32 cr0_get(void) { u32 cr0; @@ -79,18 +87,39 @@ CLEAR void cr4_set(u32 cr4) __asm__ volatile("movl %%eax, %%cr4" ::"a"(cr4)); } -static void fpu_handler(struct regs *r) +/** + * FPU + */ + +PROTECTED static u8 fpu_initial[512] ALIGNED(16); +static u8 fpu_regs[512] ALIGNED(16); + +static void fpu_handler(void) { - UNUSED(r); __asm__ volatile("clts"); } -static u8 fpu_state[512] ALIGNED(16); -void fpu_restore(void) +void fpu_init(struct proc *proc) +{ + memcpy(&proc->fpu, &fpu_initial, sizeof(fpu_initial)); +} + +void fpu_save(struct proc *proc) +{ + __asm__ volatile("fxsave (%0)" ::"r"(fpu_regs)); + memcpy(&proc->fpu, &fpu_regs, sizeof(fpu_regs)); +} + +void fpu_restore(struct proc *proc) { - __asm__ volatile("fxrstor (%0)" ::"r"(fpu_state)); + memcpy(&fpu_regs, &proc->fpu, sizeof(proc->fpu)); + __asm__ volatile("fxrstor (%0)" ::"r"(fpu_regs)); } +/** + * CPU features + */ + CLEAR static struct cpuid cpuid(u32 code) { u32 a, b, c, d; @@ -129,8 +158,10 @@ CLEAR void cpu_enable_features(void) // Enable SSE if (cpu_features.edx & CPUID_FEAT_EDX_SSE) { + __asm__ volatile("clts"); cr0_set(cr0_get() & ~(1 << 2)); cr0_set(cr0_get() | (1 << 1)); + cr0_set(cr0_get() | (1 << 5)); cr4_set(cr4_get() | (3 << 9)); } else { panic("No SSE support!\n"); @@ -139,8 +170,8 @@ CLEAR void cpu_enable_features(void) // Enable FPU if (cpu_features.edx & CPUID_FEAT_EDX_FPU) { __asm__ volatile("fninit"); - __asm__ volatile("fxsave %0" : "=m"(fpu_state)); - irq_install_handler(7, fpu_handler); + __asm__ volatile("fxsave %0" : "=m"(fpu_initial)); + int_event_handler_add(7, fpu_handler); } else { panic("No FPU support!\n"); } @@ -177,6 +208,10 @@ CLEAR void cpu_enable_features(void) } } +/** + * SMAP + */ + void clac(void) { if (cpu_extended_features.ebx & CPUID_EXT_FEAT_EBX_SMAP) @@ -188,13 +223,3 @@ void stac(void) if (cpu_extended_features.ebx & CPUID_EXT_FEAT_EBX_SMAP) __asm__ volatile("stac" ::: "cc"); } - -CLEAR void cli(void) -{ - __asm__ volatile("cli"); -} - -CLEAR void sti(void) -{ - __asm__ volatile("sti"); -} diff --git a/kernel/drivers/int.asm b/kernel/drivers/int.asm new file mode 100644 index 0000000..30e9eb0 --- /dev/null +++ b/kernel/drivers/int.asm @@ -0,0 +1,162 @@ +; MIT License, Copyright (c) 2021 Marvin Borner + +%macro INT_REGISTER 1 +dd int%1 +%endmacro + +%macro INT_ERR 1 +int%1: + push %1 + jmp int_common +%endmacro + +%macro INT_NOERR 1 +int%1: + push 0 + push %1 + jmp int_common +%endmacro + +%macro INT_SYSCALL 1 +int%1: + push 0 + push %1 + jmp int_common +%endmacro + +extern int_handler +int_common: + cld + + pushad + push ds + push es + push fs + push gs + + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + push esp + call int_handler + mov esp, eax + + pop gs + pop fs + pop es + pop ds + popad + + add esp, 8 + iret + +INT_NOERR 0 +INT_NOERR 1 +INT_NOERR 2 +INT_NOERR 3 +INT_NOERR 4 +INT_NOERR 5 +INT_NOERR 6 +INT_NOERR 7 +INT_ERR 8 +INT_NOERR 9 +INT_ERR 10 +INT_ERR 11 +INT_ERR 12 +INT_ERR 13 +INT_ERR 14 +INT_NOERR 15 +INT_NOERR 16 +INT_ERR 17 +INT_NOERR 18 +INT_NOERR 19 +INT_NOERR 20 +INT_NOERR 21 +INT_NOERR 22 +INT_NOERR 23 +INT_NOERR 24 +INT_NOERR 25 +INT_NOERR 26 +INT_NOERR 27 +INT_NOERR 28 +INT_NOERR 29 +INT_ERR 30 +INT_NOERR 31 + +INT_NOERR 32 +INT_NOERR 33 +INT_NOERR 34 +INT_NOERR 35 +INT_NOERR 36 +INT_NOERR 37 +INT_NOERR 38 +INT_NOERR 39 +INT_NOERR 40 +INT_NOERR 41 +INT_NOERR 42 +INT_NOERR 43 +INT_NOERR 44 +INT_NOERR 45 +INT_NOERR 46 +INT_NOERR 47 + +INT_SYSCALL 128 +INT_NOERR 129 + +global int_table +int_table: + INT_REGISTER 0 + INT_REGISTER 1 + INT_REGISTER 2 + INT_REGISTER 3 + INT_REGISTER 4 + INT_REGISTER 5 + INT_REGISTER 6 + INT_REGISTER 7 + INT_REGISTER 8 + INT_REGISTER 9 + INT_REGISTER 10 + INT_REGISTER 11 + INT_REGISTER 12 + INT_REGISTER 13 + INT_REGISTER 14 + INT_REGISTER 15 + INT_REGISTER 16 + INT_REGISTER 17 + INT_REGISTER 18 + INT_REGISTER 19 + INT_REGISTER 20 + INT_REGISTER 21 + INT_REGISTER 22 + INT_REGISTER 23 + INT_REGISTER 24 + INT_REGISTER 25 + INT_REGISTER 26 + INT_REGISTER 27 + INT_REGISTER 28 + INT_REGISTER 29 + INT_REGISTER 30 + INT_REGISTER 31 + + INT_REGISTER 32 + INT_REGISTER 33 + INT_REGISTER 34 + INT_REGISTER 35 + INT_REGISTER 36 + INT_REGISTER 37 + INT_REGISTER 38 + INT_REGISTER 39 + INT_REGISTER 40 + INT_REGISTER 41 + INT_REGISTER 42 + INT_REGISTER 43 + INT_REGISTER 44 + INT_REGISTER 45 + INT_REGISTER 46 + INT_REGISTER 47 + + INT_REGISTER 128 + INT_REGISTER 129 diff --git a/kernel/drivers/int.c b/kernel/drivers/int.c new file mode 100644 index 0000000..47a2699 --- /dev/null +++ b/kernel/drivers/int.c @@ -0,0 +1,187 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <assert.h> +#include <def.h> +#include <drivers/int.h> +#include <drivers/pic.h> +#include <drivers/serial.h> + +/** + * IDT + */ + +PROTECTED extern u32 int_table[]; +PROTECTED static struct idt_entry idt[256] = { 0 }; +PROTECTED static struct idt_ptr idt_ptr = { 0 }; + +CLEAR void idt_install(void) +{ + idt_ptr.size = sizeof(idt) - 1; + idt_ptr.base = &idt; + + for (u8 i = 0; i < 3; i++) + idt[i] = IDT_ENTRY(int_table[i], 0x08, INT_GATE); + + idt[3] = IDT_ENTRY(int_table[3], 0x08, INT_TRAP); + idt[4] = IDT_ENTRY(int_table[4], 0x08, INT_TRAP); + + for (u8 i = 5; i < 48; i++) + idt[i] = IDT_ENTRY(int_table[i], 0x08, INT_GATE); + + idt[128] = IDT_ENTRY(int_table[48], 0x08, INT_GATE | INT_USER); + idt[129] = IDT_ENTRY(int_table[49], 0x08, INT_GATE); + + __asm__ volatile("lidt %0" : : "m"(idt_ptr)); +} + +/** + * Exception (trap) handling + */ + +PROTECTED const char *int_trap_names[32] = { + "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", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", +}; + +PROTECTED static void (*int_trap_handlers[16])(u32 esp) = { 0 }; + +CLEAR void int_trap_handler_add(u32 int_no, void (*handler)(u32 esp)) +{ + assert(int_no < COUNT(int_trap_handlers)); + int_trap_handlers[int_no] = handler; +} + +static void int_trap_handler(struct int_frame *frame) +{ + static u8 faulting = 0; + faulting++; + + if (faulting == 2) { + // Fall back to serial driver + serial_print("Double fault, halting immediatly\n"); + while (1) + __asm__ volatile("cli\nhlt"); + } + + assert(frame->int_no < COUNT(int_trap_handlers)); + void (*handler)(u32 esp) = int_trap_handlers[frame->int_no]; + if (handler) + handler((u32)frame); + + printf("%s Exception (code %x) at 0x%x (ring %d), exiting!\n", + int_trap_names[frame->int_no], frame->err_code, frame->eip, RING(frame)); + struct proc *proc = proc_current(); + if (proc) { + printf("\t-> Exception occurred in %s at addr 0x%x (offset 0x%x)\n", proc->name, + frame->eip, frame->eip - proc->entry); + printf("\t\t-> Process: [entry: %x, kstack: %x, esp %x, ustack: %x]\n", proc->entry, + proc->stack.kernel, frame->esp, proc->stack.user); + proc_exit(proc, 1); + faulting--; + } else { + while (1) + __asm__ volatile("cli\nhlt"); + } +} + +/** + * Event handling + */ + +PROTECTED static void (*int_event_handlers[16])(void) = { 0 }; + +CLEAR void int_event_handler_add(u32 int_no, void (*handler)(void)) +{ + assert(int_no < COUNT(int_event_handlers)); + int_event_handlers[int_no] = handler; +} + +#include <mm.h> +static u32 int_event_handler(struct int_frame *frame) +{ + u32 int_no = frame->int_no - 32; + assert(int_no < COUNT(int_event_handlers)); + void (*handler)(void) = int_event_handlers[int_no]; + if (handler) + handler(); + + if (!int_no) + return scheduler((u32)frame); + return (u32)frame; +} + +/** + * Special interrupts (e.g. syscall, yield) + */ + +PROTECTED static u32 (*int_special_handlers[16])(u32 esp) = { 0 }; + +CLEAR void int_special_handler_add(u32 int_no, u32 (*handler)(u32 esp)) +{ + assert(int_no < COUNT(int_event_handlers)); + int_special_handlers[int_no] = handler; +} + +static u32 int_special_handler(struct int_frame *frame) +{ + u32 int_no = frame->int_no - 128; + assert(int_no < COUNT(int_event_handlers)); + u32 (*handler)(u32 esp) = int_special_handlers[int_no]; + if (handler) + return handler((u32)frame); + return (u32)frame; +} + +/** + * Universal handler + */ + +u32 int_handler(u32 esp); +u32 int_handler(u32 esp) +{ + struct int_frame *frame = (struct int_frame *)esp; + if (frame->int_no < 32) + int_trap_handler(frame); + else if (frame->int_no < 48) + esp = int_event_handler(frame); + else if (frame->int_no >= 128 && frame->int_no < 144) + esp = int_special_handler(frame); + else + panic("Unknown interrupt: %d\n", frame->int_no); + + pic_ack(frame->int_no); + return esp; +} diff --git a/kernel/drivers/interrupts.asm b/kernel/drivers/interrupts.asm deleted file mode 100644 index 18cf007..0000000 --- a/kernel/drivers/interrupts.asm +++ /dev/null @@ -1,140 +0,0 @@ -; MIT License, Copyright (c) 2020 Marvin Borner - -; IRQ - -%macro IRQ 2 - global irq%1 - irq%1: - push byte 0 - push byte %2 - jmp irq_common_stub -%endmacro - -IRQ 0, 32 -IRQ 1, 33 -IRQ 2, 34 -IRQ 3, 35 -IRQ 4, 36 -IRQ 5, 37 -IRQ 6, 38 -IRQ 7, 39 -IRQ 8, 40 -IRQ 9, 41 -IRQ 10, 42 -IRQ 11, 43 -IRQ 12, 44 -IRQ 13, 45 -IRQ 14, 46 -IRQ 15, 47 - -extern irq_handler -irq_common_stub: - pusha - - push ds - push es - push fs - push gs - - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - cld - - push esp - call irq_handler - add esp, 4 - - pop gs - pop fs - pop es - pop ds - popa - - add esp, 8 - sti - iret - -; ISR - -%macro ISR_NOERRCODE 1 - global isr%1 - isr%1: - push byte 0 - push %1 - jmp isr_common_stub -%endmacro - -%macro ISR_ERRCODE 1 - global isr%1 - isr%1: - push byte %1 - jmp isr_common_stub -%endmacro - -ISR_NOERRCODE 0 -ISR_NOERRCODE 1 -ISR_NOERRCODE 2 -ISR_NOERRCODE 3 -ISR_NOERRCODE 4 -ISR_NOERRCODE 5 -ISR_NOERRCODE 6 -ISR_NOERRCODE 7 -ISR_ERRCODE 8 -ISR_NOERRCODE 9 -ISR_ERRCODE 10 -ISR_ERRCODE 11 -ISR_ERRCODE 12 -ISR_ERRCODE 13 -ISR_ERRCODE 14 -ISR_NOERRCODE 15 -ISR_NOERRCODE 16 -ISR_NOERRCODE 17 -ISR_NOERRCODE 18 -ISR_NOERRCODE 19 -ISR_NOERRCODE 20 -ISR_NOERRCODE 21 -ISR_NOERRCODE 22 -ISR_NOERRCODE 23 -ISR_NOERRCODE 24 -ISR_NOERRCODE 25 -ISR_NOERRCODE 26 -ISR_NOERRCODE 27 -ISR_NOERRCODE 28 -ISR_NOERRCODE 29 -ISR_NOERRCODE 30 -ISR_NOERRCODE 31 -ISR_NOERRCODE 127 -ISR_NOERRCODE 128 - -extern isr_handler -isr_common_stub: - pusha - - push ds - push es - push fs - push gs - - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - cld - - push esp - call isr_handler - add esp, 4 - - pop gs - pop fs - pop es - pop ds - popa - - add esp, 8 - sti - iret diff --git a/kernel/drivers/interrupts.c b/kernel/drivers/interrupts.c deleted file mode 100644 index 39a59a0..0000000 --- a/kernel/drivers/interrupts.c +++ /dev/null @@ -1,261 +0,0 @@ -// MIT License, Copyright (c) 2020 Marvin Borner -// TODO: Remove some magic numbers - -#include <assert.h> -#include <def.h> -#include <drivers/cpu.h> -#include <drivers/interrupts.h> -#include <drivers/serial.h> -#include <mem.h> -#include <mm.h> -#include <print.h> -#include <proc.h> - -/** - * IDT - */ - -PROTECTED static struct idt_entry idt[256] = { 0 }; -PROTECTED static struct idt_ptr idt_ptr = { 0 }; - -CLEAR void idt_set_gate(u8 num, u32 base, u16 sel, u8 flags) -{ - // Specify the interrupt routine's base address - idt[num].base_low = (u16)(base & 0xffff); - idt[num].base_high = (u16)((base >> 16) & 0xffff); - - // Set selector/segment of IDT entry - idt[num].sel = sel; - idt[num].always0 = 0; - idt[num].flags = flags; -} - -// Install IDT -CLEAR static void idt_install(void) -{ - // Set IDT pointer and limit - idt_ptr.limit = sizeof(idt) - 1; - idt_ptr.base = &idt; - - // Clear IDT by setting memory cells to 0 - memset(&idt, 0, sizeof(idt)); - - __asm__ volatile("lidt %0" : : "m"(idt_ptr)); -} - -/** - * IRQ - */ - -PROTECTED static void (*irq_routines[16])(struct regs *) = { 0 }; - -// Install IRQ handler -CLEAR void irq_install_handler(int irq, void (*handler)(struct regs *r)) -{ - irq_routines[irq] = handler; -} - -// Remove IRQ handler -CLEAR void irq_uninstall_handler(int irq) -{ - irq_routines[irq] = 0; -} - -// Remap the IRQ table -CLEAR static void irq_remap(void) -{ - outb(0x20, 0x11); - outb(0xa0, 0x11); - outb(0x21, 0x20); - outb(0xa1, 0x28); - outb(0x21, 0x04); - outb(0xa1, 0x02); - outb(0x21, 0x01); - outb(0xa1, 0x01); - outb(0x21, 0x00); - outb(0xa1, 0x00); -} - -// Handle IRQ ISRs -void irq_handler(struct regs *r); -void irq_handler(struct regs *r) -{ - void (*handler)(struct regs * r); - - // Execute custom handler if exists - handler = irq_routines[r->int_no - 32]; - if (handler) - handler(r); - - // Send EOI to second (slave) PIC - if (r->int_no >= 40) - outb(0xa0, 0x20); - - // Send EOI to master PIC - outb(0x20, 0x20); -} - -// Map ISRs to the correct entries in the IDT -CLEAR static void irq_install(void) -{ - irq_remap(); - - idt_set_gate(32, (u32)irq0, 0x08, 0x8e); - idt_set_gate(33, (u32)irq1, 0x08, 0x8e); - idt_set_gate(34, (u32)irq2, 0x08, 0x8e); - idt_set_gate(35, (u32)irq3, 0x08, 0x8e); - idt_set_gate(36, (u32)irq4, 0x08, 0x8e); - idt_set_gate(37, (u32)irq5, 0x08, 0x8e); - idt_set_gate(38, (u32)irq6, 0x08, 0x8e); - idt_set_gate(39, (u32)irq7, 0x08, 0x8e); - - idt_set_gate(40, (u32)irq8, 0x08, 0x8e); - idt_set_gate(41, (u32)irq9, 0x08, 0x8e); - idt_set_gate(42, (u32)irq10, 0x08, 0x8e); - idt_set_gate(43, (u32)irq11, 0x08, 0x8e); - idt_set_gate(44, (u32)irq12, 0x08, 0x8e); - idt_set_gate(45, (u32)irq13, 0x08, 0x8e); - idt_set_gate(46, (u32)irq14, 0x08, 0x8e); - idt_set_gate(47, (u32)irq15, 0x08, 0x8e); -} - -/** - * ISR - */ - -PROTECTED static void (*isr_routines[256])(struct regs *) = { 0 }; - -PROTECTED const char *isr_exceptions[32] = { - "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", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", -}; - -CLEAR void isr_install_handler(int isr, void (*handler)(struct regs *r)) -{ - isr_routines[isr] = handler; -} - -CLEAR void isr_uninstall_handler(int isr) -{ - isr_routines[isr] = 0; -} - -void isr_panic(struct regs *r) -{ - printf("%s Exception (code %x) at 0x%x (ring %d), exiting!\n", isr_exceptions[r->int_no], - r->err_code, r->eip, RING(r)); - struct proc *proc = proc_current(); - if (proc) { - printf("\t-> Exception occurred in %s at addr 0x%x (offset 0x%x)\n", proc->name, - r->eip, r->eip - proc->entry); - printf("\t\t-> Process: [entry: %x, kstack: %x, esp %x, ustack: %x, uesp %x]\n", - proc->entry, proc->stack.kernel, r->esp, proc->stack.user, r->useresp); - proc_exit(proc, r, 1); - } else { - __asm__ volatile("cli\nhlt"); - } - proc_yield_regs(r); -} - -void isr_handler(struct regs *r); -void isr_handler(struct regs *r) -{ - assert(r->int_no < sizeof(isr_routines)); - - // Execute fault handler if exists - void (*handler)(struct regs * r) = isr_routines[r->int_no]; - if (handler) - handler(r); - else - isr_panic(r); -} - -CLEAR static void isr_install(void) -{ - idt_set_gate(0, (u32)isr0, 0x08, 0x8e); - idt_set_gate(1, (u32)isr1, 0x08, 0x8e); - idt_set_gate(2, (u32)isr2, 0x08, 0x8e); - idt_set_gate(3, (u32)isr3, 0x08, 0x8e); - idt_set_gate(4, (u32)isr4, 0x08, 0x8e); - idt_set_gate(5, (u32)isr5, 0x08, 0x8e); - idt_set_gate(6, (u32)isr6, 0x08, 0x8e); - idt_set_gate(7, (u32)isr7, 0x08, 0x8e); - - idt_set_gate(8, (u32)isr8, 0x08, 0x8e); - idt_set_gate(9, (u32)isr9, 0x08, 0x8e); - idt_set_gate(10, (u32)isr10, 0x08, 0x8e); - idt_set_gate(11, (u32)isr11, 0x08, 0x8e); - idt_set_gate(12, (u32)isr12, 0x08, 0x8e); - idt_set_gate(13, (u32)isr13, 0x08, 0x8e); - idt_set_gate(14, (u32)isr14, 0x08, 0x8e); - idt_set_gate(15, (u32)isr15, 0x08, 0x8e); - - idt_set_gate(16, (u32)isr16, 0x08, 0x8e); - idt_set_gate(17, (u32)isr17, 0x08, 0x8e); - idt_set_gate(18, (u32)isr18, 0x08, 0x8e); - idt_set_gate(19, (u32)isr19, 0x08, 0x8e); - idt_set_gate(20, (u32)isr20, 0x08, 0x8e); - idt_set_gate(21, (u32)isr21, 0x08, 0x8e); - idt_set_gate(22, (u32)isr22, 0x08, 0x8e); - idt_set_gate(23, (u32)isr23, 0x08, 0x8e); - - idt_set_gate(24, (u32)isr24, 0x08, 0x8e); - idt_set_gate(25, (u32)isr25, 0x08, 0x8e); - idt_set_gate(26, (u32)isr26, 0x08, 0x8e); - idt_set_gate(27, (u32)isr27, 0x08, 0x8e); - idt_set_gate(28, (u32)isr28, 0x08, 0x8e); - idt_set_gate(29, (u32)isr29, 0x08, 0x8e); - idt_set_gate(30, (u32)isr30, 0x08, 0x8e); - idt_set_gate(31, (u32)isr31, 0x08, 0x8e); - - // Set default routines - for (u32 i = 0; i < 256; i++) - isr_routines[i] = isr_panic; - - // Set page fault handler - isr_install_handler(14, page_fault_handler); -} - -/** - * Combined - */ - -CLEAR void interrupts_install(void) -{ - idt_install(); - isr_install(); - irq_install(); -} diff --git a/kernel/drivers/pic.c b/kernel/drivers/pic.c new file mode 100644 index 0000000..55ecfd6 --- /dev/null +++ b/kernel/drivers/pic.c @@ -0,0 +1,66 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <def.h> +#include <drivers/cpu.h> +#include <drivers/pic.h> + +#define PIC1 0x20 +#define PIC1_COMMAND PIC1 +#define PIC1_OFFSET 0x20 +#define PIC1_DATA (PIC1 + 1) + +#define PIC2 0xa0 +#define PIC2_COMMAND PIC2 +#define PIC2_OFFSET 0x28 +#define PIC2_DATA (PIC2 + 1) + +#define ICW1_ICW4 0x01 +#define ICW1_INIT 0x10 + +INLINE void pic_wait(void) +{ + __asm__ volatile("jmp 1f\n\t" + "1:\n\t" + " jmp 2f\n\t" + "2:"); +} + +CLEAR void pic_install(void) +{ + // Initialize + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); + pic_wait(); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + pic_wait(); + + // Remap + outb(PIC1_DATA, PIC1_OFFSET); + pic_wait(); + outb(PIC2_DATA, PIC2_OFFSET); + pic_wait(); + + outb(PIC1_DATA, 0x04); + pic_wait(); + outb(PIC2_DATA, 0x02); + pic_wait(); + + // Set 8086 mode + outb(PIC1_DATA, 0x01); + pic_wait(); + outb(PIC2_DATA, 0x01); + pic_wait(); + + outb(PIC1_DATA, 0x00); + pic_wait(); + outb(PIC2_DATA, 0x00); + pic_wait(); +} + +void pic_ack(u32 int_no) +{ + if (int_no >= 40) { + outb(PIC2, 0x20); + } + + outb(PIC1, 0x20); +} diff --git a/kernel/drivers/ps2/keyboard.c b/kernel/drivers/ps2/keyboard.c index bf1a520..3516a7e 100644 --- a/kernel/drivers/ps2/keyboard.c +++ b/kernel/drivers/ps2/keyboard.c @@ -2,7 +2,7 @@ #include <def.h> #include <drivers/cpu.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <drivers/ps2.h> #include <errno.h> #include <io.h> @@ -18,9 +18,8 @@ PROTECTED static struct stack *queue = NULL; static struct event_keyboard *event = NULL; static int state = 0; static int merged = 0; -static void keyboard_handler(struct regs *r) +static void keyboard_handler(void) { - UNUSED(r); u8 scancode = ps2_read_data(); // TODO: Support more than two-byte scancodes @@ -73,7 +72,7 @@ CLEAR void ps2_keyboard_install(u8 device) { UNUSED(device); - irq_install_handler(1, keyboard_handler); + int_event_handler_add(1, keyboard_handler); queue = stack_new(); struct io_dev *dev = zalloc(sizeof(*dev)); diff --git a/kernel/drivers/ps2/mouse.c b/kernel/drivers/ps2/mouse.c index 680183d..ab20c90 100644 --- a/kernel/drivers/ps2/mouse.c +++ b/kernel/drivers/ps2/mouse.c @@ -2,7 +2,7 @@ #include <assert.h> #include <drivers/cpu.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <drivers/ps2.h> #include <errno.h> #include <io.h> @@ -36,9 +36,8 @@ static void mouse_finish(void) io_unblock(IO_MOUSE); } -static void mouse_handler(struct regs *r) +static void mouse_handler(void) { - UNUSED(r); switch (mouse_cycle) { case 0: mouse_byte[0] = ps2_read_data(); @@ -139,7 +138,7 @@ CLEAR void ps2_mouse_install(u8 device) { ps2_mouse_enable(device); - irq_install_handler(12, mouse_handler); + int_event_handler_add(12, mouse_handler); queue = stack_new(); struct io_dev *dev = zalloc(sizeof(*dev)); diff --git a/kernel/drivers/timer.c b/kernel/drivers/timer.c index 3ddc229..44d66f3 100644 --- a/kernel/drivers/timer.c +++ b/kernel/drivers/timer.c @@ -2,7 +2,7 @@ #include <def.h> #include <drivers/cpu.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <drivers/rtc.h> #include <drivers/timer.h> #include <io.h> @@ -10,7 +10,6 @@ #include <proc.h> static u32 timer_ticks = 0; -PROTECTED static u8 call_scheduler = 0; CLEAR static void timer_phase(int hz) { @@ -25,36 +24,20 @@ u32 timer_get(void) return timer_ticks; } -void timer_handler(struct regs *r) +static void timer_handler(void) { if (timer_ticks >= U32_MAX) timer_ticks = 0; else timer_ticks++; - - if (call_scheduler) - scheduler(r); } // "Delay" function with CPU sleep void timer_wait(u32 ticks) { u32 eticks = timer_ticks + ticks; - while (timer_ticks < eticks) { + while (timer_ticks < eticks) __asm__ volatile("sti\nhlt\ncli"); - } -} - -CLEAR void scheduler_enable(void) -{ - call_scheduler = 1; - irq_install_handler(0, timer_handler); -} - -CLEAR void scheduler_disable(void) -{ - call_scheduler = 0; - irq_install_handler(0, timer_handler); } static struct timer timer_struct(void) @@ -85,7 +68,7 @@ CLEAR void timer_install(void) /* hpet_install(10000); // TODO: Find optimal femtosecond period */ /* if (!hpet) */ timer_phase(1000); - irq_install_handler(0, timer_handler); + int_event_handler_add(0, timer_handler); struct io_dev *dev = zalloc(sizeof(*dev)); dev->read = timer_read; diff --git a/kernel/drivers/vmware.c b/kernel/drivers/vmware.c index 169865f..24f56a0 100644 --- a/kernel/drivers/vmware.c +++ b/kernel/drivers/vmware.c @@ -2,7 +2,7 @@ // VMWare extensions/backdoors for better VM integration #include <def.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <drivers/ps2.h> #include <drivers/vmware.h> #include <io.h> @@ -94,9 +94,8 @@ CLEAR static void vmware_mouse_enable(void) vmware_out(&command); } -static void vmware_mouse_handler(struct regs *r) +static void vmware_mouse_handler(void) { - UNUSED(r); ps2_read_data(); // Unused, for PS/2 compatibility struct vmware_command command = { .b.bx = 0, .c.command = VMMOUSE_STATUS }; @@ -150,7 +149,7 @@ CLEAR void vmware_mouse_install(u8 device) ps2_mouse_enable(device); vmware_mouse_enable(); - irq_install_handler(12, vmware_mouse_handler); + int_event_handler_add(12, vmware_mouse_handler); queue = stack_new(); struct io_dev *dev = zalloc(sizeof(*dev)); diff --git a/kernel/features/io.c b/kernel/features/io.c index 28388ae..8126ccf 100644 --- a/kernel/features/io.c +++ b/kernel/features/io.c @@ -5,7 +5,7 @@ #include <def.h> #include <drivers/bga.h> #include <drivers/cpu.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <drivers/ps2.h> #include <drivers/timer.h> #include <drivers/vbe.h> diff --git a/kernel/features/load.c b/kernel/features/load.c index 1059240..4951351 100644 --- a/kernel/features/load.c +++ b/kernel/features/load.c @@ -14,13 +14,11 @@ res elf_load(const char *name, struct proc *proc) if (!memory_readable(name)) return -EFAULT; - stac(); char path[64] = { "/apps/" }; - strlcat(path, name, sizeof(path)); - strlcpy(proc->dir, path, sizeof(proc->dir)); - strlcat(path, "/exec", sizeof(path)); - strlcpy(proc->name, name, sizeof(proc->name)); - clac(); + strlcat_user(path, name, sizeof(path)); + strlcpy_user(proc->dir, path, sizeof(proc->dir)); + strlcat_user(path, "/exec", sizeof(path)); + strlcpy_user(proc->name, name, sizeof(proc->name)); struct stat s = { 0 }; memory_bypass_enable(); @@ -30,11 +28,11 @@ res elf_load(const char *name, struct proc *proc) return stat; struct elf_header header = { 0 }; - stac(); memory_bypass_enable(); + stac(); res read = vfs_read(path, &header, 0, sizeof(header)); - memory_bypass_disable(); clac(); + memory_bypass_disable(); if (read < 0) return read; if (read != sizeof(header)) @@ -124,22 +122,6 @@ res elf_load(const char *name, struct proc *proc) } memory_bypass_disable(); - // TODO: Use section and symbol name for logging or something? (e.g. in page fault handler) - /* u32 offset = section_strings.offset + section.name; */ - /* if (offset >= s.size) */ - /* return -ENOEXEC; */ - /* memory_bypass_enable(); */ - /* char name[64] = { 0 }; // Max length? */ - /* if (vfs_read(path, &name, offset, sizeof(name)) != sizeof(name)) { */ - /* memory_bypass_disable(); */ - /* return -ENOEXEC; */ - /* } */ - /* memory_bypass_disable(); */ - /* printf("%d\n", section.name); */ - /* if (section.type == ELF_SECTION_TYPE_SYMTAB) { */ - /* } else if (section.type == ELF_SECTION_TYPE_STRTAB && i != header.shstrndx) { */ - /* } */ - // Remap readonly sections if (!(section.flags & ELF_SECTION_FLAG_WRITE) && section.addr && memory_is_user((void *)section.addr)) { @@ -149,26 +131,8 @@ res elf_load(const char *name, struct proc *proc) } } - struct page_dir *prev; - memory_backup_dir(&prev); - memory_switch_dir(proc->page_dir); - - // Allocate user stack with readonly lower and upper page boundary - u32 user_stack = (u32)memory_alloc_with_boundary(proc->page_dir, PROC_STACK_SIZE, - MEMORY_CLEAR | MEMORY_USER); - - // Allocate kernel stack with readonly lower and upper page boundary - u32 kernel_stack = - (u32)memory_alloc_with_boundary(proc->page_dir, PROC_STACK_SIZE, MEMORY_CLEAR); - - proc->stack.user = user_stack + PROC_STACK_SIZE; - proc->stack.kernel = kernel_stack + PROC_STACK_SIZE; - proc->regs.esp = proc->stack.kernel; - proc->regs.ebp = proc->stack.user; - proc->regs.useresp = proc->stack.user; - proc->regs.eip = header.entry + rand_off; proc->entry = header.entry + rand_off; + proc_make_regs(proc); - memory_switch_dir(prev); return EOK; } diff --git a/kernel/features/mm.c b/kernel/features/mm.c index 227ba0a..0137256 100644 --- a/kernel/features/mm.c +++ b/kernel/features/mm.c @@ -14,6 +14,7 @@ PROTECTED static struct page_dir kernel_dir ALIGNED(PAGE_SIZE) = { 0 }; static struct page_table kernel_tables[PAGE_KERNEL_COUNT] ALIGNED(PAGE_SIZE) = { 0 }; +static struct page_dir *current_dir = NULL; extern u32 kernel_rw_start; extern u32 kernel_rw_end; @@ -66,14 +67,15 @@ static const char *page_fault_section(u32 addr) return section; } -void page_fault_handler(struct regs *r) +static void page_fault_handler(u32 esp) { + struct int_frame *frame = (struct int_frame *)esp; print("--- PAGE FAULT! ---\n"); // Check error code - const char *type = (r->err_code & 1) ? "present" : "non-present"; - const char *operation = (r->err_code & 2) ? "write" : "read"; - const char *super = (r->err_code & 4) ? "User" : "Super"; + const char *type = (frame->err_code & 1) ? "present" : "non-present"; + const char *operation = (frame->err_code & 2) ? "write" : "read"; + const char *super = (frame->err_code & 4) ? "User" : "Super"; // Check cr2 address (virtual and physical) u32 vaddr; @@ -87,16 +89,13 @@ void page_fault_handler(struct regs *r) printf("%s process tried to %s a %s page at [vaddr=%x; paddr=%x]\n", super, operation, type, vaddr, paddr); - if (proc && vaddr > proc->regs.ebp - PROC_STACK_SIZE - PAGE_SIZE && - vaddr < proc->regs.ebp + PAGE_SIZE) + if (proc && vaddr > proc->stack.user_ptr - PROC_STACK_SIZE - PAGE_SIZE && + vaddr < proc->stack.user_ptr + PAGE_SIZE) print("Probably a stack overflow\n"); printf("Sections: [vaddr_section=%s; paddr_section=%s; eip_section=%s]\n", - page_fault_section(vaddr), page_fault_section(paddr), page_fault_section(r->eip)); - - /* printf("%b\n", virtual_entry(dir, vaddr)->uint); */ - - isr_panic(r); + page_fault_section(vaddr), page_fault_section(paddr), + page_fault_section(frame->eip)); } /** @@ -424,8 +423,18 @@ void *memory_alloc(struct page_dir *dir, u32 size, u32 flags) goto err; } - if (flags & MEMORY_CLEAR) - memset_user((void *)vaddr, 0, size); + if (flags & MEMORY_CLEAR) { + // TODO: Neater solution + if (dir == current_dir) { + memset_user((void *)vaddr, 0, size); + } else { + struct page_dir *bak; + memory_backup_dir(&bak); + memory_switch_dir(dir); + memset_user((void *)vaddr, 0, size); + memory_switch_dir(bak); + } + } return (void *)vaddr; @@ -587,6 +596,7 @@ res memory_sys_shaccess(struct page_dir *dir, u32 id, u32 *addr, u32 *size) void memory_switch_dir(struct page_dir *dir) { + current_dir = dir; paging_switch_dir(virtual_to_physical(&kernel_dir, (u32)dir)); } @@ -760,4 +770,6 @@ CLEAR void memory_install(void) paging_enable(); memory_objects = list_new(); + + int_trap_handler_add(14, page_fault_handler); } diff --git a/kernel/features/proc.c b/kernel/features/proc.c index 8fc922e..ce33495 100644 --- a/kernel/features/proc.c +++ b/kernel/features/proc.c @@ -27,24 +27,26 @@ PROTECTED static struct list *proc_list_idle = NULL; // TODO: Use less memcpy and only copy relevant registers // TODO: 20 priority queues (https://www.kernel.org/doc/html/latest/scheduler/sched-nice-design.html) -HOT FLATTEN void scheduler(struct regs *regs) +HOT FLATTEN u32 scheduler(u32 esp) { spinlock(&locked); - if (RING(regs) == 3) - PROC(current)->ticks.user++; - else - PROC(current)->ticks.kernel++; + if (!current) { + current = idle_proc; + locked = 0; + return PROC(current)->stack.kernel_ptr; + } if (PROC(current)->quantum.cnt >= PROC(current)->quantum.val) { PROC(current)->quantum.cnt = 0; } else { PROC(current)->quantum.cnt++; locked = 0; - return; + return esp; } - memcpy(&PROC(current)->regs, regs, sizeof(*regs)); + fpu_save(PROC(current)); + PROC(current)->stack.kernel_ptr = esp; if (current->next) { current = current->next; @@ -54,17 +56,21 @@ HOT FLATTEN void scheduler(struct regs *regs) current = idle_proc; } - tss_set_stack(PROC(current)->stack.kernel); memory_switch_dir(PROC(current)->page_dir); - memcpy(regs, &PROC(current)->regs, sizeof(*regs)); + tss_set_stack(PROC(current)->stack.kernel_ptr); + fpu_restore(PROC(current)); #if DEBUG_SCHEDULER - if (current != idle_proc) + if (current != idle_proc) { + struct int_frame_user *frame = + (struct int_frame_user *)PROC(current)->stack.kernel_ptr; printf("%s (%d): eip %x esp %x useresp %x\n", PROC(current)->name, - PROC(current)->pid, regs->eip, regs->esp, regs->useresp); + PROC(current)->pid, frame->eip, frame->esp, frame->useresp); + } #endif locked = 0; + return PROC(current)->stack.kernel_ptr; } void proc_print(void) @@ -151,7 +157,7 @@ void proc_state(struct proc *proc, enum proc_state state) // else: Nothing to do! } -void proc_exit(struct proc *proc, struct regs *r, s32 status) +void proc_exit(struct proc *proc, s32 status) { assert(proc != idle_proc->data); @@ -162,8 +168,8 @@ void proc_exit(struct proc *proc, struct regs *r, s32 status) } if (current->data == proc) { - current = idle_proc; - memcpy(r, &PROC(idle_proc)->regs, sizeof(*r)); + memory_switch_dir(virtual_kernel_dir()); + current = NULL; } printf("Process %s (%d) exited with status %d (%s)\n", @@ -188,28 +194,46 @@ void proc_exit(struct proc *proc, struct regs *r, s32 status) stack_destroy(proc->messages); list_destroy(proc->memory); // TODO: Decrement memory ref links virtual_destroy_dir(proc->page_dir); - + memset(proc, 0, sizeof(*proc)); free(proc); - proc_yield_regs(r); + proc_yield(); + assert_not_reached(); } void proc_yield(void) { - // TODO: Fix yielding without debug mode (File size?! Regs?! IDK?!) - proc_reset_quantum(PROC(current)); - __asm__ volatile("int $127"); + __asm__ volatile("int $129"); } -void proc_yield_regs(struct regs *r) +void proc_stack_user_push(struct proc *proc, const void *data, u32 size) { - proc_reset_quantum(PROC(current)); - scheduler(r); + struct page_dir *prev; + memory_backup_dir(&prev); + memory_switch_dir(proc->page_dir); + + proc->stack.user_ptr -= size; + memcpy_user((void *)proc->stack.user_ptr, data, size); + + memory_switch_dir(prev); +} + +void proc_stack_kernel_push(struct proc *proc, const void *data, u32 size) +{ + struct page_dir *prev; + memory_backup_dir(&prev); + memory_switch_dir(proc->page_dir); + + proc->stack.kernel_ptr -= size; + memcpy_user((void *)proc->stack.kernel_ptr, data, size); + + memory_switch_dir(prev); } struct proc *proc_make(enum proc_priv priv) { struct proc *proc = zalloc(sizeof(*proc)); + fpu_init(proc); proc->pid = current_pid++; proc->priv = priv; proc->messages = stack_new(); @@ -219,35 +243,55 @@ struct proc *proc_make(enum proc_priv priv) proc->quantum.val = PROC_QUANTUM; proc->quantum.cnt = 0; - // Init regs - u8 is_kernel = priv == PROC_PRIV_KERNEL; - u32 data = is_kernel ? GDT_SUPER_DATA_OFFSET : GDT_USER_DATA_OFFSET; - u32 code = is_kernel ? GDT_SUPER_CODE_OFFSET : GDT_USER_CODE_OFFSET; - proc->regs.gs = data; - proc->regs.fs = data; - proc->regs.es = data; - proc->regs.ds = data; - proc->regs.ss = data; - proc->regs.cs = code; - proc->regs.eflags = EFLAGS_ALWAYS | EFLAGS_INTERRUPTS; - - list_add(proc_list_running, proc); - return proc; } -void proc_stack_push(struct proc *proc, u32 data) +void proc_make_regs(struct proc *proc) { - struct page_dir *prev; - memory_backup_dir(&prev); - memory_switch_dir(proc->page_dir); + struct int_frame_user frame = { 0 }; - proc->regs.useresp -= sizeof(data); - stac(); - *(u32 *)proc->regs.useresp = data; - clac(); + assert(proc->entry); + frame.eip = proc->entry; - memory_switch_dir(prev); + // Allocate user stack with readonly lower and upper page boundary + u32 user_stack = (u32)memory_alloc_with_boundary(proc->page_dir, PROC_STACK_SIZE, + MEMORY_CLEAR | MEMORY_USER); + + // Allocate kernel stack with readonly lower and upper page boundary + u32 kernel_stack = + (u32)memory_alloc_with_boundary(proc->page_dir, PROC_STACK_SIZE, MEMORY_CLEAR); + + proc->stack.user = user_stack + PROC_STACK_SIZE; + proc->stack.user_ptr = proc->stack.user; + + proc->stack.kernel = kernel_stack + PROC_STACK_SIZE; + proc->stack.kernel_ptr = proc->stack.kernel; + + frame.esp = proc->stack.kernel; + frame.ebp = proc->stack.kernel; + frame.useresp = proc->stack.user; + + // Init regs + u8 is_kernel = proc->priv == PROC_PRIV_KERNEL; + u32 data = is_kernel ? GDT_SUPER_DATA_OFFSET : GDT_USER_DATA_OFFSET; + u32 code = is_kernel ? GDT_SUPER_CODE_OFFSET : GDT_USER_CODE_OFFSET; + frame.gs = data; + frame.fs = data; + frame.es = data; + frame.ds = data; + frame.ss = data; + frame.cs = code; + frame.eflags = EFLAGS_ALWAYS | EFLAGS_INTERRUPTS; + + // Push frame as the values get popped (see int.asm) + proc_stack_kernel_push(proc, &frame, sizeof(frame)); + + // Push argc and argv // TODO + u32 arg = 0; + proc_stack_user_push(proc, &arg, sizeof(arg)); + proc_stack_user_push(proc, &arg, sizeof(arg)); + + list_add(proc_list_running, proc); } // TODO: Procfs needs a simpler interface structure (memcmp and everything sucks) @@ -331,8 +375,6 @@ void proc_init(void) if (proc_list_running) panic("Already initialized processes!"); - cli(); - scheduler_enable(); proc_list_running = list_new(); proc_list_blocked = list_new(); proc_list_idle = list_new(); @@ -354,8 +396,6 @@ void proc_init(void) // TODO: Reimplement hlt privileges in idle proc (SMEP!) struct proc *kernel_proc = proc_make(PROC_PRIV_NONE); assert(elf_load("idle", kernel_proc) == EOK); - proc_stack_push(kernel_proc, 0); - proc_stack_push(kernel_proc, 0); kernel_proc->state = PROC_BLOCKED; kernel_proc->quantum.val = 0; kernel_proc->quantum.cnt = 0; @@ -365,12 +405,10 @@ void proc_init(void) // Init proc (root) struct proc *init = proc_make(PROC_PRIV_ROOT); assert(elf_load("init", init) == EOK); - proc_stack_push(init, 0); - proc_stack_push(init, 0); current = list_first_data(proc_list_running, init); - _eip = init->regs.eip; - _esp = init->regs.useresp; + _eip = init->entry; + _esp = init->stack.user_ptr; // We'll shortly jump to usermode. Clear and protect every secret! memory_user_hook(); @@ -381,6 +419,5 @@ void proc_init(void) // You're waiting for a train. A train that will take you far away... proc_jump_userspace(); - - panic("Returned from limbo!\n"); + assert_not_reached(); } diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c index 9efb849..93355db 100644 --- a/kernel/features/syscall.c +++ b/kernel/features/syscall.c @@ -1,7 +1,7 @@ // MIT License, Copyright (c) 2020 Marvin Borner #include <drivers/cpu.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <drivers/timer.h> #include <errno.h> #include <fs.h> @@ -15,103 +15,106 @@ #include <sys.h> #include <syscall.h> -static void syscall_handler(struct regs *r) +static u32 syscall_handler(u32 esp) { - enum sys num = r->eax; + struct int_frame_user *frame = (struct int_frame_user *)esp; + enum sys num = frame->eax; - /* printf("[SYSCALL] %d from %s\n", num, proc_current()->name); */ +#if DEBUG_SYSCALLS + printf("[SYSCALL] %d from %s\n", num, proc_current()->name); +#endif switch (num) { // Memory operations case SYS_ALLOC: { - r->eax = memory_sys_alloc(proc_current()->page_dir, r->ebx, (u32 *)r->ecx, - (u32 *)r->edx, (u8)r->esi); + frame->eax = memory_sys_alloc(proc_current()->page_dir, frame->ebx, + (u32 *)frame->ecx, (u32 *)frame->edx, (u8)frame->esi); break; } case SYS_FREE: { - r->eax = memory_sys_free(proc_current()->page_dir, r->ebx); + frame->eax = memory_sys_free(proc_current()->page_dir, frame->ebx); break; } case SYS_SHACCESS: { - r->eax = memory_sys_shaccess(proc_current()->page_dir, r->ebx, (u32 *)r->ecx, - (u32 *)r->edx); + frame->eax = memory_sys_shaccess(proc_current()->page_dir, frame->ebx, + (u32 *)frame->ecx, (u32 *)frame->edx); break; } // File operations case SYS_STAT: { - r->eax = vfs_stat((char *)r->ebx, (struct stat *)r->ecx); + frame->eax = vfs_stat((char *)frame->ebx, (struct stat *)frame->ecx); break; } case SYS_READ: { - r->eax = vfs_read((char *)r->ebx, (void *)r->ecx, r->edx, r->esi); + frame->eax = + vfs_read((char *)frame->ebx, (void *)frame->ecx, frame->edx, frame->esi); break; } case SYS_WRITE: { - r->eax = vfs_write((char *)r->ebx, (void *)r->ecx, r->edx, r->esi); + frame->eax = + vfs_write((char *)frame->ebx, (void *)frame->ecx, frame->edx, frame->esi); break; } // I/O operations case SYS_IOPOLL: { - r->eax = io_poll((void *)r->ebx); + frame->eax = io_poll((void *)frame->ebx); break; } case SYS_IOREAD: { - res ready = io_ready(r->ebx); + res ready = io_ready(frame->ebx); if (ready == -EAGAIN) { - io_block(r->ebx, proc_current()); + io_block(frame->ebx, proc_current()); } else if (ready != EOK) { - r->eax = ready; + frame->eax = ready; break; } - r->eax = io_read(r->ebx, (void *)r->ecx, r->edx, r->esi); + frame->eax = io_read(frame->ebx, (void *)frame->ecx, frame->edx, frame->esi); break; } case SYS_IOWRITE: { - r->eax = io_write(r->ebx, (void *)r->ecx, r->edx, r->esi); + frame->eax = io_write(frame->ebx, (void *)frame->ecx, frame->edx, frame->esi); break; } case SYS_IOCONTROL: { - r->eax = io_control(r->ebx, r->ecx, (void *)r->edx, (void *)r->esi, (void *)r->edi); + frame->eax = io_control(frame->ebx, frame->ecx, (void *)frame->edx, + (void *)frame->esi, (void *)frame->edi); break; } // Process operations case SYS_EXEC: { - char *path = (char *)r->ebx; + char *path = (char *)frame->ebx; struct proc *proc = proc_make(PROC_PRIV_NONE); - r->eax = (u32)elf_load(path, proc); - if (r->eax != EOK) { - proc_exit(proc, r, -r->eax); - } else { - // TODO: Reimplement argc,argv - proc_stack_push(proc, 0); - proc_yield_regs(r); - } + frame->eax = (u32)elf_load(path, proc); + if (frame->eax != EOK) + proc_exit(proc, -frame->eax); + else + proc_yield(); break; } case SYS_EXIT: { - r->eax = EOK; - proc_exit(proc_current(), r, (s32)r->ebx); + frame->eax = EOK; + proc_exit(proc_current(), (s32)frame->ebx); break; } case SYS_YIELD: { - r->eax = EOK; - proc_yield_regs(r); + frame->eax = EOK; + proc_yield(); break; } // System operations case SYS_BOOT: { // TODO: Move - if (r->ebx != SYS_BOOT_MAGIC) { - r->eax = -EINVAL; + if (frame->ebx != SYS_BOOT_MAGIC) { + frame->eax = -EINVAL; break; } if (!proc_super()) { - r->eax = -EACCES; + frame->eax = -EACCES; } - switch (r->ecx) { + switch (frame->ecx) { case SYS_BOOT_REBOOT: print("Rebooting...\n"); outb(0x64, 0xfe); @@ -126,38 +129,36 @@ static void syscall_handler(struct regs *r) __asm__ volatile("cli\nud2"); break; default: - r->eax = -EINVAL; + frame->eax = -EINVAL; } break; } case SYS_MIN: case SYS_MAX: - r->eax = -EINVAL; + frame->eax = -EINVAL; break; - // TODO: Reimplement network functions using VFS default: { - r->eax = -EINVAL; + frame->eax = -EINVAL; printf("Unknown syscall %d!\n", num); break; } } + + return esp; } -// For kernel syscalls (internal) -static void syscall_special_handler(struct regs *r) +// Internal scheduler (=> yield) call +static u32 syscall_special_handler(u32 esp) { - if (RING(r) != 0) - return; - - scheduler(r); + if (proc_current()) + proc_reset_quantum(proc_current()); + return scheduler(esp); } CLEAR void syscall_init(void) { - idt_set_gate(0x7f, (u32)isr127, 0x08, 0x8e); - idt_set_gate(0x80, (u32)isr128, 0x08, 0xee); - isr_install_handler(0x7f, syscall_special_handler); - isr_install_handler(0x80, syscall_handler); + int_special_handler_add(0, syscall_handler); + int_special_handler_add(1, syscall_special_handler); } diff --git a/kernel/inc/drivers/cpu.h b/kernel/inc/drivers/cpu.h index 75e0495..36b8928 100644 --- a/kernel/inc/drivers/cpu.h +++ b/kernel/inc/drivers/cpu.h @@ -4,6 +4,7 @@ #define CPU_H #include <def.h> +#include <proc.h> UNUSED_FUNC static inline void spinlock(u32 *ptr) { @@ -21,9 +22,12 @@ void outb(u16 port, u8 data); void outw(u16 port, u16 data); void outl(u16 port, u32 data); +void fpu_init(struct proc *proc); +void fpu_save(struct proc *proc); +void fpu_restore(struct proc *proc); + void cpu_print(void); void cpu_enable_features(void); -void fpu_restore(void); u32 cr0_get(void); void cr0_set(u32 cr0); @@ -35,9 +39,6 @@ void cr4_set(u32 cr4); void clac(void); void stac(void); -void cli(void); -void sti(void); - struct cpuid { u32 eax; u32 ebx; diff --git a/kernel/inc/drivers/int.h b/kernel/inc/drivers/int.h new file mode 100644 index 0000000..8146898 --- /dev/null +++ b/kernel/inc/drivers/int.h @@ -0,0 +1,52 @@ +// MIT License, Copyright (c) 2020 Marvin Borner + +#ifndef IDT_H +#define IDT_H + +#include <def.h> + +#define INT_GATE 0x8e +#define INT_TRAP 0xef +#define INT_USER 0x60 +#define IDT_ENTRY(offset, selector, type) \ + (struct idt_entry) \ + { \ + .base_low = (u16)((offset)&0xffff), .sel = (selector), .zero = 0, .flags = (type), \ + .base_high = (u16)(((offset) >> 16) & 0xffff), \ + } + +struct int_frame { + u32 gs, fs, es, ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 int_no, err_code; + u32 eip, cs, eflags; +} PACKED; + +struct int_frame_user { + u32 gs, fs, es, ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 int_no, err_code; + u32 eip, cs, eflags; + u32 useresp, ss; +} PACKED; + +struct idt_entry { + u16 base_low; + u16 sel; // Kernel segment + u8 zero; // Always 0 + u8 flags; + u16 base_high; +} PACKED; + +struct idt_ptr { + u16 size; + void *base; +} PACKED; + +void idt_install(void); + +void int_trap_handler_add(u32 int_no, void (*handler)(u32 esp)); +void int_event_handler_add(u32 int_no, void (*handler)(void)); +void int_special_handler_add(u32 int_no, u32 (*handler)(u32 esp)); + +#endif diff --git a/kernel/inc/drivers/interrupts.h b/kernel/inc/drivers/interrupts.h deleted file mode 100644 index 7c0c1e7..0000000 --- a/kernel/inc/drivers/interrupts.h +++ /dev/null @@ -1,95 +0,0 @@ -// MIT License, Copyright (c) 2020 Marvin Borner - -#ifndef IDT_H -#define IDT_H - -#include <def.h> - -struct regs { - u32 gs, fs, es, ds; - u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; - u32 int_no, err_code; - u32 eip, cs, eflags, useresp, ss; -}; - -struct idt_entry { - u16 base_low; - u16 sel; // Kernel segment - u8 always0; // Always 0 - u8 flags; - u16 base_high; -} PACKED; - -struct idt_ptr { - u16 limit; - void *base; -} PACKED; - -void idt_set_gate(u8 num, u32 base, u16 sel, u8 flags); - -void irq_install_handler(int irq, void (*handler)(struct regs *r)) NONNULL; -void irq_uninstall_handler(int irq); - -void isr_install_handler(int isr, void (*handler)(struct regs *r)) NONNULL; -void isr_uninstall_handler(int isr); -void isr_panic(struct regs *r) NONNULL; - -void interrupts_install(void); - -// External handlers (ASM) - -extern void isr0(struct regs *r); -extern void isr1(struct regs *r); -extern void isr2(struct regs *r); -extern void isr3(struct regs *r); -extern void isr4(struct regs *r); -extern void isr5(struct regs *r); -extern void isr6(struct regs *r); -extern void isr7(struct regs *r); -extern void isr8(struct regs *r); -extern void isr9(struct regs *r); -extern void isr10(struct regs *r); -extern void isr11(struct regs *r); -extern void isr12(struct regs *r); -extern void isr13(struct regs *r); -extern void isr14(struct regs *r); -extern void isr15(struct regs *r); -extern void isr16(struct regs *r); -extern void isr17(struct regs *r); -extern void isr18(struct regs *r); -extern void isr19(struct regs *r); -extern void isr20(struct regs *r); -extern void isr21(struct regs *r); -extern void isr22(struct regs *r); -extern void isr23(struct regs *r); -extern void isr24(struct regs *r); -extern void isr25(struct regs *r); -extern void isr26(struct regs *r); -extern void isr27(struct regs *r); -extern void isr28(struct regs *r); -extern void isr29(struct regs *r); -extern void isr30(struct regs *r); -extern void isr31(struct regs *r); -extern void isr127(struct regs *r); -extern void isr128(struct regs *r); - -extern void irq0(struct regs *r); -extern void irq1(struct regs *r); -extern void irq2(struct regs *r); -extern void irq3(struct regs *r); -extern void irq4(struct regs *r); -extern void irq5(struct regs *r); -extern void irq6(struct regs *r); -extern void irq7(struct regs *r); -extern void irq8(struct regs *r); -extern void irq9(struct regs *r); -extern void irq10(struct regs *r); -extern void irq11(struct regs *r); -extern void irq12(struct regs *r); -extern void irq13(struct regs *r); -extern void irq14(struct regs *r); -extern void irq15(struct regs *r); -extern void irq127(struct regs *r); -extern void irq128(struct regs *r); - -#endif diff --git a/kernel/inc/drivers/pic.h b/kernel/inc/drivers/pic.h new file mode 100644 index 0000000..c2a7d87 --- /dev/null +++ b/kernel/inc/drivers/pic.h @@ -0,0 +1,11 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef PIC_H +#define PIC_H + +#include <def.h> + +void pic_install(void); +void pic_ack(u32 int_no); + +#endif diff --git a/kernel/inc/drivers/timer.h b/kernel/inc/drivers/timer.h index 9ff23f8..ea1643b 100644 --- a/kernel/inc/drivers/timer.h +++ b/kernel/inc/drivers/timer.h @@ -4,14 +4,9 @@ #define TIMER_H #include <def.h> -#include <drivers/interrupts.h> u32 timer_get(void); void timer_wait(u32 ticks); void timer_install(void); -void timer_handler(struct regs *r) NONNULL; - -void scheduler_enable(void); -void scheduler_disable(void); #endif diff --git a/kernel/inc/io.h b/kernel/inc/io.h index 275fcae..c20a6f7 100644 --- a/kernel/inc/io.h +++ b/kernel/inc/io.h @@ -4,7 +4,7 @@ #define IO_H #include <def.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <proc.h> #include <sys.h> diff --git a/kernel/inc/mm.h b/kernel/inc/mm.h index 0a2bb81..4f3f537 100644 --- a/kernel/inc/mm.h +++ b/kernel/inc/mm.h @@ -4,7 +4,7 @@ #define PAGING_H #include <def.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <errno.h> struct memory_range { @@ -18,7 +18,6 @@ struct memory_range { void paging_disable(void); void paging_enable(void); -void page_fault_handler(struct regs *r) NONNULL; /** * Physical diff --git a/kernel/inc/proc.h b/kernel/inc/proc.h index 1144782..b8310d1 100644 --- a/kernel/inc/proc.h +++ b/kernel/inc/proc.h @@ -4,12 +4,12 @@ #define PROC_H #include <def.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <list.h> #include <stack.h> #include <sys.h> -#define PROC_QUANTUM 42 // Milliseconds or something // TODO +#define PROC_QUANTUM 15 // Milliseconds or something // TODO #define PROC_STACK_SIZE 0x4000 // 16KiB #define EFLAGS_ALWAYS 0x2 // Always one @@ -26,8 +26,8 @@ struct proc { char name[64]; char dir[64]; + u8 fpu[512]; struct page_dir *page_dir; - struct regs regs; enum proc_priv priv; enum proc_state state; struct stack *messages; @@ -37,7 +37,9 @@ struct proc { struct { u32 user; + u32 user_ptr; u32 kernel; + u32 kernel_ptr; } stack; struct { @@ -51,20 +53,21 @@ struct proc { } quantum; }; -void scheduler(struct regs *regs) NONNULL; +u32 scheduler(u32 esp); NORETURN void proc_init(void); void proc_print(void); struct proc *proc_current(void); u8 proc_super(void); u8 proc_idle(void); struct proc *proc_from_pid(u32 pid); -void proc_exit(struct proc *proc, struct regs *r, s32 status) NONNULL; +void proc_exit(struct proc *proc, s32 status) NONNULL; void proc_yield(void); -void proc_yield_regs(struct regs *r) NONNULL; -void proc_set_quantum(struct proc *proc, u32 value); -void proc_reset_quantum(struct proc *proc); -void proc_state(struct proc *proc, enum proc_state state); +void proc_set_quantum(struct proc *proc, u32 value) NONNULL; +void proc_reset_quantum(struct proc *proc) NONNULL; +void proc_state(struct proc *proc, enum proc_state state) NONNULL; struct proc *proc_make(enum proc_priv priv); -void proc_stack_push(struct proc *proc, u32 data) NONNULL; +void proc_make_regs(struct proc *proc); +void proc_stack_user_push(struct proc *proc, const void *data, u32 size) NONNULL; +void proc_stack_kernel_push(struct proc *proc, const void *data, u32 size) NONNULL; #endif diff --git a/kernel/main.c b/kernel/main.c index 44198e4..d6e7727 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -3,8 +3,9 @@ #include <drivers/cpu.h> #include <drivers/gdt.h> #include <drivers/ide.h> -#include <drivers/interrupts.h> +#include <drivers/int.h> #include <drivers/pci.h> +#include <drivers/pic.h> #include <drivers/rtc.h> #include <drivers/serial.h> #include <fs.h> @@ -39,12 +40,10 @@ int kernel_main(u32 magic, u32 addr, u32 esp) vfs_install(); ata_install(); pci_install(); - interrupts_install(); + pic_install(); + idt_install(); io_install(); - // Enable drivers - sti(); - syscall_init(); proc_init(); diff --git a/libs/libc/alloc.c b/libs/libc/alloc.c index 6663a0e..f02b015 100644 --- a/libs/libc/alloc.c +++ b/libs/libc/alloc.c @@ -91,9 +91,9 @@ static struct liballoc_major *allocate_new_page(u32 size) u32 st = size + MAJOR_SIZE + MINOR_SIZE; if ((st % l_page_size) == 0) - st = st / (l_page_size); + st = st / l_page_size; else - st = st / (l_page_size) + 1; + st = st / l_page_size + 1; st = MAX(st, l_page_count); diff --git a/libs/libc/inc/assert.h b/libs/libc/inc/assert.h index 6b35dd3..178a733 100644 --- a/libs/libc/inc/assert.h +++ b/libs/libc/inc/assert.h @@ -12,7 +12,8 @@ if (!(exp)) { \ printf("%s:%d: %s: Kernel assertion '%s' failed\n", __FILE__, __LINE__, \ __func__, #exp); \ - __asm__ volatile("cli\nhlt"); \ + while (1) \ + __asm__ volatile("cli\nhlt"); \ } \ } #elif defined(USER) @@ -25,4 +26,7 @@ } #endif +#define assert_not_reached() \ + panic("%s:%d: %s: Reached code that should not be reached\n", __FILE__, __LINE__, __func__) + #endif diff --git a/libs/libc/print.c b/libs/libc/print.c index 264f893..7c40a8b 100644 --- a/libs/libc/print.c +++ b/libs/libc/print.c @@ -194,9 +194,10 @@ int printf(const char *format, ...) int print_prefix(void) { - serial_print(CYN "[LOG] to "); - serial_print(proc_current()->name); - serial_print(": "); + char buf[64] = { 0 }; + snprintf(buf, sizeof(buf), CYN "[LOG] to %s (%d): ", proc_current()->name, + proc_current()->pid); + serial_print(buf); return 1; } diff --git a/libs/libc/sanitize.c b/libs/libc/sanitize.c index 00c9032..ee3c154 100644 --- a/libs/libc/sanitize.c +++ b/libs/libc/sanitize.c @@ -56,6 +56,10 @@ struct overflow { struct type_descriptor *type; }; +struct pointer_overflow { + struct source_location location; +}; + struct out_of_bounds { struct source_location location; struct type_descriptor *left_type; @@ -224,8 +228,10 @@ void __ubsan_handle_invalid_builtin(void) panic("UBSAN: invalid-builtin\n"); } -void __ubsan_handle_pointer_overflow(void); -void __ubsan_handle_pointer_overflow(void) +void __ubsan_handle_pointer_overflow(struct pointer_overflow *data, void *value); +void __ubsan_handle_pointer_overflow(struct pointer_overflow *data, void *value) { - panic("UBSAN: pointer-overflow\n"); + UNUSED(value); + struct source_location *loc = &data->location; + panic("%s:%d: UBSAN: pointer-overflow\n", loc->file, loc->line); } |