From 25e07a90831c151b78517030fac41db5104f45a0 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Tue, 4 Mar 2014 00:11:13 +0100 Subject: [PATCH] Refactor kernel interrupt and thread register support. --- kernel/Makefile | 6 +- kernel/com.cpp | 2 +- kernel/debugger.cpp | 108 ++++----- kernel/include/sortix/kernel/cpu.h | 86 ------- kernel/include/sortix/kernel/interrupt.h | 11 +- .../include/sortix/kernel/memorymanagement.h | 4 +- kernel/include/sortix/kernel/process.h | 8 +- kernel/include/sortix/kernel/registers.h | 207 ++++++++++++++++ kernel/include/sortix/kernel/scheduler.h | 17 +- kernel/include/sortix/kernel/signal.h | 5 +- kernel/include/sortix/kernel/thread.h | 40 +--- kernel/kb/ps2.cpp | 17 +- kernel/kb/ps2.h | 2 +- kernel/kernel.cpp | 21 +- kernel/kthread.cpp | 2 +- kernel/log.cpp | 2 +- kernel/process.cpp | 127 ++++++++-- kernel/registers.cpp | 76 ++++++ kernel/scheduler.cpp | 196 +++++++++++---- kernel/signal.cpp | 121 +++++----- kernel/thread.cpp | 226 ++++++------------ kernel/x64/boot.S | 5 +- kernel/x64/interrupt.S | 3 + kernel/x64/memorymanagement.cpp | 13 +- kernel/x64/process.cpp | 83 ------- kernel/x64/x64.cpp | 49 ---- kernel/x86-family/float.cpp | 99 +------- kernel/x86-family/float.h | 33 +-- kernel/x86-family/gdt.cpp | 24 +- kernel/x86-family/gdt.h | 3 +- kernel/x86-family/interrupt.cpp | 72 +++--- kernel/x86-family/memorymanagement.cpp | 40 +--- kernel/x86-family/time.cpp | 6 +- kernel/x86/boot.S | 5 +- kernel/x86/interrupt.S | 9 +- kernel/x86/memorymanagement.cpp | 11 +- kernel/x86/process.cpp | 75 ------ kernel/x86/syscall.S | 5 + kernel/x86/x86.cpp | 45 ---- 39 files changed, 866 insertions(+), 998 deletions(-) create mode 100644 kernel/include/sortix/kernel/registers.h create mode 100644 kernel/registers.cpp delete mode 100644 kernel/x64/process.cpp delete mode 100644 kernel/x64/x64.cpp delete mode 100644 kernel/x86/process.cpp delete mode 100644 kernel/x86/x86.cpp diff --git a/kernel/Makefile b/kernel/Makefile index 9739f608..81e83fba 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -31,13 +31,13 @@ BOOTOBJS:= ifeq ($(CPU),x86) X86FAMILY:=1 - CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o $(CPU)/x86.o + CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o endif ifeq ($(CPU),x64) X86FAMILY:=1 CXXFLAGS:=$(CXXFLAGS) -mno-red-zone -mno-mmx -mno-sse -mno-sse2 - CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o $(CPU)/x64.o + CPUOBJS:=$(CPU)/boot.o $(CPU)/base.o endif ifdef X86FAMILY @@ -50,7 +50,6 @@ ifdef X86FAMILY x86-family/gdt.o \ x86-family/idt.o \ $(CPU)/syscall.o \ - $(CPU)/process.o \ x86-family/cmos.o \ x86-family/time.o \ x86-family/mtrr.o \ @@ -124,6 +123,7 @@ pipe.o \ poll.o \ process.o \ refcount.o \ +registers.o \ resource.o \ scheduler.o \ segment.o \ diff --git a/kernel/com.cpp b/kernel/com.cpp index f0e7856b..6e49e465 100644 --- a/kernel/com.cpp +++ b/kernel/com.cpp @@ -406,7 +406,7 @@ void DevCOMPort::OnInterrupt() Ref comdevices[1+NUMCOMPORTS]; -static void UARTIRQHandler(CPU::InterruptRegisters* /*regs*/, void* /*user*/) +static void UARTIRQHandler(struct interrupt_context* /*intctx*/, void* /*user*/) { for ( size_t i = 1; i <= NUMCOMPORTS; i++ ) { diff --git a/kernel/debugger.cpp b/kernel/debugger.cpp index 30837e81..08d725eb 100644 --- a/kernel/debugger.cpp +++ b/kernel/debugger.cpp @@ -337,14 +337,12 @@ int ThreadId(Thread* thread) int main_bt(int /*argc*/, char* /*argv*/[]) { - CPU::InterruptRegisters regs; - current_thread->LoadRegisters(®s); #if defined(__x86_64__) - unsigned long ip = regs.rip; - unsigned long bp = regs.rbp; + unsigned long ip = current_thread->registers.rip; + unsigned long bp = current_thread->registers.rbp; #elif defined(__i386__) - unsigned long ip = regs.eip; - unsigned long bp = regs.ebp; + unsigned long ip = current_thread->registers.eip; + unsigned long bp = current_thread->registers.ebp; #endif bool userspace = false; @@ -434,7 +432,7 @@ int main_pid(int argc, char* argv[]) return 1; } current_thread = process->firstthread; - Memory::SwitchAddressSpace(current_thread->addrspace); + Memory::SwitchAddressSpace(current_thread->registers.cr3); } Print("%c %i\t`%s'\n", '*', (int) current_process->pid, current_process->program_image_path); @@ -455,54 +453,48 @@ int main_ps(int /*argc*/, char* /*argv*/[]) int main_rs(int /*argc*/, char* /*argv*/[]) { - CPU::InterruptRegisters regs; - current_thread->LoadRegisters(®s); #if defined(__x86_64__) - Print("rax=0x%lx, ", regs.rax); - Print("rbx=0x%lx, ", regs.rbx); - Print("rcx=0x%lx, ", regs.rcx); - Print("rdx=0x%lx, ", regs.rdx); - Print("rdi=0x%lx, ", regs.rdi); - Print("rsi=0x%lx, ", regs.rsi); - Print("rsp=0x%lx, ", regs.rsp); - Print("rbp=0x%lx, ", regs.rbp); - Print("r8=0x%lx, ", regs.r8); - Print("r9=0x%lx, ", regs.r9); - Print("r10=0x%lx, ", regs.r10); - Print("r11=0x%lx, ", regs.r11); - Print("r12=0x%lx, ", regs.r12); - Print("r13=0x%lx, ", regs.r13); - Print("r14=0x%lx, ", regs.r14); - Print("r15=0x%lx, ", regs.r15); - Print("rip=0x%lx, ", regs.rip); - Print("rflags=0x%lx, ", regs.rflags); - Print("int_no=%lu, ", regs.int_no); - Print("err_code=0x%lx, ", regs.err_code); - Print("cs=0x%lx, ", regs.cs); - Print("ds=0x%lx, ", regs.ds); - Print("ss=0x%lx, ", regs.ss); - Print("kerrno=%lu, ", regs.kerrno); - Print("cr2=%lx, ", regs.cr2); - Print("signal_pending=%lu.", regs.signal_pending); + Print("rax=0x%lX, ", current_thread->registers.rax); + Print("rbx=0x%lX, ", current_thread->registers.rbx); + Print("rcx=0x%lX, ", current_thread->registers.rcx); + Print("rdx=0x%lX, ", current_thread->registers.rdx); + Print("rdi=0x%lX, ", current_thread->registers.rdi); + Print("rsi=0x%lX, ", current_thread->registers.rsi); + Print("rsp=0x%lX, ", current_thread->registers.rsp); + Print("rbp=0x%lX, ", current_thread->registers.rbp); + Print("r8=0x%lX, ", current_thread->registers.r8); + Print("r9=0x%lX, ", current_thread->registers.r9); + Print("r10=0x%lX, ", current_thread->registers.r10); + Print("r11=0x%lX, ", current_thread->registers.r11); + Print("r12=0x%lX, ", current_thread->registers.r12); + Print("r13=0x%lX, ", current_thread->registers.r13); + Print("r14=0x%lX, ", current_thread->registers.r14); + Print("r15=0x%lX, ", current_thread->registers.r15); + Print("rip=0x%lX, ", current_thread->registers.rip); + Print("rflags=0x%lX, ", current_thread->registers.rflags); + Print("fsbase=0x%lX, ", current_thread->registers.fsbase); + Print("gsbase=0x%lX, ", current_thread->registers.gsbase); + Print("cr3=0x%lX, ", current_thread->registers.cr3); + Print("kernel_stack=0x%lX, ", current_thread->registers.kernel_stack); + Print("kerrno=%lu, ", current_thread->registers.kerrno); + Print("signal_pending=%lu.", current_thread->registers.signal_pending); #elif defined(__i386__) - Print("eax=0x%lx, ", regs.eax); - Print("ebx=0x%lx, ", regs.ebx); - Print("ecx=0x%lx, ", regs.ecx); - Print("edx=0x%lx, ", regs.edx); - Print("edi=0x%lx, ", regs.edi); - Print("esi=0x%lx, ", regs.esi); - Print("esp=0x%lx, ", regs.esp); - Print("ebp=0x%lx, ", regs.ebp); - Print("eip=0x%lx, ", regs.eip); - Print("eflags=0x%lx, ", regs.eflags); - Print("int_no=%lu, ", regs.int_no); - Print("err_code=0x%lx, ", regs.err_code); - Print("cs=0x%lx, ", regs.cs); - Print("ds=0x%lx, ", regs.ds); - Print("ss=0x%lx, ", regs.ss); - Print("kerrno=%lu, ", regs.kerrno); - Print("cr2=%lx, ", regs.cr2); - Print("signal_pending=%lu.", regs.signal_pending); + Print("eax=0x%lX, ", current_thread->registers.eax); + Print("ebx=0x%lX, ", current_thread->registers.ebx); + Print("ecx=0x%lX, ", current_thread->registers.ecx); + Print("edx=0x%lX, ", current_thread->registers.edx); + Print("edi=0x%lX, ", current_thread->registers.edi); + Print("esi=0x%lX, ", current_thread->registers.esi); + Print("esp=0x%lX, ", current_thread->registers.esp); + Print("ebp=0x%lX, ", current_thread->registers.ebp); + Print("eip=0x%lX, ", current_thread->registers.eip); + Print("eflags=0x%lX, ", current_thread->registers.eflags); + Print("fsbase=0x%lX, ", current_thread->registers.fsbase); + Print("gsbase=0x%lX, ", current_thread->registers.gsbase); + Print("cr3=0x%lX, ", current_thread->registers.cr3); + Print("kernel_stack=0x%lX, ", current_thread->registers.kernel_stack); + Print("kerrno=%lX, ", current_thread->registers.kerrno); + Print("signal_pending=%lu.", current_thread->registers.signal_pending); #endif Print("\n"); return 0; @@ -510,12 +502,10 @@ int main_rs(int /*argc*/, char* /*argv*/[]) static void DescribeThread(int tid, Thread* thread) { - CPU::InterruptRegisters regs; - thread->LoadRegisters(®s); #if defined(__x86_64__) - unsigned long ip = regs.rip; + unsigned long ip = thread->registers.rip; #elif defined(__i386__) - unsigned long ip = regs.eip; + unsigned long ip = thread->registers.eip; #endif Print("%c ", thread == current_thread ? '*' : ' '); @@ -538,7 +528,7 @@ int main_tid(int argc, char* argv[]) return 1; } current_thread = thread; - Memory::SwitchAddressSpace(current_thread->addrspace); + Memory::SwitchAddressSpace(current_thread->registers.cr3); } DescribeThread(ThreadId(current_thread), current_thread); return 0; @@ -624,7 +614,7 @@ void Run() first_f10 = true; - addr_t saved_addrspace = current_thread->addrspace; + addr_t saved_addrspace = current_thread->registers.cr3; memcpy(saved_video_memory, VIDEO_MEMORY, sizeof(saved_video_memory)); int saved_x, saved_y; diff --git a/kernel/include/sortix/kernel/cpu.h b/kernel/include/sortix/kernel/cpu.h index bdd8e4bf..05b06d9d 100644 --- a/kernel/include/sortix/kernel/cpu.h +++ b/kernel/include/sortix/kernel/cpu.h @@ -40,92 +40,6 @@ void ShutDown(); } // namespace CPU #endif -// CPU flag register bits for 32-bit and 64-bit x86. -#if defined(__i386__) || defined(__x86_64__) -const size_t FLAGS_CARRY = 1<<0; // 0x000001 -const size_t FLAGS_RESERVED1 = 1<<1; // 0x000002, read as one -const size_t FLAGS_PARITY = 1<<2; // 0x000004 -const size_t FLAGS_RESERVED2 = 1<<3; // 0x000008 -const size_t FLAGS_AUX = 1<<4; // 0x000010 -const size_t FLAGS_RESERVED3 = 1<<5; // 0x000020 -const size_t FLAGS_ZERO = 1<<6; // 0x000040 -const size_t FLAGS_SIGN = 1<<7; // 0x000080 -const size_t FLAGS_TRAP = 1<<8; // 0x000100 -const size_t FLAGS_INTERRUPT = 1<<9; // 0x000200 -const size_t FLAGS_DIRECTION = 1<<10; // 0x000400 -const size_t FLAGS_OVERFLOW = 1<<11; // 0x000800 -const size_t FLAGS_IOPRIVLEVEL = 1<<12 | 1<<13; -const size_t FLAGS_NESTEDTASK = 1<<14; // 0x004000 -const size_t FLAGS_RESERVED4 = 1<<15; // 0x008000 -const size_t FLAGS_RESUME = 1<<16; // 0x010000 -const size_t FLAGS_VIRTUAL8086 = 1<<17; // 0x020000 -const size_t FLAGS_ALIGNCHECK = 1<<18; // 0x040000 -const size_t FLAGS_VIRTINTR = 1<<19; // 0x080000 -const size_t FLAGS_VIRTINTRPEND = 1<<20; // 0x100000 -const size_t FLAGS_ID = 1<<21; // 0x200000 -#endif - -// x86 interrupt registers structure. -#if defined(__i386__) -namespace X86 { -struct InterruptRegisters -{ - uint32_t signal_pending, kerrno, cr2; - uint32_t ds; // Data segment selector - uint32_t edi, esi, ebp, not_esp, ebx, edx, ecx, eax; // Pushed by pusha. - uint32_t int_no, err_code; // Interrupt number and error code (if applicable) - uint32_t eip, cs, eflags, esp, ss; // Pushed by the processor automatically. - -public: - void LogRegisters() const; - bool InUserspace() const { return (cs & 0x3) != 0; } - -}; -} // namespace X86 -#endif - -// x86_64 interrupt -#if defined(__x86_64__) -namespace X64 { -struct InterruptRegisters -{ - uint64_t signal_pending, kerrno, cr2; - uint64_t ds; // Data segment selector - uint64_t rdi, rsi, rbp, not_rsp, rbx, rdx, rcx, rax; - uint64_t r8, r9, r10, r11, r12, r13, r14, r15; - uint64_t int_no, err_code; // Interrupt number and error code (if applicable) - uint64_t rip, cs, rflags, rsp, ss; // Pushed by the processor automatically. - -public: - void LogRegisters() const; - bool InUserspace() const { return (cs & 0x3) != 0; } - -}; -} // namespace X64 -#endif - -// Segment values for 32-bit and 64-bit x86. -#if defined(__i386__) || defined(__x86_64__) -const uint64_t KCS = 0x08; -const uint64_t KDS = 0x10; -const uint64_t KRPL = 0x0; -const uint64_t UCS = 0x18; -const uint64_t UDS = 0x20; -const uint64_t URPL = 0x3; -#endif - -// Portable functions for loading registers. -namespace CPU { -extern "C" __attribute__((noreturn)) -void load_registers(InterruptRegisters* regs, size_t size); - -__attribute__((noreturn)) -inline void LoadRegisters(InterruptRegisters* regs) -{ - load_registers(regs, sizeof(*regs)); -} -} // namespace CPU - } // namespace Sortix #endif diff --git a/kernel/include/sortix/kernel/interrupt.h b/kernel/include/sortix/kernel/interrupt.h index 5e3e37fd..d9923217 100644 --- a/kernel/include/sortix/kernel/interrupt.h +++ b/kernel/include/sortix/kernel/interrupt.h @@ -28,14 +28,7 @@ #include #include - -namespace Sortix { -namespace CPU { - -struct InterruptRegisters; - -} // namespace CPU -} // namespace Sortix +#include namespace Sortix { namespace Interrupt { @@ -108,7 +101,7 @@ inline bool SetEnabled(bool is_enabled) } -typedef void (*Handler)(CPU::InterruptRegisters* regs, void* user); +typedef void (*Handler)(struct interrupt_context* intctx, void* user); void RegisterHandler(unsigned int index, Handler handler, void* user); void Init(); diff --git a/kernel/include/sortix/kernel/memorymanagement.h b/kernel/include/sortix/kernel/memorymanagement.h index 927dfc7a..f60a4171 100644 --- a/kernel/include/sortix/kernel/memorymanagement.h +++ b/kernel/include/sortix/kernel/memorymanagement.h @@ -77,9 +77,7 @@ void Flush(); addr_t Fork(); addr_t GetAddressSpace(); addr_t SwitchAddressSpace(addr_t addrspace); -void DestroyAddressSpace(addr_t fallback = 0, - void (*func)(addr_t, void*) = NULL, - void* user = NULL); +void DestroyAddressSpace(addr_t fallback = 0); bool Map(addr_t physical, addr_t mapto, int prot); addr_t Unmap(addr_t mapto); addr_t Physical(addr_t mapto); diff --git a/kernel/include/sortix/kernel/process.h b/kernel/include/sortix/kernel/process.h index 8b2849a7..7ce7a086 100644 --- a/kernel/include/sortix/kernel/process.h +++ b/kernel/include/sortix/kernel/process.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -168,7 +169,7 @@ public: int Execute(const char* programname, const uint8_t* program, size_t programsize, int argc, const char* const* argv, int envc, const char* const* envp, - CPU::InterruptRegisters* regs); + struct thread_registers* regs); void ResetAddressSpace(); void ExitThroughSignal(int signal); void ExitWithCode(int exit_code); @@ -187,9 +188,6 @@ public: Process* Fork(); private: - void ExecuteCPU(int argc, char** argv, int envc, char** envp, - addr_t stackpos, addr_t entry, - CPU::InterruptRegisters* regs); void OnLastThreadExit(); void LastPrayer(); void NotifyMemberExit(Process* child); @@ -212,8 +210,6 @@ private: }; -void InitializeThreadRegisters(CPU::InterruptRegisters* regs, - const struct tfork* requested); Process* CurrentProcess(); } // namespace Sortix diff --git a/kernel/include/sortix/kernel/registers.h b/kernel/include/sortix/kernel/registers.h new file mode 100644 index 00000000..83d3d200 --- /dev/null +++ b/kernel/include/sortix/kernel/registers.h @@ -0,0 +1,207 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 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 . + + sortix/kernel/registers.h + Register structures and platform-specific bits. + +*******************************************************************************/ + +#ifndef INCLUDE_SORTIX_KERNEL_REGISTERS_H +#define INCLUDE_SORTIX_KERNEL_REGISTERS_H + +#include +#include + +namespace Sortix { +// CPU flag register bits for 32-bit and 64-bit x86. +#if defined(__i386__) || defined(__x86_64__) +const size_t FLAGS_CARRY = 1 << 0; // 0x000001 +const size_t FLAGS_RESERVED1 = 1 << 1; // 0x000002, read as one +const size_t FLAGS_PARITY = 1 << 2; // 0x000004 +const size_t FLAGS_RESERVED2 = 1 << 3; // 0x000008 +const size_t FLAGS_AUX = 1 << 4; // 0x000010 +const size_t FLAGS_RESERVED3 = 1 << 5; // 0x000020 +const size_t FLAGS_ZERO = 1 << 6; // 0x000040 +const size_t FLAGS_SIGN = 1 << 7; // 0x000080 +const size_t FLAGS_TRAP = 1 << 8; // 0x000100 +const size_t FLAGS_INTERRUPT = 1 << 9; // 0x000200 +const size_t FLAGS_DIRECTION = 1 << 10; // 0x000400 +const size_t FLAGS_OVERFLOW = 1 << 11; // 0x000800 +const size_t FLAGS_IOPRIVLEVEL = 1 << 12 | 1 << 13; +const size_t FLAGS_NESTEDTASK = 1 << 14; // 0x004000 +const size_t FLAGS_RESERVED4 = 1 << 15; // 0x008000 +const size_t FLAGS_RESUME = 1 << 16; // 0x010000 +const size_t FLAGS_VIRTUAL8086 = 1 << 17; // 0x020000 +const size_t FLAGS_ALIGNCHECK = 1 << 18; // 0x040000 +const size_t FLAGS_VIRTINTR = 1 << 19; // 0x080000 +const size_t FLAGS_VIRTINTRPEND = 1 << 20; // 0x100000 +const size_t FLAGS_ID = 1 << 21; // 0x200000 +#endif + +// i386 registers structures. +#if defined(__i386__) +const uint32_t KCS = 0x08; +const uint32_t KDS = 0x10; +const uint32_t KRPL = 0x0; +const uint32_t UCS = 0x18; +const uint32_t UDS = 0x20; +const uint32_t URPL = 0x3; +const uint32_t RPLMASK = 0x3; + +struct interrupt_context +{ + uint32_t signal_pending; + uint32_t kerrno; + uint32_t cr2; + uint32_t ds; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t not_esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t int_no; + uint32_t err_code; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t esp; + uint32_t ss; +}; + +__attribute__((unused)) +static inline bool InUserspace(const struct interrupt_context* intctx) +{ + return (intctx->cs & RPLMASK) != KRPL; +} + +struct thread_registers +{ + uint32_t signal_pending; + uint32_t kerrno; + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t edi; + uint32_t esi; + uint32_t esp; + uint32_t ebp; + uint32_t eip; + uint32_t eflags; + uint32_t fsbase; + uint32_t gsbase; + uint32_t cr3; + uint32_t kernel_stack; + uint32_t cs; + uint32_t ds; + uint32_t ss; + __attribute__((aligned(16))) uint8_t fpuenv[512]; +}; +#endif + +// x86_64 registers structures. +#if defined(__x86_64__) +const uint64_t KCS = 0x08; +const uint64_t KDS = 0x10; +const uint64_t KRPL = 0x0; +const uint64_t UCS = 0x18; +const uint64_t UDS = 0x20; +const uint64_t URPL = 0x3; +const uint64_t RPLMASK = 0x3; + +struct interrupt_context +{ + uint64_t signal_pending; + uint64_t kerrno; + uint64_t cr2; + uint64_t ds; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t not_rsp; + uint64_t rbx; + uint64_t rdx; + uint64_t rcx; + uint64_t rax; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t int_no; + uint64_t err_code; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}; + +__attribute__((unused)) +static inline bool InUserspace(const struct interrupt_context* intctx) +{ + return (intctx->cs & RPLMASK) != KRPL; +} + +struct thread_registers +{ + uint64_t signal_pending; + uint64_t kerrno; + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rdi; + uint64_t rsi; + uint64_t rsp; + uint64_t rbp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; + uint64_t rflags; + uint64_t fsbase; + uint64_t gsbase; + uint64_t cr3; + uint64_t kernel_stack; + uint64_t cs; + uint64_t ds; + uint64_t ss; + __attribute__((aligned(16))) uint8_t fpuenv[512]; +}; +#endif + +void LogInterruptContext(const struct interrupt_context* intctx); +__attribute__((noreturn)) +void LoadRegisters(const struct thread_registers* registers); + +} // namespace Sortix + +#endif diff --git a/kernel/include/sortix/kernel/scheduler.h b/kernel/include/sortix/kernel/scheduler.h index e43c860a..74f8b994 100644 --- a/kernel/include/sortix/kernel/scheduler.h +++ b/kernel/include/sortix/kernel/scheduler.h @@ -26,18 +26,13 @@ #define INCLUDE_SORTIX_KERNEL_SCHEDULER_H #include +#include namespace Sortix { class Process; class Thread; } // namespace Sortix -namespace Sortix { -namespace CPU { -struct InterruptRegisters; -} // namespace CPU -} // namespace Sortix - namespace Sortix { enum ThreadState { NONE, RUNNABLE, BLOCKING, DEAD }; } // namespace Sortix @@ -59,15 +54,19 @@ static inline void ExitThread() #endif void Init(); -void Switch(CPU::InterruptRegisters* regs); +void Switch(struct interrupt_context* intctx); void SetThreadState(Thread* thread, ThreadState state); ThreadState GetThreadState(Thread* thread); void SetIdleThread(Thread* thread); void SetInitProcess(Process* init); Process* GetInitProcess(); Process* GetKernelProcess(); -void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* user); -void ThreadExitCPU(CPU::InterruptRegisters* regs, void* user); +void InterruptYieldCPU(struct interrupt_context* intctx, void* user); +void ThreadExitCPU(struct interrupt_context* intctx, void* user); +void SaveInterruptedContext(const struct interrupt_context* intctx, + struct thread_registers* registers); +void LoadInterruptedContext(struct interrupt_context* intctx, + const struct thread_registers* registers); } // namespace Scheduler } // namespace Sortix diff --git a/kernel/include/sortix/kernel/signal.h b/kernel/include/sortix/kernel/signal.h index f844e471..eb850e1f 100644 --- a/kernel/include/sortix/kernel/signal.h +++ b/kernel/include/sortix/kernel/signal.h @@ -29,6 +29,7 @@ #include #include +#include namespace Sortix { @@ -38,8 +39,8 @@ namespace Signal { void Init(); inline bool IsPending() { return asm_signal_is_pending != 0; } -void DispatchHandler(CPU::InterruptRegisters* regs, void* user); -void ReturnHandler(CPU::InterruptRegisters* regs, void* user); +void DispatchHandler(struct interrupt_context* intctx, void* user); +void ReturnHandler(struct interrupt_context* intctx, void* user); } // namespace Signal diff --git a/kernel/include/sortix/kernel/thread.h b/kernel/include/sortix/kernel/thread.h index bd324f06..58255da3 100644 --- a/kernel/include/sortix/kernel/thread.h +++ b/kernel/include/sortix/kernel/thread.h @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -40,8 +41,7 @@ class Process; class Thread; // 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, struct thread_registers* regs); Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user, size_t stacksize = 0); Thread* CreateKernelThread(void (*entry)(void*), void* user, size_t stacksize = 0); @@ -50,18 +50,13 @@ Thread* CreateKernelThread(void (*entry)(void*), void* user, size_t stacksize = void StartKernelThread(Thread* thread); // Alternatively, these functions both create and start the thread. -Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs); +Thread* RunKernelThread(Process* process, struct thread_registers* regs); Thread* RunKernelThread(Process* process, void (*entry)(void*), void* user, size_t stacksize = 0); 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 UpdatePendingSignals(Thread* thread); - public: static void Init(); @@ -70,49 +65,34 @@ public: ~Thread(); public: + struct thread_registers registers; + uint8_t* self_allocation; size_t id; Process* process; Thread* prevsibling; Thread* nextsibling; - -public: Thread* scheduler_list_prev; Thread* scheduler_list_next; volatile ThreadState state; - uint8_t fpuenv[512UL + 16UL]; - uint8_t* fpuenvaligned; - bool fpuinitialized; - -public: sigset_t signal_pending; sigset_t signal_mask; stack_t signal_stack; - addr_t addrspace; addr_t kernelstackpos; size_t kernelstacksize; bool kernelstackmalloced; bool pledged_destruction; -#if defined(__i386__) || defined(__x86_64__) public: - unsigned long fsbase; - unsigned long gsbase; -#endif - -private: - CPU::InterruptRegisters registers; - -public: - void SaveRegisters(const CPU::InterruptRegisters* src); - void LoadRegisters(CPU::InterruptRegisters* dest); - void HandleSignal(CPU::InterruptRegisters* regs); - void HandleSigreturn(CPU::InterruptRegisters* regs); + void HandleSignal(struct interrupt_context* intctx); + void HandleSigreturn(struct interrupt_context* intctx); bool DeliverSignal(int signum); bool DeliverSignalUnlocked(int signum); - addr_t SwitchAddressSpace(addr_t newaddrspace); }; +Thread* AllocateThread(); +void FreeThread(Thread* thread); + Thread* CurrentThread(); } // namespace Sortix diff --git a/kernel/kb/ps2.cpp b/kernel/kb/ps2.cpp index 3a2067e1..0dbf334c 100644 --- a/kernel/kb/ps2.cpp +++ b/kernel/kb/ps2.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #if defined(__i386__) @@ -57,9 +58,9 @@ const uint8_t LED_SCRLCK = 1 << 0; const uint8_t LED_NUMLCK = 1 << 1; const uint8_t LED_CAPSLCK = 1 << 2; -void PS2Keyboard__OnInterrupt(CPU::InterruptRegisters* regs, void* user) +void PS2Keyboard__OnInterrupt(struct interrupt_context* intctx, void* user) { - ((PS2Keyboard*) user)->OnInterrupt(regs); + ((PS2Keyboard*) user)->OnInterrupt(intctx); } PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt) @@ -100,20 +101,12 @@ static void PS2Keyboard__InterruptWork(void* kb_ptr, void* payload, size_t size) ((PS2Keyboard*) kb_ptr)->InterruptWork(work->scancode); } -void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* regs) +void PS2Keyboard::OnInterrupt(struct interrupt_context* intctx) { uint8_t scancode = PopScancode(); if ( scancode == KBKEY_F10 ) { - Thread* thread = CurrentThread(); -#if defined(__i386__) - thread->fsbase = (unsigned long) GDT::GetFSBase(); - thread->gsbase = (unsigned long) GDT::GetGSBase(); -#elif defined(__x86_64__) - thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE); - thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE); -#endif - thread->SaveRegisters(regs); + Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers); Debugger::Run(); } PS2KeyboardWork work; diff --git a/kernel/kb/ps2.h b/kernel/kb/ps2.h index 7ce93e1d..19941eab 100644 --- a/kernel/kb/ps2.h +++ b/kernel/kb/ps2.h @@ -44,7 +44,7 @@ public: virtual void SetOwner(KeyboardOwner* owner, void* user); public: - void OnInterrupt(CPU::InterruptRegisters* regs); + void OnInterrupt(struct interrupt_context* intctx); void InterruptWork(uint8_t scancode); private: diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index 1ee67d1c..bd58beb9 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -104,7 +104,7 @@ // Keep the stack size aligned with $CPU/base.s const size_t STACK_SIZE = 64*1024; -extern "C" { size_t stack[STACK_SIZE / sizeof(size_t)] = {0}; } +extern "C" { __attribute__((aligned(16))) size_t stack[STACK_SIZE / sizeof(size_t)]; } namespace Sortix { @@ -290,6 +290,7 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo) // Initialize the GDT and TSS structures. GDT::Init(); + GDT::SetKernelStack((uintptr_t) stack + STACK_SIZE); // Initialize the interrupt handler table and enable interrupts. Interrupt::Init(); @@ -436,9 +437,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo) // Now that the base system has been loaded, it's time to go threaded. First // we create an object that represents this thread. Process* system = new Process; - if ( !system ) { Panic("Could not allocate the system process"); } - addr_t systemaddrspace = Memory::GetAddressSpace(); - system->addrspace = systemaddrspace; + if ( !system ) + Panic("Could not allocate the system process"); + system->addrspace = Memory::GetAddressSpace(); system->group = system; system->groupprev = NULL; system->groupnext = NULL; @@ -451,13 +452,11 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo) // create a kernel thread that is the current thread and isn't put into the // scheduler's set of runnable threads, but rather run whenever there is // _nothing_ else to run on this CPU. - Thread* idlethread = new Thread; + Thread* idlethread = AllocateThread(); idlethread->process = system; - idlethread->addrspace = idlethread->process->addrspace; idlethread->kernelstackpos = (addr_t) stack; idlethread->kernelstacksize = STACK_SIZE; idlethread->kernelstackmalloced = false; - idlethread->fpuinitialized = true; system->firstthread = idlethread; Scheduler::SetIdleThread(idlethread); @@ -467,9 +466,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo) // we must become the system idle thread. RunKernelThread(BootThread, NULL); - // Set up such that floating point registers are lazily switched. - Float::Init(); - // The time driver will run the scheduler on the next timer interrupt. Time::Start(); @@ -766,7 +762,8 @@ static void InitThread(void* /*user*/) const char* cputype = "cputype=" CPUTYPE_STR; int envc = 1; const char* envp[] = { cputype, NULL }; - CPU::InterruptRegisters regs; + struct thread_registers regs; + assert((((uintptr_t) ®s) & (alignof(regs)-1)) == 0); if ( process->Execute(initpath, program, programsize, argc, argv, envc, envp, ®s) ) @@ -775,7 +772,7 @@ static void InitThread(void* /*user*/) delete[] program; // Now become the init process and the operation system shall run. - CPU::LoadRegisters(®s); + LoadRegisters(®s); } } // namespace Sortix diff --git a/kernel/kthread.cpp b/kernel/kthread.cpp index 98cb2d3f..015e122d 100644 --- a/kernel/kthread.cpp +++ b/kernel/kthread.cpp @@ -39,7 +39,7 @@ static void kthread_do_kill_thread(void* user) Thread* thread = (Thread*) user; while ( thread->state != ThreadState::DEAD ) kthread_yield(); - delete thread; + FreeThread(thread); } extern "C" void kthread_exit() diff --git a/kernel/log.cpp b/kernel/log.cpp index 3fef6ddf..3b9f1333 100644 --- a/kernel/log.cpp +++ b/kernel/log.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of Sortix. diff --git a/kernel/process.cpp b/kernel/process.cpp index 6031e674..607ba79b 100644 --- a/kernel/process.cpp +++ b/kernel/process.cpp @@ -67,6 +67,7 @@ #include "initrd.h" #if defined(__i386__) || defined(__x86_64__) +#include "x86-family/float.h" #include "x86-family/gdt.h" #endif @@ -249,11 +250,6 @@ void Process::OnLastThreadExit() LastPrayer(); } -static void SwitchCurrentAddrspace(addr_t addrspace, void* user) -{ - ((Thread*) user)->SwitchAddressSpace(addrspace); -} - void Process::DeleteTimers() { for ( timer_t i = 0; i < PROCESS_TIMER_NUM_MAX; i++ ) @@ -290,7 +286,7 @@ void Process::LastPrayer() // We need to temporarily reload the correct addrese space of the dying // process such that we can unmap and free its memory. - addr_t prevaddrspace = curthread->SwitchAddressSpace(addrspace); + addr_t prevaddrspace = Memory::SwitchAddressSpace(addrspace); ResetAddressSpace(); @@ -301,9 +297,7 @@ void Process::LastPrayer() // Destroy the address space and safely switch to the replacement // address space before things get dangerous. - Memory::DestroyAddressSpace(prevaddrspace, - SwitchCurrentAddrspace, - curthread); + Memory::DestroyAddressSpace(prevaddrspace); addrspace = 0; // Unload the process symbol and string tables. @@ -814,7 +808,7 @@ bool Process::MapSegment(struct segment* result, void* hint, size_t size, int Process::Execute(const char* programname, const uint8_t* program, size_t programsize, int argc, const char* const* argv, int envc, const char* const* envp, - CPU::InterruptRegisters* regs) + struct thread_registers* regs) { assert(argc != INT_MAX); assert(envc != INT_MAX); @@ -969,10 +963,43 @@ int Process::Execute(const char* programname, const uint8_t* program, uthread->arg_size = arg_segment.size; memset(uthread + 1, 0, aux.uthread_size - sizeof(struct uthread)); + memset(regs, 0, sizeof(*regs)); #if defined(__i386__) - GDT::SetGSBase((uint32_t) uthread); + regs->eax = argc; + regs->ebx = (size_t) target_argv; + regs->edx = envc; + regs->ecx = (size_t) target_envp; + regs->eip = entry; + regs->esp = (stack_segment.addr + stack_segment.size) & ~15UL; + regs->ebp = regs->esp; + regs->cs = UCS | URPL; + regs->ds = UDS | URPL; + regs->ss = UDS | URPL; + regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + regs->signal_pending = 0; + regs->gsbase = (uint32_t) uthread; + regs->cr3 = addrspace; + regs->kernel_stack = GDT::GetKernelStack(); + memcpy(regs->fpuenv, Float::fpu_initialized_regs, 512); #elif defined(__x86_64__) - wrmsr(MSRID_FSBASE, (uint64_t) uthread); + regs->rdi = argc; + regs->rsi = (size_t) target_argv; + regs->rdx = envc; + regs->rcx = (size_t) target_envp; + regs->rip = entry; + regs->rsp = (stack_segment.addr + stack_segment.size) & ~15UL; + regs->rbp = regs->rsp; + regs->cs = UCS | URPL; + regs->ds = UDS | URPL; + regs->ss = UDS | URPL; + regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + regs->signal_pending = 0; + regs->fsbase = (uint64_t) uthread; + regs->cr3 = addrspace; + regs->kernel_stack = GDT::GetKernelStack(); + memcpy(regs->fpuenv, Float::fpu_initialized_regs, 512); +#else +#warning "You need to implement initializing the first thread after execute" #endif uint8_t* auxcode = (uint8_t*) auxcode_segment.addr; @@ -991,8 +1018,6 @@ int Process::Execute(const char* programname, const uint8_t* program, dtable->OnExecute(); - ExecuteCPU(argc, target_argv, envc, target_envp, stack_segment.addr + stack_segment.size, entry, regs); - return 0; } @@ -1002,7 +1027,7 @@ int sys_execve_kernel(const char* filename, char* const argv[], int envc, char* const envp[], - CPU::InterruptRegisters* regs) + struct thread_registers* regs) { Process* process = CurrentProcess(); @@ -1054,7 +1079,7 @@ int sys_execve(const char* user_filename, char** argv; char** envp; int result = -1; - CPU::InterruptRegisters regs; + struct thread_registers regs; memset(®s, 0, sizeof(regs)); if ( !user_filename || !user_argv || !user_envp ) @@ -1135,7 +1160,7 @@ cleanup_filename: delete[] filename; cleanup_done: if ( result == 0 ) - CPU::LoadRegisters(®s); + LoadRegisters(®s); return result; } @@ -1158,15 +1183,22 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs) if ( regs.altstack.ss_flags & ~__SS_SUPPORTED_FLAGS ) return errno = EINVAL, -1; - CPU::InterruptRegisters cpuregs; - InitializeThreadRegisters(&cpuregs, ®s); + size_t stack_alignment = 16; // TODO: Is it a hack to create a new kernel stack here? Thread* curthread = CurrentThread(); - uint8_t* newkernelstack = new uint8_t[curthread->kernelstacksize]; + size_t newkernelstacksize = curthread->kernelstacksize; + uint8_t* newkernelstack = new uint8_t[newkernelstacksize + stack_alignment]; if ( !newkernelstack ) return -1; + uintptr_t stack_aligned = (uintptr_t) newkernelstack; + size_t stack_aligned_size = newkernelstacksize; + + if ( ((uintptr_t) stack_aligned) & (stack_alignment-1) ) + stack_aligned = (stack_aligned + 16) & ~(stack_alignment-1); + stack_aligned_size &= 0xFFFFFFF0; + Process* child_process; if ( making_thread ) child_process = CurrentProcess(); @@ -1176,10 +1208,59 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs) return -1; } + struct thread_registers cpuregs; + memset(&cpuregs, 0, sizeof(cpuregs)); +#if defined(__i386__) + cpuregs.eip = regs.eip; + cpuregs.esp = regs.esp; + cpuregs.eax = regs.eax; + cpuregs.ebx = regs.ebx; + cpuregs.ecx = regs.ecx; + cpuregs.edx = regs.edx; + cpuregs.edi = regs.edi; + cpuregs.esi = regs.esi; + cpuregs.ebp = regs.ebp; + cpuregs.cs = UCS | URPL; + cpuregs.ds = UDS | URPL; + cpuregs.ss = UDS | URPL; + cpuregs.eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + cpuregs.fsbase = regs.fsbase; + cpuregs.gsbase = regs.gsbase; + cpuregs.cr3 = child_process->addrspace; + cpuregs.kernel_stack = stack_aligned + stack_aligned_size; +#elif defined(__x86_64__) + cpuregs.rip = regs.rip; + cpuregs.rsp = regs.rsp; + cpuregs.rax = regs.rax; + cpuregs.rbx = regs.rbx; + cpuregs.rcx = regs.rcx; + cpuregs.rdx = regs.rdx; + cpuregs.rdi = regs.rdi; + cpuregs.rsi = regs.rsi; + cpuregs.rbp = regs.rbp; + cpuregs.r8 = regs.r8; + cpuregs.r9 = regs.r9; + cpuregs.r10 = regs.r10; + cpuregs.r11 = regs.r11; + cpuregs.r12 = regs.r12; + cpuregs.r13 = regs.r13; + cpuregs.r14 = regs.r14; + cpuregs.r15 = regs.r15; + cpuregs.cs = UCS | URPL; + cpuregs.ds = UDS | URPL; + cpuregs.ss = UDS | URPL; + cpuregs.rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; + cpuregs.fsbase = regs.fsbase; + cpuregs.gsbase = regs.gsbase; + cpuregs.cr3 = child_process->addrspace; + cpuregs.kernel_stack = stack_aligned + stack_aligned_size; +#else +#warning "You need to implement initializing the registers of the new thread" +#endif + // If the thread could not be created, make the process commit suicide // in a manner such that we don't wait for its zombie. - Thread* thread = CreateKernelThread(child_process, &cpuregs, regs.fsbase, - regs.gsbase); + Thread* thread = CreateKernelThread(child_process, &cpuregs); if ( !thread ) { if ( making_process ) @@ -1188,7 +1269,7 @@ static pid_t sys_tfork(int flags, struct tfork* user_regs) } thread->kernelstackpos = (addr_t) newkernelstack; - thread->kernelstacksize = curthread->kernelstacksize; + thread->kernelstacksize = newkernelstacksize; thread->kernelstackmalloced = true; memcpy(&thread->signal_mask, ®s.sigmask, sizeof(sigset_t)); memcpy(&thread->signal_stack, ®s.altstack, sizeof(stack_t)); diff --git a/kernel/registers.cpp b/kernel/registers.cpp new file mode 100644 index 00000000..a8c547bf --- /dev/null +++ b/kernel/registers.cpp @@ -0,0 +1,76 @@ +/******************************************************************************* + + Copyright(C) Jonas 'Sortie' Termansen 2011, 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 . + + registers.cpp + Register structures and platform-specific bits. + +*******************************************************************************/ + +#include + +#include +#include +#include + +namespace Sortix { + +void LogInterruptContext(const struct interrupt_context* intctx) +{ +#if defined(__i386__) + Log::PrintF("[cr2=0x%zx,ds=0x%zx,edi=0x%zx,esi=0x%zx,ebp=0x%zx," + "ebx=0x%zx,edx=0x%zx,ecx=0x%zx,eax=0x%zx," + "int_no=0x%zx,err_code=0x%zx,eip=0x%zx,cs=0x%zx," + "eflags=0x%zx,esp=0x%zx,ss=0x%zx]", + intctx->cr2, intctx->ds, intctx->edi, intctx->esi, intctx->ebp, + intctx->ebx, intctx->edx, intctx->ecx, intctx->eax, + intctx->int_no, intctx->err_code, intctx->eip, intctx->cs, + intctx->eflags, intctx->esp, intctx->ss); +#elif defined(__x86_64__) + Log::PrintF("[cr2=0x%zx,ds=0x%zx,rdi=0x%zx,rsi=0x%zx,rbp=0x%zx," + "rbx=0x%zx,rdx=0x%zx,rcx=0x%zx,rax=0x%zx," + "r8=0x%zx,r9=0x%zx,r10=0x%zx,r11=0x%zx,r12=0x%zx," + "r13=0x%zx,r14=0x%zx,r15=0x%zx,int_no=0x%zx," + "err_code=0x%zx,rip=0x%zx,cs=0x%zx,rflags=0x%zx," + "rsp=0x%zx,ss=0x%zx]", + intctx->cr2, intctx->ds, intctx->rdi, intctx->rsi, intctx->rbp, + intctx->rbx, intctx->rdx, intctx->rcx, intctx->rax, + intctx->r8, intctx->r9, intctx->r10, intctx->r11, intctx->r12, + intctx->r13, intctx->r14, intctx->r15, intctx->int_no, + intctx->err_code, intctx->rip, intctx->cs, intctx->rflags, + intctx->rsp, intctx->ss); +#else +#warning "You need to implement printing an interrupt context" +#endif +} + +extern "C" __attribute__((noreturn)) +void load_registers(const struct interrupt_context* inctx); + +__attribute__((noreturn)) +void LoadRegisters(const struct thread_registers* registers) +{ + struct interrupt_context intctx; + memset(&intctx, 0, sizeof(intctx)); + + Scheduler::LoadInterruptedContext(&intctx, registers); + + load_registers(&intctx); +} + +} // namespace Sortix diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp index f2b7051b..4277c9ba 100644 --- a/kernel/scheduler.cpp +++ b/kernel/scheduler.cpp @@ -25,10 +25,13 @@ #include #include -#include #include #include +#if defined(__x86_64__) +#include +#endif + #include #include @@ -37,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -52,9 +56,143 @@ namespace Sortix { namespace Scheduler { static Thread* current_thread; + +void SaveInterruptedContext(const struct interrupt_context* intctx, + struct thread_registers* registers) +{ +#if defined(__i386__) + registers->signal_pending = intctx->signal_pending; + registers->kerrno = intctx->kerrno; + registers->eax = intctx->eax; + registers->ebx = intctx->ebx; + registers->ecx = intctx->ecx; + registers->edx = intctx->edx; + registers->edi = intctx->edi; + registers->esi = intctx->esi; + registers->esp = intctx->esp; + registers->ebp = intctx->ebp; + registers->eip = intctx->eip; + registers->eflags = intctx->eflags; + registers->fsbase = (unsigned long) GDT::GetFSBase(); + registers->gsbase = (unsigned long) GDT::GetGSBase(); + asm ( "mov %%cr3, %0" : "=r"(registers->cr3) ); + registers->kernel_stack = GDT::GetKernelStack(); + registers->cs = intctx->cs; + registers->ds = intctx->ds; + registers->ss = intctx->ss; + asm volatile ("fxsave (%0)" : : "r"(registers->fpuenv)); +#elif defined(__x86_64__) + registers->signal_pending = intctx->signal_pending; + registers->kerrno = intctx->kerrno; + registers->rax = intctx->rax; + registers->rbx = intctx->rbx; + registers->rcx = intctx->rcx; + registers->rdx = intctx->rdx; + registers->rdi = intctx->rdi; + registers->rsi = intctx->rsi; + registers->rsp = intctx->rsp; + registers->rbp = intctx->rbp; + registers->r8 = intctx->r8; + registers->r9 = intctx->r9; + registers->r10 = intctx->r10; + registers->r11 = intctx->r11; + registers->r12 = intctx->r12; + registers->r13 = intctx->r13; + registers->r14 = intctx->r14; + registers->r15 = intctx->r15; + registers->r15 = intctx->r15; + registers->rip = intctx->rip; + registers->rflags = intctx->rflags; + registers->fsbase = (unsigned long) rdmsr(MSRID_FSBASE); + registers->gsbase = (unsigned long) rdmsr(MSRID_GSBASE); + asm ( "mov %%cr3, %0" : "=r"(registers->cr3) ); + registers->kernel_stack = GDT::GetKernelStack(); + registers->cs = intctx->cs; + registers->ds = intctx->ds; + registers->ss = intctx->ss; + asm volatile ("fxsave (%0)" : : "r"(registers->fpuenv)); +#else +#warning "You need to implement register saving" +#endif +} + +void LoadInterruptedContext(struct interrupt_context* intctx, + const struct thread_registers* registers) +{ +#if defined(__i386__) + intctx->signal_pending = registers->signal_pending; + intctx->kerrno = registers->kerrno; + intctx->eax = registers->eax; + intctx->ebx = registers->ebx; + intctx->ecx = registers->ecx; + intctx->edx = registers->edx; + intctx->edi = registers->edi; + intctx->esi = registers->esi; + intctx->esp = registers->esp; + intctx->ebp = registers->ebp; + intctx->eip = registers->eip; + intctx->eflags = registers->eflags; + GDT::SetFSBase(registers->fsbase); + GDT::SetGSBase(registers->gsbase); + asm volatile ( "mov %0, %%cr3" : : "r"(registers->cr3) ); + GDT::SetKernelStack(registers->kernel_stack); + intctx->cs = registers->cs; + intctx->ds = registers->ds; + intctx->ss = registers->ss; + asm volatile ("fxrstor (%0)" : : "r"(registers->fpuenv)); +#elif defined(__x86_64__) + intctx->signal_pending = registers->signal_pending; + intctx->kerrno = registers->kerrno; + intctx->rax = registers->rax; + intctx->rbx = registers->rbx; + intctx->rcx = registers->rcx; + intctx->rdx = registers->rdx; + intctx->rdi = registers->rdi; + intctx->rsi = registers->rsi; + intctx->rsp = registers->rsp; + intctx->rbp = registers->rbp; + intctx->r8 = registers->r8; + intctx->r9 = registers->r9; + intctx->r10 = registers->r10; + intctx->r11 = registers->r11; + intctx->r12 = registers->r12; + intctx->r13 = registers->r13; + intctx->r14 = registers->r14; + intctx->r15 = registers->r15; + intctx->r15 = registers->r15; + intctx->rip = registers->rip; + intctx->rflags = registers->rflags; + wrmsr(MSRID_FSBASE, registers->fsbase); + wrmsr(MSRID_GSBASE, registers->gsbase); + asm volatile ( "mov %0, %%cr3" : : "r"(registers->cr3) ); + GDT::SetKernelStack(registers->kernel_stack); + intctx->cs = registers->cs; + intctx->ds = registers->ds; + intctx->ss = registers->ss; + asm volatile ("fxrstor (%0)" : : "r"(registers->fpuenv)); +#else +#warning "You need to implement register loading" +#endif +} + +static +void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next) +{ + if ( prev == next ) + return; + + SaveInterruptedContext(intctx, &prev->registers); + if ( !prev->registers.cr3 ) + Log::PrintF("Thread %p had cr3=0x%zx\n", prev, prev->registers.cr3); + if ( !next->registers.cr3 ) + Log::PrintF("Thread %p has cr3=0x%zx\n", next, next->registers.cr3); + LoadInterruptedContext(intctx, &next->registers); + + current_thread = next; +} + static Thread* idle_thread; static Thread* first_runnable_thread; -static Thread* first_sleeping_thread; static Process* init_process; static Thread* PopNextThread() @@ -69,63 +207,26 @@ static Thread* PopNextThread() return idle_thread; } -static void DoActualSwitch(CPU::InterruptRegisters* regs) +void Switch(struct interrupt_context* intctx) { - Thread* prev = CurrentThread(); - Thread* next = PopNextThread(); + SwitchThread(intctx, CurrentThread(), PopNextThread()); - if ( prev == next ) - return; - - prev->SaveRegisters(regs); - next->LoadRegisters(regs); - - Memory::SwitchAddressSpace(next->addrspace); - current_thread = next; - -#if defined(__i386__) || defined(__x86_64__) - Float::NotityTaskSwitch(); - GDT::SetKernelStack(next->kernelstackpos, next->kernelstacksize, - next->kernelstackpos + next->kernelstacksize); -#endif - -#if defined(__i386__) - prev->fsbase = (unsigned long) GDT::GetFSBase(); - prev->gsbase = (unsigned long) GDT::GetGSBase(); - GDT::SetFSBase((uint32_t) next->fsbase); - GDT::SetGSBase((uint32_t) next->gsbase); -#elif defined(__x86_64__) - prev->fsbase = (unsigned long) rdmsr(MSRID_FSBASE); - prev->gsbase = (unsigned long) rdmsr(MSRID_GSBASE); - wrmsr(MSRID_FSBASE, (uint64_t) next->fsbase); - wrmsr(MSRID_GSBASE, (uint64_t) next->gsbase); -#endif -} - -void Switch(CPU::InterruptRegisters* regs) -{ - DoActualSwitch(regs); - - if ( regs->signal_pending && regs->InUserspace() ) + if ( intctx->signal_pending && InUserspace(intctx) ) { Interrupt::Enable(); - Signal::DispatchHandler(regs, NULL); + Signal::DispatchHandler(intctx, NULL); } } -void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* /*user*/) +void InterruptYieldCPU(struct interrupt_context* intctx, void* /*user*/) { - Switch(regs); + Switch(intctx); } -void ThreadExitCPU(CPU::InterruptRegisters* regs, void* /*user*/) +void ThreadExitCPU(struct interrupt_context* intctx, void* /*user*/) { -#if defined(__i386__) || defined(__x86_64__) - // Can't use floating point instructions from now. - Float::NofityTaskExit(current_thread); -#endif SetThreadState(current_thread, ThreadState::DEAD); - InterruptYieldCPU(regs, NULL); + InterruptYieldCPU(intctx, NULL); } // The idle thread serves no purpose except being an infinite loop that does @@ -206,7 +307,6 @@ static int sys_sched_yield(void) void Init() { first_runnable_thread = NULL; - first_sleeping_thread = NULL; idle_thread = NULL; Syscall::Register(SYSCALL_SCHED_YIELD, (void*) sys_sched_yield); diff --git a/kernel/signal.cpp b/kernel/signal.cpp index 4fff0d74..9482571d 100644 --- a/kernel/signal.cpp +++ b/kernel/signal.cpp @@ -44,10 +44,6 @@ #include #include -#if defined(__i386__) || defined(__x86_64__) -#include "x86-family/float.h" -#endif - namespace Sortix { sigset_t default_ignored_signals; @@ -57,6 +53,7 @@ sigset_t unblockable_signals; // A per-cpu value whether a signal is pending in the running task. extern "C" { volatile unsigned long asm_signal_is_pending = 0; } +static void UpdatePendingSignals(Thread* thread) // thread->process->signal_lock held { struct sigaction* signal_actions = thread->process->signal_actions; @@ -400,7 +397,9 @@ static int PickImportantSignal(const sigset_t* set) return 0; } -static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs) +static void EncodeMachineContext(mcontext_t* mctx, + const struct thread_registers* regs, + const struct interrupt_context* intctx) { memset(mctx, 0, sizeof(*mctx)); #if defined(__i386__) @@ -419,10 +418,9 @@ static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs mctx->gregs[REG_EIP] = regs->eip; // TODO: REG_CS mctx->gregs[REG_EFL] = regs->eflags & 0x0000FFFF; - mctx->gregs[REG_CR2] = regs->cr2; + mctx->gregs[REG_CR2] = intctx->cr2; // TODO: REG_SS - Float::Yield(); - memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512); + memcpy(mctx->fpuenv, regs->fpuenv, 512); #elif defined(__x86_64__) mctx->gregs[REG_R8] = regs->r8; mctx->gregs[REG_R9] = regs->r9; @@ -443,17 +441,17 @@ static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs mctx->gregs[REG_RIP] = regs->rip; mctx->gregs[REG_EFL] = regs->rflags & 0x000000000000FFFF; // TODO: REG_CSGSFS. - mctx->gregs[REG_CR2] = regs->cr2; + mctx->gregs[REG_CR2] = intctx->cr2; mctx->gregs[REG_FSBASE] = 0x0; mctx->gregs[REG_GSBASE] = 0x0; - Float::Yield(); - memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512); + memcpy(mctx->fpuenv, regs->fpuenv, 512); #else #error "You need to implement conversion to mcontext" #endif } -static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs) +static void DecodeMachineContext(const mcontext_t* mctx, + struct thread_registers* regs) { #if defined(__i386__) || defined(__x86_64__) unsigned long user_flags = FLAGS_CARRY | FLAGS_PARITY | FLAGS_AUX @@ -472,9 +470,7 @@ static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs regs->eip = mctx->gregs[REG_EIP]; regs->eflags &= ~user_flags; regs->eflags |= mctx->gregs[REG_EFL] & user_flags; - regs->cr2 = mctx->gregs[REG_CR2]; - Float::Yield(); - memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512); + memcpy(regs->fpuenv, mctx->fpuenv, 512); #elif defined(__x86_64__) regs->r8 = mctx->gregs[REG_R8]; regs->r9 = mctx->gregs[REG_R9]; @@ -495,9 +491,7 @@ static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs regs->rip = mctx->gregs[REG_RIP]; regs->rflags &= ~user_flags; regs->rflags |= mctx->gregs[REG_EFL] & user_flags; - regs->cr2 = mctx->gregs[REG_CR2]; - Float::Yield(); - memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512); + memcpy(regs->fpuenv, mctx->fpuenv, 512); #else #error "You need to implement conversion to mcontext" #endif @@ -525,7 +519,7 @@ struct stack_frame #error "You need to implement struct stack_frame" #endif -void Thread::HandleSignal(CPU::InterruptRegisters* regs) +void Thread::HandleSignal(struct interrupt_context* intctx) { assert(Interrupt::IsEnabled()); assert(this == CurrentThread()); @@ -553,7 +547,7 @@ retry_another_signal: // Unmark the selected signal as pending. sigdelset(&signal_pending, signum); UpdatePendingSignals(this); - regs->signal_pending = asm_signal_is_pending; + intctx->signal_pending = asm_signal_is_pending; // Destroy the current thread if the signal is critical. if ( signum == SIGKILL ) @@ -614,28 +608,31 @@ retry_another_signal: // threads in the kernel cannot be delivered signals except when returning // from a system call, so we'll simply save the state that would have been // returned to user-space had no signal occured. - if ( !regs->InUserspace() ) + if ( !InUserspace(intctx) ) { #if defined(__i386__) - uint32_t* params = (uint32_t*) regs->ebx; - regs->eip = params[0]; - regs->eflags = params[2]; - regs->esp = params[3]; - regs->cs = UCS | URPL; - regs->ds = UDS | URPL; - regs->ss = UDS | URPL; + uint32_t* params = (uint32_t*) intctx->ebx; + intctx->eip = params[0]; + intctx->eflags = params[2]; + intctx->esp = params[3]; + intctx->cs = UCS | URPL; + intctx->ds = UDS | URPL; + intctx->ss = UDS | URPL; #elif defined(__x86_64__) - regs->rip = regs->rdi; - regs->rflags = regs->rsi; - regs->rsp = regs->r8; - regs->cs = UCS | URPL; - regs->ds = UDS | URPL; - regs->ss = UDS | URPL; + intctx->rip = intctx->rdi; + intctx->rflags = intctx->rsi; + intctx->rsp = intctx->r8; + intctx->cs = UCS | URPL; + intctx->ds = UDS | URPL; + intctx->ss = UDS | URPL; #else #error "You may need to fix the registers" #endif } + struct thread_registers stopped_regs; + Scheduler::SaveInterruptedContext(intctx, &stopped_regs); + sigset_t new_signal_mask; memcpy(&new_signal_mask, &action->sa_mask, sizeof(sigset_t)); sigorset(&new_signal_mask, &new_signal_mask, &signal_mask); @@ -670,15 +667,16 @@ retry_another_signal: old_signal_stack.ss_size = 0; new_signal_stack = signal_stack; #if defined(__i386__) - stack_location = (uintptr_t) regs->esp; + stack_location = (uintptr_t) stopped_regs.esp; #elif defined(__x86_64__) - stack_location = (uintptr_t) regs->rsp; + stack_location = (uintptr_t) stopped_regs.rsp; #else #error "You need to implement getting the user-space stack pointer" #endif } - CPU::InterruptRegisters new_regs = *regs; + struct thread_registers handler_regs; + memcpy(&handler_regs, &stopped_regs, sizeof(handler_regs)); struct stack_frame stack_frame; memset(&stack_frame, 0, sizeof(stack_frame)); @@ -700,9 +698,9 @@ retry_another_signal: stack_frame.ucontext_param = &stack->ucontext; stack_frame.cookie_param = action->sa_cookie; - new_regs.esp = (unsigned long) stack; - new_regs.eip = (unsigned long) handler_ptr; - new_regs.eflags &= ~FLAGS_DIRECTION; + handler_regs.esp = (unsigned long) stack; + handler_regs.eip = (unsigned long) handler_ptr; + handler_regs.eflags &= ~FLAGS_DIRECTION; #elif defined(__x86_64__) stack_location -= 128; /* Red zone. */ stack_location -= sizeof(stack_frame); @@ -710,14 +708,14 @@ retry_another_signal: struct stack_frame* stack = (struct stack_frame*) stack_location; stack_frame.sigreturn = (unsigned long) process->sigreturn; - new_regs.rdi = (unsigned long) signum; - new_regs.rsi = (unsigned long) &stack->siginfo; - new_regs.rdx = (unsigned long) &stack->ucontext; - new_regs.rcx = (unsigned long) action->sa_cookie; + handler_regs.rdi = (unsigned long) signum; + handler_regs.rsi = (unsigned long) &stack->siginfo; + handler_regs.rdx = (unsigned long) &stack->ucontext; + handler_regs.rcx = (unsigned long) action->sa_cookie; - new_regs.rsp = (unsigned long) stack; - new_regs.rip = (unsigned long) handler_ptr; - new_regs.rflags &= ~FLAGS_DIRECTION; + handler_regs.rsp = (unsigned long) stack; + handler_regs.rip = (unsigned long) handler_ptr; + handler_regs.rflags &= ~FLAGS_DIRECTION; #else #error "You need to format the stack frame" #endif @@ -727,7 +725,7 @@ retry_another_signal: #if defined(__i386__) || defined(__x86_64__) // TODO: Is this cr2 value trustworthy? I don't think it is. if ( signum == SIGSEGV ) - stack_frame.siginfo.si_addr = (void*) regs->cr2; + stack_frame.siginfo.si_addr = (void*) intctx->cr2; #else #warning "You need to tell user-space where it crashed" #endif @@ -736,7 +734,7 @@ retry_another_signal: stack_frame.ucontext.uc_link = NULL; memcpy(&stack_frame.ucontext.uc_sigmask, &signal_mask, sizeof(signal_mask)); memcpy(&stack_frame.ucontext.uc_stack, &signal_stack, sizeof(signal_stack)); - EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, regs); + EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, &stopped_regs, intctx); if ( !CopyToUser(stack, &stack_frame, sizeof(stack_frame)) ) { @@ -764,7 +762,7 @@ retry_another_signal: signal_stack = new_signal_stack; // Update the current registers. - *regs = new_regs; + Scheduler::LoadInterruptedContext(intctx, &handler_regs); // TODO: SA_RESETHAND: // "If set, the disposition of the signal shall be reset to SIG_DFL @@ -776,7 +774,7 @@ retry_another_signal: return; } -void Thread::HandleSigreturn(CPU::InterruptRegisters* regs) +void Thread::HandleSigreturn(struct interrupt_context* intctx) { assert(Interrupt::IsEnabled()); assert(this == CurrentThread()); @@ -786,9 +784,9 @@ void Thread::HandleSigreturn(CPU::InterruptRegisters* regs) struct stack_frame stack_frame; const struct stack_frame* user_stack_frame; #if defined(__i386__) - user_stack_frame = (const struct stack_frame*) (regs->esp - 4); + user_stack_frame = (const struct stack_frame*) (intctx->esp - 4); #elif defined(__x86_64__) - user_stack_frame = (const struct stack_frame*) (regs->rsp - 8); + user_stack_frame = (const struct stack_frame*) (intctx->rsp - 8); #else #error "You need to locate the stack we passed the signal handler" #endif @@ -798,27 +796,30 @@ void Thread::HandleSigreturn(CPU::InterruptRegisters* regs) memcpy(&signal_mask, &stack_frame.ucontext.uc_sigmask, sizeof(signal_mask)); memcpy(&signal_stack, &stack_frame.ucontext.uc_stack, sizeof(signal_stack)); signal_stack.ss_flags &= __SS_SUPPORTED_FLAGS; - DecodeMachineContext(&stack_frame.ucontext.uc_mcontext, regs); + struct thread_registers resume_regs; + Scheduler::SaveInterruptedContext(intctx, &resume_regs); + DecodeMachineContext(&stack_frame.ucontext.uc_mcontext, &resume_regs); + Scheduler::LoadInterruptedContext(intctx, &resume_regs); } UpdatePendingSignals(this); - regs->signal_pending = asm_signal_is_pending; + intctx->signal_pending = asm_signal_is_pending; lock.Reset(); - HandleSignal(regs); + HandleSignal(intctx); } namespace Signal { -void DispatchHandler(CPU::InterruptRegisters* regs, void* /*user*/) +void DispatchHandler(struct interrupt_context* intctx, void* /*user*/) { - return CurrentThread()->HandleSignal(regs); + return CurrentThread()->HandleSignal(intctx); } -void ReturnHandler(CPU::InterruptRegisters* regs, void* /*user*/) +void ReturnHandler(struct interrupt_context* intctx, void* /*user*/) { - return CurrentThread()->HandleSigreturn(regs); + return CurrentThread()->HandleSigreturn(intctx); } void Init() diff --git a/kernel/thread.cpp b/kernel/thread.cpp index c7eecefe..f63c3e9a 100644 --- a/kernel/thread.cpp +++ b/kernel/thread.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -44,10 +45,39 @@ #include #include +void* operator new (size_t /*size*/, void* address) throw() +{ + return address; +} + namespace Sortix { +Thread* AllocateThread() +{ + uint8_t* allocation = (uint8_t*) malloc(sizeof(class Thread) + 16); + if ( !allocation ) + return NULL; + + uint8_t* aligned = allocation; + if ( ((uintptr_t) aligned & 0xFUL) ) + aligned = (uint8_t*) (((uintptr_t) aligned + 16) & ~0xFUL); + + assert(!((uintptr_t) aligned & 0xFUL)); + Thread* thread = new (aligned) Thread; + assert(!((uintptr_t) thread->registers.fpuenv & 0xFUL)); + return thread->self_allocation = allocation, thread; +} + +void FreeThread(Thread* thread) +{ + uint8_t* allocation = thread->self_allocation; + thread->~Thread(); + free(allocation); +} + Thread::Thread() { + assert(!((uintptr_t) registers.fpuenv & 0xFUL)); id = 0; // TODO: Make a thread id. process = NULL; prevsibling = NULL; @@ -56,17 +86,10 @@ Thread::Thread() scheduler_list_next = NULL; state = NONE; memset(®isters, 0, sizeof(registers)); - fsbase = 0; - gsbase = 0; kernelstackpos = 0; kernelstacksize = 0; kernelstackmalloced = false; pledged_destruction = false; - fpuinitialized = false; - // If malloc isn't 16-byte aligned, then we can't rely on offsets in - // our own class, so we'll just fix ourselves nicely up. - unsigned long fpuaddr = ((unsigned long) fpuenv+16UL) & ~(16UL-1UL); - fpuenvaligned = (uint8_t*) fpuaddr; sigemptyset(&signal_pending); sigemptyset(&signal_mask); memset(&signal_stack, 0, sizeof(signal_stack)); @@ -82,129 +105,22 @@ Thread::~Thread() delete[] (uint8_t*) kernelstackpos; } -void Thread::SaveRegisters(const CPU::InterruptRegisters* src) +Thread* CreateKernelThread(Process* process, struct thread_registers* regs) { -#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); - addr_t result = addrspace; - addrspace = newaddrspace; - Memory::SwitchAddressSpace(newaddrspace); - Interrupt::SetEnabled(wasenabled); - return result; -} - -Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs, - unsigned long fsbase, unsigned long gsbase) -{ -#if defined(__x86_64__) - if ( fsbase >> 48 != 0x0000 && fsbase >> 48 != 0xFFFF ) - return errno = EINVAL, (Thread*) NULL; - if ( gsbase >> 48 != 0x0000 && gsbase >> 48 != 0xFFFF ) - return errno = EINVAL, (Thread*) NULL; -#endif - assert(process && regs && process->addrspace); - Thread* thread = new Thread; + +#if defined(__x86_64__) + if ( regs->fsbase >> 48 != 0x0000 && regs->fsbase >> 48 != 0xFFFF ) + return errno = EINVAL, (Thread*) NULL; + if ( regs->gsbase >> 48 != 0x0000 && regs->gsbase >> 48 != 0xFFFF ) + return errno = EINVAL, (Thread*) NULL; +#endif + + Thread* thread = AllocateThread(); if ( !thread ) return NULL; - thread->addrspace = process->addrspace; - thread->SaveRegisters(regs); - thread->fsbase = fsbase; - thread->gsbase = gsbase; + memcpy(&thread->registers, regs, sizeof(struct thread_registers)); kthread_mutex_lock(&process->threadlock); @@ -221,48 +137,62 @@ Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs, return thread; } -static void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, +static void SetupKernelThreadRegs(struct thread_registers* regs, + Process* process, void (*entry)(void*), void* user, uintptr_t stack, size_t stack_size) { + memset(regs, 0, sizeof(*regs)); + + size_t stack_alignment = 16; + while ( stack & (stack_alignment-1) ) + { + assert(stack_size); + stack++; + stack_size--; + } + + stack_size &= ~(stack_alignment-1); + #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); + assert(5 * 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 */ + /* -- 16-byte aligned -- */ + /* -1 padding */ + stack_values[-2] = (uintptr_t) 0; /* null eip */ + stack_values[-3] = (uintptr_t) 0; /* null ebp */ + stack_values[-4] = (uintptr_t) user; /* thread parameter */ + /* -- 16-byte aligned -- */ + stack_values[-5] = (uintptr_t) kthread_exit; /* return to kthread_exit */ + /* upcoming ebp */ + /* -7 padding */ + /* -8 padding */ + /* -- 16-byte aligned -- */ regs->eip = (uintptr_t) entry; - regs->esp = (uintptr_t) (stack_values - 4); + regs->esp = (uintptr_t) (stack_values - 5); 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->ebp = (uintptr_t) (stack_values - 3); 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; + regs->kernel_stack = stack + stack_size; + regs->cr3 = process->addrspace; #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 */ @@ -292,8 +222,10 @@ static void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; regs->kerrno = 0; regs->signal_pending = 0; + regs->kernel_stack = stack + stack_size; + regs->cr3 = process->addrspace; #else -#warning "You need to add thread register initialization support" +#warning "You need to add kernel thread register initialization support" #endif } @@ -307,10 +239,10 @@ Thread* CreateKernelThread(Process* process, void (*entry)(void*), void* user, if ( !stack ) return NULL; - CPU::InterruptRegisters regs; - SetupKernelThreadRegs(®s, entry, user, (uintptr_t) stack, stacksize); + struct thread_registers regs; + SetupKernelThreadRegs(®s, process, entry, user, (uintptr_t) stack, stacksize); - Thread* thread = CreateKernelThread(process, ®s, 0, 0); + Thread* thread = CreateKernelThread(process, ®s); if ( !thread ) { delete[] stack; return NULL; } thread->kernelstackpos = (uintptr_t) stack; @@ -330,9 +262,9 @@ void StartKernelThread(Thread* thread) Scheduler::SetThreadState(thread, ThreadState::RUNNABLE); } -Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs) +Thread* RunKernelThread(Process* process, struct thread_registers* regs) { - Thread* thread = CreateKernelThread(process, regs, 0, 0); + Thread* thread = CreateKernelThread(process, regs); if ( !thread ) return NULL; StartKernelThread(thread); diff --git a/kernel/x64/boot.S b/kernel/x64/boot.S index 75c2c3e5..c9b77f0e 100644 --- a/kernel/x64/boot.S +++ b/kernel/x64/boot.S @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. This file is part of Sortix. @@ -141,6 +141,9 @@ Realm64: or $0x600, %rax mov %rax, %cr4 + # Store a copy of the initialial floating point registers. + fxsave fpu_initialized_regs + # Alright, that was the bootstrap code. Now begin preparing to run the # actual 64-bit kernel. jmp Main diff --git a/kernel/x64/interrupt.S b/kernel/x64/interrupt.S index 92de72f7..bfa43942 100644 --- a/kernel/x64/interrupt.S +++ b/kernel/x64/interrupt.S @@ -386,7 +386,10 @@ interrupt_handler_prepare: # Now call the interrupt handler. movq %rsp, %rdi + movq %rsp, %rbx + andq $0xFFFFFFFFFFFFFFF0, %rsp call interrupt_handler + movq %rbx, %rsp load_interrupted_registers: # Restore whether signals are pending. diff --git a/kernel/x64/memorymanagement.cpp b/kernel/x64/memorymanagement.cpp index 23a19cdc..95da839d 100644 --- a/kernel/x64/memorymanagement.cpp +++ b/kernel/x64/memorymanagement.cpp @@ -44,8 +44,6 @@ void ExtendStack(); namespace Sortix { namespace Memory { -extern addr_t currentdir; - void InitCPU() { // The x64 boot code already set up virtual memory and identity @@ -87,8 +85,6 @@ void InitCPU() BOOTPML3->entry[0] = (addr_t) FORKPML2 | flags | PML_FORK; FORKPML2->entry[0] = (addr_t) FORKPML1 | flags | PML_FORK; - currentdir = (addr_t) BOOTPML4; - // The virtual memory structures are now available on the predefined // locations. This means the virtual memory code is bootstrapped. Of // course, we still have no physical page allocator, so that's the @@ -139,7 +135,7 @@ void RecursiveFreeUserspacePages(size_t level, size_t offset) } } -void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* user) +void DestroyAddressSpace(addr_t fallback) { // Look up the last few entries used for the fractal mapping. These // cannot be unmapped as that would destroy the world. Instead, we @@ -150,7 +146,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use addr_t fractal2 = (PMLS[3] + 510UL)->entry[510]; addr_t fork1 = (PMLS[2] + 510UL * 512UL + 0)->entry[0]; addr_t fractal1 = (PMLS[2] + 510UL * 512UL + 510UL)->entry[510]; - addr_t dir = currentdir; + addr_t dir = GetAddressSpace(); // We want to free the pages, but we are still using them ourselves, // so lock the page allocation structure until we are done. @@ -167,10 +163,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use if ( !fallback ) fallback = (addr_t) BOOTPML4; - if ( func ) - func(fallback, user); - else - SwitchAddressSpace(fallback); + SwitchAddressSpace(fallback); // Ok, now we got marked everything left behind as unused, we can // now safely let another thread use the pages. diff --git a/kernel/x64/process.cpp b/kernel/x64/process.cpp deleted file mode 100644 index 98cb3885..00000000 --- a/kernel/x64/process.cpp +++ /dev/null @@ -1,83 +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/process.cpp - CPU-specific process code. - -*******************************************************************************/ - -#include - -#include -#include - -#include - -#include -#include - -namespace Sortix { - -void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp, - addr_t stackpos, addr_t entry, - CPU::InterruptRegisters* regs) -{ - memset(regs, 0, sizeof(*regs)); - regs->rdi = argc; - regs->rsi = (size_t) argv; - regs->rdx = envc; - regs->rcx = (size_t) envp; - regs->rip = entry; - regs->rsp = stackpos & ~15UL; - regs->rbp = regs->rsp; - regs->cs = UCS | URPL; - regs->ds = UDS | URPL; - regs->ss = UDS | URPL; - regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; - regs->signal_pending = 0; -} - -void InitializeThreadRegisters(CPU::InterruptRegisters* regs, - const struct tfork* requested) -{ - memset(regs, 0, sizeof(*regs)); - regs->rip = requested->rip; - regs->rsp = requested->rsp; - regs->rax = requested->rax; - regs->rbx = requested->rbx; - regs->rcx = requested->rcx; - regs->rdx = requested->rdx; - regs->rdi = requested->rdi; - regs->rsi = requested->rsi; - regs->rbp = requested->rbp; - regs->r8 = requested->r8; - regs->r9 = requested->r9; - regs->r10 = requested->r10; - regs->r11 = requested->r11; - regs->r12 = requested->r12; - regs->r13 = requested->r13; - regs->r14 = requested->r14; - regs->r15 = requested->r15; - regs->cs = 0x18 | 0x3; - regs->ds = 0x20 | 0x3; - regs->ss = 0x20 | 0x3; - regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; -} - -} // namespace Sortix diff --git a/kernel/x64/x64.cpp b/kernel/x64/x64.cpp deleted file mode 100644 index 207b10a7..00000000 --- a/kernel/x64/x64.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - - Copyright(C) Jonas 'Sortie' Termansen 2011, 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/x64.cpp - CPU stuff for the x64 platform. - -*******************************************************************************/ - -#include -#include -#include - -namespace Sortix { -namespace X64 { - -void InterruptRegisters::LogRegisters() const -{ - Log::PrintF("[cr2=0x%zx,ds=0x%zx,rdi=0x%zx,rsi=0x%zx,rbp=0x%zx," - "rbx=0x%zx,rdx=0x%zx,rcx=0x%zx,rax=0x%zx," - "r8=0x%zx,r9=0x%zx,r10=0x%zx,r11=0x%zx,r12=0x%zx," - "r13=0x%zx,r14=0x%zx,r15=0x%zx,int_no=0x%zx," - "err_code=0x%zx,rip=0x%zx,cs=0x%zx,rflags=0x%zx," - "rsp=0x%zx,ss=0x%zx]", - cr2, ds, rdi, rsi, rbp, - rbx, rdx, rcx, rax, - r8, r9, r10, r11, r12, - r13, r14, r15, int_no, - err_code, rip, cs, rflags, - rsp, ss); -} - -} // namespace X64 -} // namespace Sortix diff --git a/kernel/x86-family/float.cpp b/kernel/x86-family/float.cpp index 17978e80..b0148cef 100644 --- a/kernel/x86-family/float.cpp +++ b/kernel/x86-family/float.cpp @@ -33,104 +33,7 @@ namespace Sortix { namespace Float { -static Thread* fputhread; -bool fpu_is_enabled = false; - -static inline void InitFPU() -{ - asm volatile ("fninit"); -} - -static inline void SaveState(uint8_t* dest) -{ - assert( (((unsigned long) dest) & (16UL-1UL)) == 0 ); - asm volatile ("fxsave (%0)" : : "r"(dest)); -} - -static inline void LoadState(const uint8_t* src) -{ - assert( (((unsigned long) src) & (16UL-1UL)) == 0 ); - asm volatile ("fxrstor (%0)" : : "r"(src)); -} - -void Yield() -{ - Thread* thread = CurrentThread(); - - Interrupt::Disable(); - - bool fpu_was_enabled = fpu_is_enabled; - - // The FPU contains the registers for this thread. - if ( fputhread == thread ) - { - if ( !fpu_was_enabled ) - EnableFPU(); - SaveState(thread->fpuenvaligned); - fputhread = NULL; - DisableFPU(); - } - - // This thread has used the FPU once. - else if ( thread->fpuinitialized ) - { - // Nothing needs to be done, the FPU is owned by another thread and the - // FPU registers are already stored in the thread structure. - } - - // This thread has never used the FPU and needs its registers initialized. - else - { - if ( !fpu_was_enabled ) - EnableFPU(); - - if ( fputhread ) - SaveState(fputhread->fpuenvaligned); - - InitFPU(); - SaveState(thread->fpuenvaligned); - - if ( fputhread ) - LoadState(fputhread->fpuenvaligned); - - if ( !fpu_was_enabled ) - DisableFPU(); - } - - Interrupt::Enable(); -} - -static void OnFPUAccess(CPU::InterruptRegisters* /*regs*/, void* /*user*/) -{ - EnableFPU(); - Thread* thread = CurrentThread(); - if ( thread == fputhread ) - return; - if ( fputhread ) - SaveState(fputhread->fpuenvaligned); - fputhread = thread; - if ( !thread->fpuinitialized ) - { - InitFPU(); - thread->fpuinitialized = true; - return; - } - LoadState(thread->fpuenvaligned); -} - -void Init() -{ - fputhread = CurrentThread(); - assert(fputhread); - Interrupt::RegisterHandler(7, OnFPUAccess, NULL); -} - -void NofityTaskExit(Thread* thread) -{ - if ( fputhread == thread ) - fputhread = NULL; - DisableFPU(); -} +extern "C" { __attribute__((aligned(16))) uint8_t fpu_initialized_regs[512]; } } // namespace Float } // namespace Sortix diff --git a/kernel/x86-family/float.h b/kernel/x86-family/float.h index a8810145..1bccfe15 100644 --- a/kernel/x86-family/float.h +++ b/kernel/x86-family/float.h @@ -25,39 +25,14 @@ #ifndef SORTIX_FLOAT_H #define SORTIX_FLOAT_H +#include + namespace Sortix { - -class Thread; - namespace Float { -extern bool fpu_is_enabled; - -void Init(); -void NofityTaskExit(Thread* thread); -void Yield(); - -static inline void EnableFPU() -{ - asm volatile ("clts"); - fpu_is_enabled = true; -} - -static inline void DisableFPU() -{ - fpu_is_enabled = false; - unsigned long cr0; - asm volatile ("mov %%cr0, %0" : "=r"(cr0)); - cr0 |= 1UL<<3UL; - asm volatile ("mov %0, %%cr0" : : "r"(cr0)); -} - -static inline void NotityTaskSwitch() -{ - DisableFPU(); -} +extern "C" uint8_t fpu_initialized_regs[512]; } // namespace Float - } // namespace Sortix + #endif diff --git a/kernel/x86-family/gdt.cpp b/kernel/x86-family/gdt.cpp index 9285266e..4ad6c663 100644 --- a/kernel/x86-family/gdt.cpp +++ b/kernel/x86-family/gdt.cpp @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014. This file is part of Sortix. @@ -22,10 +22,12 @@ *******************************************************************************/ +#include #include #include #include +#include #include "gdt.h" @@ -254,16 +256,22 @@ void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0) #endif } -void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher) +uintptr_t GetKernelStack() { #if defined(__i386__) - (void) stacklower; - (void) stacksize; - tss_entry.esp0 = (uint32_t) stackhigher; + return tss_entry.esp0; #elif defined(__x86_64__) - (void) stacklower; - (void) stacksize; - tss_entry.stack0 = (uint64_t) stackhigher; + return tss_entry.stack0; +#endif +} + +void SetKernelStack(uintptr_t stack_pointer) +{ + assert((stack_pointer & 0xF) == 0); +#if defined(__i386__) + tss_entry.esp0 = (uint32_t) stack_pointer; +#elif defined(__x86_64__) + tss_entry.stack0 = (uint64_t) stack_pointer; #endif } diff --git a/kernel/x86-family/gdt.h b/kernel/x86-family/gdt.h index 1c448b51..1fbd5789 100644 --- a/kernel/x86-family/gdt.h +++ b/kernel/x86-family/gdt.h @@ -32,7 +32,8 @@ namespace GDT { void Init(); void WriteTSS(int32_t num, uint16_t ss0, uintptr_t stack0); -void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhigher); +uintptr_t GetKernelStack(); +void SetKernelStack(uintptr_t stack_pointer); #if defined(__i386__) uint32_t GetFSBase(); uint32_t GetGSBase(); diff --git a/kernel/x86-family/interrupt.cpp b/kernel/x86-family/interrupt.cpp index 8cd8e082..0b67c62b 100644 --- a/kernel/x86-family/interrupt.cpp +++ b/kernel/x86-family/interrupt.cpp @@ -244,49 +244,41 @@ void Init() Interrupt::Enable(); } -const char* ExceptionName(const CPU::InterruptRegisters* regs) +const char* ExceptionName(const struct interrupt_context* intctx) { - if ( regs->int_no < NUM_KNOWN_EXCEPTIONS ) - return exception_names[regs->int_no]; + if ( intctx->int_no < NUM_KNOWN_EXCEPTIONS ) + return exception_names[intctx->int_no]; return "Unknown"; } -uintptr_t ExceptionLocation(const CPU::InterruptRegisters* regs) +uintptr_t ExceptionLocation(const struct interrupt_context* intctx) { #if defined(__x86_64__) - return regs->rip; + return intctx->rip; #elif defined(__i386__) - return regs->eip; + return intctx->eip; #endif } -void CrashCalltrace(const CPU::InterruptRegisters* regs) +void CrashCalltrace(const struct interrupt_context* intctx) { #if defined(__x86_64__) - Calltrace::Perform(regs->rbp); + Calltrace::Perform(intctx->rbp); #elif defined(__i386__) - Calltrace::Perform(regs->ebp); + Calltrace::Perform(intctx->ebp); #else #warning "Please provide a calltrace implementation for your CPU." #endif } __attribute__((noreturn)) -void KernelCrashHandler(CPU::InterruptRegisters* regs) +void KernelCrashHandler(struct interrupt_context* intctx) { - Thread* thread = CurrentThread(); -#if defined(__i386__) - thread->fsbase = (unsigned long) GDT::GetFSBase(); - thread->gsbase = (unsigned long) GDT::GetGSBase(); -#elif defined(__x86_64__) - thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE); - thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE); -#endif - thread->SaveRegisters(regs); + Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers); // Walk and print the stack frames if this is a debug build. if ( CALLTRACE_KERNEL ) - CrashCalltrace(regs); + CrashCalltrace(intctx); // Possibly switch to the kernel debugger in event of a crash. if ( RUN_DEBUGGER_ON_KERNEL_CRASH ) @@ -294,27 +286,19 @@ void KernelCrashHandler(CPU::InterruptRegisters* regs) // Panic the kernel with a diagnostic message. PanicF("Unhandled CPU Exception id %zu `%s' at ip=0x%zx (cr2=0x%zx, " - "err_code=0x%zx)", regs->int_no, ExceptionName(regs), - ExceptionLocation(regs), regs->cr2, regs->err_code); + "err_code=0x%zx)", intctx->int_no, ExceptionName(intctx), + ExceptionLocation(intctx), intctx->cr2, intctx->err_code); } -void UserCrashHandler(CPU::InterruptRegisters* regs) +void UserCrashHandler(struct interrupt_context* intctx) { - Thread* thread = CurrentThread(); -#if defined(__i386__) - thread->fsbase = (unsigned long) GDT::GetFSBase(); - thread->gsbase = (unsigned long) GDT::GetGSBase(); -#elif defined(__x86_64__) - thread->fsbase = (unsigned long) rdmsr(MSRID_FSBASE); - thread->gsbase = (unsigned long) rdmsr(MSRID_GSBASE); -#endif - thread->SaveRegisters(regs); + Scheduler::SaveInterruptedContext(intctx, &CurrentThread()->registers); // Execute this crash handler with preemption on. Interrupt::Enable(); // TODO: Also send signals for other types of user-space crashes. - if ( regs->int_no == 14 /* Page fault */ ) + if ( intctx->int_no == 14 /* Page fault */ ) { struct sigaction* act = &CurrentProcess()->signal_actions[SIGSEGV]; kthread_mutex_lock(&CurrentProcess()->signal_lock); @@ -323,12 +307,12 @@ void UserCrashHandler(CPU::InterruptRegisters* regs) CurrentThread()->DeliverSignalUnlocked(SIGSEGV); kthread_mutex_unlock(&CurrentProcess()->signal_lock); if ( handled ) - return Signal::DispatchHandler(regs, NULL); + return Signal::DispatchHandler(intctx, NULL); } // Walk and print the stack frames if this is a debug build. if ( CALLTRACE_USER ) - CrashCalltrace(regs); + CrashCalltrace(intctx); // Possibly switch to the kernel debugger in event of a crash. if ( RUN_DEBUGGER_ON_USER_CRASH ) @@ -338,20 +322,20 @@ void UserCrashHandler(CPU::InterruptRegisters* regs) Log::PrintF("The current process (pid %ji `%s') crashed and was terminated:\n", (intmax_t) CurrentProcess()->pid, CurrentProcess()->program_image_path); Log::PrintF("%s exception at ip=0x%zx (cr2=0x%zx, err_code=0x%zx)\n", - ExceptionName(regs), ExceptionLocation(regs), regs->cr2, - regs->err_code); + ExceptionName(intctx), ExceptionLocation(intctx), intctx->cr2, + intctx->err_code); // Exit the process with the right error code. // TODO: Send a SIGINT, SIGBUS, or whatever instead. CurrentProcess()->ExitThroughSignal(SIGSEGV); // Deliver signals to this thread so it can exit correctly. - Signal::DispatchHandler(regs, NULL); + Signal::DispatchHandler(intctx, NULL); } -extern "C" void interrupt_handler(CPU::InterruptRegisters* regs) +extern "C" void interrupt_handler(struct interrupt_context* intctx) { - unsigned int int_no = regs->int_no; + unsigned int int_no = intctx->int_no; // IRQ 7 and 15 might be spurious and might need to be ignored. if ( int_no == IRQ7 && !(PIC::ReadISR() & (1 << 7)) ) @@ -362,17 +346,17 @@ extern "C" void interrupt_handler(CPU::InterruptRegisters* regs) return; } - bool is_in_kernel = (regs->cs & 0x3) == KRPL; + bool is_in_kernel = (intctx->cs & 0x3) == KRPL; bool is_in_user = !is_in_kernel; bool is_crash = int_no < 32 && int_no != 7; // Invoke the appropriate interrupt handler. if ( is_crash && is_in_kernel ) - KernelCrashHandler(regs); + KernelCrashHandler(intctx); else if ( is_crash && is_in_user ) - UserCrashHandler(regs); + UserCrashHandler(intctx); else if ( interrupt_handlers[int_no] ) - interrupt_handlers[int_no](regs, interrupt_handler_context[int_no]); + interrupt_handlers[int_no](intctx, interrupt_handler_context[int_no]); // Send an end of interrupt signal to the PICs if we got an IRQ. if ( IRQ0 <= int_no && int_no <= IRQ15 ) diff --git a/kernel/x86-family/memorymanagement.cpp b/kernel/x86-family/memorymanagement.cpp index 41b8edfd..9f230cd7 100644 --- a/kernel/x86-family/memorymanagement.cpp +++ b/kernel/x86-family/memorymanagement.cpp @@ -62,8 +62,6 @@ kthread_mutex_t pagelock; namespace Sortix { namespace Memory { -addr_t currentdir = 0; - void InitCPU(); void AllocateKernelPMLs(); int SysMemStat(size_t* memused, size_t* memtotal); @@ -485,42 +483,30 @@ void InvalidatePage(addr_t /*addr*/) Flush(); } -// Flushes the Translation Lookaside Buffer (TLB). -void Flush() -{ - asm volatile("mov %0, %%cr3":: "r"(currentdir)); -} addr_t GetAddressSpace() { - return currentdir; + addr_t result; + asm ( "mov %%cr3, %0" : "=r"(result) ); + return result; } addr_t SwitchAddressSpace(addr_t addrspace) { - // Have fun debugging this. - if ( currentdir != Page::AlignDown(currentdir) ) - PanicF("The variable containing the current address space " - "contains garbage all of sudden: it isn't page-aligned. " - "It contains the value 0x%zx.", currentdir); - - // Don't switch if we are already there. - if ( addrspace == currentdir ) - return currentdir; - - if ( addrspace & 0xFFFUL ) - PanicF("addrspace 0x%zx was not page-aligned!", addrspace); - - addr_t previous = currentdir; - - // Switch and flush the TLB. - asm volatile("mov %0, %%cr3":: "r"(addrspace)); - - currentdir = addrspace; + assert(Page::IsAligned(addrspace)); + addr_t previous = GetAddressSpace(); + asm volatile ( "mov %0, %%cr3" : : "r"(addrspace) ); return previous; } +void Flush() +{ + addr_t previous; + asm ( "mov %%cr3, %0" : "=r"(previous) ); + asm volatile ( "mov %0, %%cr3" : : "r"(previous) ); +} + bool MapRange(addr_t where, size_t bytes, int protection) { for ( addr_t page = where; page < where + bytes; page += 4096UL ) diff --git a/kernel/x86-family/time.cpp b/kernel/x86-family/time.cpp index 5edde288..db022403 100644 --- a/kernel/x86-family/time.cpp +++ b/kernel/x86-family/time.cpp @@ -78,10 +78,10 @@ static struct timespec tick_period; static long tick_frequency; static uint16_t tick_divisor; -static void OnIRQ0(CPU::InterruptRegisters* regs, void* /*user*/) +static void OnIRQ0(struct interrupt_context* intctx, void* /*user*/) { - OnTick(tick_period, !regs->InUserspace()); - Scheduler::Switch(regs); + OnTick(tick_period, !InUserspace(intctx)); + Scheduler::Switch(intctx); // TODO: There is a horrible bug that causes Sortix to only receive // one IRQ0 on my laptop, but it works in virtual machines. But diff --git a/kernel/x86/boot.S b/kernel/x86/boot.S index 50910e2d..c4aeffce 100644 --- a/kernel/x86/boot.S +++ b/kernel/x86/boot.S @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2014. This file is part of Sortix. @@ -62,4 +62,7 @@ prepare_kernel_execution: mov %eax, %cr4 mov 0x100000, %eax + # Store a copy of the initialial floating point registers. + fxsave fpu_initialized_regs + jmp beginkernel diff --git a/kernel/x86/interrupt.S b/kernel/x86/interrupt.S index 7752439e..231b3eb5 100644 --- a/kernel/x86/interrupt.S +++ b/kernel/x86/interrupt.S @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2011, 2012. + Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014. This file is part of Sortix. @@ -382,9 +382,12 @@ fixup_relocate_stack_complete: pushl %ebp # Now call the interrupt handler. - pushl %esp + movl %esp, %ebx + subl $4, %esp + andl $0xFFFFFFF0, %esp + movl %ebx, (%esp) call interrupt_handler - addl $4, %esp + movl %ebx, %esp load_interrupted_registers: # Restore whether signals are pending. diff --git a/kernel/x86/memorymanagement.cpp b/kernel/x86/memorymanagement.cpp index ec8f3b4b..be6caf5a 100644 --- a/kernel/x86/memorymanagement.cpp +++ b/kernel/x86/memorymanagement.cpp @@ -45,8 +45,6 @@ void ExtendStack(); namespace Sortix { namespace Memory { -extern addr_t currentdir; - void InitCPU() { PML* const BOOTPML2 = (PML* const) 0x11000UL; @@ -132,14 +130,14 @@ void RecursiveFreeUserspacePages(size_t level, size_t offset) } } -void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* user) +void DestroyAddressSpace(addr_t fallback) { // Look up the last few entries used for the fractal mapping. These // cannot be unmapped as that would destroy the world. Instead, we // will remember them, switch to another adress space, and safely // mark them as unused. Also handling the forking related pages. addr_t fractal1 = PMLS[2]->entry[1022]; - addr_t dir = currentdir; + addr_t dir = GetAddressSpace(); // We want to free the pages, but we are still using them ourselves, // so lock the page allocation structure until we are done. @@ -156,10 +154,7 @@ void DestroyAddressSpace(addr_t fallback, void (*func)(addr_t, void*), void* use if ( !fallback ) fallback = (addr_t) BOOTPML2; - if ( func ) - func(fallback, user); - else - SwitchAddressSpace(fallback); + SwitchAddressSpace(fallback); // Ok, now we got marked everything left behind as unused, we can // now safely let another thread use the pages. diff --git a/kernel/x86/process.cpp b/kernel/x86/process.cpp deleted file mode 100644 index 5b6b5bd7..00000000 --- a/kernel/x86/process.cpp +++ /dev/null @@ -1,75 +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/process.cpp - CPU-specific process code. - -*******************************************************************************/ - -#include - -#include -#include - -#include - -#include -#include - -namespace Sortix { - -void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp, - addr_t stackpos, addr_t entry, - CPU::InterruptRegisters* regs) -{ - memset(regs, 0, sizeof(*regs)); - regs->eax = argc; - regs->ebx = (size_t) argv; - regs->edx = envc; - regs->ecx = (size_t) envp; - regs->eip = entry; - regs->esp = stackpos & ~(15UL); - regs->ebp = regs->esp; - regs->cs = UCS | URPL; - regs->ds = UDS | URPL; - regs->ss = UDS | URPL; - regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; - regs->signal_pending = 0; -} - -void InitializeThreadRegisters(CPU::InterruptRegisters* regs, - const struct tfork* requested) -{ - memset(regs, 0, sizeof(*regs)); - regs->eip = requested->eip; - regs->esp = requested->esp; - regs->eax = requested->eax; - regs->ebx = requested->ebx; - regs->ecx = requested->ecx; - regs->edx = requested->edx; - regs->edi = requested->edi; - regs->esi = requested->esi; - regs->ebp = requested->ebp; - regs->cs = UCS | URPL; - regs->ds = UDS | URPL; - regs->ss = UDS | URPL; - regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID; -} - -} // namespace Sortix diff --git a/kernel/x86/syscall.S b/kernel/x86/syscall.S index 3c40e73c..a9ffc9d7 100644 --- a/kernel/x86/syscall.S +++ b/kernel/x86/syscall.S @@ -27,13 +27,16 @@ .section .text .type syscall_handler, @function syscall_handler: + /* -- stack is 12 bytes from being 16-byte aligned -- */ movl $0, global_errno # Reset errno pushl %ebp + /* -- stack is 8 bytes from being 16-byte aligned -- */ # Grant ourselves kernel permissions to the data segment. movl %ds, %ebp pushl %ebp + /* -- stack is 4 bytes from being 16-byte aligned -- */ movw $0x10, %bp movl %ebp, %ds movl %ebp, %es @@ -53,10 +56,12 @@ valid_syscall: # Call the system call. pushl %esi + /* -- stack is 16-byte aligned -- */ pushl %edi pushl %edx pushl %ecx pushl %ebx + /* -- stack is 16-byte aligned -- */ calll *%eax addl $20, %esp diff --git a/kernel/x86/x86.cpp b/kernel/x86/x86.cpp deleted file mode 100644 index 31312ce1..00000000 --- a/kernel/x86/x86.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - - Copyright(C) Jonas 'Sortie' Termansen 2011, 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/x86.cpp - CPU stuff for the x86 platform. - -*******************************************************************************/ - -#include -#include -#include - -namespace Sortix { -namespace X86 { - -void InterruptRegisters::LogRegisters() const -{ - Log::PrintF("[cr2=0x%zx,ds=0x%zx,edi=0x%zx,esi=0x%zx,ebp=0x%zx," - "ebx=0x%zx,edx=0x%zx,ecx=0x%zx,eax=0x%zx," - "int_no=0x%zx,err_code=0x%zx,eip=0x%zx,cs=0x%zx," - "eflags=0x%zx,esp=0x%zx,ss=0x%zx]", - cr2, ds, edi, esi, ebp, - ebx, edx, ecx, eax, - int_no, err_code, eip, cs, - eflags, esp, ss); -} - -} // namespace X86 -} // namespace Sortix