Commit ae119678 authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Andrei Vagin

x86: restore TLS

Put dumped TLS descriptors back to GDT.
Do it only if it was present.

Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarDmitry Safonov <dsafonov@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
Signed-off-by: 's avatarAndrei Vagin <avagin@virtuozzo.com>
parent 2bcfa2c1
......@@ -28,7 +28,28 @@
;
#endif /* CONFIG_X86_64 */
#define core_get_tls(pcore, ptls)
static inline void core_get_tls(CoreEntry *pcore, tls_t *ptls)
{
ThreadInfoX86 *ti = pcore->thread_info;
int i;
for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) {
user_desc_t *to = &ptls->desc[i];
UserDescT *from = ti->tls[i];
#define COPY_TLS(field) to->field = from->field
COPY_TLS(entry_number);
COPY_TLS(base_addr);
COPY_TLS(limit);
COPY_TLS(seg_32bit);
to->contents = ((u32)from->contents_h << 1) | from->contents_l;
COPY_TLS(read_exec_only);
COPY_TLS(limit_in_pages);
COPY_TLS(seg_not_present);
COPY_TLS(useable);
#undef COPY_TLS
}
}
int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core);
......
......@@ -118,10 +118,7 @@ static inline void _setup_sas(struct rt_sigframe* sigframe, ThreadSasEntry *sas)
int restore_gpregs(struct rt_sigframe *f, UserX86RegsEntry *r);
int restore_nonsigframe_gpregs(UserX86RegsEntry *r);
static inline void restore_tls(tls_t *ptls)
{
(void)ptls;
}
void restore_tls(tls_t *ptls);
int ptrace_set_breakpoint(pid_t pid, void *addr);
int ptrace_flush_breakpoints(pid_t pid);
......
......@@ -5,6 +5,7 @@
#include "restorer.h"
#include "asm/restorer.h"
#include "asm/fpu.h"
#include "asm/string.h"
#include "syscall.h"
#include "log.h"
......@@ -32,3 +33,64 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r)
#endif
return 0;
}
extern unsigned long call32_from_64(void *stack, void *func);
asm ( " .pushsection .text \n"
" .global restore_set_thread_area \n"
" .code32 \n"
"restore_set_thread_area: \n"
" movl $"__stringify(__NR32_set_thread_area)",%eax\n"
" int $0x80 \n"
" ret \n"
" .popsection \n"
" .code64");
extern char restore_set_thread_area;
static void *stack32;
static int prepare_stack32(void)
{
if (stack32)
return 0;
stack32 = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (stack32 == MAP_FAILED) {
stack32 = NULL;
pr_err("Failed to allocate stack for 32-bit TLS restore\n");
return -1;
}
return 0;
}
void restore_tls(tls_t *ptls)
{
int i;
for (i = 0; i < GDT_ENTRY_TLS_NUM; i++) {
user_desc_t *desc = &ptls->desc[i];
int ret;
if (desc->seg_not_present)
continue;
if (prepare_stack32() < 0)
return;
builtin_memcpy(stack32, desc, sizeof(user_desc_t));
/* user_desc parameter for set_thread_area syscall */
asm volatile ("\t movl %%ebx,%%ebx\n" : :"b"(stack32));
call32_from_64(stack32 + PAGE_SIZE, &restore_set_thread_area);
asm volatile ("\t movl %%eax,%0\n" : "=r"(ret));
if (ret)
pr_err("Failed to restore TLS descriptor %d in GDT ret %d\n",
desc->entry_number, ret);
}
if (stack32)
sys_munmap(stack32, PAGE_SIZE);
}
......@@ -14,6 +14,7 @@ restorer-obj-y += ./$(ARCH_DIR)/restorer.o
ifeq ($(ARCH),x86)
restorer-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o
restorer-obj-y += ./$(ARCH_DIR)/call32.o
native-obj-y += ./$(ARCH_DIR)/parasite-head-64.o
native-obj-e += ./$(ARCH_DIR)/syscalls-64.built-in.o
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment