diff options
author | Andreas Kling <awesomekling@gmail.com> | 2018-10-19 11:28:43 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2018-10-19 11:31:18 +0200 |
commit | 46ff281695fc6daa1897de4f4693c7407abaced0 (patch) | |
tree | 8ff418e135ca3597f292f2e89aefb8b5e9854d35 /Kernel | |
parent | 2d1d01661b0c21fad05532f8a0bbfe0efbe2663a (diff) | |
download | serenity-46ff281695fc6daa1897de4f4693c7407abaced0.zip |
Turn the syscall interrupt into a trap (by switching the gate type.)
This leaves interrupts enabled while we're in the kernel, which is
precisely what we want.
This uncovered a horrendous problem with kernel tasks silently
overflowing their stacks. For now I've simply increased the stack size
but I need a more MMU-y solution for this eventually.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Task.cpp | 16 | ||||
-rw-r--r-- | Kernel/i386.cpp | 65 | ||||
-rw-r--r-- | Kernel/i386.h | 4 | ||||
-rw-r--r-- | Kernel/i8253.cpp | 12 | ||||
-rw-r--r-- | Kernel/init.cpp | 34 | ||||
-rw-r--r-- | Kernel/panel.cpp | 10 |
6 files changed, 116 insertions, 25 deletions
diff --git a/Kernel/Task.cpp b/Kernel/Task.cpp index 2c69ad929f..ea80ad97ba 100644 --- a/Kernel/Task.cpp +++ b/Kernel/Task.cpp @@ -162,13 +162,14 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring) kprintf("basically ready\n"); - // NOTE: Each task gets 4KB of stack. - static const DWORD defaultStackSize = 4096; + // NOTE: Each task gets 16KB of stack. + static const DWORD defaultStackSize = 16384; if (isRing0()) { // FIXME: This memory is leaked. // But uh, there's also no kernel task termination, so I guess it's not technically leaked... - m_stackTop = ((DWORD)kmalloc(defaultStackSize) + defaultStackSize) & 0xffffff8; + dword stackBottom = (dword)kmalloc(defaultStackSize); + m_stackTop = (stackBottom + defaultStackSize) & 0xffffff8; m_tss.esp = m_stackTop; } else { auto* region = allocateRegion(defaultStackSize, "stack"); @@ -235,8 +236,8 @@ void Task::dumpRegions() void Task::taskDidCrash(Task* crashedTask) { + // NOTE: This is called from an excepton handler, so interrupts are disabled. crashedTask->setState(Crashing); - crashedTask->dumpRegions(); s_tasks->remove(crashedTask); @@ -260,8 +261,11 @@ void yield() //kprintf("%s<%u> yield()\n", current->name().characters(), current->pid()); - if (!scheduleNewTask()) + cli(); + if (!scheduleNewTask()) { + sti(); return; + } //kprintf("yield() jumping to new task: %x (%s)\n", current->farPtr().selector, current->name().characters()); switchNow(); @@ -272,7 +276,7 @@ void switchNow() Descriptor& descriptor = getGDTEntry(current->selector()); descriptor.type = 9; flushGDT(); - asm( + asm("sti\n" "ljmp *(%%eax)\n" ::"a"(¤t->farPtr()) ); diff --git a/Kernel/i386.cpp b/Kernel/i386.cpp index 99db7cd24e..233ebc1d11 100644 --- a/Kernel/i386.cpp +++ b/Kernel/i386.cpp @@ -68,6 +68,67 @@ asm( \ " iret\n" \ ); +#define EH_ENTRY_NO_CODE(ec) \ +extern "C" void exception_ ## ec ## _handler(); \ +extern "C" void exception_ ## ec ## _entry(); \ +asm( \ + ".globl exception_" # ec "_entry\n" \ + "exception_" # ec "_entry: \n" \ + " pusha\n" \ + " pushw %ds\n" \ + " pushw %es\n" \ + " pushw %fs\n" \ + " pushw %gs\n" \ + " pushw %ss\n" \ + " pushw %ss\n" \ + " pushw %ss\n" \ + " pushw %ss\n" \ + " popw %ds\n" \ + " popw %es\n" \ + " popw %fs\n" \ + " popw %gs\n" \ + " mov %esp, exception_state_dump\n" \ + " call exception_" # ec "_handler\n" \ + " popw %gs\n" \ + " popw %fs\n" \ + " popw %es\n" \ + " popw %ds\n" \ + " popa\n" \ + " iret\n" \ +); + +// 6: Invalid Opcode +EH_ENTRY_NO_CODE(6); +void exception_6_handler() +{ + auto& regs = *reinterpret_cast<RegisterDump*>(exception_state_dump); + kprintf("%s invalid opcode: %u(%s)\n", current->isRing0() ? "Kernel" : "Process", current->pid(), current->name().characters()); + + word ss; + dword esp; + if (current->isRing0()) { + ss = regs.ds; + esp = regs.esp; + } else { + ss = regs.ss_if_crossRing; + esp = regs.esp_if_crossRing; + } + + kprintf("exception code: %w\n", exception_code); + kprintf("pc=%w:%x ds=%w es=%w fs=%w gs=%w\n", regs.cs, regs.eip, regs.ds, regs.es, regs.fs, regs.gs); + kprintf("eax=%x ebx=%x ecx=%x edx=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx); + kprintf("ebp=%x esp=%x esi=%x edi=%x\n", regs.ebp, esp, regs.esi, regs.edi); + + if (current->isRing0()) { + kprintf("Oh shit, we've crashed in ring 0 :(\n"); + HANG; + } + HANG; + + // NOTE: This will schedule a new task. + Task::taskDidCrash(current); +} + // 13: General Protection Fault EH_ENTRY(13); void exception_13_handler() @@ -239,7 +300,7 @@ void registerInterruptHandler(BYTE index, void (*f)()) void registerUserCallableInterruptHandler(BYTE index, void (*f)()) { s_idt[index].low = 0x00080000 | LSW((f)); - s_idt[index].high = ((DWORD)(f) & 0xffff0000) | 0xee00; + s_idt[index].high = ((DWORD)(f) & 0xffff0000) | 0xef00; flushIDT(); } @@ -276,7 +337,7 @@ void idt_init() registerInterruptHandler(0x03, _exception3); registerInterruptHandler(0x04, _exception4); registerInterruptHandler(0x05, _exception5); - registerInterruptHandler(0x06, _exception6); + registerInterruptHandler(0x06, exception_6_entry); registerInterruptHandler(0x07, _exception7); registerInterruptHandler(0x08, _exception8); registerInterruptHandler(0x09, _exception9); diff --git a/Kernel/i386.h b/Kernel/i386.h index 73c23e5fbf..666a026a7c 100644 --- a/Kernel/i386.h +++ b/Kernel/i386.h @@ -72,8 +72,8 @@ void writeGDTEntry(WORD selector, Descriptor&); #define LSB(x) ((x) & 0xFF) #define MSB(x) (((x)>>8) & 0xFF) -#define disableInterrupts() asm volatile("cli"); -#define enableInterrupts() asm volatile("sti"); +#define cli() asm volatile("cli") +#define sti() asm volatile("sti") /* Map IRQ0-15 @ ISR 0x50-0x5F */ #define IRQ_VECTOR_BASE 0x50 diff --git a/Kernel/i8253.cpp b/Kernel/i8253.cpp index 86319bb135..0f603b4410 100644 --- a/Kernel/i8253.cpp +++ b/Kernel/i8253.cpp @@ -98,11 +98,12 @@ void clock_handle() WORD foo = vga_get_cursor(); vga_set_attr(0x50); - vga_set_cursor(1600); + vga_set_cursor(0); - kprintf("Task %u interrupted at %x\n", current->pid(), regs.eip ); - kprintf("EAX=%x EBX=%x ECX=%x EDX=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx); - kprintf("ESI=%x EDI=%x EBP=%x ESP=%x\n", regs.esi, regs.edi, regs.ebp, regs.esp); + kprintf("\n\n"); + kprintf("Task %u interrupted at %x \n", current->pid(), regs.eip ); + kprintf("EAX=%x EBX=%x ECX=%x EDX=%x \n", regs.eax, regs.ebx, regs.ecx, regs.edx); + kprintf("ESI=%x EDI=%x EBP=%x ESP=%x \n", regs.esi, regs.edi, regs.ebp, regs.esp); kprintf("FLAGS=%x", regs.eflags); vga_set_cursor(foo); @@ -111,6 +112,9 @@ void clock_handle() // Compute task ESP. // Add 12 for CS, EIP, EFLAGS (interrupt mechanic) + + // FIXME: Hmm. Should we add an extra 8 here for SS:ESP in some cases? + // If this IRQ occurred while in a user task, wouldn't that also push the stack ptr? current->tss().esp = regs.esp + 12; // Prepare a new task to run; diff --git a/Kernel/init.cpp b/Kernel/init.cpp index 85f6dbb537..5ab81f4005 100644 --- a/Kernel/init.cpp +++ b/Kernel/init.cpp @@ -25,6 +25,9 @@ #include "MemoryManager.h" #include <ELFLoader/ELFLoader.h> +#define TEST_ELF_LOADER +#define TEST_CRASHY_USER_PROCESSES + #if 0 /* Keyboard LED disco task ;^) */ @@ -63,6 +66,18 @@ static void motd_main() } } +static void syscall_test_main() NORETURN; +static void syscall_test_main() +{ + kprintf("Hello in syscall_test_main!\n"); + for (;;) { + Userspace::getuid(); +// Userspace::yield(); + //kprintf("getuid(): %u\n", Userspace::getuid()); + sleep(1 * TICKS_PER_SECOND); + } +} + static void user_main() NORETURN; static void user_main() { @@ -106,7 +121,7 @@ void banner() void init() { - disableInterrupts(); + cli(); kmalloc_init(); vga_init(); @@ -123,6 +138,8 @@ void init() Keyboard::initialize(); Task::initialize(); + VirtualFileSystem::initializeGlobals(); + memset(&system, 0, sizeof(system)); WORD base_memory = (CMOS::read(0x16) << 8) | CMOS::read(0x15); @@ -138,12 +155,12 @@ void init() //new Task(led_disco, "led-disco", IPC::Handle::Any, Task::Ring0); scheduleNewTask(); - enableInterrupts(); - banner(); + sti(); Disk::initialize(); +#if 1 auto vfs = make<VirtualFileSystem>(); auto dev_zero = make<ZeroDevice>(); @@ -164,11 +181,13 @@ void init() vfs->mountRoot(e2fs.copyRef()); - //new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0); +#ifdef TEST_CRASHY_USER_PROCESSES new Task(user_main, "user", IPC::Handle::UserTask, Task::Ring3); new Task(user_kprintf_main, "user_kprintf", IPC::Handle::UserTask, Task::Ring3); +#endif //vfs->listDirectory("/"); +#endif #if 1 { @@ -182,6 +201,7 @@ void init() } #endif +#ifdef TEST_ELF_LOADER { auto testExecutable = vfs->open("/_hello.o"); ASSERT(testExecutable); @@ -197,9 +217,11 @@ void init() kprintf("elf_entry: %p\n", elf_entry); int rc = reinterpret_cast<MainFunctionPtr>(elf_entry)(); kprintf("it returned %d\n", rc); - - HANG; } +#endif + + new Task(motd_main, "motd", IPC::Handle::MotdTask, Task::Ring0); + new Task(syscall_test_main, "syscall_test", IPC::Handle::MotdTask, Task::Ring0); // The idle task will spend its eternity here for now. for (;;) { diff --git a/Kernel/panel.cpp b/Kernel/panel.cpp index 2a127619a6..360737f1df 100644 --- a/Kernel/panel.cpp +++ b/Kernel/panel.cpp @@ -16,12 +16,12 @@ panel_main() for( ;; ) { - c = vga_get_cursor(); - a = vga_get_attr(); - /* HACK: Avoid getting interrupted while painting since * that could lead to fugly artifacts ;P */ - disableInterrupts(); + cli(); + + c = vga_get_cursor(); + a = vga_get_attr(); vga_set_attr( 0x17 ); vga_set_cursor( 80 * 24 ); @@ -39,7 +39,7 @@ panel_main() vga_set_cursor( c ); /* HACK cont.d */ - enableInterrupts(); + sti(); sleep( 1 * TICKS_PER_SECOND ); } |