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:
Pawel Dziepak
2013-12-17 04:08:51 +01:00
parent 611376fef7
commit a5b070f1fa
3 changed files with 24 additions and 19 deletions
@@ -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
+5 -12
View File
@@ -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 */
+17 -7
View File
@@ -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)