[PATCHv3,26/30] x86: restore TLS

Submitted by Dmitry Safonov on June 28, 2016, 7:24 p.m.

Details

Message ID 20160628192423.14943-27-dsafonov@virtuozzo.com
State Rejected
Series "x86 Compatible C/R, part 2"
Headers show

Commit Message

Dmitry Safonov June 28, 2016, 7:24 p.m.
Put dumped TLS descriptors back to GDT.
Do it only if it was present.

Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
---
 criu/arch/x86/include/asm/restore.h  | 23 ++++++++++++-
 criu/arch/x86/include/asm/restorer.h |  5 +--
 criu/arch/x86/restorer.c             | 62 ++++++++++++++++++++++++++++++++++++
 criu/pie/Makefile                    |  1 +
 4 files changed, 86 insertions(+), 5 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/arch/x86/include/asm/restore.h b/criu/arch/x86/include/asm/restore.h
index c00553dff24a..c5aa7cdebf03 100644
--- a/criu/arch/x86/include/asm/restore.h
+++ b/criu/arch/x86/include/asm/restore.h
@@ -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);
diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h
index 70df7149ba83..2ab68bad3d70 100644
--- a/criu/arch/x86/include/asm/restorer.h
+++ b/criu/arch/x86/include/asm/restorer.h
@@ -334,10 +334,7 @@  int restore_nonsigframe_gpregs(UserX86RegsEntry *r);
 int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe,
 		struct rt_sigframe *rsigframe);
 
-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);
diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c
index 364b156be91e..d45c009e87ce 100644
--- a/criu/arch/x86/restorer.c
+++ b/criu/arch/x86/restorer.c
@@ -4,6 +4,7 @@ 
 #include "restorer.h"
 #include "asm/restorer.h"
 #include "asm/fpu.h"
+#include "asm/string.h"
 
 #include "syscall.h"
 #include "log.h"
@@ -31,3 +32,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);
+}
diff --git a/criu/pie/Makefile b/criu/pie/Makefile
index 4adec495fe74..fee5d3c6f911 100644
--- a/criu/pie/Makefile
+++ b/criu/pie/Makefile
@@ -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