kernel/x86: add ability to set GS segment base from userland

Needed for Wine.

Co-authored-by: Jérôme Duval <[email protected]>

Change-Id: I13f6a5802fce04fd2ebb4cc01ecd2f12c90830db
Reviewed-on: https://review.haiku-os.org/c/haiku/+/4839
Reviewed-by: Jérôme Duval <[email protected]>
Reviewed-by: X512 <[email protected]>
Reviewed-by: Fredrik Holmqvist <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
X512
2022-03-09 18:28:00 +00:00
committed by waddlesplash
co-authored by Jérôme Duval
parent 397102c17d
commit b19f5c839b
4 changed files with 48 additions and 0 deletions
@@ -48,6 +48,8 @@ struct arch_thread {
uintptr_t* current_stack; uintptr_t* current_stack;
uintptr_t instruction_pointer; uintptr_t instruction_pointer;
uint64 user_gs_base;
#else #else
struct farcall current_stack; struct farcall current_stack;
struct farcall interrupt_stack; struct farcall interrupt_stack;
@@ -0,0 +1,13 @@
/*
* Copyright 2022, The Haiku Team. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _X86_THREAD_DEFS_H
#define _X86_THREAD_DEFS_H
#define THREAD_SYSCALLS "thread"
#define THREAD_SET_GS_BASE 1
#endif /* _X86_THREAD_DEFS_H */
+32
View File
@@ -13,9 +13,11 @@
#include <string.h> #include <string.h>
#include <arch_thread_defs.h>
#include <commpage.h> #include <commpage.h>
#include <cpu.h> #include <cpu.h>
#include <debug.h> #include <debug.h>
#include <generic_syscall.h>
#include <kernel.h> #include <kernel.h>
#include <ksignal.h> #include <ksignal.h>
#include <int.h> #include <int.h>
@@ -96,6 +98,7 @@ x86_set_tls_context(Thread* thread)
{ {
// Set FS segment base address to the TLS segment. // Set FS segment base address to the TLS segment.
x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage); x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
x86_write_msr(IA32_MSR_KERNEL_GS_BASE, thread->arch_info.user_gs_base);
} }
@@ -135,6 +138,32 @@ get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action,
} }
static status_t
arch_thread_control(const char* subsystem, uint32 function, void* buffer,
size_t bufferSize)
{
switch (function) {
case THREAD_SET_GS_BASE:
{
uint64 base;
if (bufferSize != sizeof(base))
return B_BAD_VALUE;
if (!IS_USER_ADDRESS(buffer)
|| user_memcpy(&base, buffer, sizeof(base)) < B_OK) {
return B_BAD_ADDRESS;
}
Thread* thread = thread_get_current_thread();
thread->arch_info.user_gs_base = base;
x86_write_msr(IA32_MSR_KERNEL_GS_BASE, base);
return B_OK;
}
}
return B_BAD_HANDLER;
}
// #pragma mark - // #pragma mark -
@@ -172,6 +201,9 @@ arch_thread_init(kernel_args* args)
"fxsaveq %0" "fxsaveq %0"
:: "m" (sInitialState.fpu_state)); :: "m" (sInitialState.fpu_state));
} }
register_generic_syscall(THREAD_SYSCALLS, arch_thread_control, 1, 0);
return B_OK; return B_OK;
} }
+1
View File
@@ -11,6 +11,7 @@ SubDirHdrs $(SUBDIR) timers ;
UsePrivateKernelHeaders ; UsePrivateKernelHeaders ;
UsePrivateHeaders shared ; UsePrivateHeaders shared ;
UsePrivateHeaders [ FDirName system arch x86 ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) paging ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) paging ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) timers ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) timers ] ;