[PATCH 3/4] x86_64: make some changes to fs/gs register handling

serue at us.ibm.com serue at us.ibm.com
Mon Jan 25 17:48:14 PST 2010


From: Serge E. Hallyn <serue at us.ibm.com>

1. always save/restore fs/gs

	not just if CONFIG_COMPAT and the task is 64-bit.  Pretty
	sure that block wasn't doing what it wanted to do anyway :)

2. use rdmsrl for fs/gs for self-checkpoint

	<shrug>  other code seems to do it.  It doesn't seem to make
	a difference one way or the other.

3. null out fs/gs if index is set

	like __switch_to() does

4. fs and gs are not encoded segments, so don't run them through
check_segment().

Signed-off-by: Serge E. Hallyn <serue at us.ibm.com>
---
 arch/x86/kernel/checkpoint_64.c |   32 ++++++++++++++++----------------
 1 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/arch/x86/kernel/checkpoint_64.c b/arch/x86/kernel/checkpoint_64.c
index ee01e17..46f2256 100644
--- a/arch/x86/kernel/checkpoint_64.c
+++ b/arch/x86/kernel/checkpoint_64.c
@@ -162,21 +162,26 @@ void save_cpu_regs(struct ckpt_hdr_cpu *h, struct task_struct *t)
 		savesegment(es, _es);
 		savesegment(fs, _fs);
 		savesegment(gs, _gs);
+		rdmsrl(MSR_FS_BASE, h->fs);
+		rdmsrl(MSR_KERNEL_GS_BASE, h->gs);
 	} else {
 		_ds = t->thread.ds;
 		_es = t->thread.es;
 		_fs = t->thread.fsindex;
 		_gs = t->thread.gsindex;
+		h->fs = t->thread.fs;
+		h->gs = t->thread.gs;
 	}
 	h->ds = encode_segment(_ds);
 	h->es = encode_segment(_es);
 	h->fsindex = encode_segment(_fs);
 	h->gsindex = encode_segment(_gs);
 
-	if (!test_tsk_thread_flag(t, TIF_IA32)) {
-		h->fs = t->thread.fs;
-		h->gs = t->thread.gs;
-	}
+	/* see comment in __switch_to() */
+	if (_fs)
+		h->fs = 0;
+	if (_gs)
+		h->gs = 0;
 
 	/*
 	 * for checkpoint in process context (from within a container),
@@ -203,12 +208,6 @@ int load_cpu_regs(struct ckpt_hdr_cpu *h, struct task_struct *t)
 	    !check_segment(h->fsindex) || !check_segment(h->gsindex))
 		return -EINVAL;
 
-#ifdef CONFIG_COMPAT
-	if (test_tsk_thread_flag(t, TIF_IA32) &&
-	    (!check_segment(h->fs) || !check_segment(h->gs)))
-		return -EINVAL;
-#endif
-
 	regs->r15 = h->r15;
 	regs->r14 = h->r14;
 	regs->r13 = h->r13;
@@ -240,18 +239,19 @@ int load_cpu_regs(struct ckpt_hdr_cpu *h, struct task_struct *t)
 	thread->fsindex = decode_segment(h->fsindex);
 	thread->gsindex = decode_segment(h->gsindex);
 
-#ifdef CONFIG_COMPAT
-	if (!test_tsk_thread_flag(t, TIF_IA32)) {
-		thread->fs = h->fs;
-		thread->gs = h->gs;
-	}
-#endif
+	thread->fs = h->fs;
+	thread->gs = h->gs;
 
 	/* XXX - unsure is this really needed ... */
 	loadsegment(fs, thread->fsindex);
         if (thread->fs)
 		wrmsrl(MSR_FS_BASE, thread->fs);
 	load_gs_index(thread->gsindex);
+	/*
+	 * when we switch to user-space, the MSR_KERNEL_GS_BASE
+	 * will be moved back to MSR_GS_BASE.
+	 * http://lists.openwall.net/linux-kernel/2008/11/18/340
+	 */
         if (thread->gs)
 		wrmsrl(MSR_KERNEL_GS_BASE, thread->gs);
 
-- 
1.6.0.6



More information about the Containers mailing list