Maintain fsbase and gsbase as per-thread registers.

Note: This is an incompatible ABI change.
This commit is contained in:
Jonas 'Sortie' Termansen 2013-09-14 18:59:15 +02:00
parent 92d7c1807e
commit 1f72c1637c
16 changed files with 169 additions and 29 deletions

View File

@ -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;

View File

@ -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 <sys/cdefs.h>
#include <stdint.h>
__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

View File

@ -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 <sys/cdefs.h>
#include <stdint.h>
__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

View File

@ -27,6 +27,10 @@
#include <stdint.h>
#include <string.h>
#if defined(__x86_64__)
#include <msr.h>
#endif
#include <sortix/keycodes.h>
#include <sortix/kernel/cpu.h>
@ -36,6 +40,10 @@
#include <sortix/kernel/keyboard.h>
#include <sortix/kernel/thread.h>
#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;

View File

@ -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();

View File

@ -25,6 +25,7 @@
#include <sys/types.h>
#include <assert.h>
#include <msr.h>
#include <string.h>
#include <timespec.h>
@ -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);
}

View File

@ -51,6 +51,8 @@ Thread::Thread()
schedulerlistnext = NULL;
state = NONE;
memset(&registers, 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(&regs, entry, user, (addr_t) stack, stacksize);
Thread* thread = CreateKernelThread(process, &regs);
Thread* thread = CreateKernelThread(process, &regs, 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);

View File

@ -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

View File

@ -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

View File

@ -25,12 +25,20 @@
#ifndef SORTIX_X86_FAMILY_GDT_H
#define SORTIX_X86_FAMILY_GDT_H
#include <stdint.h>
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

View File

@ -24,6 +24,7 @@
#include <assert.h>
#include <errno.h>
#include <msr.h>
#include <stdint.h>
#include <string.h>
@ -38,6 +39,7 @@
#include <sortix/kernel/syscall.h>
#include <sortix/kernel/thread.h>
#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();

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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