x86: Store pointer to the current thread in gs:0
Apparently, reading from dr3 is slower than reading from memory with cache hit. Also, depending on hypervisor configuration, accessing dr3 may cause a VM exit (and, at least on kvm, it does), what makes it much slower than a memory access even when there is a cache miss.
This commit is contained in:
@@ -38,6 +38,8 @@
|
||||
#define USER_CODE_SELECTOR ((USER_CODE_SEGMENT << 3) | DPL_USER)
|
||||
#define USER_DATA_SELECTOR ((USER_DATA_SEGMENT << 3) | DPL_USER)
|
||||
|
||||
#define KERNEL_TLS_SELECTOR ((KERNEL_TLS_SEGMENT << 3) | DPL_KERNEL)
|
||||
|
||||
|
||||
#ifndef _ASSEMBLER
|
||||
// this file can also be included from assembler as well
|
||||
|
||||
@@ -30,9 +30,6 @@ void x86_restart_syscall(struct iframe* frame);
|
||||
void x86_set_tls_context(Thread* thread);
|
||||
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
|
||||
static inline Thread*
|
||||
arch_thread_get_current_thread(void)
|
||||
{
|
||||
@@ -42,6 +39,9 @@ arch_thread_get_current_thread(void)
|
||||
}
|
||||
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
|
||||
static inline void
|
||||
arch_thread_set_current_thread(Thread* t)
|
||||
{
|
||||
@@ -59,18 +59,10 @@ arch_thread_set_current_thread(Thread* t)
|
||||
void arch_syscall_64_bit_return_value(void);
|
||||
|
||||
|
||||
static inline Thread*
|
||||
arch_thread_get_current_thread(void)
|
||||
{
|
||||
Thread* t = (Thread*)x86_read_dr3();
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
arch_thread_set_current_thread(Thread* t)
|
||||
{
|
||||
x86_write_dr3(t);
|
||||
asm volatile("mov %0, %%gs:0" : : "r" (t));
|
||||
}
|
||||
|
||||
|
||||
@@ -82,3 +74,4 @@ arch_thread_set_current_thread(Thread* t)
|
||||
#endif
|
||||
|
||||
#endif /* _KERNEL_ARCH_x86_THREAD_H */
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
\
|
||||
/* restore pointers and clear fault handler */ \
|
||||
movl %edx, %esi; /* syscall info pointer */ \
|
||||
movl %dr3, %edi; /* thread pointer */ \
|
||||
movl %gs:0, %edi; /* thread pointer */ \
|
||||
movl $0, THREAD_fault_handler(%edi)
|
||||
|
||||
#if SYSCALL_TRACING
|
||||
@@ -509,6 +509,9 @@ FUNCTION_END(trap14_double_fault)
|
||||
STATIC_FUNCTION(int_bottom):
|
||||
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
|
||||
|
||||
movl $KERNEL_TLS_SELECTOR, %edx
|
||||
movw %dx, %gs
|
||||
|
||||
movl %esp, %ebp // frame pointer is the iframe
|
||||
|
||||
// Set the RF (resume flag) in EFLAGS. This prevents an instruction
|
||||
@@ -524,7 +527,7 @@ STATIC_FUNCTION(int_bottom):
|
||||
// so that we have to do it in the instruction before, thus opening a
|
||||
// window for an interrupt while still being in the kernel, but having set
|
||||
// up everything for userland already.
|
||||
movl %dr3, %edi // thread pointer
|
||||
movl %gs:0, %edi // thread pointer
|
||||
cmpb $0, THREAD_in_kernel(%edi)
|
||||
je int_bottom_user
|
||||
|
||||
@@ -546,7 +549,7 @@ STATIC_FUNCTION(int_bottom_user):
|
||||
movl %eax,%es
|
||||
|
||||
// disable breakpoints, if installed
|
||||
movl %dr3, %edi // thread pointer
|
||||
movl %gs:0, %edi // thread pointer
|
||||
cli // disable interrupts
|
||||
STOP_USER_DEBUGGING()
|
||||
|
||||
@@ -600,6 +603,9 @@ FUNCTION_END(trap99)
|
||||
|
||||
|
||||
STATIC_FUNCTION(handle_syscall):
|
||||
movl $KERNEL_TLS_SELECTOR, %edx
|
||||
movw %dx, %gs
|
||||
|
||||
// save %eax, the number of the syscall
|
||||
movl %eax, %esi
|
||||
|
||||
@@ -610,7 +616,7 @@ STATIC_FUNCTION(handle_syscall):
|
||||
|
||||
lea 4(%esp), %ebp // skipping the return address, the stack
|
||||
// frame pointer is the iframe
|
||||
movl %dr3, %edi // thread pointer
|
||||
movl %gs:0, %edi // thread pointer
|
||||
|
||||
// disable breakpoints, if installed
|
||||
cli // disable interrupts
|
||||
@@ -745,7 +751,7 @@ FUNCTION_END(handle_syscall)
|
||||
|
||||
STATIC_FUNCTION(bad_syscall_params):
|
||||
// clear the fault handler and exit normally
|
||||
movl %dr3, %edi
|
||||
movl %gs:0, %edi
|
||||
movl $0, THREAD_fault_handler(%edi)
|
||||
jmp kernel_exit_work
|
||||
FUNCTION_END(bad_syscall_params)
|
||||
@@ -756,7 +762,11 @@ FUNCTION_END(handle_syscall)
|
||||
*/
|
||||
FUNCTION(x86_sysenter):
|
||||
// get the thread
|
||||
movl %dr3, %edx
|
||||
push %gs
|
||||
movl $KERNEL_TLS_SELECTOR, %edx
|
||||
movw %dx, %gs
|
||||
movl %gs:0, %edx
|
||||
pop %gs
|
||||
|
||||
// push the iframe
|
||||
pushl $USER_DATA_SELECTOR // user_ss
|
||||
@@ -816,7 +826,7 @@ FUNCTION(x86_return_to_userland):
|
||||
movl %ebp, %esp
|
||||
|
||||
// check, if any kernel exit work has to be done
|
||||
movl %dr3, %edi
|
||||
movl %gs:0, %edi
|
||||
testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
|
||||
| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \
|
||||
, THREAD_flags(%edi)
|
||||
|
||||
Reference in New Issue
Block a user