summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2018-10-19 11:28:43 +0200
committerAndreas Kling <awesomekling@gmail.com>2018-10-19 11:31:18 +0200
commit46ff281695fc6daa1897de4f4693c7407abaced0 (patch)
tree8ff418e135ca3597f292f2e89aefb8b5e9854d35 /Kernel
parent2d1d01661b0c21fad05532f8a0bbfe0efbe2663a (diff)
downloadserenity-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.cpp16
-rw-r--r--Kernel/i386.cpp65
-rw-r--r--Kernel/i386.h4
-rw-r--r--Kernel/i8253.cpp12
-rw-r--r--Kernel/init.cpp34
-rw-r--r--Kernel/panel.cpp10
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"(&current->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 );
}