diff --git a/kernel/include/sortix/kernel/thread.h b/kernel/include/sortix/kernel/thread.h index 49f43793..39eeead3 100644 --- a/kernel/include/sortix/kernel/thread.h +++ b/kernel/include/sortix/kernel/thread.h @@ -50,7 +50,8 @@ extern "C" __attribute__((noreturn)) void BootstrapKernelThread(void* user, ThreadEntry entry); // These functions create a new kernel process but doesn't start it. -Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs); +Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs, + unsigned long fsbase, unsigned long gsbase); Thread* CreateKernelThread(Process* process, ThreadEntry entry, void* user, size_t stacksize = 0); Thread* CreateKernelThread(ThreadEntry entry, void* user, size_t stacksize = 0); @@ -74,7 +75,8 @@ typedef void (*sighandler_t)(int); class Thread { friend Thread* CreateKernelThread(Process* process, - CPU::InterruptRegisters* regs); + CPU::InterruptRegisters* regs, + unsigned long fsbase, unsigned long gsbase); friend void KernelInit(unsigned long magic, multiboot_info_t* bootinfo); friend void Thread__OnSigKill(Thread* thread); @@ -111,6 +113,12 @@ public: size_t kernelstacksize; bool kernelstackmalloced; +#if defined(__i386__) || defined(__x86_64__) +public: + unsigned long fsbase; + unsigned long gsbase; +#endif + private: CPU::InterruptRegisters registers; Signal::Queue signalqueue; diff --git a/kernel/include/sortix/x64/fork.h b/kernel/include/sortix/x64/fork.h index 79ccff33..8a6b6c5a 100644 --- a/kernel/include/sortix/x64/fork.h +++ b/kernel/include/sortix/x64/fork.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. This file is part of Sortix. @@ -27,6 +27,8 @@ #include +#include + __BEGIN_DECLS struct tforkregs_x64 @@ -49,6 +51,8 @@ struct tforkregs_x64 uint64_t r14; uint64_t r15; uint64_t rflags; + uint64_t fsbase; + uint64_t gsbase; }; __END_DECLS diff --git a/kernel/include/sortix/x86/fork.h b/kernel/include/sortix/x86/fork.h index 19692444..b3c6f545 100644 --- a/kernel/include/sortix/x86/fork.h +++ b/kernel/include/sortix/x86/fork.h @@ -1,6 +1,6 @@ /******************************************************************************* - Copyright(C) Jonas 'Sortie' Termansen 2012. + Copyright(C) Jonas 'Sortie' Termansen 2012, 2013. This file is part of Sortix. @@ -27,6 +27,8 @@ #include +#include + __BEGIN_DECLS struct tforkregs_x86 @@ -41,6 +43,8 @@ struct tforkregs_x86 uint32_t esp; uint32_t ebp; uint32_t eflags; + uint32_t fsbase; + uint32_t gsbase; }; __END_DECLS diff --git a/kernel/kb/ps2.cpp b/kernel/kb/ps2.cpp index 9803785b..952dbfca 100644 --- a/kernel/kb/ps2.cpp +++ b/kernel/kb/ps2.cpp @@ -27,6 +27,10 @@ #include #include +#if defined(__x86_64__) +#include +#endif + #include #include @@ -36,6 +40,10 @@ #include #include +#if defined(__i386__) +#include "../x86-family/gdt.h" +#endif + #include "ps2.h" namespace Sortix { @@ -97,7 +105,15 @@ void PS2Keyboard::OnInterrupt(CPU::InterruptRegisters* regs) uint8_t scancode = PopScancode(); if ( scancode == KBKEY_F10 ) { - CurrentThread()->SaveRegisters(regs); + 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); Debugger::Run(); } PS2KeyboardWork work; diff --git a/kernel/process.cpp b/kernel/process.cpp index 8d739106..fba7718f 100644 --- a/kernel/process.cpp +++ b/kernel/process.cpp @@ -995,7 +995,8 @@ static pid_t sys_tfork(int flags, tforkregs_t* user_regs) // 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(clone, &cpuregs); + Thread* thread = CreateKernelThread(clone, &cpuregs, regs.fsbase, + regs.gsbase); if ( !thread ) { clone->AbortConstruction(); diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp index e72331bc..1d73a2dc 100644 --- a/kernel/scheduler.cpp +++ b/kernel/scheduler.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -130,6 +131,18 @@ static void DoActualSwitch(CPU::InterruptRegisters* regs) assert(stacklower && stacksize && stackhigher); GDT::SetKernelStack(stacklower, stacksize, stackhigher); +#if defined(__x86_64__) + current->fsbase = (unsigned long) rdmsr(MSRID_FSBASE); + current->gsbase = (unsigned long) rdmsr(MSRID_GSBASE); + wrmsr(MSRID_FSBASE, (uint64_t) next->fsbase); + wrmsr(MSRID_GSBASE, (uint64_t) next->gsbase); +#elif defined(__i386__) + current->fsbase = (unsigned long) GDT::GetFSBase(); + current->gsbase = (unsigned long) GDT::GetGSBase(); + GDT::SetFSBase((uint32_t) next->fsbase); + GDT::SetGSBase((uint32_t) next->gsbase); +#endif + LogEndSwitch(next, regs); } diff --git a/kernel/thread.cpp b/kernel/thread.cpp index b7c3ed34..a1abce0b 100644 --- a/kernel/thread.cpp +++ b/kernel/thread.cpp @@ -51,6 +51,8 @@ Thread::Thread() schedulerlistnext = NULL; state = NONE; memset(®isters, 0, sizeof(registers)); + fsbase = 0; + gsbase = 0; kernelstackpos = 0; kernelstacksize = 0; kernelstackmalloced = false; @@ -96,8 +98,16 @@ extern "C" void BootstrapKernelThread(void* user, ThreadEntry entry) kthread_exit(); } -Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs) +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 ( !thread ) @@ -105,6 +115,8 @@ Thread* CreateKernelThread(Process* process, CPU::InterruptRegisters* regs) thread->addrspace = process->addrspace; thread->SaveRegisters(regs); + thread->fsbase = fsbase; + thread->gsbase = gsbase; kthread_mutex_lock(&process->threadlock); @@ -134,7 +146,7 @@ Thread* CreateKernelThread(Process* process, ThreadEntry entry, void* user, CPU::InterruptRegisters regs; SetupKernelThreadRegs(®s, entry, user, (addr_t) stack, stacksize); - Thread* thread = CreateKernelThread(process, ®s); + Thread* thread = CreateKernelThread(process, ®s, 0, 0); if ( !thread ) { delete[] stack; return NULL; } thread->kernelstackpos = (addr_t) stack; @@ -156,7 +168,7 @@ void StartKernelThread(Thread* thread) Thread* RunKernelThread(Process* process, CPU::InterruptRegisters* regs) { - Thread* thread = CreateKernelThread(process, regs); + Thread* thread = CreateKernelThread(process, regs, 0, 0); if ( !thread ) return NULL; StartKernelThread(thread); diff --git a/kernel/x64/interrupt.S b/kernel/x64/interrupt.S index 72aed0fa..92de72f7 100644 --- a/kernel/x64/interrupt.S +++ b/kernel/x64/interrupt.S @@ -371,8 +371,6 @@ interrupt_handler_prepare: movw $0x10, %bp movl %ebp, %ds movl %ebp, %es - movl %ebp, %fs - movl %ebp, %gs # Push CR2 in case of page faults movq %cr2, %rbp @@ -406,8 +404,6 @@ load_interrupted_registers: popq %rbp movl %ebp, %ds movl %ebp, %es - movl %ebp, %fs - movl %ebp, %gs popq %rdi popq %rsi diff --git a/kernel/x86-family/gdt.cpp b/kernel/x86-family/gdt.cpp index 23b2698b..9285266e 100644 --- a/kernel/x86-family/gdt.cpp +++ b/kernel/x86-family/gdt.cpp @@ -110,7 +110,13 @@ struct tss_entry } __attribute__((packed)); #endif +#if defined(__i386__) +const size_t GDT_NUM_ENTRIES = 9; +const size_t GDT_FS_ENTRY = 7; +const size_t GDT_GS_ENTRY = 8; +#else const size_t GDT_NUM_ENTRIES = 7; +#endif static struct gdt_entry gdt_entries[GDT_NUM_ENTRIES]; static struct tss_entry tss_entry; @@ -166,6 +172,11 @@ void Init() WriteTSS(5, 0x10, 0x0); +#if defined(__i386__) + SetGate(GDT_FS_ENTRY, 0, 0xFFFFFFFF, 0xF2, gran); + SetGate(GDT_GS_ENTRY, 0, 0xFFFFFFFF, 0xF2, gran); +#endif + // Reload the Global Descriptor Table. volatile struct gdt_ptr gdt_ptr; gdt_ptr.limit = (sizeof(struct gdt_entry) * GDT_NUM_ENTRIES) - 1; @@ -175,11 +186,17 @@ void Init() // Switch the current data segment. asm volatile ("mov %0, %%ds\n" "mov %0, %%es\n" - "mov %0, %%fs\n" - "mov %0, %%gs\n" "mov %0, %%ss\n" : : "r"(KDS)); +#if defined(__i386__) + asm volatile ("mov %0, %%fs" : : "r"(GDT_FS_ENTRY << 3 | URPL)); + asm volatile ("mov %0, %%gs" : : "r"(GDT_GS_ENTRY << 3 | URPL)); +#elif defined(__x86_64__) + asm volatile ("mov %0, %%fs" : : "r"(UDS | URPL)); + asm volatile ("mov %0, %%gs" : : "r"(UDS | URPL)); +#endif + // Switch the current code segment. #if defined(__i386__) asm volatile ("push %0\n" @@ -250,5 +267,41 @@ void SetKernelStack(uintptr_t stacklower, size_t stacksize, uintptr_t stackhighe #endif } +#if defined(__i386__) +uint32_t GetFSBase() +{ + struct gdt_entry* entry = gdt_entries + GDT_FS_ENTRY; + return (uint32_t) entry->base_low << 0 | + (uint32_t) entry->base_middle << 16 | + (uint32_t) entry->base_high << 24; +} + +uint32_t GetGSBase() +{ + struct gdt_entry* entry = gdt_entries + GDT_GS_ENTRY; + return (uint32_t) entry->base_low << 0 | + (uint32_t) entry->base_middle << 16 | + (uint32_t) entry->base_high << 24; +} + +void SetFSBase(uint32_t fsbase) +{ + struct gdt_entry* entry = gdt_entries + GDT_FS_ENTRY; + entry->base_low = fsbase >> 0 & 0xFFFF; + entry->base_middle = fsbase >> 16 & 0xFF; + entry->base_high = fsbase >> 24 & 0xFF; + asm volatile ("mov %0, %%fs" : : "r"(GDT_FS_ENTRY << 3 | URPL)); +} + +void SetGSBase(uint32_t gsbase) +{ + struct gdt_entry* entry = gdt_entries + GDT_GS_ENTRY; + entry->base_low = gsbase >> 0 & 0xFFFF; + entry->base_middle = gsbase >> 16 & 0xFF; + entry->base_high = gsbase >> 24 & 0xFF; + asm volatile ("mov %0, %%gs" : : "r"(GDT_GS_ENTRY << 3 | URPL)); +} +#endif + } // namespace GDT } // namespace Sortix diff --git a/kernel/x86-family/gdt.h b/kernel/x86-family/gdt.h index 48a84cd7..1c448b51 100644 --- a/kernel/x86-family/gdt.h +++ b/kernel/x86-family/gdt.h @@ -25,12 +25,20 @@ #ifndef SORTIX_X86_FAMILY_GDT_H #define SORTIX_X86_FAMILY_GDT_H +#include + namespace Sortix { 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); +#if defined(__i386__) +uint32_t GetFSBase(); +uint32_t GetGSBase(); +void SetFSBase(uint32_t fsbase); +void SetGSBase(uint32_t gsbase); +#endif } // namespace GDT } // namespace Sortix diff --git a/kernel/x86-family/interrupt.cpp b/kernel/x86-family/interrupt.cpp index 232d9918..0e17d88b 100644 --- a/kernel/x86-family/interrupt.cpp +++ b/kernel/x86-family/interrupt.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -38,6 +39,7 @@ #include #include +#include "gdt.h" #include "idt.h" #include "pic.h" @@ -272,7 +274,15 @@ void CrashCalltrace(const CPU::InterruptRegisters* regs) __attribute__((noreturn)) void KernelCrashHandler(CPU::InterruptRegisters* regs) { - CurrentThread()->SaveRegisters(regs); + 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); // Walk and print the stack frames if this is a debug build. if ( CALLTRACE_KERNEL ) @@ -290,7 +300,15 @@ void KernelCrashHandler(CPU::InterruptRegisters* regs) void UserCrashHandler(CPU::InterruptRegisters* regs) { - CurrentThread()->SaveRegisters(regs); + 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); // Execute this crash handler with preemption on. Interrupt::Enable(); diff --git a/kernel/x86/interrupt.S b/kernel/x86/interrupt.S index 45380311..7752439e 100644 --- a/kernel/x86/interrupt.S +++ b/kernel/x86/interrupt.S @@ -368,8 +368,6 @@ fixup_relocate_stack_complete: movw $0x10, %bp movl %ebp, %ds movl %ebp, %es - movl %ebp, %fs - movl %ebp, %gs # Push CR2 in case of page faults movl %cr2, %ebp @@ -404,8 +402,6 @@ load_interrupted_registers: popl %ebp movl %ebp, %ds movl %ebp, %es - movl %ebp, %fs - movl %ebp, %gs popl %edi popl %esi diff --git a/kernel/x86/syscall.S b/kernel/x86/syscall.S index e0d1ce38..3c40e73c 100644 --- a/kernel/x86/syscall.S +++ b/kernel/x86/syscall.S @@ -37,8 +37,6 @@ syscall_handler: movw $0x10, %bp movl %ebp, %ds movl %ebp, %es - movl %ebp, %fs - movl %ebp, %gs # Make sure the requested system call is valid. cmp SYSCALL_MAX, %eax @@ -66,8 +64,6 @@ valid_syscall: popl %ebp movl %ebp, %ds movl %ebp, %es - movl %ebp, %fs - movl %ebp, %gs # Return to user-space, system call result in %eax:%edx, errno in %ecx. popl %ebp diff --git a/libc/include/msr.h b/libc/include/msr.h index c35ccee3..da190177 100644 --- a/libc/include/msr.h +++ b/libc/include/msr.h @@ -34,6 +34,9 @@ __BEGIN_DECLS +#define MSRID_FSBASE __UINT32_C(0xC0000100) +#define MSRID_GSBASE __UINT32_C(0xC0000101) + __attribute__((unused)) static __inline uint64_t rdmsr(uint32_t msrid) { diff --git a/libc/x64/fork.S b/libc/x64/fork.S index 42c36271..af789a22 100644 --- a/libc/x64/fork.S +++ b/libc/x64/fork.S @@ -22,6 +22,9 @@ *******************************************************************************/ +#define MSRID_FSBASE 0xC0000100 +#define MSRID_GSBASE 0xC0000101 + .section .text .globl __call_tfork_with_regs @@ -30,10 +33,16 @@ __call_tfork_with_regs: pushq %rbp movq %rsp, %rbp + # Save the flags parameter so rdmsr won't trash it and align stack. + pushq %rdi + sub $8, %rsp + # The actual system call expects a struct tforkregs_x64 containing the state # of each register in the child. Since we create an identical copy, we # simply set each member of the structure to our own state. Note that since # the stack goes downwards, we create it in the reverse order. + pushq $0 # gsbase + pushq $0 # fsbase pushfq pushq %r15 pushq %r14 @@ -53,8 +62,7 @@ __call_tfork_with_regs: pushq $0 # rax, result of sfork is 0 for the child. pushq $.Lafter_fork # rip, child will start execution from here. - # Call tfork with a nice pointer to our structure. Note that %rdi contains - # the flag parameter that this function accepted. + # Call tfork with a nice pointer to our structure. movq %rsp, %rsi call tfork diff --git a/libc/x86/fork.S b/libc/x86/fork.S index 7cc7aa62..d3c0879f 100644 --- a/libc/x86/fork.S +++ b/libc/x86/fork.S @@ -22,6 +22,9 @@ *******************************************************************************/ +#define MSRID_FSBASE 0xC0000100 +#define MSRID_GSBASE 0xC0000101 + .section .text .globl __call_tfork_with_regs @@ -30,12 +33,12 @@ __call_tfork_with_regs: pushl %ebp movl %esp, %ebp - movl 8(%ebp), %edx # flags parameter, edx need not be preserved. - # The actual system call expects a struct tforkregs_x86 containing the state # of each register in the child. Since we create an identical copy, we # simply set each member of the structure to our own state. Note that since # the stack goes downwards, we create it in the reverse order. + pushl $0 # gsbase + pushl $0 # fsbase pushfl pushl %ebp pushl %esp @@ -49,6 +52,7 @@ __call_tfork_with_regs: # Call tfork with a nice pointer to our structure. Note that %edi contains # the flag parameter that this function accepted. + movl 8(%ebp), %edx # flags parameter, edx need not be preserved. pushl %esp pushl %edx call tfork