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_CODE_SELECTOR ((USER_CODE_SEGMENT << 3) | DPL_USER)
|
||||||
#define USER_DATA_SELECTOR ((USER_DATA_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
|
#ifndef _ASSEMBLER
|
||||||
// this file can also be included from assembler as well
|
// 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);
|
void x86_set_tls_context(Thread* thread);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __x86_64__
|
|
||||||
|
|
||||||
|
|
||||||
static inline Thread*
|
static inline Thread*
|
||||||
arch_thread_get_current_thread(void)
|
arch_thread_get_current_thread(void)
|
||||||
{
|
{
|
||||||
@@ -42,6 +39,9 @@ arch_thread_get_current_thread(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arch_thread_set_current_thread(Thread* t)
|
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);
|
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
|
static inline void
|
||||||
arch_thread_set_current_thread(Thread* t)
|
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
|
||||||
|
|
||||||
#endif /* _KERNEL_ARCH_x86_THREAD_H */
|
#endif /* _KERNEL_ARCH_x86_THREAD_H */
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,7 @@
|
|||||||
\
|
\
|
||||||
/* restore pointers and clear fault handler */ \
|
/* restore pointers and clear fault handler */ \
|
||||||
movl %edx, %esi; /* syscall info pointer */ \
|
movl %edx, %esi; /* syscall info pointer */ \
|
||||||
movl %dr3, %edi; /* thread pointer */ \
|
movl %gs:0, %edi; /* thread pointer */ \
|
||||||
movl $0, THREAD_fault_handler(%edi)
|
movl $0, THREAD_fault_handler(%edi)
|
||||||
|
|
||||||
#if SYSCALL_TRACING
|
#if SYSCALL_TRACING
|
||||||
@@ -509,6 +509,9 @@ FUNCTION_END(trap14_double_fault)
|
|||||||
STATIC_FUNCTION(int_bottom):
|
STATIC_FUNCTION(int_bottom):
|
||||||
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
|
PUSH_IFRAME_BOTTOM(IFRAME_TYPE_OTHER)
|
||||||
|
|
||||||
|
movl $KERNEL_TLS_SELECTOR, %edx
|
||||||
|
movw %dx, %gs
|
||||||
|
|
||||||
movl %esp, %ebp // frame pointer is the iframe
|
movl %esp, %ebp // frame pointer is the iframe
|
||||||
|
|
||||||
// Set the RF (resume flag) in EFLAGS. This prevents an instruction
|
// 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
|
// 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
|
// window for an interrupt while still being in the kernel, but having set
|
||||||
// up everything for userland already.
|
// up everything for userland already.
|
||||||
movl %dr3, %edi // thread pointer
|
movl %gs:0, %edi // thread pointer
|
||||||
cmpb $0, THREAD_in_kernel(%edi)
|
cmpb $0, THREAD_in_kernel(%edi)
|
||||||
je int_bottom_user
|
je int_bottom_user
|
||||||
|
|
||||||
@@ -546,7 +549,7 @@ STATIC_FUNCTION(int_bottom_user):
|
|||||||
movl %eax,%es
|
movl %eax,%es
|
||||||
|
|
||||||
// disable breakpoints, if installed
|
// disable breakpoints, if installed
|
||||||
movl %dr3, %edi // thread pointer
|
movl %gs:0, %edi // thread pointer
|
||||||
cli // disable interrupts
|
cli // disable interrupts
|
||||||
STOP_USER_DEBUGGING()
|
STOP_USER_DEBUGGING()
|
||||||
|
|
||||||
@@ -600,6 +603,9 @@ FUNCTION_END(trap99)
|
|||||||
|
|
||||||
|
|
||||||
STATIC_FUNCTION(handle_syscall):
|
STATIC_FUNCTION(handle_syscall):
|
||||||
|
movl $KERNEL_TLS_SELECTOR, %edx
|
||||||
|
movw %dx, %gs
|
||||||
|
|
||||||
// save %eax, the number of the syscall
|
// save %eax, the number of the syscall
|
||||||
movl %eax, %esi
|
movl %eax, %esi
|
||||||
|
|
||||||
@@ -610,7 +616,7 @@ STATIC_FUNCTION(handle_syscall):
|
|||||||
|
|
||||||
lea 4(%esp), %ebp // skipping the return address, the stack
|
lea 4(%esp), %ebp // skipping the return address, the stack
|
||||||
// frame pointer is the iframe
|
// frame pointer is the iframe
|
||||||
movl %dr3, %edi // thread pointer
|
movl %gs:0, %edi // thread pointer
|
||||||
|
|
||||||
// disable breakpoints, if installed
|
// disable breakpoints, if installed
|
||||||
cli // disable interrupts
|
cli // disable interrupts
|
||||||
@@ -745,7 +751,7 @@ FUNCTION_END(handle_syscall)
|
|||||||
|
|
||||||
STATIC_FUNCTION(bad_syscall_params):
|
STATIC_FUNCTION(bad_syscall_params):
|
||||||
// clear the fault handler and exit normally
|
// clear the fault handler and exit normally
|
||||||
movl %dr3, %edi
|
movl %gs:0, %edi
|
||||||
movl $0, THREAD_fault_handler(%edi)
|
movl $0, THREAD_fault_handler(%edi)
|
||||||
jmp kernel_exit_work
|
jmp kernel_exit_work
|
||||||
FUNCTION_END(bad_syscall_params)
|
FUNCTION_END(bad_syscall_params)
|
||||||
@@ -756,7 +762,11 @@ FUNCTION_END(handle_syscall)
|
|||||||
*/
|
*/
|
||||||
FUNCTION(x86_sysenter):
|
FUNCTION(x86_sysenter):
|
||||||
// get the thread
|
// 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
|
// push the iframe
|
||||||
pushl $USER_DATA_SELECTOR // user_ss
|
pushl $USER_DATA_SELECTOR // user_ss
|
||||||
@@ -816,7 +826,7 @@ FUNCTION(x86_return_to_userland):
|
|||||||
movl %ebp, %esp
|
movl %ebp, %esp
|
||||||
|
|
||||||
// check, if any kernel exit work has to be done
|
// 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 \
|
testl $(THREAD_FLAGS_DEBUGGER_INSTALLED | THREAD_FLAGS_SIGNALS_PENDING \
|
||||||
| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \
|
| THREAD_FLAGS_DEBUG_THREAD | THREAD_FLAGS_BREAKPOINTS_DEFINED) \
|
||||||
, THREAD_flags(%edi)
|
, THREAD_flags(%edi)
|
||||||
|
|||||||
Reference in New Issue
Block a user