[PATCH] uml: maintain own LDT entries

Patch imlements full LDT handling in SKAS:
 * UML holds it's own LDT table, used to deliver data on
   modify_ldt(READ)
 * UML disables the default_ldt, inherited from the host (SKAS3)
   or resets LDT entries, set by host's clib and inherited in
   SKAS0
 * A new global variable skas_needs_stub is inserted, that
   can be used to decide, whether stub-pages must be supported
   or not.
 * Uses the syscall-stub to replace missing PTRACE_LDT (therefore,
   write_ldt_entry needs to be modified)

Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com>
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
index 09536f8..44110c5 100644
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -8,6 +8,7 @@
 
 #include "linux/config.h"
 #include "mm_id.h"
+#include "asm/ldt.h"
 
 struct mmu_context_skas {
 	struct mm_id id;
@@ -15,6 +16,7 @@
 #ifdef CONFIG_3_LEVEL_PGTABLES
         unsigned long last_pmd;
 #endif
+	uml_ldt_t ldt;
 };
 
 extern void switch_mm_skas(struct mm_id * mm_idp);
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index 0609347..daa2f85 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -10,7 +10,8 @@
 #include "sysdep/ptrace.h"
 
 extern int userspace_pid[];
-extern int proc_mm, ptrace_faultinfo;
+extern int proc_mm, ptrace_faultinfo, ptrace_ldt;
+extern int skas_needs_stub;
 
 extern void switch_threads(void *me, void *next);
 extern void thread_wait(void *sw, void *fb);
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 147466d..88ab96c 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -20,7 +20,7 @@
 	*task_size_out = CONFIG_HOST_TASK_SIZE;
 #else
 	*host_size_out = top;
-	if (proc_mm && ptrace_faultinfo)
+	if (!skas_needs_stub)
 		*task_size_out = top;
 	else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
 #endif
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 9e5e39c..677871f 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -15,6 +15,7 @@
 #include "asm/mmu.h"
 #include "asm/pgalloc.h"
 #include "asm/pgtable.h"
+#include "asm/ldt.h"
 #include "os.h"
 #include "skas.h"
 
@@ -74,13 +75,12 @@
 
 int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
 {
-	struct mm_struct *cur_mm = current->mm;
-	struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
-	struct mm_id *mm_id = &mm->context.skas.id;
+ 	struct mmu_context_skas *from_mm = NULL;
+	struct mmu_context_skas *to_mm = &mm->context.skas;
 	unsigned long stack = 0;
-	int from, ret = -ENOMEM;
+	int from_fd, ret = -ENOMEM;
 
-	if(!proc_mm || !ptrace_faultinfo){
+	if(skas_needs_stub){
 		stack = get_zeroed_page(GFP_KERNEL);
 		if(stack == 0)
 			goto out;
@@ -102,33 +102,43 @@
 
 		mm->nr_ptes--;
 	}
-	mm_id->stack = stack;
+
+	to_mm->id.stack = stack;
+	if(current->mm != NULL && current->mm != &init_mm)
+		from_mm = &current->mm->context.skas;
 
 	if(proc_mm){
-		if((cur_mm != NULL) && (cur_mm != &init_mm))
-			from = cur_mm_id->u.mm_fd;
-		else from = -1;
+		if(from_mm)
+			from_fd = from_mm->id.u.mm_fd;
+		else from_fd = -1;
 
-		ret = new_mm(from, stack);
+		ret = new_mm(from_fd, stack);
 		if(ret < 0){
 			printk("init_new_context_skas - new_mm failed, "
 			       "errno = %d\n", ret);
 			goto out_free;
 		}
-		mm_id->u.mm_fd = ret;
+		to_mm->id.u.mm_fd = ret;
 	}
 	else {
-		if((cur_mm != NULL) && (cur_mm != &init_mm))
-			mm_id->u.pid = copy_context_skas0(stack,
-							  cur_mm_id->u.pid);
-		else mm_id->u.pid = start_userspace(stack);
+		if(from_mm)
+			to_mm->id.u.pid = copy_context_skas0(stack,
+							     from_mm->id.u.pid);
+		else to_mm->id.u.pid = start_userspace(stack);
+	}
+
+	ret = init_new_ldt(to_mm, from_mm);
+	if(ret < 0){
+		printk("init_new_context_skas - init_ldt"
+		       " failed, errno = %d\n", ret);
+		goto out_free;
 	}
 
 	return 0;
 
  out_free:
-	if(mm_id->stack != 0)
-		free_page(mm_id->stack);
+	if(to_mm->id.stack != 0)
+		free_page(to_mm->id.stack);
  out:
 	return ret;
 }
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 42f2da6..599d679 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -381,9 +381,9 @@
 }
 
 /*
- * This is used only, if proc_mm is available, while PTRACE_FAULTINFO
- * isn't. Opening /proc/mm creates a new mm_context, which lacks the stub-pages
- * Thus, we map them using /proc/mm-fd
+ * This is used only, if stub pages are needed, while proc_mm is
+ * availabl. Opening /proc/mm creates a new mm_context, which lacks
+ * the stub-pages. Thus, we map them using /proc/mm-fd
  */
 void map_stub_pages(int fd, unsigned long code,
 		    unsigned long data, unsigned long stack)
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index efe92e8..9c99025 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -145,7 +145,7 @@
 			       "err = %d\n", -n);
 	}
 
-	if(!ptrace_faultinfo)
+	if(skas_needs_stub)
 		map_stub_pages(fd, CONFIG_STUB_CODE, CONFIG_STUB_DATA, stack);
 
 	return(fd);