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_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
+5 -12
View File
@@ -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 */
+17 -7
View File
@@ -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)