diff --git a/kernel/Makefile b/kernel/Makefile index c14857e6..9739f608 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -50,7 +50,6 @@ ifdef X86FAMILY x86-family/gdt.o \ x86-family/idt.o \ $(CPU)/syscall.o \ - $(CPU)/thread.o \ $(CPU)/process.o \ x86-family/cmos.o \ x86-family/time.o \ diff --git a/kernel/include/sortix/kernel/kthread.h b/kernel/include/sortix/kernel/kthread.h index 61d08efd..af9e3467 100644 --- a/kernel/include/sortix/kernel/kthread.h +++ b/kernel/include/sortix/kernel/kthread.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2014. This file is part of Sortix. @@ -34,7 +34,7 @@ namespace Sortix { extern "C" { inline static void kthread_yield(void) { asm volatile ("int $129"); } -__attribute__((noreturn)) void kthread_exit(void* param = NULL); +__attribute__((noreturn)) void kthread_exit(); typedef unsigned kthread_mutex_t; const kthread_mutex_t KTHREAD_MUTEX_INITIALIZER = 0; unsigned kthread_mutex_trylock(kthread_mutex_t* mutex); diff --git a/kernel/include/sortix/kernel/thread.h b/kernel/include/sortix/kernel/thread.h index 1c266d4f..bd324f06 100644 --- a/kernel/include/sortix/kernel/thread.h +++ b/kernel/include/sortix/kernel/thread.h @@ -34,59 +34,39 @@ #include #include -typedef struct multiboot_info multiboot_info_t; - namespace Sortix { class Process; class Thread; -extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo); - -typedef void (*ThreadEntry)(void* user); - -// Simply exits the kernel thread. -__attribute__((noreturn)) void KernelThreadExit(); - -// Internally used as a kernel thread entry point that exits the thread -// upon the actual thread entry returning. -extern "C" __attribute__((noreturn)) -void BootstrapKernelThread(void* user, ThreadEntry entry); - // These functions create a new kernel process but doesn't start it. Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs, unsigned long fsbase, unsigned long gsbase); -Thread* CreateKernelThread(Process* process, ThreadEntry entry, void* user, +Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user, size_t stacksize = 0); -Thread* CreateKernelThread(ThreadEntry entry, void* user, size_t stacksize = 0); +Thread* CreateKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0); // This function can be used to start a thread from the above functions. void StartKernelThread(Thread* thread); // Alternatively, these functions both create and start the thread. Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs); -Thread* RunKernelThread(Process* process, ThreadEntry entry, void* user, +Thread* RunKernelThread(Process* process, void (*entry)(void*), void* user, size_t stacksize = 0); -Thread* RunKernelThread(ThreadEntry entry, void* user, size_t stacksize = 0); - -void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, ThreadEntry entry, - void* user, addr_t stack, size_t stacksize); +Thread* RunKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0); class Thread { friend Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs, unsigned long fsbase, unsigned long gsbase); -friend void KernelInit(unsigned long magic, multiboot_info_t* bootinfo); friend void UpdatePendingSignals(Thread* thread); public: static void Init(); -private: - Thread(); - public: + Thread(); ~Thread(); public: diff --git a/kernel/kthread.cpp b/kernel/kthread.cpp index 4e8a1b16..98cb2d3f 100644 --- a/kernel/kthread.cpp +++ b/kernel/kthread.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2014. This file is part of Sortix. @@ -42,7 +42,7 @@ static void kthread_do_kill_thread(void* user) delete thread; } -extern "C" void kthread_exit(void* /*param*/) +extern "C" void kthread_exit() { Worker::Schedule(kthread_do_kill_thread, CurrentThread()); Scheduler::ExitThread(); diff --git a/kernel/thread.cpp b/kernel/thread.cpp index 1d729171..c7eecefe 100644 --- a/kernel/thread.cpp +++ b/kernel/thread.cpp @@ -82,6 +82,100 @@ Thread::~Thread() delete[] (uint8_t*) kernelstackpos; } +void Thread::SaveRegisters(const CPU::InterruptRegisters* src) +{ +#if defined(__i386__) + registers.eip = src->eip; + registers.esp = src->esp; + registers.eax = src->eax; + registers.ebx = src->ebx; + registers.ecx = src->ecx; + registers.edx = src->edx; + registers.edi = src->edi; + registers.esi = src->esi; + registers.ebp = src->ebp; + registers.cs = src->cs; + registers.ds = src->ds; + registers.ss = src->ss; + registers.eflags = src->eflags; + registers.kerrno = src->kerrno; + registers.signal_pending = src->signal_pending; +#elif defined(__x86_64__) + registers.rip = src->rip; + registers.rsp = src->rsp; + registers.rax = src->rax; + registers.rbx = src->rbx; + registers.rcx = src->rcx; + registers.rdx = src->rdx; + registers.rdi = src->rdi; + registers.rsi = src->rsi; + registers.rbp = src->rbp; + registers.r8 = src->r8; + registers.r9 = src->r9; + registers.r10 = src->r10; + registers.r11 = src->r11; + registers.r12 = src->r12; + registers.r13 = src->r13; + registers.r14 = src->r14; + registers.r15 = src->r15; + registers.cs = src->cs; + registers.ds = src->ds; + registers.ss = src->ss; + registers.rflags = src->rflags; + registers.kerrno = src->kerrno; + registers.signal_pending = src->signal_pending; +#else +#warning "You need to add register saving support" +#endif +} + +void Thread::LoadRegisters(CPU::InterruptRegisters* dest) +{ +#if defined(__i386__) + dest->eip = registers.eip; + dest->esp = registers.esp; + dest->eax = registers.eax; + dest->ebx = registers.ebx; + dest->ecx = registers.ecx; + dest->edx = registers.edx; + dest->edi = registers.edi; + dest->esi = registers.esi; + dest->ebp = registers.ebp; + dest->cs = registers.cs; + dest->ds = registers.ds; + dest->ss = registers.ss; + dest->eflags = registers.eflags; + dest->kerrno = registers.kerrno; + dest->signal_pending = registers.signal_pending; +#elif defined(__x86_64__) + dest->rip = registers.rip; + dest->rsp = registers.rsp; + dest->rax = registers.rax; + dest->rbx = registers.rbx; + dest->rcx = registers.rcx; + dest->rdx = registers.rdx; + dest->rdi = registers.rdi; + dest->rsi = registers.rsi; + dest->rbp = registers.rbp; + dest->r8 = registers.r8; + dest->r9 = registers.r9; + dest->r10 = registers.r10; + dest->r11 = registers.r11; + dest->r12 = registers.r12; + dest->r13 = registers.r13; + dest->r14 = registers.r14; + dest->r15 = registers.r15; + dest->cs = registers.cs; + dest->ds = registers.ds; + dest->ss = registers.ss; + dest->rflags = registers.rflags; + dest->kerrno = registers.kerrno; + dest->signal_pending = registers.signal_pending; +#else +#warning "You need to add register loading support" +#endif +} + addr_t Thread::SwitchAddressSpace(addr_t newaddrspace) { bool wasenabled = Interrupt::SetEnabled(false); @@ -92,12 +186,6 @@ addr_t Thread::SwitchAddressSpace(addr_t newaddrspace) return result; } -extern "C" void BootstrapKernelThread(void* user, ThreadEntry entry) -{ - entry(user); - kthread_exit(); -} - Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs, unsigned long fsbase, unsigned long gsbase) { @@ -133,7 +221,83 @@ Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs, return thread; } -Thread* CreateKernelThread(Process* process, ThreadEntry entry, void* user, +static void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, + void (*entry)(void*), + void* user, + uintptr_t stack, + size_t stack_size) +{ +#if defined(__i386__) + uintptr_t* stack_values = (uintptr_t*) (stack + stack_size); + + assert(!((uintptr_t) stack_values & 3UL)); + assert(4 * sizeof(uintptr_t) <= stack_size); + + stack_values[-1] = (uintptr_t) 0; /* null eip */ + stack_values[-2] = (uintptr_t) 0; /* null ebp */ + stack_values[-3] = (uintptr_t) user; /* thread parameter */ + stack_values[-4] = (uintptr_t) kthread_exit; /* return to kthread_exit */ + + regs->eip = (uintptr_t) entry; + regs->esp = (uintptr_t) (stack_values - 4); + regs->eax = 0; + regs->ebx = 0; + regs->ecx = 0; + regs->edx = 0; + regs->edi = 0; + regs->esi = 0; + regs->ebp = (uintptr_t) (stack_values - 2); + regs->cs = KCS | KRPL; + regs->ds = KDS | KRPL; + regs->ss = KDS | KRPL; + regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + regs->kerrno = 0; + regs->signal_pending = 0; +#elif defined(__x86_64__) + if ( (stack & 15UL) == 8 && 8 <= stack_size ) + { + stack += 8; + stack_size -= 8; + } + + uintptr_t* stack_values = (uintptr_t*) (stack + stack_size); + + assert(!((uintptr_t) stack_values & 15UL)); + assert(3 * sizeof(uintptr_t) <= stack_size); + + stack_values[-1] = (uintptr_t) 0; /* null rip */ + stack_values[-2] = (uintptr_t) 0; /* null rbp */ + stack_values[-3] = (uintptr_t) kthread_exit; /* return to kthread_exit */ + + regs->rip = (uintptr_t) entry; + regs->rsp = (uintptr_t) (stack_values - 3); + regs->rax = 0; + regs->rbx = 0; + regs->rcx = 0; + regs->rdx = 0; + regs->rdi = (uintptr_t) user; + regs->rsi = 0; + regs->rbp = 0; + regs->r8 = 0; + regs->r9 = 0; + regs->r10 = 0; + regs->r11 = 0; + regs->r12 = 0; + regs->r13 = 0; + regs->r14 = 0; + regs->r15 = 0; + regs->cs = KCS | KRPL; + regs->ds = KDS | KRPL; + regs->ss = KDS | KRPL; + regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + regs->kerrno = 0; + regs->signal_pending = 0; +#else +#warning "You need to add thread register initialization support" +#endif +} + +Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user, size_t stacksize) { const size_t DEFAULT_KERNEL_STACK_SIZE = 8 * 1024UL; @@ -144,19 +308,19 @@ Thread* CreateKernelThread(Process* process, ThreadEntry entry, void* user, return NULL; CPU::InterruptRegisters regs; - SetupKernelThreadRegs(®s, entry, user, (addr_t) stack, stacksize); + SetupKernelThreadRegs(®s, entry, user, (uintptr_t) stack, stacksize); Thread* thread = CreateKernelThread(process, ®s, 0, 0); if ( !thread ) { delete[] stack; return NULL; } - thread->kernelstackpos = (addr_t) stack; + thread->kernelstackpos = (uintptr_t) stack; thread->kernelstacksize = stacksize; thread->kernelstackmalloced = true; return thread; } -Thread* CreateKernelThread(ThreadEntry entry, void* user, size_t stacksize) +Thread* CreateKernelThread(void (*entry)(void*), void* user, size_t stacksize) { return CreateKernelThread(CurrentProcess(), entry, user, stacksize); } @@ -175,7 +339,7 @@ Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs) return thread; } -Thread* RunKernelThread(Process* process, ThreadEntry entry, void* user, +Thread* RunKernelThread(Process* process, void (*entry)(void*), void* user, size_t stacksize) { Thread* thread = CreateKernelThread(process, entry, user, stacksize); @@ -185,7 +349,7 @@ Thread* RunKernelThread(Process* process, ThreadEntry entry, void* user, return thread; } -Thread* RunKernelThread(ThreadEntry entry, void* user, size_t stacksize) +Thread* RunKernelThread(void (*entry)(void*), void* user, size_t stacksize) { Thread* thread = CreateKernelThread(entry, user, stacksize); if ( !thread ) diff --git a/kernel/x64/thread.cpp b/kernel/x64/thread.cpp deleted file mode 100644 index 689da0c6..00000000 --- a/kernel/x64/thread.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/******************************************************************************* - - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014. - - This file is part of Sortix. - - Sortix is free software: you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation, either version 3 of the License, or (at your option) any later - version. - - Sortix is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - You should have received a copy of the GNU General Public License along with - Sortix. If not, see . - - x64/thread.cpp - x64 specific parts of thread.cpp. - -*******************************************************************************/ - -#include -#include - -#include -#include - -namespace Sortix { - -void Thread::SaveRegisters(const CPU::InterruptRegisters* src) -{ - registers.rip = src->rip; - registers.rsp = src->rsp; - registers.rax = src->rax; - registers.rbx = src->rbx; - registers.rcx = src->rcx; - registers.rdx = src->rdx; - registers.rdi = src->rdi; - registers.rsi = src->rsi; - registers.rbp = src->rbp; - registers.r8 = src->r8; - registers.r9 = src->r9; - registers.r10 = src->r10; - registers.r11 = src->r11; - registers.r12 = src->r12; - registers.r13 = src->r13; - registers.r14 = src->r14; - registers.r15 = src->r15; - registers.cs = src->cs; - registers.ds = src->ds; - registers.ss = src->ss; - registers.rflags = src->rflags; - registers.kerrno = src->kerrno; - registers.signal_pending = src->signal_pending; -} - -void Thread::LoadRegisters(CPU::InterruptRegisters* dest) -{ - dest->rip = registers.rip; - dest->rsp = registers.rsp; - dest->rax = registers.rax; - dest->rbx = registers.rbx; - dest->rcx = registers.rcx; - dest->rdx = registers.rdx; - dest->rdi = registers.rdi; - dest->rsi = registers.rsi; - dest->rbp = registers.rbp; - dest->r8 = registers.r8; - dest->r9 = registers.r9; - dest->r10 = registers.r10; - dest->r11 = registers.r11; - dest->r12 = registers.r12; - dest->r13 = registers.r13; - dest->r14 = registers.r14; - dest->r15 = registers.r15; - dest->cs = registers.cs; - dest->ds = registers.ds; - dest->ss = registers.ss; - dest->rflags = registers.rflags; - dest->kerrno = registers.kerrno; - dest->signal_pending = registers.signal_pending; -} - -void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, ThreadEntry entry, - void* user, addr_t stack, size_t stacksize) -{ - // Instead of directly calling the desired entry point, we call a small - // stub that calls it for us and then destroys the kernel thread if - // the entry function returns. Note that since we use a register based - // calling convention, we call BootstrapKernelThread directly. - regs->rip = (addr_t) BootstrapKernelThread; - regs->rsp = stack + stacksize - sizeof(size_t); - *((size_t*) regs->rsp) = 0; /* back tracing stops at NULL rip */ - regs->rax = 0; - regs->rbx = 0; - regs->rcx = 0; - regs->rdx = 0; - regs->rdi = (addr_t) user; - regs->rsi = (addr_t) entry; - regs->rbp = 0; - regs->r8 = 0; - regs->r9 = 0; - regs->r10 = 0; - regs->r11 = 0; - regs->r12 = 0; - regs->r13 = 0; - regs->r14 = 0; - regs->r15 = 0; - regs->cs = KCS | KRPL; - regs->ds = KDS | KRPL; - regs->ss = KDS | KRPL; - regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; - regs->kerrno = 0; - regs->signal_pending = 0; -} - -} // namespace Sortix diff --git a/kernel/x86/kthread.S b/kernel/x86/kthread.S index 336585c2..92c1e423 100644 --- a/kernel/x86/kthread.S +++ b/kernel/x86/kthread.S @@ -90,12 +90,3 @@ kthread_mutex_unlock: leavel retl .size kthread_mutex_lock_signal, . - kthread_mutex_lock_signal - -.global asm_call_BootstrapKernelThread -.type asm_call_BootstrapKernelThread, @function -asm_call_BootstrapKernelThread: - pushl %esi - pushl %edi - call BootstrapKernelThread - # BootstrapKernelThread is noreturn, no need for code here. -.size asm_call_BootstrapKernelThread, . - asm_call_BootstrapKernelThread diff --git a/kernel/x86/thread.cpp b/kernel/x86/thread.cpp deleted file mode 100644 index 304eecd0..00000000 --- a/kernel/x86/thread.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/******************************************************************************* - - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014. - - This file is part of Sortix. - - Sortix is free software: you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation, either version 3 of the License, or (at your option) any later - version. - - Sortix is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - You should have received a copy of the GNU General Public License along with - Sortix. If not, see . - - x86/thread.cpp - x86 specific parts of thread.cpp. - -*******************************************************************************/ - -#include -#include - -#include -#include - -namespace Sortix { - -void Thread::SaveRegisters(const CPU::InterruptRegisters* src) -{ - registers.eip = src->eip; - registers.esp = src->esp; - registers.eax = src->eax; - registers.ebx = src->ebx; - registers.ecx = src->ecx; - registers.edx = src->edx; - registers.edi = src->edi; - registers.esi = src->esi; - registers.ebp = src->ebp; - registers.cs = src->cs; - registers.ds = src->ds; - registers.ss = src->ss; - registers.eflags = src->eflags; - registers.kerrno = src->kerrno; - registers.signal_pending = src->signal_pending; -} - -void Thread::LoadRegisters(CPU::InterruptRegisters* dest) -{ - dest->eip = registers.eip; - dest->esp = registers.esp; - dest->eax = registers.eax; - dest->ebx = registers.ebx; - dest->ecx = registers.ecx; - dest->edx = registers.edx; - dest->edi = registers.edi; - dest->esi = registers.esi; - dest->ebp = registers.ebp; - dest->cs = registers.cs; - dest->ds = registers.ds; - dest->ss = registers.ss; - dest->eflags = registers.eflags; - dest->kerrno = registers.kerrno; - dest->signal_pending = registers.signal_pending; -} - -extern "C" void asm_call_BootstrapKernelThread(void); - -void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, ThreadEntry entry, - void* user, addr_t stack, size_t stacksize) -{ - // Instead of directly calling the desired entry point, we call a small - // stub that calls it for us and then destroys the kernel thread if - // the entry function returns. Note that since we use a stack based - // calling convention, we go through a proxy that uses %edi and %esi - // as parameters and pushes them to the stack and then does the call. - regs->eip = (addr_t) asm_call_BootstrapKernelThread; - regs->esp = stack + stacksize - sizeof(size_t); - *((size_t*) regs->esp) = 0; /* back tracing stops at NULL rip */ - regs->eax = 0; - regs->ebx = 0; - regs->ecx = 0; - regs->edx = 0; - regs->edi = (addr_t) user; - regs->esi = (addr_t) entry; - regs->ebp = 0; - regs->cs = KCS | KRPL; - regs->ds = KDS | KRPL; - regs->ss = KDS | KRPL; - regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; - regs->kerrno = 0; - regs->signal_pending = 0; -} - -} // namespace Sortix