Maintain fsbase and gsbase as per-thread registers.
Note: This is an incompatible ABI change.
This commit is contained in:
parent
92d7c1807e
commit
1f72c1637c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue