mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 15:07:45 +00:00
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.
This commit is contained in:
parent
2d1d01661b
commit
46ff281695
6 changed files with 116 additions and 25 deletions
|
@ -162,13 +162,14 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||||
|
|
||||||
kprintf("basically ready\n");
|
kprintf("basically ready\n");
|
||||||
|
|
||||||
// NOTE: Each task gets 4KB of stack.
|
// NOTE: Each task gets 16KB of stack.
|
||||||
static const DWORD defaultStackSize = 4096;
|
static const DWORD defaultStackSize = 16384;
|
||||||
|
|
||||||
if (isRing0()) {
|
if (isRing0()) {
|
||||||
// FIXME: This memory is leaked.
|
// FIXME: This memory is leaked.
|
||||||
// But uh, there's also no kernel task termination, so I guess it's not technically 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;
|
m_tss.esp = m_stackTop;
|
||||||
} else {
|
} else {
|
||||||
auto* region = allocateRegion(defaultStackSize, "stack");
|
auto* region = allocateRegion(defaultStackSize, "stack");
|
||||||
|
@ -235,8 +236,8 @@ void Task::dumpRegions()
|
||||||
|
|
||||||
void Task::taskDidCrash(Task* crashedTask)
|
void Task::taskDidCrash(Task* crashedTask)
|
||||||
{
|
{
|
||||||
|
// NOTE: This is called from an excepton handler, so interrupts are disabled.
|
||||||
crashedTask->setState(Crashing);
|
crashedTask->setState(Crashing);
|
||||||
|
|
||||||
crashedTask->dumpRegions();
|
crashedTask->dumpRegions();
|
||||||
|
|
||||||
s_tasks->remove(crashedTask);
|
s_tasks->remove(crashedTask);
|
||||||
|
@ -260,8 +261,11 @@ void yield()
|
||||||
|
|
||||||
//kprintf("%s<%u> yield()\n", current->name().characters(), current->pid());
|
//kprintf("%s<%u> yield()\n", current->name().characters(), current->pid());
|
||||||
|
|
||||||
if (!scheduleNewTask())
|
cli();
|
||||||
|
if (!scheduleNewTask()) {
|
||||||
|
sti();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//kprintf("yield() jumping to new task: %x (%s)\n", current->farPtr().selector, current->name().characters());
|
//kprintf("yield() jumping to new task: %x (%s)\n", current->farPtr().selector, current->name().characters());
|
||||||
switchNow();
|
switchNow();
|
||||||
|
@ -272,7 +276,7 @@ void switchNow()
|
||||||
Descriptor& descriptor = getGDTEntry(current->selector());
|
Descriptor& descriptor = getGDTEntry(current->selector());
|
||||||
descriptor.type = 9;
|
descriptor.type = 9;
|
||||||
flushGDT();
|
flushGDT();
|
||||||
asm(
|
asm("sti\n"
|
||||||
"ljmp *(%%eax)\n"
|
"ljmp *(%%eax)\n"
|
||||||
::"a"(¤t->farPtr())
|
::"a"(¤t->farPtr())
|
||||||
);
|
);
|
||||||
|
|
|
@ -68,6 +68,67 @@ asm( \
|
||||||
" iret\n" \
|
" 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
|
// 13: General Protection Fault
|
||||||
EH_ENTRY(13);
|
EH_ENTRY(13);
|
||||||
void exception_13_handler()
|
void exception_13_handler()
|
||||||
|
@ -239,7 +300,7 @@ void registerInterruptHandler(BYTE index, void (*f)())
|
||||||
void registerUserCallableInterruptHandler(BYTE index, void (*f)())
|
void registerUserCallableInterruptHandler(BYTE index, void (*f)())
|
||||||
{
|
{
|
||||||
s_idt[index].low = 0x00080000 | LSW((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();
|
flushIDT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +337,7 @@ void idt_init()
|
||||||
registerInterruptHandler(0x03, _exception3);
|
registerInterruptHandler(0x03, _exception3);
|
||||||
registerInterruptHandler(0x04, _exception4);
|
registerInterruptHandler(0x04, _exception4);
|
||||||
registerInterruptHandler(0x05, _exception5);
|
registerInterruptHandler(0x05, _exception5);
|
||||||
registerInterruptHandler(0x06, _exception6);
|
registerInterruptHandler(0x06, exception_6_entry);
|
||||||
registerInterruptHandler(0x07, _exception7);
|
registerInterruptHandler(0x07, _exception7);
|
||||||
registerInterruptHandler(0x08, _exception8);
|
registerInterruptHandler(0x08, _exception8);
|
||||||
registerInterruptHandler(0x09, _exception9);
|
registerInterruptHandler(0x09, _exception9);
|
||||||
|
|
|
@ -72,8 +72,8 @@ void writeGDTEntry(WORD selector, Descriptor&);
|
||||||
#define LSB(x) ((x) & 0xFF)
|
#define LSB(x) ((x) & 0xFF)
|
||||||
#define MSB(x) (((x)>>8) & 0xFF)
|
#define MSB(x) (((x)>>8) & 0xFF)
|
||||||
|
|
||||||
#define disableInterrupts() asm volatile("cli");
|
#define cli() asm volatile("cli")
|
||||||
#define enableInterrupts() asm volatile("sti");
|
#define sti() asm volatile("sti")
|
||||||
|
|
||||||
/* Map IRQ0-15 @ ISR 0x50-0x5F */
|
/* Map IRQ0-15 @ ISR 0x50-0x5F */
|
||||||
#define IRQ_VECTOR_BASE 0x50
|
#define IRQ_VECTOR_BASE 0x50
|
||||||
|
|
|
@ -98,11 +98,12 @@ void clock_handle()
|
||||||
WORD foo = vga_get_cursor();
|
WORD foo = vga_get_cursor();
|
||||||
|
|
||||||
vga_set_attr(0x50);
|
vga_set_attr(0x50);
|
||||||
vga_set_cursor(1600);
|
vga_set_cursor(0);
|
||||||
|
|
||||||
kprintf("Task %u interrupted at %x\n", current->pid(), regs.eip );
|
kprintf("\n\n");
|
||||||
kprintf("EAX=%x EBX=%x ECX=%x EDX=%x\n", regs.eax, regs.ebx, regs.ecx, regs.edx);
|
kprintf("Task %u interrupted at %x \n", current->pid(), regs.eip );
|
||||||
kprintf("ESI=%x EDI=%x EBP=%x ESP=%x\n", regs.esi, regs.edi, regs.ebp, regs.esp);
|
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);
|
kprintf("FLAGS=%x", regs.eflags);
|
||||||
|
|
||||||
vga_set_cursor(foo);
|
vga_set_cursor(foo);
|
||||||
|
@ -111,6 +112,9 @@ void clock_handle()
|
||||||
|
|
||||||
// Compute task ESP.
|
// Compute task ESP.
|
||||||
// Add 12 for CS, EIP, EFLAGS (interrupt mechanic)
|
// 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;
|
current->tss().esp = regs.esp + 12;
|
||||||
|
|
||||||
// Prepare a new task to run;
|
// Prepare a new task to run;
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
#include "MemoryManager.h"
|
#include "MemoryManager.h"
|
||||||
#include <ELFLoader/ELFLoader.h>
|
#include <ELFLoader/ELFLoader.h>
|
||||||
|
|
||||||
|
#define TEST_ELF_LOADER
|
||||||
|
#define TEST_CRASHY_USER_PROCESSES
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Keyboard LED disco task ;^) */
|
/* 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() NORETURN;
|
||||||
static void user_main()
|
static void user_main()
|
||||||
{
|
{
|
||||||
|
@ -106,7 +121,7 @@ void banner()
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
disableInterrupts();
|
cli();
|
||||||
|
|
||||||
kmalloc_init();
|
kmalloc_init();
|
||||||
vga_init();
|
vga_init();
|
||||||
|
@ -123,6 +138,8 @@ void init()
|
||||||
Keyboard::initialize();
|
Keyboard::initialize();
|
||||||
Task::initialize();
|
Task::initialize();
|
||||||
|
|
||||||
|
VirtualFileSystem::initializeGlobals();
|
||||||
|
|
||||||
memset(&system, 0, sizeof(system));
|
memset(&system, 0, sizeof(system));
|
||||||
|
|
||||||
WORD base_memory = (CMOS::read(0x16) << 8) | CMOS::read(0x15);
|
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);
|
//new Task(led_disco, "led-disco", IPC::Handle::Any, Task::Ring0);
|
||||||
|
|
||||||
scheduleNewTask();
|
scheduleNewTask();
|
||||||
enableInterrupts();
|
|
||||||
|
|
||||||
banner();
|
banner();
|
||||||
|
sti();
|
||||||
|
|
||||||
Disk::initialize();
|
Disk::initialize();
|
||||||
|
|
||||||
|
#if 1
|
||||||
auto vfs = make<VirtualFileSystem>();
|
auto vfs = make<VirtualFileSystem>();
|
||||||
|
|
||||||
auto dev_zero = make<ZeroDevice>();
|
auto dev_zero = make<ZeroDevice>();
|
||||||
|
@ -164,11 +181,13 @@ void init()
|
||||||
|
|
||||||
vfs->mountRoot(e2fs.copyRef());
|
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_main, "user", IPC::Handle::UserTask, Task::Ring3);
|
||||||
new Task(user_kprintf_main, "user_kprintf", IPC::Handle::UserTask, Task::Ring3);
|
new Task(user_kprintf_main, "user_kprintf", IPC::Handle::UserTask, Task::Ring3);
|
||||||
|
#endif
|
||||||
|
|
||||||
//vfs->listDirectory("/");
|
//vfs->listDirectory("/");
|
||||||
|
#endif
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
{
|
{
|
||||||
|
@ -182,6 +201,7 @@ void init()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_ELF_LOADER
|
||||||
{
|
{
|
||||||
auto testExecutable = vfs->open("/_hello.o");
|
auto testExecutable = vfs->open("/_hello.o");
|
||||||
ASSERT(testExecutable);
|
ASSERT(testExecutable);
|
||||||
|
@ -197,9 +217,11 @@ void init()
|
||||||
kprintf("elf_entry: %p\n", elf_entry);
|
kprintf("elf_entry: %p\n", elf_entry);
|
||||||
int rc = reinterpret_cast<MainFunctionPtr>(elf_entry)();
|
int rc = reinterpret_cast<MainFunctionPtr>(elf_entry)();
|
||||||
kprintf("it returned %d\n", rc);
|
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.
|
// The idle task will spend its eternity here for now.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
|
@ -16,12 +16,12 @@ panel_main()
|
||||||
|
|
||||||
for( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
c = vga_get_cursor();
|
|
||||||
a = vga_get_attr();
|
|
||||||
|
|
||||||
/* HACK: Avoid getting interrupted while painting since
|
/* HACK: Avoid getting interrupted while painting since
|
||||||
* that could lead to fugly artifacts ;P */
|
* that could lead to fugly artifacts ;P */
|
||||||
disableInterrupts();
|
cli();
|
||||||
|
|
||||||
|
c = vga_get_cursor();
|
||||||
|
a = vga_get_attr();
|
||||||
|
|
||||||
vga_set_attr( 0x17 );
|
vga_set_attr( 0x17 );
|
||||||
vga_set_cursor( 80 * 24 );
|
vga_set_cursor( 80 * 24 );
|
||||||
|
@ -39,7 +39,7 @@ panel_main()
|
||||||
vga_set_cursor( c );
|
vga_set_cursor( c );
|
||||||
|
|
||||||
/* HACK cont.d */
|
/* HACK cont.d */
|
||||||
enableInterrupts();
|
sti();
|
||||||
|
|
||||||
sleep( 1 * TICKS_PER_SECOND );
|
sleep( 1 * TICKS_PER_SECOND );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue