[Pkg-uml-commit] r160 - in trunk/src/kernel-patch-skas: . debian

Mattia Dongili malattia at costa.debian.org
Sat Aug 26 11:26:04 UTC 2006


Author: malattia
Date: 2006-08-26 11:25:57 +0000 (Sat, 26 Aug 2006)
New Revision: 160

Added:
   trunk/src/kernel-patch-skas/host-skas3-2.4.25-v3.patch
   trunk/src/kernel-patch-skas/host-skas3-2.6.3-v1.patch
   trunk/src/kernel-patch-skas/host-skas3-2.6.6-v1.patch
   trunk/src/kernel-patch-skas/host-skas3-2.6.7-v1.patch
   trunk/src/kernel-patch-skas/host-skas3-2.6.8-v6.patch
   trunk/src/kernel-patch-skas/host-skas3-2.6.9-v7.patch
   trunk/src/kernel-patch-skas/host-skas3.patch
   trunk/src/kernel-patch-skas/skas-2.6.10-v8.patch
   trunk/src/kernel-patch-skas/skas-2.6.11-v8.2.patch
   trunk/src/kernel-patch-skas/skas-2.6.12-v9-pre7.patch
   trunk/src/kernel-patch-skas/skas-2.6.13-rc7-v9-pre7.patch
   trunk/src/kernel-patch-skas/skas-2.6.14-v9-pre7.patch
   trunk/src/kernel-patch-skas/skas-2.6.15-v9-pre8.patch
   trunk/src/kernel-patch-skas/skas-2.6.16-v9-pre9.patch
   trunk/src/kernel-patch-skas/skas-2.6.17-rc5-v9-pre9.patch
Modified:
   trunk/src/kernel-patch-skas/debian/changelog
Log:
add upstream patches

Modified: trunk/src/kernel-patch-skas/debian/changelog
===================================================================
--- trunk/src/kernel-patch-skas/debian/changelog	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/debian/changelog	2006-08-26 11:25:57 UTC (rev 160)
@@ -8,7 +8,7 @@
   * filled the gap until 2.6.16 with patches from Paolo Giarrusso..
   * updated debhelper compatibility version.
 
- -- Mattia Dongili <malattia at debian.org>  Sun, 14 May 2006 18:20:02 +0200
+ -- Mattia Dongili <malattia at debian.org>  Sat, 27 May 2006 16:52:53 +0200
 
 kernel-patch-skas (3-9.3) unstable; urgency=low
 

Added: trunk/src/kernel-patch-skas/host-skas3-2.4.25-v3.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.4.25-v3.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.4.25-v3.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,801 @@
+--- linux-2.4.25-paolo/arch/i386/kernel/ldt.c	2004-09-11 19:25:37.632440992 +0200
++++ linux-2.4.25-paolo/arch/i386/kernel/ldt.c	2004-08-29 17:21:52.276721288 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *mm)
+@@ -53,7 +54,7 @@
+ 	wmb();
+ 	pc->ldt = newldt;
+ 	pc->size = mincount;
+-	if (reload) {
++	if (reload && (&current->active_mm->context == pc)) {
+ 		load_LDT(pc);
+ #ifdef CONFIG_SMP
+ 		if (current->mm->cpu_vm_mask != (1<<smp_processor_id()))
+@@ -86,6 +87,12 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
++void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+ {
+ 	struct mm_struct * old_mm;
+@@ -102,6 +109,26 @@
+ 	return retval;
+ }
+ 
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
++{
++	int err = 0;
++	mm_context_t *new, *old;
++	new = &mm->context;
++	old = &old_mm->context;
++	if (old_mm && old_mm->context.size > 0) {
++		down(&old_mm->context.sem);
++		err = alloc_ldt(new, old->size, 0);
++		if (err < 0) {
++			up(&old_mm->context.sem);
++			goto out;
++		}
++		memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++		up(&old_mm->context.sem);
++	}
++out:
++	return err;
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  * Do not touch the ldt register, we are already
+@@ -118,11 +145,10 @@
+ 	}
+ }
+ 
+-static int read_ldt(void * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void * ptr, unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -166,9 +192,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct modify_ldt_ldt_s ldt_info;
+@@ -192,7 +217,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -243,20 +268,24 @@
+-asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++int modify_ldt(struct mm_struct * mm, int func, void *ptr, unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) {
++	return modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- linux-2.4.25-paolo/arch/i386/kernel/ptrace.c	2004-08-29 17:21:51.920775400 +0200
++++ linux-2.4.25-paolo/arch/i386/kernel/ptrace.c	2004-08-29 17:21:52.616669608 +0200
+@@ -147,6 +147,11 @@
+ 	put_stack_long(child, EFL_OFFSET, tmp);
+ }
+ 
++extern int modify_ldt(struct mm_struct *mm, int func, void *ptr,
++		      unsigned long bytecount);
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
+ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+ {
+ 	struct task_struct *child;
+@@ -270,6 +275,7 @@
+ 		  }
+ 		  break;
+ 
++	case PTRACE_SYSEMU: /* continue and replace next syscall */
+ 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ 	case PTRACE_CONT: { /* restart after signal. */
+ 		long tmp;
+@@ -277,6 +283,10 @@
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
++		if (request == PTRACE_SYSEMU)
++			child->ptrace |= PT_SYSEMU;
++		else
++			child->ptrace &= ~PT_SYSEMU;
+ 		if (request == PTRACE_SYSCALL)
+ 			child->ptrace |= PT_TRACESYS;
+ 		else
+@@ -315,7 +325,7 @@
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
+-		child->ptrace &= ~PT_TRACESYS;
++		child->ptrace &= ~(PT_TRACESYS|PT_SYSEMU);
+ 		if ((child->ptrace & PT_DTRACE) == 0) {
+ 			/* Spurious delayed TF traps may occur */
+ 			child->ptrace |= PT_DTRACE;
+@@ -419,6 +429,53 @@
+ 		break;
+ 	}
+ 
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data,
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++#if 1 /* CONFIG_PROC_MM*/
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		child->mm = new;
++		child->active_mm = new;
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = -EIO;
+ 		break;
+@@ -430,6 +487,29 @@
+ 	return ret;
+ }
+ 
++asmlinkage void syscall_emulate(void)
++{
++	if ((current->ptrace & (PT_PTRACED|PT_SYSEMU)) !=
++			(PT_PTRACED|PT_SYSEMU))
++		return;
++	/* the 0x80 provides a way for the tracing parent to distinguish
++	   between a syscall stop and SIGTRAP delivery */
++	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
++					? 0x80 : 0);
++	current->state = TASK_STOPPED;
++	notify_parent(current, SIGCHLD);
++	schedule();
++	/*
++	 * this isn't the same as continuing with a signal, but it will do
++	 * for normal use.  strace only continues with a signal if the
++	 * stopping signal is not SIGTRAP.  -brl
++	 */
++	if (current->exit_code) {
++		send_sig(current->exit_code, current, 1);
++		current->exit_code = 0;
++	}
++}
++
+ asmlinkage void syscall_trace(void)
+ {
+ 	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) !=
+--- linux-2.4.25/arch/i386/kernel/sys_i386.c~host-skas3-2.4.25-no_CONFIG	2004-08-29 17:21:51.100900040 +0200
++++ linux-2.4.25-paolo/arch/i386/kernel/sys_i386.c	2004-08-29 17:21:51.111898368 +0200
+@@ -40,7 +40,7 @@ asmlinkage int sys_pipe(unsigned long * 
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -55,9 +55,9 @@ static inline long do_mmap2(
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -69,7 +69,7 @@ asmlinkage long sys_mmap2(unsigned long 
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ 
+ /*
+@@ -100,7 +100,7 @@ asmlinkage int old_mmap(struct mmap_arg_
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ 	return err;
+ }
+--- linux-2.4.25/include/asm-i386/processor.h~host-skas3-2.4.25-no_CONFIG	2004-08-29 17:21:51.101899888 +0200
++++ linux-2.4.25-paolo/include/asm-i386/processor.h	2004-08-29 17:21:51.111898368 +0200
+@@ -433,6 +433,8 @@ extern int arch_kernel_thread(int (*fn)(
+ static inline void copy_segments(struct task_struct *p, struct mm_struct * mm) { }
+ static inline void release_segments(struct mm_struct * mm) { }
+ 
++extern int __init_new_context(struct mm_struct *old_mm, struct mm_struct *mm);
++
+ /*
+  * Return saved PC of a blocked thread.
+  */
+--- linux-2.4.25/include/asm-i386/ptrace.h~host-skas3-2.4.25-no_CONFIG	2004-08-29 17:21:51.102899736 +0200
++++ linux-2.4.25-paolo/include/asm-i386/ptrace.h	2004-08-29 17:21:51.111898368 +0200
+@@ -51,6 +51,22 @@ struct pt_regs {
+ 
+ #define PTRACE_SETOPTIONS         21
+ 
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#define PTRACE_FAULTINFO 52
++#define PTRACE_SIGPENDING 53
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++
+ /* options set using PTRACE_SETOPTIONS */
+ #define PTRACE_O_TRACESYSGOOD     0x00000001
+ 
+--- linux-2.4.25/include/linux/mm.h~host-skas3-2.4.25-no_CONFIG	2004-08-29 17:21:51.103899584 +0200
++++ linux-2.4.25-paolo/include/linux/mm.h	2004-08-29 17:21:51.112898216 +0200
+@@ -505,6 +505,9 @@ extern int ptrace_check_attach(struct ta
+ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+ 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc() that does all
+@@ -552,9 +555,10 @@ extern void exit_mmap(struct mm_struct *
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+-	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++extern unsigned long do_mmap_pgoff(struct mm_struct *mm,
++				   struct file *file, unsigned long addr,
++				   unsigned long len, unsigned long prot,
++				   unsigned long flag, unsigned long pgoff);
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+@@ -564,7 +568,7 @@ static inline unsigned long do_mmap(stru
+ 	if ((offset + PAGE_ALIGN(len)) < offset)
+ 		goto out;
+ 	if (!(offset & ~PAGE_MASK))
+-		ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
++		ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, offset >> PAGE_SHIFT);
+ out:
+ 	return ret;
+ }
+--- /dev/null	2004-06-25 17:47:25.000000000 +0200
++++ linux-2.4.25-paolo/include/linux/proc_mm.h	2004-08-29 17:21:51.112898216 +0200
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++#endif
+--- linux-2.4.25/mm/Makefile~host-skas3-2.4.25-no_CONFIG	2004-08-29 17:21:51.105899280 +0200
++++ linux-2.4.25-paolo/mm/Makefile	2004-08-29 17:21:51.112898216 +0200
+@@ -17,5 +17,6 @@ obj-y	 := memory.o mmap.o filemap.o mpro
+ 	    shmem.o
+ 
+ obj-$(CONFIG_HIGHMEM) += highmem.o
++obj-y += proc_mm.o
+ 
+ include $(TOPDIR)/Rules.make
+--- linux-2.4.25/mm/mmap.c~host-skas3-2.4.25-no_CONFIG	2004-08-29 17:21:51.106899128 +0200
++++ linux-2.4.25-paolo/mm/mmap.c	2004-08-29 17:21:51.112898216 +0200
+@@ -391,10 +391,11 @@ static int vma_merge(struct mm_struct * 
+ 	return 0;
+ }
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags, unsigned long pgoff)
++unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	unsigned int vm_flags;
+ 	int correct_wcount = 0;
+--- linux-2.4.25-paolo/mm/mprotect.c	2004-08-29 17:21:51.113898064 +0200
++++ linux-2.4.25-paolo/mm/mprotect.c	2004-08-29 17:21:52.974615192 +0200
+@@ -71,23 +71,24 @@
+ 	} while (address && (address < end));
+ }
+ 
+-static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
++static void change_protection(struct mm_struct *mm,
++	unsigned long start, unsigned long end, pgprot_t newprot)
+ {
+ 	pgd_t *dir;
+ 	unsigned long beg = start;
+ 
+-	dir = pgd_offset(current->mm, start);
+-	flush_cache_range(current->mm, beg, end);
++	dir = pgd_offset(mm, start);
++	flush_cache_range(mm, beg, end);
+ 	if (start >= end)
+ 		BUG();
+-	spin_lock(&current->mm->page_table_lock);
++	spin_lock(&mm->page_table_lock);
+ 	do {
+ 		change_pmd_range(dir, start, end - start, newprot);
+ 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ 		dir++;
+ 	} while (start && (start < end));
+-	spin_unlock(&current->mm->page_table_lock);
+-	flush_tlb_range(current->mm, beg, end);
++	spin_unlock(&mm->page_table_lock);
++	flush_tlb_range(mm, beg, end);
+ 	return;
+ }
+ 
+@@ -125,6 +126,7 @@
+ 	int newflags, pgprot_t prot)
+ {
+ 	struct vm_area_struct * n, * prev = *pprev;
++	struct mm_struct * mm = vma->vm_mm;
+ 
+ 	*pprev = vma;
+ 
+@@ -153,7 +155,7 @@
+ 	lock_vma_mappings(vma);
+ 	spin_lock(&vma->vm_mm->page_table_lock);
+ 	vma->vm_start = end;
+-	__insert_vm_struct(current->mm, n);
++	__insert_vm_struct(mm, n);
+ 	spin_unlock(&vma->vm_mm->page_table_lock);
+ 	unlock_vma_mappings(vma);
+ 
+@@ -165,6 +167,7 @@
+ 	int newflags, pgprot_t prot)
+ {
+ 	struct vm_area_struct * n;
++	struct mm_struct * mm = vma->vm_mm;
+ 
+ 	n = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
+ 	if (!n)
+@@ -182,7 +185,7 @@
+ 	lock_vma_mappings(vma);
+ 	spin_lock(&vma->vm_mm->page_table_lock);
+ 	vma->vm_end = start;
+-	__insert_vm_struct(current->mm, n);
++	__insert_vm_struct(mm, n);
+ 	spin_unlock(&vma->vm_mm->page_table_lock);
+ 	unlock_vma_mappings(vma);
+ 
+@@ -196,6 +199,7 @@
+ 	int newflags, pgprot_t prot)
+ {
+ 	struct vm_area_struct * left, * right;
++	struct mm_struct * mm = vma->vm_mm;
+ 
+ 	left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+ 	if (!left)
+@@ -226,8 +230,8 @@
+ 	vma->vm_start = start;
+ 	vma->vm_end = end;
+ 	vma->vm_flags = newflags;
+-	__insert_vm_struct(current->mm, left);
+-	__insert_vm_struct(current->mm, right);
++	__insert_vm_struct(mm, left);
++	__insert_vm_struct(mm, right);
+ 	spin_unlock(&vma->vm_mm->page_table_lock);
+ 	unlock_vma_mappings(vma);
+ 
+@@ -241,6 +245,7 @@
+ {
+ 	pgprot_t newprot;
+ 	int error;
++	struct mm_struct * mm = vma->vm_mm;
+ 
+ 	if (newflags == vma->vm_flags) {
+ 		*pprev = vma;
+@@ -260,11 +265,12 @@
+ 	if (error)
+ 		return error;
+ 
+-	change_protection(start, end, newprot);
++	change_protection(mm, start, end, newprot);
+ 	return 0;
+ }
+ 
+-asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++		 unsigned long prot)
+ {
+ 	unsigned long nstart, end, tmp;
+ 	struct vm_area_struct * vma, * next, * prev;
+@@ -281,9 +287,9 @@
+ 	if (end == start)
+ 		return 0;
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma || vma->vm_start > start)
+ 		goto out;
+@@ -335,3 +341,8 @@
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	return(do_mprotect(current->mm, start, len, prot));
++}
+--- linux-2.4.25-paolo/mm/proc_mm.c	2004-08-29 17:21:52.277721136 +0200
++++ linux-2.4.25-paolo/mm/proc_mm.c	2004-08-29 17:21:52.974615192 +0200
+@@ -0,0 +1,181 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "linux/mman.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		/*mm_copy_segments(from, mm);*/
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++
++	spin_lock(&mmlist_lock);
++	list_add(&mm->mmlist, &current->mm->mmlist);
++	mmlist_nr++;
++	spin_unlock(&mmlist_lock);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.4.25-paolo/arch/i386/kernel/entry.S	2004-08-29 17:21:51.920775400 +0200
++++ linux-2.4.25-paolo/arch/i386/kernel/entry.S	2004-08-29 17:21:52.616669608 +0200
+@@ -203,6 +203,8 @@
+ 	pushl %eax			# save orig_eax
+ 	SAVE_ALL
+ 	GET_CURRENT(%ebx)
++	testb $0x20,tsk_ptrace(%ebx)	# PT_SYSEMU
++	jne emulatesys
+ 	testb $0x02,tsk_ptrace(%ebx)	# PT_TRACESYS
+ 	jne tracesys
+ 	cmpl $(NR_syscalls),%eax
+@@ -237,6 +239,10 @@
+ 	jmp restore_all
+ 
+ 	ALIGN
++emulatesys:
++	call SYMBOL_NAME(syscall_emulate)
++	jmp ret_from_sys_call
++	ALIGN
+ tracesys:
+ 	movl $-ENOSYS,EAX(%esp)
+ 	call SYMBOL_NAME(syscall_trace)
+--- linux-2.4.25-paolo/include/linux/ptrace.h	2004-08-29 17:21:51.920775400 +0200
++++ linux-2.4.25-paolo/include/linux/ptrace.h	2004-08-29 17:21:52.616669608 +0200
+@@ -20,6 +20,7 @@
+ #define PTRACE_DETACH		0x11
+ 
+ #define PTRACE_SYSCALL		  24
++#define PTRACE_SYSEMU		  31
+ 
+ #include <asm/ptrace.h>
+ 
+--- linux-2.4.25-paolo/include/linux/sched.h	2004-08-29 17:21:51.921775248 +0200
++++ linux-2.4.25-paolo/include/linux/sched.h	2004-08-29 17:21:52.617669456 +0200
+@@ -445,6 +445,7 @@
+ #define PT_DTRACE	0x00000004	/* delayed trace (used on m68k, i386) */
+ #define PT_TRACESYSGOOD	0x00000008
+ #define PT_PTRACE_CAP	0x00000010	/* ptracer can follow suid-exec */
++#define PT_SYSEMU	0x00000020	/* syscall emulation for UML */
+ 
+ #define is_dumpable(tsk)    ((tsk)->task_dumpable && (tsk)->mm && (tsk)->mm->dumpable)
+ 
+--- linux-2.4.25/include/asm-i386/mmu_context.h~skas-avoid-ldt	2004-08-29 17:21:52.273721744 +0200
++++ linux-2.4.25-paolo/include/asm-i386/mmu_context.h	2004-08-29 17:21:52.276721288 +0200
+@@ -13,6 +13,8 @@
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
++void init_new_empty_context(struct mm_struct *mm);
+ 
+ #ifdef CONFIG_SMP
+ 

Added: trunk/src/kernel-patch-skas/host-skas3-2.6.3-v1.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.3-v1.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.3-v1.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,631 @@
+--- linux-2.6.0/include/linux/mm.h.Skas_add	2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/linux/mm.h	2003-12-31 17:13:57.000000000 +0100
+@@ -507,6 +507,9 @@
+ 	return __set_page_dirty_buffers(page);
+ }
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start, 
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -537,9 +540,15 @@
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file, 
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+--- linux-2.6.0/include/linux/proc_mm.h.Skas_add	2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/linux/proc_mm.h	2003-12-31 17:13:57.000000000 +0100
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;	
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+--- linux-2.6.0/mm/mmap.c.Skas_add	2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/mmap.c	2003-12-31 17:13:57.000000000 +0100
+@@ -460,11 +460,11 @@
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file, 
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -712,7 +712,7 @@
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+--- linux-2.6.0/mm/mprotect.c.Skas_add	2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/mprotect.c	2003-12-31 17:13:57.000000000 +0100
+@@ -221,8 +221,9 @@
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, 
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp;
+ 	struct vm_area_struct * vma, * next, * prev;
+@@ -245,9 +246,9 @@
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -326,6 +327,11 @@
+ 		prev->vm_mm->map_count--;
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++        return(do_mprotect(current->mm, start, len, prot));
++}
+--- linux-2.6.0/mm/proc_mm.c.Skas_add	2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/proc_mm.c	2003-12-31 17:13:57.000000000 +0100
+@@ -0,0 +1,174 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
++		     unsigned long len, unsigned long prot, 
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot, 
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++	
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len, 
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		__init_new_context(mm, from);
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	ret = init_new_context(current, mm);
++	if(ret)
++		goto out_free;
++
++	spin_lock(&mmlist_lock);
++	list_add(&mm->mmlist, &current->mm->mmlist);
++	mmlist_nr++;
++	spin_unlock(&mmlist_lock);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_free:
++	mmput(mm);
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.6.0/mm/Makefile.Skas_add	2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/Makefile	2003-12-31 17:13:57.000000000 +0100
+@@ -12,3 +12,5 @@
+ 			   slab.o swap.o truncate.o vmscan.o $(mmu-y)
+ 
+ obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
++
+--- linux-2.6.0/arch/i386/kernel/sys_i386.c.i386_Skas	2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/sys_i386.c	2003-12-31 16:57:39.000000000 +0100
+@@ -40,7 +40,7 @@
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -55,9 +55,9 @@
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -69,7 +69,7 @@
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ 
+ /*
+@@ -100,7 +100,7 @@
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ 	return err;
+ }
+--- linux-2.6.0/arch/i386/kernel/ptrace.c.i386_Skas	2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/ptrace.c	2003-12-31 16:57:39.000000000 +0100
+@@ -14,6 +14,7 @@
+ #include <linux/ptrace.h>
+ #include <linux/user.h>
+ #include <linux/security.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -507,6 +508,56 @@
+ 					     addr, (struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo) 
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault, 
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data, 
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data, 
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		child->mm = new;
++		child->active_mm = new;
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+--- linux-2.6.0/arch/i386/kernel/ldt.c.i386_Skas	2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/ldt.c	2003-12-31 16:57:40.000000000 +0100
+@@ -54,7 +54,7 @@
+ 	pc->size = mincount;
+ 	wmb();
+ 
+-	if (reload) {
++	if (reload && (&current->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+@@ -89,14 +89,12 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+ 	init_MUTEX(&mm->context.sem);
+ 	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+ 		retval = copy_ldt(&mm->context, &old_mm->context);
+@@ -105,6 +103,11 @@
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	return __init_new_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +124,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -169,9 +172,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -195,7 +197,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -228,23 +230,29 @@
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- linux-2.6.0/arch/i386/Kconfig.i386_Skas	2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/Kconfig	2003-12-31 16:57:40.000000000 +0100
+@@ -698,6 +698,9 @@
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation Support"
+--- linux-2.6.0/include/asm-i386/desc.h.i386_Skas	2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/asm-i386/desc.h	2003-12-31 16:57:40.000000000 +0100
+@@ -123,6 +123,9 @@
+ 	put_cpu();
+ }
+ 
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- ./include/asm-i386/processor.h.fix	2004-01-09 21:27:46.000000000 +0100
++++ ./include/asm-i386/processor.h	2004-02-11 19:13:22.000000000 +0100
+@@ -630,4 +630,6 @@
+ 
+ extern void select_idle_routine(const struct cpuinfo_x86 *c);
+ 
++extern int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #endif /* __ASM_I386_PROCESSOR_H */
+--- linux-2.6.0/include/asm-i386/ptrace.h.i386_Skas	2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/asm-i386/ptrace.h	2003-12-31 16:57:54.000000000 +0100
+@@ -59,4 +59,26 @@
+ #define instruction_pointer(regs) ((regs)->eip)
+ #endif
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++#define PTRACE_SIGPENDING	  53
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- ./include/asm-i386/mmu_context.h.fix	2003-12-25 19:24:24.000000000 +0100
++++ ./include/asm-i386/mmu_context.h	2004-02-29 16:16:54.000000000 +0100
+@@ -29,6 +29,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = cpu_tlbstate[cpu].active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +54,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
+-		BUG_ON(cpu_tlbstate[cpu].active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 

Added: trunk/src/kernel-patch-skas/host-skas3-2.6.6-v1.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.6-v1.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.6-v1.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,631 @@
+--- linux-2.6.0/include/linux/mm.h.Skas_add	2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/linux/mm.h	2003-12-31 17:13:57.000000000 +0100
+@@ -515,6 +515,9 @@
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start, 
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -548,9 +551,15 @@
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file, 
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+--- linux-2.6.0/include/linux/proc_mm.h.Skas_add	2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/linux/proc_mm.h	2003-12-31 17:13:57.000000000 +0100
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;	
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+--- linux-2.6.0/mm/mmap.c.Skas_add	2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/mmap.c	2003-12-31 17:13:57.000000000 +0100
+@@ -480,11 +480,11 @@
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file, 
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -737,7 +737,7 @@
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+--- linux-2.6.0/mm/mprotect.c.Skas_add	2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/mprotect.c	2003-12-31 17:13:57.000000000 +0100
+@@ -223,8 +223,9 @@
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, 
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp;
+ 	struct vm_area_struct * vma, * next, * prev;
+@@ -247,9 +248,9 @@
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -328,6 +329,11 @@
+ 		prev->vm_mm->map_count--;
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++        return(do_mprotect(current->mm, start, len, prot));
++}
+--- linux-2.6.0/mm/proc_mm.c.Skas_add	2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/proc_mm.c	2003-12-31 17:13:57.000000000 +0100
+@@ -0,0 +1,174 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
++		     unsigned long len, unsigned long prot, 
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot, 
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++	
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len, 
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		__init_new_context(mm, from);
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	ret = init_new_context(current, mm);
++	if(ret)
++		goto out_free;
++
++	spin_lock(&mmlist_lock);
++	list_add(&mm->mmlist, &current->mm->mmlist);
++	mmlist_nr++;
++	spin_unlock(&mmlist_lock);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_free:
++	mmput(mm);
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.6.0/mm/Makefile.Skas_add	2003-12-31 11:55:32.000000000 +0100
++++ linux-2.6.0/mm/Makefile	2003-12-31 17:13:57.000000000 +0100
+@@ -13,3 +13,5 @@
+ 
+ obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o
+ obj-$(CONFIG_HUGETLBFS)	+= hugetlb.o
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
++
+--- linux-2.6.0/arch/i386/kernel/sys_i386.c.i386_Skas	2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/sys_i386.c	2003-12-31 16:57:39.000000000 +0100
+@@ -41,7 +41,7 @@
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,7 @@
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ 
+ /*
+@@ -101,7 +101,7 @@
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ 	return err;
+ }
+--- linux-2.6.0/arch/i386/kernel/ptrace.c.i386_Skas	2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/ptrace.c	2003-12-31 16:57:39.000000000 +0100
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -508,6 +509,56 @@
+ 					     addr, (struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo) 
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault, 
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data, 
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data, 
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		child->mm = new;
++		child->active_mm = new;
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+--- linux-2.6.0/arch/i386/kernel/ldt.c.i386_Skas	2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/kernel/ldt.c	2003-12-31 16:57:40.000000000 +0100
+@@ -54,7 +54,7 @@
+ 	pc->size = mincount;
+ 	wmb();
+ 
+-	if (reload) {
++	if (reload && (&current->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+@@ -89,14 +89,12 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+ 	init_MUTEX(&mm->context.sem);
+ 	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+ 		retval = copy_ldt(&mm->context, &old_mm->context);
+@@ -105,6 +103,11 @@
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	return __init_new_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +124,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -169,9 +172,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -195,7 +197,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -228,23 +230,29 @@
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- linux-2.6.0/arch/i386/Kconfig.i386_Skas	2003-12-31 11:55:27.000000000 +0100
++++ linux-2.6.0/arch/i386/Kconfig	2003-12-31 16:57:40.000000000 +0100
+@@ -707,6 +707,9 @@
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation Support"
+--- linux-2.6.0/include/asm-i386/desc.h.i386_Skas	2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/asm-i386/desc.h	2003-12-31 16:57:40.000000000 +0100
+@@ -123,6 +123,9 @@
+ 	put_cpu();
+ }
+ 
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- ./include/asm-i386/processor.h.fix	2004-01-09 21:27:46.000000000 +0100
++++ ./include/asm-i386/processor.h	2004-02-11 19:13:22.000000000 +0100
+@@ -648,4 +648,6 @@
+ 
+ extern void select_idle_routine(const struct cpuinfo_x86 *c);
+ 
++extern int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #endif /* __ASM_I386_PROCESSOR_H */
+--- linux-2.6.0/include/asm-i386/ptrace.h.i386_Skas	2003-12-31 11:55:31.000000000 +0100
++++ linux-2.6.0/include/asm-i386/ptrace.h	2003-12-31 16:57:54.000000000 +0100
+@@ -59,4 +59,26 @@
+ #define instruction_pointer(regs) ((regs)->eip)
+ #endif
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++#define PTRACE_SIGPENDING	  53
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- ./include/asm-i386/mmu_context.h.fix	2003-12-25 19:24:24.000000000 +0100
++++ ./include/asm-i386/mmu_context.h	2004-02-29 16:16:54.000000000 +0100
+@@ -29,6 +29,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = cpu_tlbstate[cpu].active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +54,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
+-		BUG_ON(cpu_tlbstate[cpu].active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 

Added: trunk/src/kernel-patch-skas/host-skas3-2.6.7-v1.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.7-v1.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.7-v1.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,633 @@
+--- ./arch/i386/kernel/sys_i386.c.skas	2004-03-13 17:55:23.000000000 +0100
++++ ./arch/i386/kernel/sys_i386.c	2004-06-17 16:24:30.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,7 @@
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ 
+ /*
+@@ -101,7 +101,7 @@
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ 	return err;
+ }
+--- ./arch/i386/kernel/ptrace.c.skas	2004-06-16 22:25:18.000000000 +0200
++++ ./arch/i386/kernel/ptrace.c	2004-06-17 16:24:30.000000000 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -509,6 +510,56 @@
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo) 
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault, 
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data, 
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data, 
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		child->mm = new;
++		child->active_mm = new;
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+--- ./arch/i386/kernel/ldt.c.skas	2003-12-25 19:23:56.000000000 +0100
++++ ./arch/i386/kernel/ldt.c	2004-06-17 16:24:30.000000000 +0200
+@@ -54,7 +54,7 @@
+ 	pc->size = mincount;
+ 	wmb();
+ 
+-	if (reload) {
++	if (reload && (&current->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+@@ -89,14 +89,12 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+ 	init_MUTEX(&mm->context.sem);
+ 	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+ 		retval = copy_ldt(&mm->context, &old_mm->context);
+@@ -105,6 +103,11 @@
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	return __init_new_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +124,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -169,9 +172,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -195,7 +197,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -228,23 +230,29 @@
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- ./arch/i386/Kconfig.skas	2004-06-16 22:25:18.000000000 +0200
++++ ./arch/i386/Kconfig	2004-06-17 16:24:30.000000000 +0200
+@@ -720,6 +720,10 @@
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+--- ./include/linux/mm.h.skas	2004-06-16 22:27:11.000000000 +0200
++++ ./include/linux/mm.h	2004-06-17 16:24:30.000000000 +0200
+@@ -574,6 +574,9 @@
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start, 
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -632,9 +635,15 @@
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file, 
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+--- ./include/linux/proc_mm.h.skas	2004-06-17 16:24:30.000000000 +0200
++++ ./include/linux/proc_mm.h	2004-06-17 16:24:30.000000000 +0200
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;	
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+--- ./include/asm-i386/desc.h.skas	2003-12-20 17:44:08.000000000 +0100
++++ ./include/asm-i386/desc.h	2004-06-17 16:24:30.000000000 +0200
+@@ -123,6 +123,9 @@
+ 	put_cpu();
+ }
+ 
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- ./include/asm-i386/processor.h.skas	2004-06-16 22:27:00.000000000 +0200
++++ ./include/asm-i386/processor.h	2004-06-17 16:24:30.000000000 +0200
+@@ -649,6 +649,8 @@
+ 
+ extern void select_idle_routine(const struct cpuinfo_x86 *c);
+ 
++extern int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #define cache_line_size() (boot_cpu_data.x86_cache_alignment)
+ 
+ #ifdef CONFIG_SCHED_SMT
+--- ./include/asm-i386/ptrace.h.skas	2003-12-20 17:21:33.000000000 +0100
++++ ./include/asm-i386/ptrace.h	2004-06-17 16:24:30.000000000 +0200
+@@ -59,4 +59,26 @@
+ #define instruction_pointer(regs) ((regs)->eip)
+ #endif
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++#define PTRACE_SIGPENDING	  53
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- ./include/asm-i386/mmu_context.h.skas	2003-12-25 19:24:24.000000000 +0100
++++ ./include/asm-i386/mmu_context.h	2004-06-17 16:24:30.000000000 +0200
+@@ -29,6 +29,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = cpu_tlbstate[cpu].active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +54,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
+-		BUG_ON(cpu_tlbstate[cpu].active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+--- ./mm/mmap.c.skas	2004-06-16 22:27:18.000000000 +0200
++++ ./mm/mmap.c	2004-06-17 16:24:30.000000000 +0200
+@@ -725,11 +725,11 @@
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file, 
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -988,7 +988,7 @@
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+--- ./mm/mprotect.c.skas	2004-06-16 22:27:18.000000000 +0200
++++ ./mm/mprotect.c	2004-06-17 16:24:30.000000000 +0200
+@@ -185,8 +185,9 @@
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, 
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp;
+ 	struct vm_area_struct *vma, *prev;
+@@ -209,9 +210,9 @@
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -277,6 +278,11 @@
+ 		}
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++        return(do_mprotect(current->mm, start, len, prot));
++}
+--- ./mm/proc_mm.c.skas	2004-06-17 16:24:30.000000000 +0200
++++ ./mm/proc_mm.c	2004-06-17 16:24:30.000000000 +0200
+@@ -0,0 +1,174 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
++		     unsigned long len, unsigned long prot, 
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot, 
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++	
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len, 
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		__init_new_context(mm, from);
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	ret = init_new_context(current, mm);
++	if(ret)
++		goto out_free;
++
++	spin_lock(&mmlist_lock);
++	list_add(&mm->mmlist, &current->mm->mmlist);
++	mmlist_nr++;
++	spin_unlock(&mmlist_lock);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_free:
++	mmput(mm);
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- ./mm/Makefile.skas	2004-06-16 22:27:15.000000000 +0200
++++ ./mm/Makefile	2004-06-17 16:24:30.000000000 +0200
+@@ -15,3 +15,4 @@
+ obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o
+ obj-$(CONFIG_HUGETLBFS)	+= hugetlb.o
+ obj-$(CONFIG_NUMA) 	+= mempolicy.o
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o

Added: trunk/src/kernel-patch-skas/host-skas3-2.6.8-v6.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.8-v6.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.8-v6.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,872 @@
+
+
+Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade_spam at yahoo.it>
+---
+
+ vanilla-linux-2.6.8.1-paolo/Makefile                       |    2 
+ vanilla-linux-2.6.8.1-paolo/arch/i386/Kconfig              |    4 
+ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/entry.S       |    9 
+ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/ldt.c         |   38 +-
+ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/ptrace.c      |   71 ++++-
+ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/sys_i386.c    |   12 
+ vanilla-linux-2.6.8.1-paolo/include/asm-i386/desc.h        |    3 
+ vanilla-linux-2.6.8.1-paolo/include/asm-i386/mmu_context.h |   19 +
+ vanilla-linux-2.6.8.1-paolo/include/asm-i386/ptrace.h      |   22 +
+ vanilla-linux-2.6.8.1-paolo/include/asm-i386/thread_info.h |    4 
+ vanilla-linux-2.6.8.1-paolo/include/linux/mm.h             |   13 
+ vanilla-linux-2.6.8.1-paolo/include/linux/proc_mm.h        |   48 +++
+ vanilla-linux-2.6.8.1-paolo/include/linux/ptrace.h         |    1 
+ vanilla-linux-2.6.8.1-paolo/kernel/fork.c                  |    1 
+ vanilla-linux-2.6.8.1-paolo/mm/Makefile                    |    1 
+ vanilla-linux-2.6.8.1-paolo/mm/mmap.c                      |   10 
+ vanilla-linux-2.6.8.1-paolo/mm/mprotect.c                  |   23 +
+ vanilla-linux-2.6.8.1-paolo/mm/proc_mm.c                   |  181 +++++++++++++
+ 18 files changed, 415 insertions(+), 47 deletions(-)
+
+diff -puN arch/i386/Kconfig~host-skas3-2.6.8.1-v6 arch/i386/Kconfig
+--- vanilla-linux-2.6.8.1/arch/i386/Kconfig~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.166827168 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/Kconfig	2004-10-18 19:02:18.301806648 +0200
+@@ -721,6 +721,10 @@ config X86_PAE
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+diff -puN arch/i386/kernel/entry.S~host-skas3-2.6.8.1-v6 arch/i386/kernel/entry.S
+--- vanilla-linux-2.6.8.1/arch/i386/kernel/entry.S~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.202821696 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/entry.S	2004-10-18 19:02:18.335801480 +0200
+@@ -258,7 +258,7 @@ sysenter_past_esp:
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+ 
+-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++	testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	call *sys_call_table(,%eax,4)
+ 	movl %eax,EAX(%esp)
+@@ -280,8 +280,8 @@ ENTRY(system_call)
+ 	GET_THREAD_INFO(%ebp)
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+-					# system call tracing in operation
+-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++					# system call tracing in operation / emulation
++	testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ syscall_call:
+ 	call *sys_call_table(,%eax,4)
+@@ -340,6 +340,9 @@ syscall_trace_entry:
+ 	movl %esp, %eax
+ 	xorl %edx,%edx
+ 	call do_syscall_trace
++	cmpl $0, %eax
++	jne syscall_exit		# ret != 0 -> running under PTRACE_SYSEMU,
++					# so must skip actual syscall
+ 	movl ORIG_EAX(%esp), %eax
+ 	cmpl $(nr_syscalls), %eax
+ 	jnae syscall_call
+diff -puN arch/i386/kernel/ldt.c~host-skas3-2.6.8.1-v6 arch/i386/kernel/ldt.c
+--- vanilla-linux-2.6.8.1/arch/i386/kernel/ldt.c~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.203821544 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/ldt.c	2004-10-18 19:02:18.319803912 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -54,7 +55,7 @@ static int alloc_ldt(mm_context_t *pc, i
+ 	pc->size = mincount;
+ 	wmb();
+ 
+-	if (reload) {
++	if (reload && (&current->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+@@ -89,14 +90,10 @@ static inline int copy_ldt(mm_context_t 
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+ 		retval = copy_ldt(&mm->context, &old_mm->context);
+@@ -105,6 +102,12 @@ int init_new_context(struct task_struct 
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +124,11 @@ void destroy_context(struct mm_struct *m
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -169,9 +172,8 @@ static int read_default_ldt(void __user 
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -195,7 +197,7 @@ static int write_ldt(void __user * ptr, 
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -228,23 +230,29 @@ out:
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return modify_ldt(current->mm, func, ptr, bytecount);
++}
+diff -puN arch/i386/kernel/ptrace.c~host-skas3-2.6.8.1-v6 arch/i386/kernel/ptrace.c
+--- vanilla-linux-2.6.8.1/arch/i386/kernel/ptrace.c~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.204821392 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/ptrace.c	2004-10-18 19:02:18.319803912 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -357,6 +358,7 @@ asmlinkage int sys_ptrace(long request, 
+ 		  }
+ 		  break;
+ 
++	case PTRACE_SYSEMU: /* continue and replace next syscall */
+ 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ 	case PTRACE_CONT: { /* restart after signal. */
+ 		long tmp;
+@@ -364,6 +366,12 @@ asmlinkage int sys_ptrace(long request, 
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
++		if (request == PTRACE_SYSEMU) {
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		}
++		else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		}
+ 		if (request == PTRACE_SYSCALL) {
+ 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		}
+@@ -404,6 +412,7 @@ asmlinkage int sys_ptrace(long request, 
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
++		clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		if ((child->ptrace & PT_DTRACE) == 0) {
+ 			/* Spurious delayed TF traps may occur */
+@@ -509,6 +518,56 @@ asmlinkage int sys_ptrace(long request, 
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data,
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		child->mm = new;
++		child->active_mm = new;
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+@@ -524,8 +583,9 @@ out:
+  * - triggered by current->work.syscall_trace
+  */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++	int is_sysemu;
+ 	if (unlikely(current->audit_context)) {
+ 		if (!entryexit)
+ 			audit_syscall_entry(current, regs->orig_eax,
+@@ -534,11 +594,12 @@ void do_syscall_trace(struct pt_regs *re
+ 		else
+ 			audit_syscall_exit(current, regs->eax);
+ 	}
++	is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
+ 
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+-		return;
++	if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
++		return 0;
+ 	if (!(current->ptrace & PT_PTRACED))
+-		return;
++		return 0;
+ 	/* the 0x80 provides a way for the tracing parent to distinguish
+ 	   between a syscall stop and SIGTRAP delivery */
+ 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+@@ -553,4 +614,6 @@ void do_syscall_trace(struct pt_regs *re
+ 		send_sig(current->exit_code, current, 1);
+ 		current->exit_code = 0;
+ 	}
++	/* != 0 if nullifying the syscall, 0 if running it normally */
++	return is_sysemu;
+ }
+diff -puN arch/i386/kernel/sys_i386.c~host-skas3-2.6.8.1-v6 arch/i386/kernel/sys_i386.c
+--- vanilla-linux-2.6.8.1/arch/i386/kernel/sys_i386.c~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.205821240 +0200
++++ vanilla-linux-2.6.8.1-paolo/arch/i386/kernel/sys_i386.c	2004-10-18 19:02:18.320803760 +0200
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,7 @@ asmlinkage long sys_mmap2(unsigned long 
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ 
+ /*
+@@ -101,7 +101,7 @@ asmlinkage int old_mmap(struct mmap_arg_
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ 	return err;
+ }
+diff -puN include/asm-i386/desc.h~host-skas3-2.6.8.1-v6 include/asm-i386/desc.h
+--- vanilla-linux-2.6.8.1/include/asm-i386/desc.h~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.214819872 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/asm-i386/desc.h	2004-10-18 19:02:18.320803760 +0200
+@@ -124,6 +124,9 @@ static inline void load_LDT(mm_context_t
+ 	put_cpu();
+ }
+ 
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+diff -puN include/asm-i386/mmu_context.h~host-skas3-2.6.8.1-v6 include/asm-i386/mmu_context.h
+--- vanilla-linux-2.6.8.1/include/asm-i386/mmu_context.h~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.215819720 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/asm-i386/mmu_context.h	2004-10-18 19:02:18.335801480 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@ static inline void switch_mm(struct mm_s
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = cpu_tlbstate[cpu].active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
+-		BUG_ON(cpu_tlbstate[cpu].active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+diff -puN include/asm-i386/ptrace.h~host-skas3-2.6.8.1-v6 include/asm-i386/ptrace.h
+--- vanilla-linux-2.6.8.1/include/asm-i386/ptrace.h~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.216819568 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/asm-i386/ptrace.h	2004-10-18 19:02:18.335801480 +0200
+@@ -59,4 +59,26 @@ struct pt_regs {
+ #define instruction_pointer(regs) ((regs)->eip)
+ #endif
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++#define PTRACE_SIGPENDING	  53
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+diff -puN include/asm-i386/thread_info.h~host-skas3-2.6.8.1-v6 include/asm-i386/thread_info.h
+--- vanilla-linux-2.6.8.1/include/asm-i386/thread_info.h~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.217819416 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/asm-i386/thread_info.h	2004-10-18 19:02:18.336801328 +0200
+@@ -143,6 +143,7 @@ static inline unsigned long current_stac
+ #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+ #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
+ #define TIF_IRET		5	/* return with iret */
++#define TIF_SYSCALL_EMU		6	/* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+ 
+@@ -152,12 +153,13 @@ static inline unsigned long current_stac
+ #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
+ #define _TIF_IRET		(1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU	(1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+ 
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
++  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_EMU))
+ #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+ 
+ /*
+diff -puN include/linux/mm.h~host-skas3-2.6.8.1-v6 include/linux/mm.h
+--- vanilla-linux-2.6.8.1/include/linux/mm.h~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.237816376 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/linux/mm.h	2004-10-18 19:02:18.248814704 +0200
+@@ -575,6 +575,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -633,9 +636,15 @@ extern void exit_mmap(struct mm_struct *
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+diff -puN include/linux/proc_mm.h~host-skas3-2.6.8.1-v6 include/linux/proc_mm.h
+--- vanilla-linux-2.6.8.1/include/linux/proc_mm.h~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.238816224 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/linux/proc_mm.h	2004-10-18 19:02:18.275810600 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+diff -puN include/linux/ptrace.h~host-skas3-2.6.8.1-v6 include/linux/ptrace.h
+--- vanilla-linux-2.6.8.1/include/linux/ptrace.h~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.239816072 +0200
++++ vanilla-linux-2.6.8.1-paolo/include/linux/ptrace.h	2004-10-18 19:02:18.336801328 +0200
+@@ -20,6 +20,7 @@
+ #define PTRACE_DETACH		0x11
+ 
+ #define PTRACE_SYSCALL		  24
++#define PTRACE_SYSEMU		  31
+ 
+ /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
+ #define PTRACE_SETOPTIONS	0x4200
+diff -puN kernel/fork.c~host-skas3-2.6.8.1-v6 kernel/fork.c
+--- vanilla-linux-2.6.8.1/kernel/fork.c~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.240815920 +0200
++++ vanilla-linux-2.6.8.1-paolo/kernel/fork.c	2004-10-18 19:02:18.337801176 +0200
+@@ -1008,6 +1008,7 @@ struct task_struct *copy_process(unsigne
+ 	 * of CLONE_PTRACE.
+ 	 */
+ 	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
+ 
+ 	/* Our parent execution domain becomes current domain
+ 	   These must match for thread signalling to apply */
+diff -puN mm/Makefile~host-skas3-2.6.8.1-v6 mm/Makefile
+--- vanilla-linux-2.6.8.1/mm/Makefile~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.242815616 +0200
++++ vanilla-linux-2.6.8.1-paolo/mm/Makefile	2004-10-18 19:02:18.275810600 +0200
+@@ -15,3 +15,4 @@ obj-y			:= bootmem.o filemap.o mempool.o
+ obj-$(CONFIG_SWAP)	+= page_io.o swap_state.o swapfile.o
+ obj-$(CONFIG_HUGETLBFS)	+= hugetlb.o
+ obj-$(CONFIG_NUMA) 	+= mempolicy.o
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
+diff -puN mm/mmap.c~host-skas3-2.6.8.1-v6 mm/mmap.c
+--- vanilla-linux-2.6.8.1/mm/mmap.c~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.243815464 +0200
++++ vanilla-linux-2.6.8.1-paolo/mm/mmap.c	2004-10-18 19:02:18.276810448 +0200
+@@ -736,11 +736,11 @@ none:
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1006,7 +1006,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+diff -puN mm/mprotect.c~host-skas3-2.6.8.1-v6 mm/mprotect.c
+--- vanilla-linux-2.6.8.1/mm/mprotect.c~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.244815312 +0200
++++ vanilla-linux-2.6.8.1-paolo/mm/mprotect.c	2004-10-18 19:02:18.284809232 +0200
+@@ -92,19 +92,20 @@ change_protection(struct vm_area_struct 
+ {
+ 	pgd_t *dir;
+ 	unsigned long beg = start;
++	struct mm_struct * mm = vma->vm_mm;
+ 
+-	dir = pgd_offset(current->mm, start);
++	dir = pgd_offset(mm, start);
+ 	flush_cache_range(vma, beg, end);
+ 	if (start >= end)
+ 		BUG();
+-	spin_lock(&current->mm->page_table_lock);
++	spin_lock(&mm->page_table_lock);
+ 	do {
+ 		change_pmd_range(dir, start, end - start, newprot);
+ 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ 		dir++;
+ 	} while (start && (start < end));
+ 	flush_tlb_range(vma, beg, end);
+-	spin_unlock(&current->mm->page_table_lock);
++	spin_unlock(&mm->page_table_lock);
+ 	return;
+ }
+ 
+@@ -185,8 +186,9 @@ fail:
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp;
+ 	struct vm_area_struct *vma, *prev;
+@@ -215,9 +217,9 @@ sys_mprotect(unsigned long start, size_t
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -283,6 +285,11 @@ sys_mprotect(unsigned long start, size_t
+ 		}
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++        return(do_mprotect(current->mm, start, len, prot));
++}
+diff -puN mm/proc_mm.c~host-skas3-2.6.8.1-v6 mm/proc_mm.c
+--- vanilla-linux-2.6.8.1/mm/proc_mm.c~host-skas3-2.6.8.1-v6	2004-10-18 19:02:18.245815160 +0200
++++ vanilla-linux-2.6.8.1-paolo/mm/proc_mm.c	2004-10-18 19:02:18.301806648 +0200
+@@ -0,0 +1,181 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "linux/mman.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++
++	spin_lock(&mmlist_lock);
++	list_add(&mm->mmlist, &current->mm->mmlist);
++	mmlist_nr++;
++	spin_unlock(&mmlist_lock);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+_

Added: trunk/src/kernel-patch-skas/host-skas3-2.6.9-v7.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3-2.6.9-v7.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3-2.6.9-v7.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,871 @@
+--- vanilla-linux-2.6.9-paolo/arch/i386/kernel/entry.S	2004-10-26 02:24:42.196918400 +0200
++++ vanilla-linux-2.6.9-paolo/arch/i386/kernel/entry.S	2004-10-26 02:24:46.219306904 +0200
+@@ -256,7 +256,7 @@
+ 	SAVE_ALL
+ 	GET_THREAD_INFO(%ebp)
+ 
+-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++	testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -278,8 +278,8 @@
+ 	pushl %eax			# save orig_eax
+ 	SAVE_ALL
+ 	GET_THREAD_INFO(%ebp)
+-					# system call tracing in operation
+-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++					# system call tracing in operation / emulation
++	testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -340,6 +340,9 @@
+ 	movl %esp, %eax
+ 	xorl %edx,%edx
+ 	call do_syscall_trace
++	cmpl $0, %eax
++	jne syscall_exit		# ret != 0 -> running under PTRACE_SYSEMU,
++					# so must skip actual syscall
+ 	movl ORIG_EAX(%esp), %eax
+ 	cmpl $(nr_syscalls), %eax
+ 	jnae syscall_call
+--- vanilla-linux-2.6.9-paolo/arch/i386/kernel/ptrace.c	2004-10-29 00:52:30.744281064 +0200
++++ vanilla-linux-2.6.9-paolo/arch/i386/kernel/ptrace.c	2004-10-29 00:52:34.737673976 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -358,6 +359,7 @@
+ 		  }
+ 		  break;
+ 
++	case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ 	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ 	case PTRACE_CONT: { /* restart after signal. */
+ 		long tmp;
+@@ -365,10 +367,21 @@
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
++		/* If we came here with PTRACE_SYSEMU and now continue with
++		 * PTRACE_SYSCALL, entry.S used to intercept the syscall return.
++		 * But it shouldn't!
++		 * So we don't clear TIF_SYSCALL_EMU, which is always unused in
++		 * this special case, to remember, we came from SYSEMU. That
++		 * flag will be cleared by do_syscall_trace().
++		 */
++		if (request == PTRACE_SYSEMU) {
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		} else if (request == PTRACE_CONT) {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		}
+ 		if (request == PTRACE_SYSCALL) {
+ 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		}
+-		else {
++		} else {
+ 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		}
+ 		clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+@@ -407,6 +420,8 @@
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
++		/*See do_syscall_trace to know why we don't clear
++		 * TIF_SYSCALL_EMU.*/
+ 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		if ((child->ptrace & PT_DTRACE) == 0) {
+ 			/* Spurious delayed TF traps may occur */
+@@ -513,6 +528,56 @@
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data,
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		child->mm = new;
++		child->active_mm = new;
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+@@ -528,8 +593,9 @@
+  * - triggered by current->work.syscall_trace
+  */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++	int is_sysemu, is_systrace, is_singlestep;
+ 	if (unlikely(current->audit_context)) {
+ 		if (!entryexit)
+ 			audit_syscall_entry(current, regs->orig_eax,
+@@ -538,16 +604,27 @@
+ 		else
+ 			audit_syscall_exit(current, regs->eax);
+ 	}
++	is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
++	is_systrace = test_thread_flag(TIF_SYSCALL_TRACE);
++	is_singlestep = test_thread_flag(TIF_SINGLESTEP);
+ 
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
+-	    !test_thread_flag(TIF_SINGLESTEP))
+-		return;
++	if (!is_systrace && !is_singlestep && !is_sysemu)
++		return 0;
++	/* We can detect the case of coming from PTRACE_SYSEMU and now running
++	 * with PTRACE_SYSCALL or PTRACE_SINGLESTEP, by TIF_SYSCALL_EMU being
++	 * set additionally.
++	 * If so let's reset the flag and return without action.
++	 */
++	if (is_sysemu && (is_systrace || is_singlestep)) {
++		clear_thread_flag(TIF_SYSCALL_EMU);
++		return 0;
++	}
+ 	if (!(current->ptrace & PT_PTRACED))
+-		return;
++		return 0;
+ 	/* the 0x80 provides a way for the tracing parent to distinguish
+ 	   between a syscall stop and SIGTRAP delivery */
+ 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
+-				 !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
++				 !is_singlestep ? 0x80 : 0));
+ 
+ 	/*
+ 	 * this isn't the same as continuing with a signal, but it will do
+@@ -560,2 +637,4 @@
+ 	}
++	/* != 0 if nullifying the syscall, 0 if running it normally */
++	return is_sysemu;
+ }
+--- vanilla-linux-2.6.9/include/asm-i386/thread_info.h~host-sysemu-2.6.7-4	2004-10-26 02:24:42.191919160 +0200
++++ vanilla-linux-2.6.9-paolo/include/asm-i386/thread_info.h	2004-10-26 02:24:42.197918248 +0200
+@@ -143,6 +143,7 @@ static inline unsigned long current_stac
+ #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+ #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
+ #define TIF_IRET		5	/* return with iret */
++#define TIF_SYSCALL_EMU		6	/* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+ 
+@@ -152,12 +153,14 @@ static inline unsigned long current_stac
+ #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
+ #define _TIF_IRET		(1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU	(1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+ 
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
++  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++		  _TIF_SYSCALL_EMU))
+ #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+ 
+ /*
+--- vanilla-linux-2.6.9-paolo/include/linux/ptrace.h	2004-10-26 02:24:42.197918248 +0200
++++ vanilla-linux-2.6.9-paolo/include/linux/ptrace.h	2004-10-26 02:24:46.218307056 +0200
+@@ -20,6 +20,7 @@
+ #define PTRACE_DETACH		0x11
+ 
+ #define PTRACE_SYSCALL		  24
++#define PTRACE_SYSEMU		  31
+ 
+ /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
+ #define PTRACE_SETOPTIONS	0x4200
+--- vanilla-linux-2.6.9-paolo/kernel/fork.c	2004-10-26 02:24:42.197918248 +0200
++++ vanilla-linux-2.6.9-paolo/kernel/fork.c	2004-10-26 01:59:51.388555720 +0200
+@@ -1040,6 +1040,9 @@
+ 	 * of CLONE_PTRACE.
+ 	 */
+ 	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+ 
+ 	/* Our parent execution domain becomes current domain
+ 	   These must match for thread signalling to apply */
+--- vanilla-linux-2.6.9/include/linux/mm.h~Add_generic_proc_mm_support	2004-10-26 00:46:35.058899416 +0200
++++ vanilla-linux-2.6.9-paolo/include/linux/mm.h	2004-10-26 00:46:35.090894552 +0200
+@@ -623,6 +623,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -682,9 +685,15 @@ extern void exit_mmap(struct mm_struct *
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+--- vanilla-linux-2.6.9/include/linux/proc_mm.h~Add_generic_proc_mm_support	2004-10-26 00:46:35.059899264 +0200
++++ vanilla-linux-2.6.9-paolo/include/linux/proc_mm.h	2004-10-26 00:46:35.090894552 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+--- vanilla-linux-2.6.9/mm/Makefile~Add_generic_proc_mm_support	2004-10-26 00:46:35.060899112 +0200
++++ vanilla-linux-2.6.9-paolo/mm/Makefile	2004-10-26 00:46:35.091894400 +0200
+@@ -18,3 +18,4 @@ obj-$(CONFIG_NUMA) 	+= mempolicy.o
+ obj-$(CONFIG_SHMEM) += shmem.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+ 
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
+--- vanilla-linux-2.6.9/mm/mmap.c~Add_generic_proc_mm_support	2004-10-26 00:46:35.061898960 +0200
++++ vanilla-linux-2.6.9-paolo/mm/mmap.c	2004-10-26 00:46:35.091894400 +0200
+@@ -759,11 +759,11 @@ void __vm_stat_account(struct mm_struct 
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1034,7 +1034,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+--- vanilla-linux-2.6.9-paolo/mm/mprotect.c	2004-10-26 00:46:35.092894248 +0200
++++ linux-2.6.9-current-paolo/mm/mprotect.c	2004-10-14 18:35:43.018815232 +0200
+@@ -92,19 +92,20 @@
+ {
+ 	pgd_t *dir;
+ 	unsigned long beg = start;
++	struct mm_struct * mm = vma->vm_mm;
+ 
+-	dir = pgd_offset(current->mm, start);
++	dir = pgd_offset(mm, start);
+ 	flush_cache_range(vma, beg, end);
+ 	if (start >= end)
+ 		BUG();
+-	spin_lock(&current->mm->page_table_lock);
++	spin_lock(&mm->page_table_lock);
+ 	do {
+ 		change_pmd_range(dir, start, end - start, newprot);
+ 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ 		dir++;
+ 	} while (start && (start < end));
+ 	flush_tlb_range(vma, beg, end);
+-	spin_unlock(&current->mm->page_table_lock);
++	spin_unlock(&mm->page_table_lock);
+ 	return;
+ }
+ 
+@@ -187,8 +188,9 @@
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp;
+ 	struct vm_area_struct *vma, *prev;
+@@ -217,9 +219,9 @@
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -288,3 +290,8 @@
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++        return(do_mprotect(current->mm, start, len, prot));
++}
+--- linux-2.6.9-current-paolo/mm/proc_mm.c	2004-10-14 18:35:43.019815080 +0200
++++ linux-2.6.9-current-paolo/mm/proc_mm.c	2004-10-14 18:42:05.146722960 +0200
+@@ -0,0 +1,182 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "linux/mman.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++
++	spin_lock(&mmlist_lock);
++	list_add(&mm->mmlist, &current->mm->mmlist);
++	mmlist_nr++;
++	spin_unlock(&mmlist_lock);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- vanilla-linux-2.6.9/arch/i386/Kconfig~i386-specific	2004-10-29 00:52:34.701679448 +0200
++++ vanilla-linux-2.6.9-paolo/arch/i386/Kconfig	2004-10-29 00:52:34.709678232 +0200
+@@ -724,6 +724,10 @@ config X86_PAE
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+--- vanilla-linux-2.6.9-paolo/arch/i386/kernel/ldt.c	2004-10-29 00:52:34.737673976 +0200
++++ linux-2.6.9-current-paolo/arch/i386/kernel/ldt.c	2004-10-14 18:27:44.384578696 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -54,7 +55,7 @@
+ 	pc->size = mincount;
+ 	wmb();
+ 
+-	if (reload) {
++	if (reload && (&current->active_mm->context == pc)) {
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+@@ -89,14 +90,10 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+ 		retval = copy_ldt(&mm->context, &old_mm->context);
+@@ -105,6 +102,12 @@
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +124,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -174,9 +177,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -200,7 +202,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -236,20 +238,26 @@
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- vanilla-linux-2.6.9/arch/i386/kernel/sys_i386.c~i386-specific	2004-10-29 00:52:34.704678992 +0200
++++ vanilla-linux-2.6.9-paolo/arch/i386/kernel/sys_i386.c	2004-10-29 00:52:34.738673824 +0200
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,7 @@ asmlinkage long sys_mmap2(unsigned long 
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ 
+ /*
+@@ -101,7 +101,7 @@ asmlinkage int old_mmap(struct mmap_arg_
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ 	return err;
+ }
+--- vanilla-linux-2.6.9/include/asm-i386/desc.h~i386-specific	2004-10-29 00:52:34.705678840 +0200
++++ vanilla-linux-2.6.9-paolo/include/asm-i386/desc.h	2004-10-29 00:52:34.738673824 +0200
+@@ -126,6 +126,9 @@ static inline void load_LDT(mm_context_t
+ 	put_cpu();
+ }
+ 
++extern int modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- vanilla-linux-2.6.9/include/asm-i386/ptrace.h~i386-specific	2004-10-29 00:52:34.707678536 +0200
++++ vanilla-linux-2.6.9-paolo/include/asm-i386/ptrace.h	2004-10-29 00:52:34.738673824 +0200
+@@ -64,4 +64,26 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++#define PTRACE_SIGPENDING	  53
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- linux-2.6.9-current-paolo/include/asm-i386/mmu_context.h	2004-10-14 18:27:17.059732704 +0200
++++ linux-2.6.9-current-paolo/include/asm-i386/mmu_context.h	2004-10-14 18:27:44.384578696 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+--- vanilla-linux-2.6.9/arch/um/include/skas_ptrace.h~make-skas-uml-compatible	2004-10-26 01:59:51.352561192 +0200
++++ vanilla-linux-2.6.9-paolo/arch/um/include/skas_ptrace.h	2004-10-26 01:59:51.388555720 +0200
+@@ -6,6 +6,7 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
+ struct ptrace_faultinfo {
+ 	int is_write;
+ 	unsigned long addr;
+@@ -21,6 +22,7 @@ struct ptrace_ldt {
+ #define PTRACE_SIGPENDING 53
+ #define PTRACE_LDT 54
+ #define PTRACE_SWITCH_MM 55
++#endif
+ 
+ #endif

Added: trunk/src/kernel-patch-skas/host-skas3.patch
===================================================================
--- trunk/src/kernel-patch-skas/host-skas3.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/host-skas3.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,589 @@
+diff -Naur host/arch/i386/config.in host-ptrace/arch/i386/config.in
+--- host/arch/i386/config.in	Fri Aug  9 15:57:14 2002
++++ host-ptrace/arch/i386/config.in	Sun Nov 10 18:40:09 2002
+@@ -291,6 +291,8 @@
+    bool '    Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
+ fi
+ 
++bool '/proc/mm' CONFIG_PROC_MM
++
+ endmenu
+ 
+ source drivers/mtd/Config.in
+diff -Naur host/arch/i386/kernel/ldt.c host-ptrace/arch/i386/kernel/ldt.c
+--- host/arch/i386/kernel/ldt.c	Fri Oct 26 00:01:41 2001
++++ host-ptrace/arch/i386/kernel/ldt.c	Sun Nov  3 18:37:48 2002
+@@ -24,11 +24,12 @@
+  * assured by user-space anyway. Writes are atomic, to protect
+  * the security checks done on new descriptors.
+  */
+-static int read_ldt(void * ptr, unsigned long bytecount)
++static int read_ldt(struct task_struct *task, void * ptr, 
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
++	struct mm_struct * mm = task->mm;
+ 
+ 	err = 0;
+ 	if (!mm->context.segments)
+@@ -64,9 +65,10 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct task_struct *task, void * ptr, 
++		     unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
++	struct mm_struct * mm = task->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct modify_ldt_ldt_s ldt_info;
+@@ -148,23 +150,29 @@
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++int modify_ldt(struct task_struct *task, int func, void *ptr, 
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(task, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(task, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(task, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
++}
++
++asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
++{
++	return(modify_ldt(current, func, ptr, bytecount));
+ }
+diff -Naur host/arch/i386/kernel/process.c host-ptrace/arch/i386/kernel/process.c
+--- host/arch/i386/kernel/process.c	Fri Aug  9 15:57:14 2002
++++ host-ptrace/arch/i386/kernel/process.c	Wed Nov  6 22:12:45 2002
+@@ -551,13 +551,11 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
++void mm_copy_segments(struct mm_struct *old_mm, struct mm_struct *new_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	void *old_ldt, *ldt;
+ 
+ 	ldt = NULL;
+-	old_mm = current->mm;
+ 	if (old_mm && (old_ldt = old_mm->context.segments) != NULL) {
+ 		/*
+ 		 * Completely new LDT, we initialize it from the parent:
+@@ -570,6 +568,16 @@
+ 	}
+ 	new_mm->context.segments = ldt;
+ 	new_mm->context.cpuvalid = ~0UL;	/* valid on all CPU's - they can't have stale data */
++}
++
++void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
++{
++	mm_copy_segments(current->mm, new_mm);
++}
++
++void copy_task_segments(struct task_struct *from, struct mm_struct *new_mm)
++{
++	mm_copy_segments(from->mm, new_mm);
+ }
+ 
+ /*
+diff -Naur host/arch/i386/kernel/ptrace.c host-ptrace/arch/i386/kernel/ptrace.c
+--- host/arch/i386/kernel/ptrace.c	Fri Aug  9 15:57:14 2002
++++ host-ptrace/arch/i386/kernel/ptrace.c	Mon Nov 11 19:03:38 2002
+@@ -147,6 +147,11 @@
+ 	put_stack_long(child, EFL_OFFSET, tmp);
+ }
+ 
++extern int modify_ldt(struct task_struct *task, int func, void *ptr, 
++		      unsigned long bytecount);
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
+ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+ {
+ 	struct task_struct *child;
+@@ -415,6 +420,53 @@
+ 			child->ptrace |= PT_TRACESYSGOOD;
+ 		else
+ 			child->ptrace &= ~PT_TRACESYSGOOD;
++		ret = 0;
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo) 
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault, 
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data, 
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data, 
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = modify_ldt(child, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		child->mm = new;
++		child->active_mm = new;
++		mmput(old);
+ 		ret = 0;
+ 		break;
+ 	}
+diff -Naur host/arch/i386/kernel/sys_i386.c host-ptrace/arch/i386/kernel/sys_i386.c
+--- host/arch/i386/kernel/sys_i386.c	Mon Mar 19 15:35:09 2001
++++ host-ptrace/arch/i386/kernel/sys_i386.c	Mon Nov 11 17:23:25 2002
+@@ -40,7 +40,7 @@
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -55,9 +55,9 @@
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -69,7 +69,7 @@
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ 
+ /*
+@@ -100,7 +100,7 @@
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ 	return err;
+ }
+diff -Naur host/include/asm-i386/processor.h host-ptrace/include/asm-i386/processor.h
+--- host/include/asm-i386/processor.h	Sun Nov 10 18:47:37 2002
++++ host-ptrace/include/asm-i386/processor.h	Mon Nov 11 17:33:30 2002
+@@ -436,6 +436,8 @@
+ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+ 
+ /* Copy and release all segment info associated with a VM */
++extern void mm_copy_segments(struct mm_struct *old_mm, 
++			     struct mm_struct *new_mm);
+ extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
+ extern void release_segments(struct mm_struct * mm);
+ 
+diff -Naur host/include/asm-i386/ptrace.h host-ptrace/include/asm-i386/ptrace.h
+--- host/include/asm-i386/ptrace.h	Sun Sep 23 19:20:51 2001
++++ host-ptrace/include/asm-i386/ptrace.h	Sun Nov 10 18:36:22 2002
+@@ -51,6 +51,22 @@
+ 
+ #define PTRACE_SETOPTIONS         21
+ 
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#define PTRACE_FAULTINFO 52
++#define PTRACE_SIGPENDING 53
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++
+ /* options set using PTRACE_SETOPTIONS */
+ #define PTRACE_O_TRACESYSGOOD     0x00000001
+ 
+diff -Naur host/include/linux/mm.h host-ptrace/include/linux/mm.h
+--- host/include/linux/mm.h	Fri Aug 30 15:03:44 2002
++++ host-ptrace/include/linux/mm.h	Mon Nov 11 19:08:53 2002
+@@ -492,6 +492,9 @@
+ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
+ 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start, 
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc() that does all
+@@ -539,9 +542,10 @@
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+-	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++extern unsigned long do_mmap_pgoff(struct mm_struct *mm, 
++				   struct file *file, unsigned long addr,
++				   unsigned long len, unsigned long prot,
++				   unsigned long flag, unsigned long pgoff);
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+@@ -551,7 +555,7 @@
+ 	if ((offset + PAGE_ALIGN(len)) < offset)
+ 		goto out;
+ 	if (!(offset & ~PAGE_MASK))
+-		ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
++		ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, offset >> PAGE_SHIFT);
+ out:
+ 	return ret;
+ }
+diff -Naur host/include/linux/proc_mm.h host-ptrace/include/linux/proc_mm.h
+--- host/include/linux/proc_mm.h	Wed Dec 31 19:00:00 1969
++++ host-ptrace/include/linux/proc_mm.h	Mon Nov 11 17:41:09 2002
+@@ -0,0 +1,44 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;	
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++#endif
+diff -Naur host/mm/Makefile host-ptrace/mm/Makefile
+--- host/mm/Makefile	Fri Aug  9 15:57:31 2002
++++ host-ptrace/mm/Makefile	Sun Nov 10 18:37:33 2002
+@@ -17,5 +17,6 @@
+ 	    shmem.o
+ 
+ obj-$(CONFIG_HIGHMEM) += highmem.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+ 
+ include $(TOPDIR)/Rules.make
+diff -Naur host/mm/mmap.c host-ptrace/mm/mmap.c
+--- host/mm/mmap.c	Fri Aug  9 15:57:31 2002
++++ host-ptrace/mm/mmap.c	Mon Nov 11 17:24:18 2002
+@@ -390,10 +390,11 @@
+ 	return 0;
+ }
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags, unsigned long pgoff)
++unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file, 
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags, 
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	unsigned int vm_flags;
+ 	int correct_wcount = 0;
+diff -Naur host/mm/mprotect.c host-ptrace/mm/mprotect.c
+--- host/mm/mprotect.c	Fri Aug  9 15:57:31 2002
++++ host-ptrace/mm/mprotect.c	Mon Nov 11 17:47:58 2002
+@@ -264,7 +264,8 @@
+ 	return 0;
+ }
+ 
+-asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, 
++		 unsigned long prot)
+ {
+ 	unsigned long nstart, end, tmp;
+ 	struct vm_area_struct * vma, * next, * prev;
+@@ -281,9 +282,9 @@
+ 	if (end == start)
+ 		return 0;
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma || vma->vm_start > start)
+ 		goto out;
+@@ -332,6 +333,11 @@
+ 		prev->vm_mm->map_count--;
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
++}
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	return(do_mprotect(current->mm, start, len, prot));
+ }
+diff -Naur host/mm/proc_mm.c host-ptrace/mm/proc_mm.c
+--- host/mm/proc_mm.c	Wed Dec 31 19:00:00 1969
++++ host-ptrace/mm/proc_mm.c	Mon Nov 11 19:07:52 2002
+@@ -0,0 +1,173 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
++		     unsigned long len, unsigned long prot, 
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot, 
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++	
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len, 
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		mm_copy_segments(from, mm);
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	ret = init_new_context(current, mm);
++	if(ret)
++		goto out_free;
++
++	spin_lock(&mmlist_lock);
++	list_add(&mm->mmlist, &current->mm->mmlist);
++	mmlist_nr++;
++	spin_unlock(&mmlist_lock);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_free:
++	mmput(mm);
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */

Added: trunk/src/kernel-patch-skas/skas-2.6.10-v8.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.10-v8.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.10-v8.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,953 @@
+--- vanilla-linux-2.6.10-paolo/arch/i386/kernel/entry.S	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/kernel/entry.S	2005-03-10 18:16:15.000000000 +0100
+@@ -222,7 +222,7 @@
+ 	SAVE_ALL
+ 	GET_THREAD_INFO(%ebp)
+ 
+-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++	testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -245,8 +245,8 @@
+ 	pushl %eax			# save orig_eax
+ 	SAVE_ALL
+ 	GET_THREAD_INFO(%ebp)
+-					# system call tracing in operation
+-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++					# system call tracing in operation / emulation
++	testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -307,10 +307,19 @@
+ 	movl %esp, %eax
+ 	xorl %edx,%edx
+ 	call do_syscall_trace
++	cmpl $0, %eax
++	jne syscall_skip		# ret != 0 -> running under PTRACE_SYSEMU,
++					# so must skip actual syscall
+ 	movl ORIG_EAX(%esp), %eax
+ 	cmpl $(nr_syscalls), %eax
+ 	jnae syscall_call
+ 	jmp syscall_exit
++syscall_skip:
++	cli				# make sure we don't miss an interrupt
++					# setting need_resched or sigpending
++					# between sampling and the iret
++	movl TI_flags(%ebp), %ecx
++	jmp work_pending
+ 
+ 	# perform syscall exit tracing
+ 	ALIGN
+--- vanilla-linux-2.6.10-paolo/arch/i386/kernel/ptrace.c	2005-03-10 18:16:15.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/kernel/ptrace.c	2005-03-10 18:16:16.000000000 +0100
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -168,6 +169,8 @@
+ void ptrace_disable(struct task_struct *child)
+ { 
+ 	clear_singlestep(child);
++	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ }
+ 
+ /*
+@@ -406,15 +409,20 @@
+ 		  }
+ 		  break;
+ 
++	case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ 	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
+ 	case PTRACE_CONT:	/* restart after signal. */
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
+-		if (request == PTRACE_SYSCALL) {
++		if (request == PTRACE_SYSEMU) {
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++		} else if (request == PTRACE_SYSCALL) {
+ 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		}
+-		else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		} else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		}
+ 		child->exit_code = data;
+@@ -439,10 +447,17 @@
+ 		wake_up_process(child);
+ 		break;
+ 
++	case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
+ 	case PTRACE_SINGLESTEP:	/* set the trap flag. */
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
++
++		if (request == PTRACE_SYSEMU_SINGLESTEP)
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		else
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++
+ 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		set_singlestep(child);
+ 		child->exit_code = data;
+@@ -542,6 +557,58 @@
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data,
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		task_lock(child);
++		child->mm = new;
++		child->active_mm = new;
++		task_unlock(child);
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+@@ -557,26 +624,45 @@
+  * - triggered by current->work.syscall_trace
+  */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++	int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
++	/* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP */
++	int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
++
+ 	if (unlikely(current->audit_context)) {
+-		if (!entryexit)
++		if (!entryexit) {
+ 			audit_syscall_entry(current, regs->orig_eax,
+ 					    regs->ebx, regs->ecx,
+ 					    regs->edx, regs->esi);
++			/* With TIF_SYSCALL_AUDIT | TIF_SINGLESTEP &&
++			 * !TIF_SYSCALL_EMU we come in here, but must not
++			 * continue with ptrace_notify().
++			 * In the SINGLESTEP && ! _AUDIT case (i.e. normal one),
++			 * entry.S will call us only on syscall exit and not on
++			 * the syscall entry path, so let's be consistent.
++			 */
++			if (is_singlestep)
++				return 0;
++		}
+ 		else
+ 			audit_syscall_exit(current, regs->eax);
+ 	}
++	/* If a process stops on the 1st tracepoint with SYSCALL_TRACE
++	 * and then is resumed with SYSEMU_SINGLESTEP, it will come in
++	 * here. We have to check this and return */
++	if (is_sysemu && entryexit)
++		return 0;
+ 
+ 	if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
+-	    !test_thread_flag(TIF_SINGLESTEP))
+-		return;
++	    !is_singlestep && !is_sysemu)
++		return 0;
+ 	if (!(current->ptrace & PT_PTRACED))
+-		return;
++		return 0;
+ 	/* the 0x80 provides a way for the tracing parent to distinguish
+ 	   between a syscall stop and SIGTRAP delivery */
+ 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
+-				 !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
++				 !is_singlestep ? 0x80 : 0));
+ 
+ 	/*
+ 	 * this isn't the same as continuing with a signal, but it will do
+@@ -589,2 +675,10 @@
+ 	}
++	/* != 0 if nullifying the syscall, 0 if running it normally */
++	if ( !is_sysemu )
++		return 0;
++
++	regs->orig_eax = -1; /* force skip of syscall restarting */
++	if (unlikely(current->audit_context))
++		audit_syscall_exit(current, regs->eax);
++	return 1;
+ }
+--- vanilla-linux-2.6.10/include/asm-i386/thread_info.h~host-sysemu-2.6.7-4	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/asm-i386/thread_info.h	2005-03-10 18:16:11.000000000 +0100
+@@ -139,6 +139,7 @@ register unsigned long current_stack_poi
+ #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+ #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
+ #define TIF_IRET		5	/* return with iret */
++#define TIF_SYSCALL_EMU		6	/* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+ 
+@@ -148,12 +149,14 @@ register unsigned long current_stack_poi
+ #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
+ #define _TIF_IRET		(1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU	(1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+ 
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
++  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++		  _TIF_SYSCALL_EMU))
+ #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+ 
+ /*
+--- vanilla-linux-2.6.10-paolo/include/linux/ptrace.h	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/linux/ptrace.h	2005-03-10 18:16:15.000000000 +0100
+@@ -20,6 +20,8 @@
+ #define PTRACE_DETACH		0x11
+ 
+ #define PTRACE_SYSCALL		  24
++#define PTRACE_SYSEMU		  31
++#define PTRACE_SYSEMU_SINGLESTEP  32
+ 
+ /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
+ #define PTRACE_SETOPTIONS	0x4200
+--- vanilla-linux-2.6.10/kernel/fork.c~host-sysemu-2.6.7-4	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/kernel/fork.c	2005-03-10 18:16:11.000000000 +0100
+@@ -926,6 +926,9 @@ static task_t *copy_process(unsigned lon
+ 	 * of CLONE_PTRACE.
+ 	 */
+ 	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+ 
+ 	/* Our parent execution domain becomes current domain
+ 	   These must match for thread signalling to apply */
+--- vanilla-linux-2.6.10/include/linux/mm.h~Add_generic_proc_mm_support	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/linux/mm.h	2005-03-10 18:16:11.000000000 +0100
+@@ -625,6 +625,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -684,9 +687,15 @@ extern void exit_mmap(struct mm_struct *
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+--- vanilla-linux-2.6.10/include/linux/proc_mm.h~Add_generic_proc_mm_support	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/linux/proc_mm.h	2005-03-10 18:16:11.000000000 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+--- vanilla-linux-2.6.10/mm/Makefile~Add_generic_proc_mm_support	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/mm/Makefile	2005-03-10 18:16:11.000000000 +0100
+@@ -18,3 +18,4 @@ obj-$(CONFIG_NUMA) 	+= mempolicy.o
+ obj-$(CONFIG_SHMEM) += shmem.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+ 
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
+--- vanilla-linux-2.6.10/mm/mmap.c~Add_generic_proc_mm_support	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/mm/mmap.c	2005-03-10 18:16:11.000000000 +0100
+@@ -759,11 +759,11 @@ void __vm_stat_account(struct mm_struct 
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1037,7 +1037,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+--- vanilla-linux-2.6.10/mm/mprotect.c~Add_generic_proc_mm_support	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/mm/mprotect.c	2005-03-10 18:16:11.000000000 +0100
+@@ -93,19 +93,20 @@ change_protection(struct vm_area_struct 
+ {
+ 	pgd_t *dir;
+ 	unsigned long beg = start;
++	struct mm_struct * mm = vma->vm_mm;
+ 
+-	dir = pgd_offset(current->mm, start);
++	dir = pgd_offset(mm, start);
+ 	flush_cache_range(vma, beg, end);
+ 	if (start >= end)
+ 		BUG();
+-	spin_lock(&current->mm->page_table_lock);
++	spin_lock(&mm->page_table_lock);
+ 	do {
+ 		change_pmd_range(dir, start, end - start, newprot);
+ 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+ 		dir++;
+ 	} while (start && (start < end));
+ 	flush_tlb_range(vma, beg, end);
+-	spin_unlock(&current->mm->page_table_lock);
++	spin_unlock(&mm->page_table_lock);
+ 	return;
+ }
+ 
+@@ -190,8 +191,9 @@ fail:
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp;
+ 	struct vm_area_struct *vma, *prev;
+@@ -220,9 +222,9 @@ sys_mprotect(unsigned long start, size_t
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -288,6 +290,11 @@ sys_mprotect(unsigned long start, size_t
+ 		}
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++        return(do_mprotect(current->mm, start, len, prot));
++}
+--- vanilla-linux-2.6.10-paolo/mm/proc_mm.c	2005-03-10 18:16:13.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/mm/proc_mm.c	2005-03-10 18:16:13.000000000 +0100
+@@ -0,0 +1,177 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "linux/mman.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- vanilla-linux-2.6.10/arch/um/include/skas_ptrace.h~Add_generic_proc_mm_support	2005-03-10 18:16:11.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/um/include/skas_ptrace.h	2005-03-10 18:16:11.000000000 +0100
+@@ -6,6 +6,7 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
+ struct ptrace_faultinfo {
+ 	int is_write;
+ 	unsigned long addr;
+@@ -21,6 +22,7 @@ struct ptrace_ldt {
+ #define PTRACE_SIGPENDING 53
+ #define PTRACE_LDT 54
+ #define PTRACE_SWITCH_MM 55
++#endif
+ 
+ #endif
+ 
+--- vanilla-linux-2.6.10/arch/i386/Kconfig~i386-specific	2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/Kconfig	2005-03-10 18:16:12.000000000 +0100
+@@ -730,6 +730,10 @@ config X86_PAE
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+--- vanilla-linux-2.6.10-paolo/arch/i386/kernel/ldt.c	2005-03-10 18:16:14.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/kernel/ldt.c	2005-03-10 18:16:14.000000000 +0100
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,11 +28,12 @@
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	int oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= pc->size)
+ 		return 0;
+@@ -58,13 +60,15 @@
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -76,12 +80,12 @@
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -89,22 +93,24 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +127,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -174,9 +180,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -200,7 +205,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -236,20 +241,26 @@
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return __modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- vanilla-linux-2.6.10/arch/i386/kernel/sys_i386.c~i386-specific	2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/arch/i386/kernel/sys_i386.c	2005-03-10 18:16:12.000000000 +0100
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,7 @@ asmlinkage long sys_mmap2(unsigned long 
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ 
+ /*
+@@ -101,7 +101,7 @@ asmlinkage int old_mmap(struct mmap_arg_
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+ out:
+ 	return err;
+ }
+--- vanilla-linux-2.6.10-paolo/include/asm-i386/desc.h	2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/asm-i386/desc.h	2005-03-10 18:16:14.000000000 +0100
+@@ -126,6 +126,9 @@
+ 	put_cpu();
+ }
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- vanilla-linux-2.6.10/include/asm-i386/ptrace.h~i386-specific	2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/asm-i386/ptrace.h	2005-03-10 18:16:12.000000000 +0100
+@@ -64,4 +64,26 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++#define PTRACE_SIGPENDING	  53
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- vanilla-linux-2.6.10-paolo/include/asm-i386/mmu_context.h	2005-03-10 18:16:12.000000000 +0100
++++ vanilla-linux-2.6.10-paolo/include/asm-i386/mmu_context.h	2005-03-10 18:16:12.000000000 +0100
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+--- /dev/null	2005-03-26 18:29:00.701330288 +0100
++++ clean-linux-2.6.10-paolo/localversion-skas	2005-03-29 16:00:28.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v8

Added: trunk/src/kernel-patch-skas/skas-2.6.11-v8.2.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.11-v8.2.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.11-v8.2.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,946 @@
+--- clean-linux-2.6.11-paolo/arch/i386/kernel/entry.S	2005-07-10 16:56:19.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/kernel/entry.S	2005-05-03 09:08:14.000000000 +0200
+@@ -219,7 +219,7 @@
+ 	SAVE_ALL
+ 	GET_THREAD_INFO(%ebp)
+ 
+-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -242,8 +242,8 @@
+ 	pushl %eax			# save orig_eax
+ 	SAVE_ALL
+ 	GET_THREAD_INFO(%ebp)
+-					# system call tracing in operation
+-	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
++					# system call tracing in operation / emulation
++	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -304,6 +304,9 @@
+ 	movl %esp, %eax
+ 	xorl %edx,%edx
+ 	call do_syscall_trace
++	cmpl $0, %eax
++	jne resume_userspace		# ret != 0 -> running under PTRACE_SYSEMU,
++					# so must skip actual syscall
+ 	movl ORIG_EAX(%esp), %eax
+ 	cmpl $(nr_syscalls), %eax
+ 	jnae syscall_call
+--- clean-linux-2.6.11-paolo/arch/i386/kernel/ptrace.c	2005-07-10 16:57:36.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/kernel/ptrace.c	2005-07-10 16:55:40.000000000 +0200
+@@ -15,6 +15,7 @@
+ #include <linux/user.h>
+ #include <linux/security.h>
+ #include <linux/audit.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -269,6 +270,8 @@
+ void ptrace_disable(struct task_struct *child)
+ { 
+ 	clear_singlestep(child);
++	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ }
+ 
+ /*
+@@ -507,15 +510,20 @@
+ 		  }
+ 		  break;
+ 
++	case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ 	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
+ 	case PTRACE_CONT:	/* restart after signal. */
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
+-		if (request == PTRACE_SYSCALL) {
++		if (request == PTRACE_SYSEMU) {
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++		} else if (request == PTRACE_SYSCALL) {
+ 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		}
+-		else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		} else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		}
+ 		child->exit_code = data;
+@@ -540,10 +548,17 @@
+ 		wake_up_process(child);
+ 		break;
+ 
++	case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
+ 	case PTRACE_SINGLESTEP:	/* set the trap flag. */
+ 		ret = -EIO;
+ 		if ((unsigned long) data > _NSIG)
+ 			break;
++
++		if (request == PTRACE_SYSEMU_SINGLESTEP)
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		else
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++
+ 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		set_singlestep(child);
+ 		child->exit_code = data;
+@@ -643,6 +658,58 @@
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_SIGPENDING:
++		ret = copy_to_user((unsigned long *) data,
++				   &child->pending.signal,
++				   sizeof(child->pending.signal));
++		break;
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++		task_lock(child);
++		child->mm = new;
++		child->active_mm = new;
++		task_unlock(child);
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+@@ -676,29 +743,49 @@
+  * - triggered by current->work.syscall_trace
+  */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++	int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU);
++	/* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP */
++	int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
++
+ 	if (unlikely(current->audit_context)) {
+-		if (!entryexit)
++		if (!entryexit) {
+ 			audit_syscall_entry(current, regs->orig_eax,
+ 					    regs->ebx, regs->ecx,
+ 					    regs->edx, regs->esi);
++			/* With TIF_SYSCALL_AUDIT | TIF_SINGLESTEP &&
++			 * !TIF_SYSCALL_EMU we come in here, but must not
++			 * continue with ptrace_notify().
++			 * In the SINGLESTEP && ! _AUDIT case (i.e. normal one),
++			 * entry.S will call us only on syscall exit and not on
++			 * the syscall entry path, so let's be consistent.
++			 */
++			if (is_singlestep)
++				return 0;
++		}
+ 		else
+ 			audit_syscall_exit(current, regs->eax);
+ 	}
+-
+ 	if (!(current->ptrace & PT_PTRACED))
+-		return;
++		return 0;
++
++	/* If a process stops on the 1st tracepoint with SYSCALL_TRACE
++	 * and then is resumed with SYSEMU_SINGLESTEP, it will come in
++	 * here. We have to check this and return */
++	if (is_sysemu && entryexit)
++		return 0;
+ 
+ 	/* Fake a debug trap */
+-	if (test_thread_flag(TIF_SINGLESTEP))
++	if (is_singlestep)
+ 		send_sigtrap(current, regs, 0);
+ 
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+-		return;
++	if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
++		return 0;
+ 
+ 	/* the 0x80 provides a way for the tracing parent to distinguish
+ 	   between a syscall stop and SIGTRAP delivery */
++	/* Note that the debugger could change the result of test_thread_flag!*/
+ 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+ 
+ 	/*
+@@ -712,2 +799,10 @@
+ 	}
++	/* != 0 if nullifying the syscall, 0 if running it normally */
++	if ( !is_sysemu )
++		return 0;
++
++	regs->orig_eax = -1; /* force skip of syscall restarting */
++	if (unlikely(current->audit_context))
++		audit_syscall_exit(current, regs->eax);
++	return 1;
+ }
+--- clean-linux-2.6.11-paolo/include/asm-i386/thread_info.h	2005-07-10 16:55:19.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/asm-i386/thread_info.h	2005-05-03 09:08:14.000000000 +0200
+@@ -140,6 +140,7 @@
+ #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
+ #define TIF_IRET		5	/* return with iret */
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
++#define TIF_SYSCALL_EMU		9	/* syscall emulation active */
+ #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE		17
+ 
+@@ -149,12 +150,14 @@
+ #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
+ #define _TIF_IRET		(1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU	(1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+ 
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP))
++  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++		  _TIF_SYSCALL_EMU))
+ #define _TIF_ALLWORK_MASK	0x0000FFFF	/* work to do on any return to u-space */
+ 
+ /*
+--- clean-linux-2.6.11-paolo/include/linux/ptrace.h	2005-07-10 16:57:37.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/linux/ptrace.h	2005-07-10 16:55:38.000000000 +0200
+@@ -20,6 +20,8 @@
+ #define PTRACE_DETACH		0x11
+ 
+ #define PTRACE_SYSCALL		  24
++#define PTRACE_SYSEMU		  31
++#define PTRACE_SYSEMU_SINGLESTEP  32
+ 
+ /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
+ #define PTRACE_SETOPTIONS	0x4200
+--- clean-linux-2.6.11/kernel/fork.c~host-sysemu-2.6.7-4	2005-07-10 16:55:19.000000000 +0200
++++ clean-linux-2.6.11-paolo/kernel/fork.c	2005-07-10 16:55:19.000000000 +0200
+@@ -938,6 +938,9 @@ static task_t *copy_process(unsigned lon
+ 	 * of CLONE_PTRACE.
+ 	 */
+ 	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+ 
+ 	/* Our parent execution domain becomes current domain
+ 	   These must match for thread signalling to apply */
+--- clean-linux-2.6.11/include/linux/mm.h~Add_generic_proc_mm_support	2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/linux/mm.h	2005-07-10 16:55:31.000000000 +0200
+@@ -655,6 +655,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level or three-level page table, this ends up being trivial. Thus
+  * the inlining and the symmetry break with pte_alloc_map() that does all
+@@ -730,9 +733,15 @@ extern void exit_mmap(struct mm_struct *
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+--- clean-linux-2.6.11/include/linux/proc_mm.h~Add_generic_proc_mm_support	2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/linux/proc_mm.h	2005-07-10 16:55:31.000000000 +0200
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+--- clean-linux-2.6.11/mm/Makefile~Add_generic_proc_mm_support	2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/mm/Makefile	2005-07-10 16:55:31.000000000 +0200
+@@ -18,3 +18,4 @@ obj-$(CONFIG_NUMA) 	+= mempolicy.o
+ obj-$(CONFIG_SHMEM) += shmem.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+ 
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
+--- clean-linux-2.6.11/mm/mmap.c~Add_generic_proc_mm_support	2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/mm/mmap.c	2005-07-10 16:55:31.000000000 +0200
+@@ -861,11 +861,11 @@ void __vm_stat_account(struct mm_struct 
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1141,7 +1141,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+--- clean-linux-2.6.11-paolo/mm/mprotect.c	2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/mm/mprotect.c	2005-07-11 11:35:56.000000000 +0200
+@@ -117,7 +117,7 @@
+ change_protection(struct vm_area_struct *vma, unsigned long start,
+ 		unsigned long end, pgprot_t newprot)
+ {
+-	struct mm_struct *mm = current->mm;
++	struct mm_struct *mm = vma->vm_mm;
+ 	pgd_t *pgd;
+ 	unsigned long beg = start, next;
+ 	int i;
+@@ -219,8 +219,9 @@
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp;
+ 	struct vm_area_struct *vma, *prev;
+@@ -249,9 +250,9 @@
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -320,3 +321,12 @@
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	long ret = do_mprotect(current->mm, start, len, prot);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+--- clean-linux-2.6.11-paolo/mm/proc_mm.c	2005-07-10 16:57:39.000000000 +0200
++++ clean-linux-2.6.11-paolo/mm/proc_mm.c	2005-07-10 16:55:34.000000000 +0200
+@@ -0,0 +1,177 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "linux/mman.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++ out_fput:
++	fput(file);
++ out:
++	return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = do_mmap2(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset >> PAGE_SHIFT);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++
++	file->private_data = mm;
++
++	return(0);
++
++ out_mem:
++	return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- clean-linux-2.6.11/arch/um/include/skas_ptrace.h~Add_generic_proc_mm_support	2005-07-10 16:55:31.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/um/include/skas_ptrace.h	2005-07-10 16:55:31.000000000 +0200
+@@ -6,6 +6,7 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
+ struct ptrace_faultinfo {
+ 	int is_write;
+ 	unsigned long addr;
+@@ -21,6 +22,7 @@ struct ptrace_ldt {
+ #define PTRACE_SIGPENDING 53
+ #define PTRACE_LDT 54
+ #define PTRACE_SWITCH_MM 55
++#endif
+ 
+ #endif
+ 
+--- clean-linux-2.6.11/arch/i386/Kconfig~i386-specific	2005-07-10 16:55:32.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/Kconfig	2005-07-10 16:55:32.000000000 +0200
+@@ -745,6 +745,10 @@ config X86_PAE
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+--- clean-linux-2.6.11-paolo/arch/i386/kernel/ldt.c	2005-07-10 16:55:35.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/kernel/ldt.c	2005-07-11 11:35:56.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,11 +28,12 @@
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	int oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= pc->size)
+ 		return 0;
+@@ -58,13 +60,15 @@
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -76,12 +80,12 @@
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -89,22 +93,24 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +127,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -174,9 +180,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -200,7 +205,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -236,20 +241,30 @@
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	int ret = __modify_ldt(current->mm, func, ptr, bytecount);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+--- clean-linux-2.6.11-paolo/arch/i386/kernel/sys_i386.c	2005-07-10 16:57:34.000000000 +0200
++++ clean-linux-2.6.11-paolo/arch/i386/kernel/sys_i386.c	2005-07-10 16:56:25.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,12 @@
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
+ }
+ 
+ /*
+@@ -101,7 +106,10 @@
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(err);
+ out:
+ 	return err;
+ }
+--- clean-linux-2.6.11/include/asm-i386/desc.h~i386-specific	2005-07-10 16:55:32.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/asm-i386/desc.h	2005-07-10 16:55:32.000000000 +0200
+@@ -135,6 +135,9 @@ static inline unsigned long get_desc_bas
+ 	return base;
+ }
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- clean-linux-2.6.11/include/asm-i386/ptrace.h~i386-specific	2005-07-10 16:55:32.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/asm-i386/ptrace.h	2005-07-10 16:55:32.000000000 +0200
+@@ -66,4 +66,26 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++#define PTRACE_SIGPENDING	  53
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- clean-linux-2.6.11-paolo/include/asm-i386/mmu_context.h	2005-07-10 16:57:40.000000000 +0200
++++ clean-linux-2.6.11-paolo/include/asm-i386/mmu_context.h	2005-07-10 16:55:33.000000000 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+--- clean-linux-2.6.11-paolo/localversion-skas	2005-07-10 16:56:52.000000000 +0200
++++ clean-linux-2.6.11-paolo/localversion-skas	2005-07-11 11:36:04.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v8.2

Added: trunk/src/kernel-patch-skas/skas-2.6.12-v9-pre7.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.12-v9-pre7.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.12-v9-pre7.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1989 @@
+--- linux-2.6.12-paolo/arch/i386/kernel/entry.S	2005-05-08 19:52:15.000000000 +0200
++++ vanilla-linux-2.6.12-paolo/arch/i386/kernel/entry.S	2005-07-08 12:26:20.000000000 +0200
+@@ -203,7 +203,7 @@
+ 	GET_THREAD_INFO(%ebp)
+ 
+ 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+-	testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
++	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -226,9 +226,9 @@
+ 	pushl %eax			# save orig_eax
+ 	SAVE_ALL
+ 	GET_THREAD_INFO(%ebp)
+-					# system call tracing in operation
++					# system call tracing in operation / emulation
+ 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+-	testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
++	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -338,6 +338,9 @@
+ 	movl %esp, %eax
+ 	xorl %edx,%edx
+ 	call do_syscall_trace
++	cmpl $0, %eax
++	jne resume_userspace		# ret != 0 -> running under PTRACE_SYSEMU,
++					# so must skip actual syscall
+ 	movl ORIG_EAX(%esp), %eax
+ 	cmpl $(nr_syscalls), %eax
+ 	jnae syscall_call
+--- linux-2.6.git-paolo/arch/i386/kernel/ptrace.c	2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/kernel/ptrace.c	2005-05-21 18:00:55.000000000 +0200
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -271,6 +272,8 @@
+ void ptrace_disable(struct task_struct *child)
+ { 
+ 	clear_singlestep(child);
++	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ }
+ 
+ /*
+@@ -509,15 +512,20 @@
+ 		  }
+ 		  break;
+ 
++	case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ 	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
+ 	case PTRACE_CONT:	/* restart after signal. */
+ 		ret = -EIO;
+ 		if (!valid_signal(data))
+ 			break;
+-		if (request == PTRACE_SYSCALL) {
++		if (request == PTRACE_SYSEMU) {
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++		} else if (request == PTRACE_SYSCALL) {
+ 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		}
+-		else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		} else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		}
+ 		child->exit_code = data;
+@@ -542,10 +550,17 @@
+ 		wake_up_process(child);
+ 		break;
+ 
++	case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
+ 	case PTRACE_SINGLESTEP:	/* set the trap flag. */
+ 		ret = -EIO;
+ 		if (!valid_signal(data))
+ 			break;
++
++		if (request == PTRACE_SYSEMU_SINGLESTEP)
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		else
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++
+ 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		set_singlestep(child);
+ 		child->exit_code = data;
+@@ -645,6 +660,70 @@
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+@@ -678,26 +757,48 @@
+  * - triggered by current->work.syscall_trace
+  */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++	int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU), ret = 0;
++	/* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP */
++	int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
++
+ 	/* do the secure computing check first */
+ 	secure_computing(regs->orig_eax);
+ 
+-	if (unlikely(current->audit_context) && entryexit)
+-		audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++	if (unlikely(current->audit_context)) {
++		if (entryexit)
++			audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++		/* With TIF_SYSCALL_AUDIT | TIF_SINGLESTEP &&
++		 * !TIF_SYSCALL_EMU we come in here, but must not
++		 * continue with ptrace_notify().
++		 * In the SINGLESTEP && ! _AUDIT case (i.e. normal one),
++		 * entry.S will call us only on syscall exit and not on
++		 * the syscall entry path, so let's be consistent.
++		 */
++		else if (is_singlestep)
++			goto out;
++	}
+ 
+ 	if (!(current->ptrace & PT_PTRACED))
+ 		goto out;
+ 
++	/* If a process stops on the 1st tracepoint with SYSCALL_TRACE
++	 * and then is resumed with SYSEMU_SINGLESTEP, it will come in
++	 * here. We have to check this and return */
++	if (is_sysemu && entryexit)
++		return 0;
++
+ 	/* Fake a debug trap */
+-	if (test_thread_flag(TIF_SINGLESTEP))
++	if (is_singlestep)
+ 		send_sigtrap(current, regs, 0);
+ 
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
++	if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
+ 		goto out;
+ 
+ 	/* the 0x80 provides a way for the tracing parent to distinguish
+ 	   between a syscall stop and SIGTRAP delivery */
++	/* Note that the debugger could change the result of test_thread_flag!*/
+ 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+ 
+ 	/*
+@@ -711,7 +812,14 @@
+ 	}
++	ret = is_sysemu;
+  out:
+ 	if (unlikely(current->audit_context) && !entryexit)
+ 		audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
+ 				    regs->ebx, regs->ecx, regs->edx, regs->esi);
++	if (ret == 0)
++		return 0;
+ 
++	regs->orig_eax = -1; /* force skip of syscall restarting */
++	if (unlikely(current->audit_context))
++		audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++	return 1;
+ }
+--- linux-2.6.12-paolo/include/asm-i386/thread_info.h	2005-05-08 19:16:10.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/thread_info.h	2005-05-06 16:26:26.000000000 +0200
+@@ -141,6 +141,7 @@
+ #define TIF_IRET		5	/* return with iret */
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_SECCOMP		8	/* secure computing */
++#define TIF_SYSCALL_EMU		9	/* syscall emulation active */
+ #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE		17
+ 
+@@ -150,13 +151,15 @@
+ #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
+ #define _TIF_IRET		(1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU	(1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+ #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+ 
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
++  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++		  _TIF_SECCOMP|_TIF_SYSCALL_EMU))
+ /* work to do on any return to u-space */
+ #define _TIF_ALLWORK_MASK	(0x0000FFFF & ~_TIF_SECCOMP)
+ 
+--- linux-2.6.12-paolo/include/linux/ptrace.h	2005-05-08 19:16:10.000000000 +0200
++++ linux-2.6.12-paolo/include/linux/ptrace.h	2005-05-08 19:57:03.000000000 +0200
+@@ -20,6 +20,8 @@
+ #define PTRACE_DETACH		0x11
+ 
+ #define PTRACE_SYSCALL		  24
++#define PTRACE_SYSEMU		  31
++#define PTRACE_SYSEMU_SINGLESTEP  32
+ 
+ /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
+ #define PTRACE_SETOPTIONS	0x4200
+--- linux-2.6.12/kernel/fork.c~host-sysemu-2.6.7-4	2005-05-08 19:16:10.000000000 +0200
++++ linux-2.6.12-paolo/kernel/fork.c	2005-05-08 19:16:10.000000000 +0200
+@@ -989,6 +989,9 @@ static task_t *copy_process(unsigned lon
+ 	 * of CLONE_PTRACE.
+ 	 */
+ 	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+ 
+ 	/* Our parent execution domain becomes current domain
+ 	   These must match for thread signalling to apply */
+--- linux-2.6.git/include/linux/mm.h~Add_generic_proc_mm_support	2005-05-19 15:40:16.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/mm.h	2005-05-19 15:40:16.000000000 +0200
+@@ -654,6 +654,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level or three-level page table, this ends up being trivial. Thus
+  * the inlining and the symmetry break with pte_alloc_map() that does all
+@@ -730,9 +733,15 @@ extern int may_expand_vm(struct mm_struc
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+--- linux-2.6.git-paolo/include/linux/proc_mm.h	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/proc_mm.h	2005-06-02 05:02:46.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* The differences between this one and do_mmap are that:
++ * - we must perform controls for userspace-supplied params (which are
++ *   arch-specific currently). And also fget(fd) if needed and so on...
++ * - we must accept the struct mm_struct on which to act as first param, and the
++ *   offset in byte rather than page units as last param.
++ */
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off);
++
++/* This header can be used only on archs defining CONFIG_PROC_MM in their
++ * configs, so asm/proc_mm.h can still exist only for the needed archs.
++ * Including it only in the x86-64 case does not make sense.*/
++#include <asm/proc_mm.h>
++
++/*XXX: this is defined on x86_64, but not on every 64-bit arch (not on sh64).*/
++#ifdef CONFIG_64BIT
++
++#define write_proc_mm write_proc_mm_emul
++#define write_proc_mm64 write_proc_mm_native
++
++/* It would make more sense to do this mapping the reverse direction, to map the
++ * called name to the defined one and not the reverse. Like the 2nd example
++ */
++/*#define proc_mm_get_mm proc_mm_get_mm_emul
++#define proc_mm_get_mm64 proc_mm_get_mm_native*/
++
++#define proc_mm_get_mm_emul proc_mm_get_mm
++#define proc_mm_get_mm_native proc_mm_get_mm64
++
++#else
++
++#define write_proc_mm write_proc_mm_native
++#undef write_proc_mm64
++
++/*#define proc_mm_get_mm proc_mm_get_mm_native
++#undef proc_mm_get_mm64*/
++
++#define proc_mm_get_mm_native proc_mm_get_mm
++#undef proc_mm_get_mm_emul
++
++#endif
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++/* Cope with older kernels */
++#ifndef __acquires
++#define __acquires(x)
++#endif
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/*
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++extern void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock);
++#else
++static inline void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock)
++{
++	task_lock(child);
++}
++#endif
++
++#endif
+--- linux-2.6.git-paolo/mm/Makefile	2005-05-19 15:40:16.000000000 +0200
++++ linux-2.6.git-paolo/mm/Makefile	2005-05-21 18:00:57.000000000 +0200
+@@ -20,0 +21,5 @@
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m			+= proc_mm-mod.o
++endif
+--- linux-2.6.git/mm/mmap.c~Add_generic_proc_mm_support	2005-05-19 15:40:16.000000000 +0200
++++ linux-2.6.git-paolo/mm/mmap.c	2005-05-19 15:40:16.000000000 +0200
+@@ -864,11 +864,11 @@ void __vm_stat_account(struct mm_struct 
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1143,7 +1143,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+--- linux-2.6.git-paolo/mm/mprotect.c	2005-05-19 15:40:16.000000000 +0200
++++ vanilla-linux-2.6.12-paolo/mm/mprotect.c	2005-07-10 20:08:24.000000000 +0200
+@@ -177,8 +177,9 @@
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp, reqprot;
+ 	struct vm_area_struct *vma, *prev;
+@@ -209,9 +210,9 @@
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -280,3 +281,12 @@
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	long ret = do_mprotect(current->mm, start, len, prot);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+--- linux-2.6.git-paolo/mm/proc_mm.c	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/mm/proc_mm.c	2005-06-02 05:02:46.000000000 +0200
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/proc_mm.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/* Checks if a task must be considered dumpable
++ *
++ * XXX: copied from fs/proc/base.c, removed task_lock, added rmb(): this must be
++ * called with task_lock(task) held. */
++static int task_dumpable(struct task_struct *task)
++{
++	int dumpable = 0;
++	struct mm_struct *mm;
++
++	mm = task->mm;
++	if (mm) {
++		rmb();
++		dumpable = mm->dumpable;
++	}
++	return dumpable;
++}
++
++/*
++ * This is to be used in PTRACE_SWITCH_MM handling. We are going to set
++ * child->mm to new, and we must first correctly set new->dumpable.
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++void lock_fix_dumpable_setting(struct task_struct* child, struct mm_struct* new)
++	__acquires(child->alloc_lock)
++{
++	int dumpable = 1;
++
++	/* We must be safe.
++	 * If the child is ptraced from a non-dumpable process,
++	 * let's not be dumpable. If the child is non-dumpable itself,
++	 * copy this property across mm's.
++	 *
++	 * Don't try to be smart for the opposite case and turn
++	 * child->mm->dumpable to 1: I've not made sure it is safe.
++	 */
++
++	task_lock(current);
++	if (unlikely(!task_dumpable(current))) {
++		dumpable = 0;
++	}
++	task_unlock(current);
++
++	task_lock(child);
++	if (likely(dumpable) && unlikely(!task_dumpable(child))) {
++		dumpable = 0;
++	}
++
++	if (!dumpable) {
++		new->dumpable = 0;
++		wmb();
++	}
++}
++#endif
++
++/* Naming conventions are a mess, so I note them down.
++ *
++ * Things ending in _mm can be for everything. It's only for
++ * {open,release}_proc_mm.
++ *
++ * For the rest:
++ *
++ * _mm means /proc/mm, _mm64 means /proc/mm64. This is for the infrastructure
++ * only (for instance proc_mm_get_mm checks whether the file is /proc/mm or
++ * /proc/mm64; for instance the /proc handling).
++ *
++ * While for what is conversion dependant, we use the suffix _native and _emul.
++ * In some cases, there is a mapping between these ones (defined by
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++	mm->dumpable = current->mm->dumpable;
++	wmb();
++#endif
++
++	file->private_data = mm;
++
++	return 0;
++
++out_mem:
++	return ret;
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return 0;
++}
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++static ssize_t write_proc_mm_native(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_native(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
++/*These three are all for /proc/mm.*/
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++/*Macro-ify it to avoid the duplication.*/
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm);
++
++/*XXX: change the option.*/
++#ifdef CONFIG_64BIT
++static struct file_operations proc_mm64_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm64,
++};
++
++static int make_proc_mm64(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm64", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm64\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm64_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm64);
++
++struct mm_struct *proc_mm_get_mm64(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	/*This is the only change.*/
++	if(file->f_op != &proc_mm64_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.6.git/arch/um/include/skas_ptrace.h~Add_generic_proc_mm_support	2005-05-19 15:40:16.000000000 +0200
++++ linux-2.6.git-paolo/arch/um/include/skas_ptrace.h	2005-05-19 15:40:16.000000000 +0200
+@@ -6,6 +6,8 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
++
+ #define PTRACE_FAULTINFO 52
+ #define PTRACE_SWITCH_MM 55
+ 
+@@ -13,6 +15,8 @@
+ 
+ #endif
+ 
++#endif
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+--- linux-2.6.12-paolo/arch/i386/Kconfig	2005-05-08 19:47:37.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/Kconfig	2005-06-02 05:02:46.000000000 +0200
+@@ -769,6 +769,26 @@
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+--- linux-2.6.11-paolo/arch/i386/kernel/ldt.c	2005-02-10 13:25:39.841170200 +0100
++++ vanilla-linux-2.6.12-paolo/arch/i386/kernel/ldt.c	2005-07-10 20:08:06.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,11 +28,12 @@
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	int oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= pc->size)
+ 		return 0;
+@@ -58,13 +60,15 @@
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -76,12 +80,12 @@
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -89,22 +93,24 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +127,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -174,9 +180,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -200,7 +205,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -236,20 +241,30 @@
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	int ret = __modify_ldt(current->mm, func, ptr, bytecount);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+--- linux-2.6.12-paolo/arch/i386/kernel/sys_i386.c	2005-05-08 19:47:37.000000000 +0200
++++ vanilla-linux-2.6.12-paolo/arch/i386/kernel/sys_i386.c	2005-07-10 16:06:02.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,12 @@
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
+ }
+ 
+ /*
+@@ -101,7 +106,10 @@
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(err);
+ out:
+ 	return err;
+ }
+--- linux-2.6.12/include/asm-i386/desc.h~i386-specific	2005-05-08 19:47:37.000000000 +0200
++++ linux-2.6.12-paolo/include/asm-i386/desc.h	2005-05-08 19:47:37.000000000 +0200
+@@ -139,6 +139,9 @@ static inline unsigned long get_desc_bas
+ 	return base;
+ }
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- linux-2.6.git-paolo/include/asm-i386/ptrace.h	2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/ptrace.h	2005-05-21 18:00:55.000000000 +0200
+@@ -68,2 +68,31 @@
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++#define PTRACE_EX_FAULTINFO	  56
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- linux-2.6.12-paolo/include/asm-i386/mmu_context.h	2005-05-08 19:48:07.000000000 +0200
++++ linux-2.6.12-paolo/include/asm-i386/mmu_context.h	2005-05-08 19:35:02.000000000 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+--- vanilla-linux-2.6.12-paolo/localversion-skas	2005-07-10 11:36:59.000000000 +0200
++++ vanilla-linux-2.6.12-paolo/localversion-skas	2005-07-11 11:51:53.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v9-pre7
+--- linux-2.6.git-paolo/arch/x86_64/mm/proc_mm.c	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/mm/proc_mm.c	2005-05-15 18:32:11.000000000 +0200
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op32 req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap32 *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap32 *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect32 *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_emul(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
+--- /dev/null	2005-05-28 23:34:14.051125088 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/proc_mm.h	2005-06-02 05:03:04.000000000 +0200
+@@ -0,0 +1,56 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++struct mm_mmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++	compat_ulong_t prot;
++	compat_ulong_t flags;
++	compat_ulong_t fd;
++	compat_ulong_t offset;
++};
++
++struct mm_munmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++};
++
++struct mm_mprotect32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++        compat_uint_t prot;
++};
++
++struct proc_mm_op32 {
++	compat_int_t op;
++	union {
++		struct mm_mmap32 mmap;
++		struct mm_munmap32 munmap;
++	        struct mm_mprotect32 mprotect;
++		compat_int_t copy_segments;
++	} u;
++};
++
++extern ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos);
++
++extern long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	/* The latter one is stricter, since will actually check that off is page
++	 * aligned. The first one skipped the check. */
++
++	/* return do32_mmap2(mm, addr, len, prot, flags, fd, off >>
++	 * PAGE_SHIFT);*/
++	return do64_mmap(mm, addr, len, prot, flags, fd, off);
++}
++
++#endif /* __ASM_PROC_MM */
+--- linux-2.6.git-paolo/arch/x86_64/Kconfig	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/Kconfig	2005-06-02 05:02:46.000000000 +0200
+@@ -347,6 +347,26 @@
+ 	  of memory and any 32-bit devices. Don't turn on unless you know what you
+ 	  are doing.
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ config X86_MCE
+ 	bool "Machine check support" if EMBEDDED
+ 	default y
+--- linux-2.6.git-paolo/arch/x86_64/ia32/ptrace32.c	2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/ia32/ptrace32.c	2005-05-21 18:00:55.000000000 +0200
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+ 
+ /* determines which flags the user has access to. */
+ /* 1 = access 0 = no access */
+@@ -251,6 +254,11 @@
+ 	case PTRACE_SETFPXREGS:
+ 	case PTRACE_GETFPXREGS:
+ 	case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO:
++	case PTRACE_LDT:
++	case PTRACE_SWITCH_MM:
++#endif
+ 		break;
+ 	} 
+ 
+@@ -363,6 +371,65 @@
+ 		ret = 0; 
+ 		break;
+ 	}
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo32 fault;
++
++		fault = ((struct ptrace_ex_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2,
++			  .trap_no	= (compat_int_t) child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo32 fault;
++
++		fault = ((struct ptrace_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt32 ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) datap,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, compat_ptr(ldt.ptr), ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
+ 
+ 	case PTRACE_GETEVENTMSG:
+ 		ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+--- linux-2.6.git/include/asm-x86_64/mmu_context.h~x86-64-specific-addition	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/mmu_context.h	2005-06-02 05:03:04.000000000 +0200
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+  * possibly do the LDT unload here?
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
++
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #ifdef CONFIG_SMP
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+@@ -37,6 +52,9 @@ static inline void switch_mm(struct mm_s
+ 			     struct task_struct *tsk)
+ {
+ 	unsigned cpu = smp_processor_id();
++#ifdef CONFIG_SMP
++	prev = read_pda(active_mm);
++#endif
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -53,8 +71,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		write_pda(mmu_state, TLBSTATE_OK);
+-		if (read_pda(active_mm) != next)
+-			out_of_line_bug();
+ 		if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+ 			 * tlb flush IPI delivery. We must reload CR3
+--- linux-2.6.git/arch/x86_64/ia32/sys_ia32.c~x86-64-specific-addition	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/ia32/sys_ia32.c	2005-06-02 05:03:04.000000000 +0200
+@@ -832,11 +832,10 @@ sys32_adjtimex(struct timex32 __user *ut
+ 	return ret;
+ }
+ 
+-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
++long do32_mmap2(struct mm_struct *mm, unsigned long addr,
++	unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	struct mm_struct *mm = current->mm;
+ 	unsigned long error;
+ 	struct file * file = NULL;
+ 
+@@ -848,7 +847,7 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	}
+ 
+ 	down_write(&mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
+ 	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+@@ -856,6 +855,15 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	return error;
+ }
+ 
++/* XXX: this wrapper can be probably removed, we can simply use the 64-bit
++ * version.*/
++asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
++	unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long pgoff)
++{
++	return do32_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++}
++
+ asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
+ {
+ 	int error;
+--- linux-2.6.git-paolo/arch/x86_64/kernel/ldt.c	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.11-paolo/arch/x86_64/kernel/ldt.c	2005-03-05 19:49:55.120753864 +0100
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, unsigned mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	unsigned oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= (unsigned)pc->size)
+ 		return 0;
+@@ -64,12 +66,14 @@
+ 
+ 		preempt_disable();
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		load_LDT(pc);
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -81,12 +85,12 @@
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -94,22 +98,24 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * 
+  * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -170,10 +175,8 @@
+ 	return bytecount; 
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct task_struct *me = current;
+-	struct mm_struct * mm = me->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -198,7 +201,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= (unsigned)mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -234,20 +237,26 @@
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return __modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- linux-2.6.git/include/asm-x86_64/desc.h~x86-64-specific-addition	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/desc.h	2005-06-02 05:03:04.000000000 +0200
+@@ -212,6 +212,9 @@ static inline void load_LDT(mm_context_t
+ 
+ extern struct desc_ptr idt_descr;
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- linux-2.6.git-paolo/include/asm-x86_64/ptrace.h	2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/ptrace.h	2005-05-21 18:00:55.000000000 +0200
+@@ -64,6 +64,59 @@
+ /* top of stack page */ 
+ };
+ 
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#define		compat_int_t	s32
++#define		compat_long_t	s32
++#define		compat_uint_t	u32
++#define		compat_ulong_t	u32
++#define		compat_uptr_t	u32
++
++struct ptrace_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++};
++
++struct ptrace_ex_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++	compat_int_t trap_no;
++};
++
++struct ptrace_ldt32 {
++	compat_int_t func;
++	compat_uptr_t ptr; /*Actually a void pointer on i386, but must be converted.*/
++	compat_ulong_t bytecount;
++};
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#undef	compat_int_t
++#undef	compat_long_t
++#undef	compat_uint_t
++#undef	compat_ulong_t
++#undef	compat_uptr_t
++
+ #endif
+ 
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@
+ #define PTRACE_GETFPXREGS         18
+ #define PTRACE_SETFPXREGS         19
+ 
++#define PTRACE_FAULTINFO 52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++#define PTRACE_EX_FAULTINFO	  56
++
+ /* only useful for access 32bit programs */
+ #define PTRACE_GET_THREAD_AREA    25
+ #define PTRACE_SET_THREAD_AREA    26
+--- linux-2.6.git/arch/x86_64/mm/Makefile~x86-64-specific-addition	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/mm/Makefile	2005-06-02 05:03:04.000000000 +0200
+@@ -7,5 +7,6 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag
+ obj-$(CONFIG_DISCONTIGMEM) += numa.o
+ obj-$(CONFIG_K8_NUMA) += k8topology.o
+ obj-$(CONFIG_ACPI_NUMA) += srat.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+ 
+ hugetlbpage-y = ../../i386/mm/hugetlbpage.o
+--- linux-2.6.git-paolo/arch/x86_64/kernel/ptrace.c	2005-05-25 00:57:34.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/kernel/ptrace.c	2005-05-21 18:00:55.000000000 +0200
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -601,6 +602,79 @@
+ 		break;
+ 	}
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	/*Don't extend this broken interface to x86-64*/
++#if 0
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++#endif
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm64(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+--- linux-2.6.git/arch/x86_64/kernel/sys_x86_64.c~x86-64-specific-addition	2005-06-02 05:03:04.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/kernel/sys_x86_64.c	2005-06-02 05:03:04.000000000 +0200
+@@ -19,6 +19,7 @@
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+ 
+ /*
+  * sys_pipe() is the normal C calling standard for creating
+@@ -37,7 +38,7 @@ asmlinkage long sys_pipe(int __user *fil
+ 	return error;
+ }
+ 
+-asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long off)
+ {
+ 	long error;
+@@ -55,9 +56,9 @@ asmlinkage long sys_mmap(unsigned long a
+ 		if (!file)
+ 			goto out;
+ 	}
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, off >> PAGE_SHIFT);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -65,6 +66,12 @@ out:
+ 	return error;
+ }
+ 
++asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off)
++{
++	return do64_mmap(current->mm, addr, len, prot, flags, fd, off);
++}
++
+ static void find_start_end(unsigned long flags, unsigned long *begin,
+ 			   unsigned long *end)
+ {
+--- /dev/null	2005-05-28 23:34:14.051125088 +0200
++++ linux-2.6.git-paolo/include/asm-i386/proc_mm.h	2005-06-02 05:03:04.000000000 +0200
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		unsigned long len, unsigned long prot, unsigned long flags,
++		unsigned long fd, unsigned long pgoff);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	return do_mmap2(mm, addr, len, prot, flags, fd, off >> PAGE_SHIFT);
++}
++
++#endif /* __ASM_PROC_MM */
+--- /dev/null	2005-05-20 16:07:16.788013064 +0200
++++ linux-2.6.git-paolo/mm/proc_mm-mod.c	2005-05-21 18:00:57.000000000 +0200
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#ifdef CONFIG_64BIT
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "32->" #member " \t: %ld\n", (long) offsetof(struct type ## 32, member))
++#else
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "->" #member " \t: %ld\n", (long) offsetof(struct type, member))
++#endif
++
++static int debug_printoffsets(void)
++{
++	printk(KERN_DEBUG "Skas core structures layout BEGIN:\n");
++	PRINT_OFFSET(mm_mmap, addr);
++	PRINT_OFFSET(mm_mmap, len);
++	PRINT_OFFSET(mm_mmap, prot);
++	PRINT_OFFSET(mm_mmap, flags);
++	PRINT_OFFSET(mm_mmap, fd);
++	PRINT_OFFSET(mm_mmap, offset);
++
++	PRINT_OFFSET(mm_munmap, addr);
++	PRINT_OFFSET(mm_munmap, len);
++
++	PRINT_OFFSET(mm_mprotect, addr);
++	PRINT_OFFSET(mm_mprotect, len);
++	PRINT_OFFSET(mm_mprotect, prot);
++
++	PRINT_OFFSET(proc_mm_op, op);
++	PRINT_OFFSET(proc_mm_op, u);
++	PRINT_OFFSET(proc_mm_op, u.mmap);
++	PRINT_OFFSET(proc_mm_op, u.munmap);
++	PRINT_OFFSET(proc_mm_op, u.mprotect);
++	PRINT_OFFSET(proc_mm_op, u.copy_segments);
++
++	PRINT_OFFSET(ptrace_faultinfo, is_write);
++	PRINT_OFFSET(ptrace_faultinfo, addr);
++
++	PRINT_OFFSET(ptrace_ldt, func);
++	PRINT_OFFSET(ptrace_ldt, ptr);
++	PRINT_OFFSET(ptrace_ldt, bytecount);
++	printk(KERN_DEBUG "Skas core structures layout END.\n");
++
++	return 0;
++}
++#undef PRINT_OFFSET
++
++module_init(debug_printoffsets);

Added: trunk/src/kernel-patch-skas/skas-2.6.13-rc7-v9-pre7.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.13-rc7-v9-pre7.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.13-rc7-v9-pre7.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1994 @@
+--- linux-2.6.git-paolo/arch/i386/kernel/ptrace.c	2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/kernel/ptrace.c	2005-07-28 19:40:18.000000000 +0200
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -271,6 +272,8 @@
+ void ptrace_disable(struct task_struct *child)
+ { 
+ 	clear_singlestep(child);
++	clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++	clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ }
+ 
+ /*
+@@ -509,15 +512,20 @@
+ 		  }
+ 		  break;
+ 
++	case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */
+ 	case PTRACE_SYSCALL:	/* continue and stop at next (return from) syscall */
+ 	case PTRACE_CONT:	/* restart after signal. */
+ 		ret = -EIO;
+ 		if (!valid_signal(data))
+ 			break;
+-		if (request == PTRACE_SYSCALL) {
++		if (request == PTRACE_SYSEMU) {
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
++		} else if (request == PTRACE_SYSCALL) {
+ 			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+-		}
+-		else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		} else {
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
+ 			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		}
+ 		child->exit_code = data;
+@@ -542,10 +550,17 @@
+ 		wake_up_process(child);
+ 		break;
+ 
++	case PTRACE_SYSEMU_SINGLESTEP: /* Same as SYSEMU, but singlestep if not syscall */
+ 	case PTRACE_SINGLESTEP:	/* set the trap flag. */
+ 		ret = -EIO;
+ 		if (!valid_signal(data))
+ 			break;
++
++		if (request == PTRACE_SYSEMU_SINGLESTEP)
++			set_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++		else
++			clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
++
+ 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ 		set_singlestep(child);
+ 		child->exit_code = data;
+@@ -645,6 +660,70 @@
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+@@ -678,26 +757,52 @@
+  * - triggered by current->work.syscall_trace
+  */
+ __attribute__((regparm(3)))
+-void do_syscall_trace(struct pt_regs *regs, int entryexit)
++int do_syscall_trace(struct pt_regs *regs, int entryexit)
+ {
++	int is_sysemu = test_thread_flag(TIF_SYSCALL_EMU), ret = 0;
++	/* With TIF_SYSCALL_EMU set we want to ignore TIF_SINGLESTEP for syscall
++	 * interception. */
++	int is_singlestep = !is_sysemu && test_thread_flag(TIF_SINGLESTEP);
++
+ 	/* do the secure computing check first */
+ 	secure_computing(regs->orig_eax);
+ 
+-	if (unlikely(current->audit_context) && entryexit)
+-		audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++	if (unlikely(current->audit_context)) {
++		if (entryexit)
++			audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++		/* Debug traps, when using PTRACE_SINGLESTEP, must be sent only
++		 * on the syscall exit path. Normally, when TIF_SYSCALL_AUDIT is
++		 * not used, entry.S will call us only on syscall exit, not
++		 * entry; so when TIF_SYSCALL_AUDIT is used we must avoid
++		 * calling send_sigtrap() on syscall entry.
++		 *
++		 * Note that when PTRACE_SYSEMU_SINGLESTEP is used,
++		 * is_singlestep is false, despite his name, so we will still do
++		 * the correct thing.
++		 */
++		else if (is_singlestep)
++			goto out;
++	}
+ 
+ 	if (!(current->ptrace & PT_PTRACED))
+ 		goto out;
+ 
++	/* If a process stops on the 1st tracepoint with SYSCALL_TRACE
++	 * and then is resumed with SYSEMU_SINGLESTEP, it will come in
++	 * here. We have to check this and return */
++	if (is_sysemu && entryexit)
++		return 0;
++
+ 	/* Fake a debug trap */
+-	if (test_thread_flag(TIF_SINGLESTEP))
++	if (is_singlestep)
+ 		send_sigtrap(current, regs, 0);
+ 
+-	if (!test_thread_flag(TIF_SYSCALL_TRACE))
++	if (!test_thread_flag(TIF_SYSCALL_TRACE) && !is_sysemu)
+ 		goto out;
+ 
+ 	/* the 0x80 provides a way for the tracing parent to distinguish
+ 	   between a syscall stop and SIGTRAP delivery */
++	/* Note that the debugger could change the result of test_thread_flag!*/
+ 	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+ 
+ 	/*
+@@ -711,7 +816,14 @@
+ 	}
++	ret = is_sysemu;
+  out:
+ 	if (unlikely(current->audit_context) && !entryexit)
+ 		audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
+ 				    regs->ebx, regs->ecx, regs->edx, regs->esi);
++	if (ret == 0)
++		return 0;
+ 
++	regs->orig_eax = -1; /* force skip of syscall restarting */
++	if (unlikely(current->audit_context))
++		audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
++	return 1;
+ }
+--- linux-2.6.git-paolo/arch/i386/kernel/entry.S	2005-08-26 20:59:11.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/kernel/entry.S	2005-07-31 20:03:19.000000000 +0200
+@@ -203,7 +203,7 @@
+ 	GET_THREAD_INFO(%ebp)
+ 
+ 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+-	testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
++	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -226,9 +226,9 @@
+ 	pushl %eax			# save orig_eax
+ 	SAVE_ALL
+ 	GET_THREAD_INFO(%ebp)
+-					# system call tracing in operation
++					# system call tracing in operation / emulation
+ 	/* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
+-	testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)
++	testw $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+ 	jnz syscall_trace_entry
+ 	cmpl $(nr_syscalls), %eax
+ 	jae syscall_badsys
+@@ -338,6 +338,9 @@
+ 	movl %esp, %eax
+ 	xorl %edx,%edx
+ 	call do_syscall_trace
++	cmpl $0, %eax
++	jne resume_userspace		# ret != 0 -> running under PTRACE_SYSEMU,
++					# so must skip actual syscall
+ 	movl ORIG_EAX(%esp), %eax
+ 	cmpl $(nr_syscalls), %eax
+ 	jnae syscall_call
+--- linux-2.6.git-paolo/include/asm-i386/thread_info.h	2005-07-26 20:24:57.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/thread_info.h	2005-05-06 16:26:26.000000000 +0200
+@@ -141,6 +141,7 @@
+ #define TIF_IRET		5	/* return with iret */
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_SECCOMP		8	/* secure computing */
++#define TIF_SYSCALL_EMU		9	/* syscall emulation active */
+ #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE		17
+ 
+@@ -150,13 +151,15 @@
+ #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+ #define _TIF_SINGLESTEP		(1<<TIF_SINGLESTEP)
+ #define _TIF_IRET		(1<<TIF_IRET)
++#define _TIF_SYSCALL_EMU	(1<<TIF_SYSCALL_EMU)
+ #define _TIF_SYSCALL_AUDIT	(1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_SECCOMP		(1<<TIF_SECCOMP)
+ #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+ 
+ /* work to do on interrupt/exception return */
+ #define _TIF_WORK_MASK \
+-  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|_TIF_SECCOMP))
++  (0x0000FFFF & ~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP|\
++		  _TIF_SECCOMP|_TIF_SYSCALL_EMU))
+ /* work to do on any return to u-space */
+ #define _TIF_ALLWORK_MASK	(0x0000FFFF & ~_TIF_SECCOMP)
+ 
+--- linux-2.6.git-paolo/include/linux/ptrace.h	2005-07-26 20:39:57.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/ptrace.h	2005-07-26 20:27:45.000000000 +0200
+@@ -20,6 +20,8 @@
+ #define PTRACE_DETACH		0x11
+ 
+ #define PTRACE_SYSCALL		  24
++#define PTRACE_SYSEMU		  31
++#define PTRACE_SYSEMU_SINGLESTEP  32
+ 
+ /* 0x4200-0x4300 are reserved for architecture-independent additions.  */
+ #define PTRACE_SETOPTIONS	0x4200
+--- linux-2.6.git/kernel/fork.c~host-sysemu	2005-07-26 20:24:57.000000000 +0200
++++ linux-2.6.git-paolo/kernel/fork.c	2005-07-26 20:24:57.000000000 +0200
+@@ -994,6 +994,9 @@ static task_t *copy_process(unsigned lon
+ 	 * of CLONE_PTRACE.
+ 	 */
+ 	clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
++#ifdef TIF_SYSCALL_EMU
++	clear_tsk_thread_flag(p, TIF_SYSCALL_EMU);
++#endif
+ 
+ 	/* Our parent execution domain becomes current domain
+ 	   These must match for thread signalling to apply */
+--- linux-2.6.git/include/linux/mm.h~Add_generic_proc_mm_support	2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/mm.h	2005-08-21 21:43:06.000000000 +0200
+@@ -759,6 +759,9 @@ struct shrinker;
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level or three-level page table, this ends up being trivial. Thus
+  * the inlining and the symmetry break with pte_alloc_map() that does all
+@@ -841,9 +844,15 @@ extern int may_expand_vm(struct mm_struc
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+--- linux-2.6.git-paolo/include/linux/proc_mm.h	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/include/linux/proc_mm.h	2005-08-21 21:44:05.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* The differences between this one and do_mmap are that:
++ * - we must perform controls for userspace-supplied params (which are
++ *   arch-specific currently). And also fget(fd) if needed and so on...
++ * - we must accept the struct mm_struct on which to act as first param, and the
++ *   offset in byte rather than page units as last param.
++ */
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off);
++
++/* This header can be used only on archs defining CONFIG_PROC_MM in their
++ * configs, so asm/proc_mm.h can still exist only for the needed archs.
++ * Including it only in the x86-64 case does not make sense.*/
++#include <asm/proc_mm.h>
++
++/*XXX: this is defined on x86_64, but not on every 64-bit arch (not on sh64).*/
++#ifdef CONFIG_64BIT
++
++#define write_proc_mm write_proc_mm_emul
++#define write_proc_mm64 write_proc_mm_native
++
++/* It would make more sense to do this mapping the reverse direction, to map the
++ * called name to the defined one and not the reverse. Like the 2nd example
++ */
++/*#define proc_mm_get_mm proc_mm_get_mm_emul
++#define proc_mm_get_mm64 proc_mm_get_mm_native*/
++
++#define proc_mm_get_mm_emul proc_mm_get_mm
++#define proc_mm_get_mm_native proc_mm_get_mm64
++
++#else
++
++#define write_proc_mm write_proc_mm_native
++#undef write_proc_mm64
++
++/*#define proc_mm_get_mm proc_mm_get_mm_native
++#undef proc_mm_get_mm64*/
++
++#define proc_mm_get_mm_native proc_mm_get_mm
++#undef proc_mm_get_mm_emul
++
++#endif
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++/* Cope with older kernels */
++#ifndef __acquires
++#define __acquires(x)
++#endif
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/*
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++extern void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock);
++#else
++static inline void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock)
++{
++	task_lock(child);
++}
++#endif
++
++#endif
+--- linux-2.6.git-paolo/mm/Makefile	2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-paolo/mm/Makefile	2005-07-04 18:50:00.000000000 +0200
+@@ -22,0 +23,6 @@
++
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m			+= proc_mm-mod.o
++endif
+--- linux-2.6.git/mm/mmap.c~Add_generic_proc_mm_support	2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-paolo/mm/mmap.c	2005-08-21 21:43:06.000000000 +0200
+@@ -868,11 +868,11 @@ void __vm_stat_account(struct mm_struct 
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1147,7 +1147,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+--- linux-2.6.git-paolo/mm/mprotect.c	2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-broken-paolo/mm/mprotect.c	2005-07-13 19:28:33.000000000 +0200
+@@ -177,8 +177,9 @@
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp, reqprot;
+ 	struct vm_area_struct *vma, *prev;
+@@ -209,9 +210,9 @@
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -280,3 +281,12 @@
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	long ret = do_mprotect(current->mm, start, len, prot);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+--- linux-2.6.git-paolo/mm/proc_mm.c	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/mm/proc_mm.c	2005-08-21 21:44:05.000000000 +0200
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/proc_mm.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/* Checks if a task must be considered dumpable
++ *
++ * XXX: copied from fs/proc/base.c, removed task_lock, added rmb(): this must be
++ * called with task_lock(task) held. */
++static int task_dumpable(struct task_struct *task)
++{
++	int dumpable = 0;
++	struct mm_struct *mm;
++
++	mm = task->mm;
++	if (mm) {
++		rmb();
++		dumpable = mm->dumpable;
++	}
++	return dumpable;
++}
++
++/*
++ * This is to be used in PTRACE_SWITCH_MM handling. We are going to set
++ * child->mm to new, and we must first correctly set new->dumpable.
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++void lock_fix_dumpable_setting(struct task_struct* child, struct mm_struct* new)
++	__acquires(child->alloc_lock)
++{
++	int dumpable = 1;
++
++	/* We must be safe.
++	 * If the child is ptraced from a non-dumpable process,
++	 * let's not be dumpable. If the child is non-dumpable itself,
++	 * copy this property across mm's.
++	 *
++	 * Don't try to be smart for the opposite case and turn
++	 * child->mm->dumpable to 1: I've not made sure it is safe.
++	 */
++
++	task_lock(current);
++	if (unlikely(!task_dumpable(current))) {
++		dumpable = 0;
++	}
++	task_unlock(current);
++
++	task_lock(child);
++	if (likely(dumpable) && unlikely(!task_dumpable(child))) {
++		dumpable = 0;
++	}
++
++	if (!dumpable) {
++		new->dumpable = 0;
++		wmb();
++	}
++}
++#endif
++
++/* Naming conventions are a mess, so I note them down.
++ *
++ * Things ending in _mm can be for everything. It's only for
++ * {open,release}_proc_mm.
++ *
++ * For the rest:
++ *
++ * _mm means /proc/mm, _mm64 means /proc/mm64. This is for the infrastructure
++ * only (for instance proc_mm_get_mm checks whether the file is /proc/mm or
++ * /proc/mm64; for instance the /proc handling).
++ *
++ * While for what is conversion dependant, we use the suffix _native and _emul.
++ * In some cases, there is a mapping between these ones (defined by
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++	mm->dumpable = current->mm->dumpable;
++	wmb();
++#endif
++
++	file->private_data = mm;
++
++	return 0;
++
++out_mem:
++	return ret;
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return 0;
++}
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++static ssize_t write_proc_mm_native(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_native(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
++/*These three are all for /proc/mm.*/
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++/*Macro-ify it to avoid the duplication.*/
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm);
++
++/*XXX: change the option.*/
++#ifdef CONFIG_64BIT
++static struct file_operations proc_mm64_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm64,
++};
++
++static int make_proc_mm64(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm64", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm64\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm64_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm64);
++
++struct mm_struct *proc_mm_get_mm64(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	/*This is the only change.*/
++	if(file->f_op != &proc_mm64_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+--- linux-2.6.git/arch/um/include/skas_ptrace.h~Add_generic_proc_mm_support	2005-08-21 21:43:06.000000000 +0200
++++ linux-2.6.git-paolo/arch/um/include/skas_ptrace.h	2005-08-21 21:43:06.000000000 +0200
+@@ -6,6 +6,8 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
++
+ #define PTRACE_FAULTINFO 52
+ #define PTRACE_SWITCH_MM 55
+ 
+@@ -13,6 +15,8 @@
+ 
+ #endif
+ 
++#endif
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+--- linux-2.6.git-paolo/arch/i386/Kconfig	2005-08-21 21:43:37.000000000 +0200
++++ linux-2.6.git-paolo/arch/i386/Kconfig	2005-08-21 21:44:05.000000000 +0200
+@@ -748,6 +748,26 @@
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+--- linux-2.6.git-paolo/arch/i386/kernel/ldt.c	2005-07-04 18:48:33.000000000 +0200
++++ linux-2.6.git-broken-paolo/arch/i386/kernel/ldt.c	2005-07-13 19:28:33.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,11 +28,12 @@
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	int oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= pc->size)
+ 		return 0;
+@@ -58,13 +60,15 @@
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -76,12 +80,12 @@
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -89,22 +93,24 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +127,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -174,9 +180,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -200,7 +205,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -236,20 +241,30 @@
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	int ret = __modify_ldt(current->mm, func, ptr, bytecount);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+--- linux-2.6.git-paolo/arch/i386/kernel/sys_i386.c	2005-08-21 21:43:37.000000000 +0200
++++ linux-2.6.git-broken-paolo/arch/i386/kernel/sys_i386.c	2005-07-13 19:28:18.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,12 @@
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
+ }
+ 
+ /*
+@@ -101,7 +106,10 @@
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(err);
+ out:
+ 	return err;
+ }
+--- linux-2.6.git/include/asm-i386/desc.h~i386-specific	2005-08-21 21:43:37.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/desc.h	2005-08-21 21:43:37.000000000 +0200
+@@ -139,6 +139,9 @@ static inline unsigned long get_desc_bas
+ 	return base;
+ }
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- linux-2.6.git-paolo/include/asm-i386/ptrace.h	2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/ptrace.h	2005-07-28 19:40:18.000000000 +0200
+@@ -79,2 +79,31 @@
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++#define PTRACE_EX_FAULTINFO	  56
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+--- linux-2.6.git-paolo/include/asm-i386/mmu_context.h	2005-08-21 21:43:37.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/mmu_context.h	2005-07-04 18:48:25.000000000 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+--- linux-2.6.git-broken-paolo/localversion-skas	2005-07-13 19:30:11.000000000 +0200
++++ linux-2.6.git-broken-paolo/localversion-skas	2005-07-13 19:30:14.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v9-pre7
+--- linux-2.6.git-paolo/arch/x86_64/mm/proc_mm.c	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/mm/proc_mm.c	2005-05-15 18:32:11.000000000 +0200
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op32 req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap32 *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap32 *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect32 *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_emul(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
+--- /dev/null	2005-07-20 02:59:33.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/proc_mm.h	2005-07-31 18:56:20.000000000 +0200
+@@ -0,0 +1,56 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++struct mm_mmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++	compat_ulong_t prot;
++	compat_ulong_t flags;
++	compat_ulong_t fd;
++	compat_ulong_t offset;
++};
++
++struct mm_munmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++};
++
++struct mm_mprotect32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++        compat_uint_t prot;
++};
++
++struct proc_mm_op32 {
++	compat_int_t op;
++	union {
++		struct mm_mmap32 mmap;
++		struct mm_munmap32 munmap;
++	        struct mm_mprotect32 mprotect;
++		compat_int_t copy_segments;
++	} u;
++};
++
++extern ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos);
++
++extern long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	/* The latter one is stricter, since will actually check that off is page
++	 * aligned. The first one skipped the check. */
++
++	/* return do32_mmap2(mm, addr, len, prot, flags, fd, off >>
++	 * PAGE_SHIFT);*/
++	return do64_mmap(mm, addr, len, prot, flags, fd, off);
++}
++
++#endif /* __ASM_PROC_MM */
+--- linux-2.6.git-paolo/arch/x86_64/Kconfig	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/Kconfig	2005-08-21 21:44:05.000000000 +0200
+@@ -355,6 +355,26 @@
+ 	  of memory and any 32-bit devices. Don't turn on unless you know what you
+ 	  are doing.
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ config X86_MCE
+ 	bool "Machine check support" if EMBEDDED
+ 	default y
+--- linux-2.6.git-paolo/arch/x86_64/ia32/ptrace32.c	2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/ia32/ptrace32.c	2005-07-28 19:40:18.000000000 +0200
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+ 
+ /* determines which flags the user has access to. */
+ /* 1 = access 0 = no access */
+@@ -251,6 +254,11 @@
+ 	case PTRACE_SETFPXREGS:
+ 	case PTRACE_GETFPXREGS:
+ 	case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO:
++	case PTRACE_LDT:
++	case PTRACE_SWITCH_MM:
++#endif
+ 		break;
+ 	} 
+ 
+@@ -363,6 +371,65 @@
+ 		ret = 0; 
+ 		break;
+ 	}
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo32 fault;
++
++		fault = ((struct ptrace_ex_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2,
++			  .trap_no	= (compat_int_t) child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo32 fault;
++
++		fault = ((struct ptrace_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt32 ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) datap,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, compat_ptr(ldt.ptr), ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
+ 
+ 	case PTRACE_GETEVENTMSG:
+ 		ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+--- linux-2.6.git/include/asm-x86_64/mmu_context.h~x86-64-specific-addition	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/mmu_context.h	2005-07-31 18:56:20.000000000 +0200
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+  * possibly do the LDT unload here?
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
++
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #ifdef CONFIG_SMP
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+@@ -37,6 +52,9 @@ static inline void switch_mm(struct mm_s
+ 			     struct task_struct *tsk)
+ {
+ 	unsigned cpu = smp_processor_id();
++#ifdef CONFIG_SMP
++	prev = read_pda(active_mm);
++#endif
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -53,8 +71,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		write_pda(mmu_state, TLBSTATE_OK);
+-		if (read_pda(active_mm) != next)
+-			out_of_line_bug();
+ 		if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+ 			 * tlb flush IPI delivery. We must reload CR3
+--- linux-2.6.git/arch/x86_64/ia32/sys_ia32.c~x86-64-specific-addition	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/ia32/sys_ia32.c	2005-07-31 18:56:20.000000000 +0200
+@@ -833,11 +833,10 @@ sys32_adjtimex(struct timex32 __user *ut
+ 	return ret;
+ }
+ 
+-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
++long do32_mmap2(struct mm_struct *mm, unsigned long addr,
++	unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	struct mm_struct *mm = current->mm;
+ 	unsigned long error;
+ 	struct file * file = NULL;
+ 
+@@ -849,7 +848,7 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	}
+ 
+ 	down_write(&mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
+ 	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+@@ -857,6 +856,15 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	return error;
+ }
+ 
++/* XXX: this wrapper can be probably removed, we can simply use the 64-bit
++ * version.*/
++asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
++	unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long pgoff)
++{
++	return do32_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++}
++
+ asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
+ {
+ 	int error;
+--- linux-2.6.git-paolo/arch/x86_64/kernel/ldt.c	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.11-paolo/arch/x86_64/kernel/ldt.c	2005-03-05 19:49:55.120753864 +0100
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, unsigned mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	unsigned oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= (unsigned)pc->size)
+ 		return 0;
+@@ -64,12 +66,14 @@
+ 
+ 		preempt_disable();
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		load_LDT(pc);
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -81,12 +85,12 @@
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -94,22 +98,24 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * 
+  * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -170,10 +175,8 @@
+ 	return bytecount; 
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct task_struct *me = current;
+-	struct mm_struct * mm = me->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -198,7 +201,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= (unsigned)mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -234,20 +237,26 @@
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return __modify_ldt(current->mm, func, ptr, bytecount);
++}
+--- linux-2.6.git/include/asm-x86_64/desc.h~x86-64-specific-addition	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/desc.h	2005-07-31 18:56:20.000000000 +0200
+@@ -213,6 +213,9 @@ static inline void load_LDT(mm_context_t
+ 
+ extern struct desc_ptr idt_descr;
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+--- linux-2.6.git-paolo/include/asm-x86_64/ptrace.h	2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-x86_64/ptrace.h	2005-07-28 19:40:18.000000000 +0200
+@@ -64,6 +64,59 @@
+ /* top of stack page */ 
+ };
+ 
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#define		compat_int_t	s32
++#define		compat_long_t	s32
++#define		compat_uint_t	u32
++#define		compat_ulong_t	u32
++#define		compat_uptr_t	u32
++
++struct ptrace_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++};
++
++struct ptrace_ex_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++	compat_int_t trap_no;
++};
++
++struct ptrace_ldt32 {
++	compat_int_t func;
++	compat_uptr_t ptr; /*Actually a void pointer on i386, but must be converted.*/
++	compat_ulong_t bytecount;
++};
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#undef	compat_int_t
++#undef	compat_long_t
++#undef	compat_uint_t
++#undef	compat_ulong_t
++#undef	compat_uptr_t
++
+ #endif
+ 
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@
+ #define PTRACE_GETFPXREGS         18
+ #define PTRACE_SETFPXREGS         19
+ 
++#define PTRACE_FAULTINFO 52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++#define PTRACE_EX_FAULTINFO	  56
++
+ /* only useful for access 32bit programs */
+ #define PTRACE_GET_THREAD_AREA    25
+ #define PTRACE_SET_THREAD_AREA    26
+--- linux-2.6.git/arch/x86_64/mm/Makefile~x86-64-specific-addition	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/mm/Makefile	2005-07-31 18:56:20.000000000 +0200
+@@ -7,5 +7,6 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag
+ obj-$(CONFIG_NUMA) += numa.o
+ obj-$(CONFIG_K8_NUMA) += k8topology.o
+ obj-$(CONFIG_ACPI_NUMA) += srat.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+ 
+ hugetlbpage-y = ../../i386/mm/hugetlbpage.o
+--- linux-2.6.git-paolo/arch/x86_64/kernel/ptrace.c	2005-07-28 19:40:10.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/kernel/ptrace.c	2005-07-28 19:40:18.000000000 +0200
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -604,6 +605,79 @@
+ 		break;
+ 	}
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	/*Don't extend this broken interface to x86-64*/
++#if 0
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++#endif
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm64(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+--- linux-2.6.git/arch/x86_64/kernel/sys_x86_64.c~x86-64-specific-addition	2005-07-31 18:56:20.000000000 +0200
++++ linux-2.6.git-paolo/arch/x86_64/kernel/sys_x86_64.c	2005-07-31 18:56:20.000000000 +0200
+@@ -19,6 +19,7 @@
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+ 
+ /*
+  * sys_pipe() is the normal C calling standard for creating
+@@ -37,7 +38,7 @@ asmlinkage long sys_pipe(int __user *fil
+ 	return error;
+ }
+ 
+-asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long off)
+ {
+ 	long error;
+@@ -55,9 +56,9 @@ asmlinkage long sys_mmap(unsigned long a
+ 		if (!file)
+ 			goto out;
+ 	}
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, off >> PAGE_SHIFT);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -65,6 +66,12 @@ out:
+ 	return error;
+ }
+ 
++asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off)
++{
++	return do64_mmap(current->mm, addr, len, prot, flags, fd, off);
++}
++
+ static void find_start_end(unsigned long flags, unsigned long *begin,
+ 			   unsigned long *end)
+ {
+--- /dev/null	2005-07-20 02:59:33.000000000 +0200
++++ linux-2.6.git-paolo/include/asm-i386/proc_mm.h	2005-07-31 18:56:20.000000000 +0200
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		unsigned long len, unsigned long prot, unsigned long flags,
++		unsigned long fd, unsigned long pgoff);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	return do_mmap2(mm, addr, len, prot, flags, fd, off >> PAGE_SHIFT);
++}
++
++#endif /* __ASM_PROC_MM */
+--- /dev/null	2005-06-27 20:00:42.865153360 +0200
++++ linux-2.6.git-paolo/mm/proc_mm-mod.c	2005-07-04 18:50:00.000000000 +0200
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#ifdef CONFIG_64BIT
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "32->" #member " \t: %ld\n", (long) offsetof(struct type ## 32, member))
++#else
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "->" #member " \t: %ld\n", (long) offsetof(struct type, member))
++#endif
++
++static int debug_printoffsets(void)
++{
++	printk(KERN_DEBUG "Skas core structures layout BEGIN:\n");
++	PRINT_OFFSET(mm_mmap, addr);
++	PRINT_OFFSET(mm_mmap, len);
++	PRINT_OFFSET(mm_mmap, prot);
++	PRINT_OFFSET(mm_mmap, flags);
++	PRINT_OFFSET(mm_mmap, fd);
++	PRINT_OFFSET(mm_mmap, offset);
++
++	PRINT_OFFSET(mm_munmap, addr);
++	PRINT_OFFSET(mm_munmap, len);
++
++	PRINT_OFFSET(mm_mprotect, addr);
++	PRINT_OFFSET(mm_mprotect, len);
++	PRINT_OFFSET(mm_mprotect, prot);
++
++	PRINT_OFFSET(proc_mm_op, op);
++	PRINT_OFFSET(proc_mm_op, u);
++	PRINT_OFFSET(proc_mm_op, u.mmap);
++	PRINT_OFFSET(proc_mm_op, u.munmap);
++	PRINT_OFFSET(proc_mm_op, u.mprotect);
++	PRINT_OFFSET(proc_mm_op, u.copy_segments);
++
++	PRINT_OFFSET(ptrace_faultinfo, is_write);
++	PRINT_OFFSET(ptrace_faultinfo, addr);
++
++	PRINT_OFFSET(ptrace_ldt, func);
++	PRINT_OFFSET(ptrace_ldt, ptr);
++	PRINT_OFFSET(ptrace_ldt, bytecount);
++	printk(KERN_DEBUG "Skas core structures layout END.\n");
++
++	return 0;
++}
++#undef PRINT_OFFSET
++
++module_init(debug_printoffsets);

Added: trunk/src/kernel-patch-skas/skas-2.6.14-v9-pre7.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.14-v9-pre7.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.14-v9-pre7.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1874 @@
+Index: linux-2.6.14/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.14.orig/arch/i386/Kconfig	2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/arch/i386/Kconfig	2005-10-29 05:50:33.000000000 +0200
+@@ -756,6 +756,26 @@
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+Index: linux-2.6.14/arch/i386/kernel/ldt.c
+===================================================================
+--- linux-2.6.14.orig/arch/i386/kernel/ldt.c	2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/arch/i386/kernel/ldt.c	2005-10-29 05:50:30.000000000 +0200
+@@ -18,6 +18,7 @@
+ #include <asm/system.h>
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -27,11 +28,12 @@
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	int oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= pc->size)
+ 		return 0;
+@@ -58,13 +60,15 @@
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -76,12 +80,12 @@
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -89,22 +93,24 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -121,11 +127,11 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -174,9 +180,8 @@
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -200,7 +205,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -230,23 +235,33 @@
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	int ret = __modify_ldt(current->mm, func, ptr, bytecount);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+Index: linux-2.6.14/arch/i386/kernel/ptrace.c
+===================================================================
+--- linux-2.6.14.orig/arch/i386/kernel/ptrace.c	2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/arch/i386/kernel/ptrace.c	2005-10-29 05:50:34.000000000 +0200
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -659,6 +660,70 @@
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+Index: linux-2.6.14/arch/i386/kernel/sys_i386.c
+===================================================================
+--- linux-2.6.14.orig/arch/i386/kernel/sys_i386.c	2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/arch/i386/kernel/sys_i386.c	2005-10-29 05:50:28.000000000 +0200
+@@ -41,7 +41,7 @@
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,12 @@
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
+ }
+ 
+ /*
+@@ -101,7 +106,10 @@
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(err);
+ out:
+ 	return err;
+ }
+Index: linux-2.6.14/arch/um/include/skas_ptrace.h
+===================================================================
+--- linux-2.6.14.orig/arch/um/include/skas_ptrace.h	2005-10-29 05:49:33.000000000 +0200
++++ linux-2.6.14/arch/um/include/skas_ptrace.h	2005-10-29 05:50:00.000000000 +0200
+@@ -6,6 +6,8 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
++
+ #define PTRACE_FAULTINFO 52
+ #define PTRACE_SWITCH_MM 55
+ 
+@@ -13,6 +15,8 @@
+ 
+ #endif
+ 
++#endif
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+Index: linux-2.6.14/arch/x86_64/ia32/ptrace32.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/ia32/ptrace32.c	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/ia32/ptrace32.c	2005-10-29 05:50:34.000000000 +0200
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+ 
+ /* determines which flags the user has access to. */
+ /* 1 = access 0 = no access */
+@@ -251,6 +254,11 @@
+ 	case PTRACE_SETFPXREGS:
+ 	case PTRACE_GETFPXREGS:
+ 	case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO:
++	case PTRACE_LDT:
++	case PTRACE_SWITCH_MM:
++#endif
+ 		break;
+ 	} 
+ 
+@@ -363,6 +371,65 @@
+ 		ret = 0; 
+ 		break;
+ 	}
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo32 fault;
++
++		fault = ((struct ptrace_ex_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2,
++			  .trap_no	= (compat_int_t) child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo32 fault;
++
++		fault = ((struct ptrace_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt32 ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) datap,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, compat_ptr(ldt.ptr), ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
+ 
+ 	case PTRACE_GETEVENTMSG:
+ 		ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+Index: linux-2.6.14/arch/x86_64/ia32/sys_ia32.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/ia32/sys_ia32.c	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/ia32/sys_ia32.c	2005-10-29 05:50:31.000000000 +0200
+@@ -833,11 +833,10 @@
+ 	return ret;
+ }
+ 
+-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
++long do32_mmap2(struct mm_struct *mm, unsigned long addr,
++	unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	struct mm_struct *mm = current->mm;
+ 	unsigned long error;
+ 	struct file * file = NULL;
+ 
+@@ -849,7 +848,7 @@
+ 	}
+ 
+ 	down_write(&mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
+ 	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+@@ -857,6 +856,15 @@
+ 	return error;
+ }
+ 
++/* XXX: this wrapper can be probably removed, we can simply use the 64-bit
++ * version.*/
++asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
++	unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long pgoff)
++{
++	return do32_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++}
++
+ asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
+ {
+ 	int error;
+Index: linux-2.6.14/arch/x86_64/Kconfig
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/Kconfig	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/Kconfig	2005-10-29 05:50:33.000000000 +0200
+@@ -357,6 +357,26 @@
+ 	  of memory and any 32-bit devices. Don't turn on unless you know what you
+ 	  are doing.
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ config X86_MCE
+ 	bool "Machine check support" if EMBEDDED
+ 	default y
+Index: linux-2.6.14/arch/x86_64/kernel/ldt.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/kernel/ldt.c	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/kernel/ldt.c	2005-10-29 05:50:33.000000000 +0200
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, unsigned mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	unsigned oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= (unsigned)pc->size)
+ 		return 0;
+@@ -64,12 +66,14 @@
+ 
+ 		preempt_disable();
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		load_LDT(pc);
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -81,12 +85,12 @@
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -94,22 +98,24 @@
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * 
+  * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -170,10 +175,8 @@
+ 	return bytecount; 
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct task_struct *me = current;
+-	struct mm_struct * mm = me->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -198,7 +201,7 @@
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= (unsigned)mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -231,23 +234,29 @@
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return __modify_ldt(current->mm, func, ptr, bytecount);
++}
+Index: linux-2.6.14/arch/x86_64/kernel/ptrace.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/kernel/ptrace.c	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/kernel/ptrace.c	2005-10-29 05:50:34.000000000 +0200
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -604,6 +605,79 @@
+ 		break;
+ 	}
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++
++	/*Don't extend this broken interface to x86-64*/
++#if 0
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		if(ret)
++			break;
++		break;
++	}
++#endif
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm64(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+Index: linux-2.6.14/arch/x86_64/kernel/sys_x86_64.c
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/kernel/sys_x86_64.c	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/kernel/sys_x86_64.c	2005-10-29 05:50:31.000000000 +0200
+@@ -19,6 +19,7 @@
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+ 
+ /*
+  * sys_pipe() is the normal C calling standard for creating
+@@ -37,7 +38,7 @@
+ 	return error;
+ }
+ 
+-asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long off)
+ {
+ 	long error;
+@@ -55,9 +56,9 @@
+ 		if (!file)
+ 			goto out;
+ 	}
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, off >> PAGE_SHIFT);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -65,6 +66,12 @@
+ 	return error;
+ }
+ 
++asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off)
++{
++	return do64_mmap(current->mm, addr, len, prot, flags, fd, off);
++}
++
+ static void find_start_end(unsigned long flags, unsigned long *begin,
+ 			   unsigned long *end)
+ {
+Index: linux-2.6.14/arch/x86_64/mm/Makefile
+===================================================================
+--- linux-2.6.14.orig/arch/x86_64/mm/Makefile	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/arch/x86_64/mm/Makefile	2005-10-29 05:50:31.000000000 +0200
+@@ -7,5 +7,6 @@
+ obj-$(CONFIG_NUMA) += numa.o
+ obj-$(CONFIG_K8_NUMA) += k8topology.o
+ obj-$(CONFIG_ACPI_NUMA) += srat.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+ 
+ hugetlbpage-y = ../../i386/mm/hugetlbpage.o
+Index: linux-2.6.14/arch/x86_64/mm/proc_mm.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/arch/x86_64/mm/proc_mm.c	2005-10-29 05:50:31.000000000 +0200
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op32 req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap32 *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap32 *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect32 *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_emul(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
+Index: linux-2.6.14/include/asm-i386/desc.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-i386/desc.h	2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/include/asm-i386/desc.h	2005-10-29 05:50:06.000000000 +0200
+@@ -156,6 +156,9 @@
+ 	return base;
+ }
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+Index: linux-2.6.14/include/asm-i386/mmu_context.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-i386/mmu_context.h	2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/include/asm-i386/mmu_context.h	2005-10-29 05:50:11.000000000 +0200
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+Index: linux-2.6.14/include/asm-i386/proc_mm.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/include/asm-i386/proc_mm.h	2005-10-29 05:50:31.000000000 +0200
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		unsigned long len, unsigned long prot, unsigned long flags,
++		unsigned long fd, unsigned long pgoff);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	return do_mmap2(mm, addr, len, prot, flags, fd, off >> PAGE_SHIFT);
++}
++
++#endif /* __ASM_PROC_MM */
+Index: linux-2.6.14/include/asm-i386/ptrace.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-i386/ptrace.h	2005-10-29 05:49:31.000000000 +0200
++++ linux-2.6.14/include/asm-i386/ptrace.h	2005-10-29 05:50:34.000000000 +0200
+@@ -84,4 +84,33 @@
+ #endif
+ #endif /* __KERNEL__ */
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++#define PTRACE_EX_FAULTINFO	  56
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+Index: linux-2.6.14/include/asm-i386/thread_info.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-i386/thread_info.h	2005-10-29 05:49:28.000000000 +0200
++++ linux-2.6.14/include/asm-i386/thread_info.h	2005-10-29 05:50:29.000000000 +0200
+@@ -139,9 +139,9 @@
+ #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+ #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
+ #define TIF_IRET		5	/* return with iret */
+-#define TIF_SYSCALL_EMU		6	/* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_SECCOMP		8	/* secure computing */
++#define TIF_SYSCALL_EMU		9	/* syscall emulation active */
+ #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE		17
+ 
+Index: linux-2.6.14/include/asm-x86_64/desc.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-x86_64/desc.h	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/include/asm-x86_64/desc.h	2005-10-29 05:50:31.000000000 +0200
+@@ -215,6 +215,9 @@
+ 
+ extern struct desc_ptr idt_descr;
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+Index: linux-2.6.14/include/asm-x86_64/mmu_context.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-x86_64/mmu_context.h	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/include/asm-x86_64/mmu_context.h	2005-10-29 05:50:31.000000000 +0200
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+  * possibly do the LDT unload here?
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
++
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #ifdef CONFIG_SMP
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+@@ -37,6 +52,9 @@
+ 			     struct task_struct *tsk)
+ {
+ 	unsigned cpu = smp_processor_id();
++#ifdef CONFIG_SMP
++	prev = read_pda(active_mm);
++#endif
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -53,8 +71,6 @@
+ #ifdef CONFIG_SMP
+ 	else {
+ 		write_pda(mmu_state, TLBSTATE_OK);
+-		if (read_pda(active_mm) != next)
+-			out_of_line_bug();
+ 		if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+ 			 * tlb flush IPI delivery. We must reload CR3
+Index: linux-2.6.14/include/asm-x86_64/proc_mm.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/include/asm-x86_64/proc_mm.h	2005-10-29 05:50:31.000000000 +0200
+@@ -0,0 +1,56 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++struct mm_mmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++	compat_ulong_t prot;
++	compat_ulong_t flags;
++	compat_ulong_t fd;
++	compat_ulong_t offset;
++};
++
++struct mm_munmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++};
++
++struct mm_mprotect32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++        compat_uint_t prot;
++};
++
++struct proc_mm_op32 {
++	compat_int_t op;
++	union {
++		struct mm_mmap32 mmap;
++		struct mm_munmap32 munmap;
++	        struct mm_mprotect32 mprotect;
++		compat_int_t copy_segments;
++	} u;
++};
++
++extern ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos);
++
++extern long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	/* The latter one is stricter, since will actually check that off is page
++	 * aligned. The first one skipped the check. */
++
++	/* return do32_mmap2(mm, addr, len, prot, flags, fd, off >>
++	 * PAGE_SHIFT);*/
++	return do64_mmap(mm, addr, len, prot, flags, fd, off);
++}
++
++#endif /* __ASM_PROC_MM */
+Index: linux-2.6.14/include/asm-x86_64/ptrace.h
+===================================================================
+--- linux-2.6.14.orig/include/asm-x86_64/ptrace.h	2005-10-29 05:49:27.000000000 +0200
++++ linux-2.6.14/include/asm-x86_64/ptrace.h	2005-10-29 05:50:34.000000000 +0200
+@@ -64,6 +64,59 @@
+ /* top of stack page */ 
+ };
+ 
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#define		compat_int_t	s32
++#define		compat_long_t	s32
++#define		compat_uint_t	u32
++#define		compat_ulong_t	u32
++#define		compat_uptr_t	u32
++
++struct ptrace_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++};
++
++struct ptrace_ex_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++	compat_int_t trap_no;
++};
++
++struct ptrace_ldt32 {
++	compat_int_t func;
++	compat_uptr_t ptr; /*Actually a void pointer on i386, but must be converted.*/
++	compat_ulong_t bytecount;
++};
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#undef	compat_int_t
++#undef	compat_long_t
++#undef	compat_uint_t
++#undef	compat_ulong_t
++#undef	compat_uptr_t
++
+ #endif
+ 
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@
+ #define PTRACE_GETFPXREGS         18
+ #define PTRACE_SETFPXREGS         19
+ 
++#define PTRACE_FAULTINFO 52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++#define PTRACE_EX_FAULTINFO	  56
++
+ /* only useful for access 32bit programs */
+ #define PTRACE_GET_THREAD_AREA    25
+ #define PTRACE_SET_THREAD_AREA    26
+Index: linux-2.6.14/include/linux/mm.h
+===================================================================
+--- linux-2.6.14.orig/include/linux/mm.h	2005-10-29 05:49:33.000000000 +0200
++++ linux-2.6.14/include/linux/mm.h	2005-10-29 05:50:00.000000000 +0200
+@@ -759,6 +759,9 @@
+ extern struct shrinker *set_shrinker(int, shrinker_t);
+ extern void remove_shrinker(struct shrinker *shrinker);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * On a two-level or three-level page table, this ends up being trivial. Thus
+  * the inlining and the symmetry break with pte_alloc_map() that does all
+@@ -841,9 +844,15 @@
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+Index: linux-2.6.14/include/linux/proc_mm.h
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/include/linux/proc_mm.h	2005-10-29 05:50:33.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* The differences between this one and do_mmap are that:
++ * - we must perform controls for userspace-supplied params (which are
++ *   arch-specific currently). And also fget(fd) if needed and so on...
++ * - we must accept the struct mm_struct on which to act as first param, and the
++ *   offset in byte rather than page units as last param.
++ */
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off);
++
++/* This header can be used only on archs defining CONFIG_PROC_MM in their
++ * configs, so asm/proc_mm.h can still exist only for the needed archs.
++ * Including it only in the x86-64 case does not make sense.*/
++#include <asm/proc_mm.h>
++
++/*XXX: this is defined on x86_64, but not on every 64-bit arch (not on sh64).*/
++#ifdef CONFIG_64BIT
++
++#define write_proc_mm write_proc_mm_emul
++#define write_proc_mm64 write_proc_mm_native
++
++/* It would make more sense to do this mapping the reverse direction, to map the
++ * called name to the defined one and not the reverse. Like the 2nd example
++ */
++/*#define proc_mm_get_mm proc_mm_get_mm_emul
++#define proc_mm_get_mm64 proc_mm_get_mm_native*/
++
++#define proc_mm_get_mm_emul proc_mm_get_mm
++#define proc_mm_get_mm_native proc_mm_get_mm64
++
++#else
++
++#define write_proc_mm write_proc_mm_native
++#undef write_proc_mm64
++
++/*#define proc_mm_get_mm proc_mm_get_mm_native
++#undef proc_mm_get_mm64*/
++
++#define proc_mm_get_mm_native proc_mm_get_mm
++#undef proc_mm_get_mm_emul
++
++#endif
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++/* Cope with older kernels */
++#ifndef __acquires
++#define __acquires(x)
++#endif
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/*
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++extern void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock);
++#else
++static inline void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock)
++{
++	task_lock(child);
++}
++#endif
++
++#endif
+Index: linux-2.6.14/localversion-skas
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/localversion-skas	2005-10-29 05:50:35.000000000 +0200
+@@ -0,0 +1 @@
++-skas3-v9-pre7
+Index: linux-2.6.14/mm/Makefile
+===================================================================
+--- linux-2.6.14.orig/mm/Makefile	2005-10-29 05:49:32.000000000 +0200
++++ linux-2.6.14/mm/Makefile	2005-10-29 05:50:34.000000000 +0200
+@@ -20,3 +20,9 @@
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+ 
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
++
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m			+= proc_mm-mod.o
++endif
+Index: linux-2.6.14/mm/mmap.c
+===================================================================
+--- linux-2.6.14.orig/mm/mmap.c	2005-10-29 05:49:32.000000000 +0200
++++ linux-2.6.14/mm/mmap.c	2005-10-29 05:50:00.000000000 +0200
+@@ -861,11 +861,11 @@
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1140,7 +1140,7 @@
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+Index: linux-2.6.14/mm/mprotect.c
+===================================================================
+--- linux-2.6.14.orig/mm/mprotect.c	2005-10-29 05:49:32.000000000 +0200
++++ linux-2.6.14/mm/mprotect.c	2005-10-29 05:50:30.000000000 +0200
+@@ -177,8 +177,9 @@
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp, reqprot;
+ 	struct vm_area_struct *vma, *prev;
+@@ -209,9 +210,9 @@
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -278,6 +279,15 @@
+ 		}
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	long ret = do_mprotect(current->mm, start, len, prot);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+Index: linux-2.6.14/mm/proc_mm.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/mm/proc_mm.c	2005-10-29 05:50:33.000000000 +0200
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/proc_mm.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/* Checks if a task must be considered dumpable
++ *
++ * XXX: copied from fs/proc/base.c, removed task_lock, added rmb(): this must be
++ * called with task_lock(task) held. */
++static int task_dumpable(struct task_struct *task)
++{
++	int dumpable = 0;
++	struct mm_struct *mm;
++
++	mm = task->mm;
++	if (mm) {
++		rmb();
++		dumpable = mm->dumpable;
++	}
++	return dumpable;
++}
++
++/*
++ * This is to be used in PTRACE_SWITCH_MM handling. We are going to set
++ * child->mm to new, and we must first correctly set new->dumpable.
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++void lock_fix_dumpable_setting(struct task_struct* child, struct mm_struct* new)
++	__acquires(child->alloc_lock)
++{
++	int dumpable = 1;
++
++	/* We must be safe.
++	 * If the child is ptraced from a non-dumpable process,
++	 * let's not be dumpable. If the child is non-dumpable itself,
++	 * copy this property across mm's.
++	 *
++	 * Don't try to be smart for the opposite case and turn
++	 * child->mm->dumpable to 1: I've not made sure it is safe.
++	 */
++
++	task_lock(current);
++	if (unlikely(!task_dumpable(current))) {
++		dumpable = 0;
++	}
++	task_unlock(current);
++
++	task_lock(child);
++	if (likely(dumpable) && unlikely(!task_dumpable(child))) {
++		dumpable = 0;
++	}
++
++	if (!dumpable) {
++		new->dumpable = 0;
++		wmb();
++	}
++}
++#endif
++
++/* Naming conventions are a mess, so I note them down.
++ *
++ * Things ending in _mm can be for everything. It's only for
++ * {open,release}_proc_mm.
++ *
++ * For the rest:
++ *
++ * _mm means /proc/mm, _mm64 means /proc/mm64. This is for the infrastructure
++ * only (for instance proc_mm_get_mm checks whether the file is /proc/mm or
++ * /proc/mm64; for instance the /proc handling).
++ *
++ * While for what is conversion dependant, we use the suffix _native and _emul.
++ * In some cases, there is a mapping between these ones (defined by
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++	mm->dumpable = current->mm->dumpable;
++	wmb();
++#endif
++
++	file->private_data = mm;
++
++	return 0;
++
++out_mem:
++	return ret;
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return 0;
++}
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++static ssize_t write_proc_mm_native(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_native(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
++/*These three are all for /proc/mm.*/
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++/*Macro-ify it to avoid the duplication.*/
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm);
++
++/*XXX: change the option.*/
++#ifdef CONFIG_64BIT
++static struct file_operations proc_mm64_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm64,
++};
++
++static int make_proc_mm64(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm64", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm64\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm64_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm64);
++
++struct mm_struct *proc_mm_get_mm64(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	/*This is the only change.*/
++	if(file->f_op != &proc_mm64_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.6.14/mm/proc_mm-mod.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.14/mm/proc_mm-mod.c	2005-10-29 05:50:34.000000000 +0200
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#ifdef CONFIG_64BIT
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "32->" #member " \t: %ld\n", (long) offsetof(struct type ## 32, member))
++#else
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "->" #member " \t: %ld\n", (long) offsetof(struct type, member))
++#endif
++
++static int debug_printoffsets(void)
++{
++	printk(KERN_DEBUG "Skas core structures layout BEGIN:\n");
++	PRINT_OFFSET(mm_mmap, addr);
++	PRINT_OFFSET(mm_mmap, len);
++	PRINT_OFFSET(mm_mmap, prot);
++	PRINT_OFFSET(mm_mmap, flags);
++	PRINT_OFFSET(mm_mmap, fd);
++	PRINT_OFFSET(mm_mmap, offset);
++
++	PRINT_OFFSET(mm_munmap, addr);
++	PRINT_OFFSET(mm_munmap, len);
++
++	PRINT_OFFSET(mm_mprotect, addr);
++	PRINT_OFFSET(mm_mprotect, len);
++	PRINT_OFFSET(mm_mprotect, prot);
++
++	PRINT_OFFSET(proc_mm_op, op);
++	PRINT_OFFSET(proc_mm_op, u);
++	PRINT_OFFSET(proc_mm_op, u.mmap);
++	PRINT_OFFSET(proc_mm_op, u.munmap);
++	PRINT_OFFSET(proc_mm_op, u.mprotect);
++	PRINT_OFFSET(proc_mm_op, u.copy_segments);
++
++	PRINT_OFFSET(ptrace_faultinfo, is_write);
++	PRINT_OFFSET(ptrace_faultinfo, addr);
++
++	PRINT_OFFSET(ptrace_ldt, func);
++	PRINT_OFFSET(ptrace_ldt, ptr);
++	PRINT_OFFSET(ptrace_ldt, bytecount);
++	printk(KERN_DEBUG "Skas core structures layout END.\n");
++
++	return 0;
++}
++#undef PRINT_OFFSET
++
++module_init(debug_printoffsets);

Added: trunk/src/kernel-patch-skas/skas-2.6.15-v9-pre8.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.15-v9-pre8.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.15-v9-pre8.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1860 @@
+Index: linux-2.6.15/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.15.orig/arch/i386/Kconfig
++++ linux-2.6.15/arch/i386/Kconfig
+@@ -458,6 +458,26 @@ config X86_PAE
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+Index: linux-2.6.15/arch/i386/kernel/ldt.c
+===================================================================
+--- linux-2.6.15.orig/arch/i386/kernel/ldt.c
++++ linux-2.6.15/arch/i386/kernel/ldt.c
+@@ -28,11 +28,12 @@ static void flush_ldt(void *null)
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	int oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= pc->size)
+ 		return 0;
+@@ -59,13 +60,15 @@ static int alloc_ldt(mm_context_t *pc, i
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -77,12 +80,12 @@ static int alloc_ldt(mm_context_t *pc, i
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -90,22 +93,24 @@ static inline int copy_ldt(mm_context_t 
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -122,11 +127,11 @@ void destroy_context(struct mm_struct *m
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -175,9 +180,8 @@ static int read_default_ldt(void __user 
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -201,7 +205,7 @@ static int write_ldt(void __user * ptr, 
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -231,23 +235,33 @@ out:
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	int ret = __modify_ldt(current->mm, func, ptr, bytecount);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+Index: linux-2.6.15/arch/i386/kernel/ptrace.c
+===================================================================
+--- linux-2.6.15.orig/arch/i386/kernel/ptrace.c
++++ linux-2.6.15/arch/i386/kernel/ptrace.c
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -622,6 +623,66 @@ long arch_ptrace(struct task_struct *chi
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+Index: linux-2.6.15/arch/i386/kernel/sys_i386.c
+===================================================================
+--- linux-2.6.15.orig/arch/i386/kernel/sys_i386.c
++++ linux-2.6.15/arch/i386/kernel/sys_i386.c
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,12 @@ asmlinkage long sys_mmap2(unsigned long 
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
+ }
+ 
+ /*
+@@ -101,7 +106,10 @@ asmlinkage int old_mmap(struct mmap_arg_
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(err);
+ out:
+ 	return err;
+ }
+Index: linux-2.6.15/arch/um/include/skas_ptrace.h
+===================================================================
+--- linux-2.6.15.orig/arch/um/include/skas_ptrace.h
++++ linux-2.6.15/arch/um/include/skas_ptrace.h
+@@ -6,6 +6,8 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
++
+ #define PTRACE_FAULTINFO 52
+ #define PTRACE_SWITCH_MM 55
+ 
+@@ -13,6 +15,8 @@
+ 
+ #endif
+ 
++#endif
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+Index: linux-2.6.15/arch/x86_64/ia32/ptrace32.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/ia32/ptrace32.c
++++ linux-2.6.15/arch/x86_64/ia32/ptrace32.c
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+ 
+ /* determines which flags the user has access to. */
+ /* 1 = access 0 = no access */
+@@ -251,6 +254,11 @@ asmlinkage long sys32_ptrace(long reques
+ 	case PTRACE_SETFPXREGS:
+ 	case PTRACE_GETFPXREGS:
+ 	case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++	case PTRACE_FAULTINFO:
++	case PTRACE_LDT:
++	case PTRACE_SWITCH_MM:
++#endif
+ 		break;
+ 	} 
+ 
+@@ -363,6 +371,65 @@ asmlinkage long sys32_ptrace(long reques
+ 		ret = 0; 
+ 		break;
+ 	}
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo32 fault;
++
++		fault = ((struct ptrace_ex_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2,
++			  .trap_no	= (compat_int_t) child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo32 fault;
++
++		fault = ((struct ptrace_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt32 ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) datap,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, compat_ptr(ldt.ptr), ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
+ 
+ 	case PTRACE_GETEVENTMSG:
+ 		ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+Index: linux-2.6.15/arch/x86_64/ia32/sys_ia32.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/ia32/sys_ia32.c
++++ linux-2.6.15/arch/x86_64/ia32/sys_ia32.c
+@@ -833,11 +833,10 @@ sys32_adjtimex(struct timex32 __user *ut
+ 	return ret;
+ }
+ 
+-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
++long do32_mmap2(struct mm_struct *mm, unsigned long addr,
++	unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	struct mm_struct *mm = current->mm;
+ 	unsigned long error;
+ 	struct file * file = NULL;
+ 
+@@ -849,7 +848,7 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	}
+ 
+ 	down_write(&mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
+ 	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+@@ -857,6 +856,15 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	return error;
+ }
+ 
++/* XXX: this wrapper can be probably removed, we can simply use the 64-bit
++ * version.*/
++asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
++	unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long pgoff)
++{
++	return do32_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++}
++
+ asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
+ {
+ 	int error;
+Index: linux-2.6.15/arch/x86_64/Kconfig
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/Kconfig
++++ linux-2.6.15/arch/x86_64/Kconfig
+@@ -374,6 +374,26 @@ config DUMMY_IOMMU
+ 	  of memory and any 32-bit devices. Don't turn on unless you know what you
+ 	  are doing.
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ config X86_MCE
+ 	bool "Machine check support" if EMBEDDED
+ 	default y
+Index: linux-2.6.15/arch/x86_64/kernel/ldt.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/kernel/ldt.c
++++ linux-2.6.15/arch/x86_64/kernel/ldt.c
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@ static void flush_ldt(void *null)
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, unsigned mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	unsigned oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= (unsigned)pc->size)
+ 		return 0;
+@@ -64,12 +66,14 @@ static int alloc_ldt(mm_context_t *pc, u
+ 
+ 		preempt_disable();
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		load_LDT(pc);
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -81,12 +85,12 @@ static int alloc_ldt(mm_context_t *pc, u
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -94,22 +98,24 @@ static inline int copy_ldt(mm_context_t 
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * 
+  * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@ void destroy_context(struct mm_struct *m
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -170,10 +175,8 @@ static int read_default_ldt(void __user 
+ 	return bytecount; 
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct task_struct *me = current;
+-	struct mm_struct * mm = me->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -198,7 +201,7 @@ static int write_ldt(void __user * ptr, 
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= (unsigned)mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -231,23 +234,29 @@ out:
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return __modify_ldt(current->mm, func, ptr, bytecount);
++}
+Index: linux-2.6.15/arch/x86_64/kernel/ptrace.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/kernel/ptrace.c
++++ linux-2.6.15/arch/x86_64/kernel/ptrace.c
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -567,6 +568,75 @@ long arch_ptrace(struct task_struct *chi
+ 		break;
+ 	}
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	/*Don't extend this broken interface to x86-64*/
++#if 0
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++#endif
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm64(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+Index: linux-2.6.15/arch/x86_64/kernel/sys_x86_64.c
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/kernel/sys_x86_64.c
++++ linux-2.6.15/arch/x86_64/kernel/sys_x86_64.c
+@@ -19,6 +19,7 @@
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+ 
+ /*
+  * sys_pipe() is the normal C calling standard for creating
+@@ -37,7 +38,7 @@ asmlinkage long sys_pipe(int __user *fil
+ 	return error;
+ }
+ 
+-asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long off)
+ {
+ 	long error;
+@@ -55,9 +56,9 @@ asmlinkage long sys_mmap(unsigned long a
+ 		if (!file)
+ 			goto out;
+ 	}
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, off >> PAGE_SHIFT);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -65,6 +66,12 @@ out:
+ 	return error;
+ }
+ 
++asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off)
++{
++	return do64_mmap(current->mm, addr, len, prot, flags, fd, off);
++}
++
+ static void find_start_end(unsigned long flags, unsigned long *begin,
+ 			   unsigned long *end)
+ {
+Index: linux-2.6.15/arch/x86_64/mm/Makefile
+===================================================================
+--- linux-2.6.15.orig/arch/x86_64/mm/Makefile
++++ linux-2.6.15/arch/x86_64/mm/Makefile
+@@ -7,5 +7,6 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag
+ obj-$(CONFIG_NUMA) += numa.o
+ obj-$(CONFIG_K8_NUMA) += k8topology.o
+ obj-$(CONFIG_ACPI_NUMA) += srat.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+ 
+ hugetlbpage-y = ../../i386/mm/hugetlbpage.o
+Index: linux-2.6.15/arch/x86_64/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.15/arch/x86_64/mm/proc_mm.c
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op32 req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap32 *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap32 *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect32 *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_emul(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
+Index: linux-2.6.15/include/asm-i386/desc.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-i386/desc.h
++++ linux-2.6.15/include/asm-i386/desc.h
+@@ -158,6 +158,9 @@ static inline unsigned long get_desc_bas
+ 	return base;
+ }
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+Index: linux-2.6.15/include/asm-i386/mmu_context.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-i386/mmu_context.h
++++ linux-2.6.15/include/asm-i386/mmu_context.h
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@ static inline void switch_mm(struct mm_s
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+Index: linux-2.6.15/include/asm-i386/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.15/include/asm-i386/proc_mm.h
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		unsigned long len, unsigned long prot, unsigned long flags,
++		unsigned long fd, unsigned long pgoff);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	return do_mmap2(mm, addr, len, prot, flags, fd, off >> PAGE_SHIFT);
++}
++
++#endif /* __ASM_PROC_MM */
+Index: linux-2.6.15/include/asm-i386/ptrace.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-i386/ptrace.h
++++ linux-2.6.15/include/asm-i386/ptrace.h
+@@ -84,4 +84,33 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif /* __KERNEL__ */
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++#define PTRACE_EX_FAULTINFO	  56
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+Index: linux-2.6.15/include/asm-i386/thread_info.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-i386/thread_info.h
++++ linux-2.6.15/include/asm-i386/thread_info.h
+@@ -139,9 +139,9 @@ register unsigned long current_stack_poi
+ #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+ #define TIF_SINGLESTEP		4	/* restore singlestep on return to user mode */
+ #define TIF_IRET		5	/* return with iret */
+-#define TIF_SYSCALL_EMU		6	/* syscall emulation active */
+ #define TIF_SYSCALL_AUDIT	7	/* syscall auditing active */
+ #define TIF_SECCOMP		8	/* secure computing */
++#define TIF_SYSCALL_EMU		9	/* syscall emulation active */
+ #define TIF_POLLING_NRFLAG	16	/* true if poll_idle() is polling TIF_NEED_RESCHED */
+ #define TIF_MEMDIE		17
+ 
+Index: linux-2.6.15/include/asm-x86_64/desc.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-x86_64/desc.h
++++ linux-2.6.15/include/asm-x86_64/desc.h
+@@ -225,6 +225,9 @@ static inline void load_LDT(mm_context_t
+ 
+ extern struct desc_ptr idt_descr;
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+Index: linux-2.6.15/include/asm-x86_64/mmu_context.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-x86_64/mmu_context.h
++++ linux-2.6.15/include/asm-x86_64/mmu_context.h
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+  * possibly do the LDT unload here?
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
++
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ #ifdef CONFIG_SMP
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+@@ -37,6 +52,9 @@ static inline void switch_mm(struct mm_s
+ 			     struct task_struct *tsk)
+ {
+ 	unsigned cpu = smp_processor_id();
++#ifdef CONFIG_SMP
++	prev = read_pda(active_mm);
++#endif
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -53,8 +71,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		write_pda(mmu_state, TLBSTATE_OK);
+-		if (read_pda(active_mm) != next)
+-			out_of_line_bug();
+ 		if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+ 			 * tlb flush IPI delivery. We must reload CR3
+Index: linux-2.6.15/include/asm-x86_64/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.15/include/asm-x86_64/proc_mm.h
+@@ -0,0 +1,58 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++struct mm_mmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++	compat_ulong_t prot;
++	compat_ulong_t flags;
++	compat_ulong_t fd;
++	compat_ulong_t offset;
++};
++
++struct mm_munmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++};
++
++struct mm_mprotect32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++        compat_uint_t prot;
++};
++
++struct proc_mm_op32 {
++	compat_int_t op;
++	union {
++		struct mm_mmap32 mmap;
++		struct mm_munmap32 munmap;
++	        struct mm_mprotect32 mprotect;
++		compat_int_t copy_segments;
++	} u;
++};
++
++extern ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos);
++
++extern struct mm_struct *proc_mm_get_mm64(int fd);
++
++extern long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	/* The latter one is stricter, since will actually check that off is page
++	 * aligned. The first one skipped the check. */
++
++	/* return do32_mmap2(mm, addr, len, prot, flags, fd, off >>
++	 * PAGE_SHIFT);*/
++	return do64_mmap(mm, addr, len, prot, flags, fd, off);
++}
++
++#endif /* __ASM_PROC_MM */
+Index: linux-2.6.15/include/asm-x86_64/ptrace.h
+===================================================================
+--- linux-2.6.15.orig/include/asm-x86_64/ptrace.h
++++ linux-2.6.15/include/asm-x86_64/ptrace.h
+@@ -64,6 +64,59 @@ struct pt_regs {
+ /* top of stack page */ 
+ };
+ 
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#define		compat_int_t	s32
++#define		compat_long_t	s32
++#define		compat_uint_t	u32
++#define		compat_ulong_t	u32
++#define		compat_uptr_t	u32
++
++struct ptrace_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++};
++
++struct ptrace_ex_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++	compat_int_t trap_no;
++};
++
++struct ptrace_ldt32 {
++	compat_int_t func;
++	compat_uptr_t ptr; /*Actually a void pointer on i386, but must be converted.*/
++	compat_ulong_t bytecount;
++};
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#undef	compat_int_t
++#undef	compat_long_t
++#undef	compat_uint_t
++#undef	compat_ulong_t
++#undef	compat_uptr_t
++
+ #endif
+ 
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@ struct pt_regs {
+ #define PTRACE_GETFPXREGS         18
+ #define PTRACE_SETFPXREGS         19
+ 
++#define PTRACE_FAULTINFO 52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++#define PTRACE_EX_FAULTINFO	  56
++
+ /* only useful for access 32bit programs */
+ #define PTRACE_GET_THREAD_AREA    25
+ #define PTRACE_SET_THREAD_AREA    26
+Index: linux-2.6.15/include/linux/mm.h
+===================================================================
+--- linux-2.6.15.orig/include/linux/mm.h
++++ linux-2.6.15/include/linux/mm.h
+@@ -719,6 +719,9 @@ extern unsigned long do_mremap(unsigned 
+ 			       unsigned long old_len, unsigned long new_len,
+ 			       unsigned long flags, unsigned long new_addr);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ /*
+  * Prototype to add a shrinker callback for ageable caches.
+  * 
+@@ -872,9 +875,15 @@ extern int may_expand_vm(struct mm_struc
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+Index: linux-2.6.15/include/linux/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.15/include/linux/proc_mm.h
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* The differences between this one and do_mmap are that:
++ * - we must perform controls for userspace-supplied params (which are
++ *   arch-specific currently). And also fget(fd) if needed and so on...
++ * - we must accept the struct mm_struct on which to act as first param, and the
++ *   offset in byte rather than page units as last param.
++ */
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off);
++
++/* This header can be used only on archs defining CONFIG_PROC_MM in their
++ * configs, so asm/proc_mm.h can still exist only for the needed archs.
++ * Including it only in the x86-64 case does not make sense.*/
++#include <asm/proc_mm.h>
++
++/*XXX: this is defined on x86_64, but not on every 64-bit arch (not on sh64).*/
++#ifdef CONFIG_64BIT
++
++#define write_proc_mm write_proc_mm_emul
++#define write_proc_mm64 write_proc_mm_native
++
++/* It would make more sense to do this mapping the reverse direction, to map the
++ * called name to the defined one and not the reverse. Like the 2nd example
++ */
++/*#define proc_mm_get_mm proc_mm_get_mm_emul
++#define proc_mm_get_mm64 proc_mm_get_mm_native*/
++
++#define proc_mm_get_mm_emul proc_mm_get_mm
++#define proc_mm_get_mm_native proc_mm_get_mm64
++
++#else
++
++#define write_proc_mm write_proc_mm_native
++#undef write_proc_mm64
++
++/*#define proc_mm_get_mm proc_mm_get_mm_native
++#undef proc_mm_get_mm64*/
++
++#define proc_mm_get_mm_native proc_mm_get_mm
++#undef proc_mm_get_mm_emul
++
++#endif
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++/* Cope with older kernels */
++#ifndef __acquires
++#define __acquires(x)
++#endif
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/*
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++extern void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock);
++#else
++static inline void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock)
++{
++	task_lock(child);
++}
++#endif
++
++#endif
+Index: linux-2.6.15/localversion-skas
+===================================================================
+--- /dev/null
++++ linux-2.6.15/localversion-skas
+@@ -0,0 +1 @@
++-skas3-v9-pre8
+Index: linux-2.6.15/mm/Makefile
+===================================================================
+--- linux-2.6.15.orig/mm/Makefile
++++ linux-2.6.15/mm/Makefile
+@@ -20,3 +20,9 @@ obj-$(CONFIG_SHMEM) += shmem.o
+ obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
++
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m			+= proc_mm-mod.o
++endif
+Index: linux-2.6.15/mm/mmap.c
+===================================================================
+--- linux-2.6.15.orig/mm/mmap.c
++++ linux-2.6.15/mm/mmap.c
+@@ -867,11 +867,11 @@ void vm_stat_account(struct mm_struct *m
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1146,7 +1146,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+Index: linux-2.6.15/mm/mprotect.c
+===================================================================
+--- linux-2.6.15.orig/mm/mprotect.c
++++ linux-2.6.15/mm/mprotect.c
+@@ -176,8 +176,9 @@ fail:
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp, reqprot;
+ 	struct vm_area_struct *vma, *prev;
+@@ -208,9 +209,9 @@ sys_mprotect(unsigned long start, size_t
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -277,6 +278,15 @@ sys_mprotect(unsigned long start, size_t
+ 		}
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	long ret = do_mprotect(current->mm, start, len, prot);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+Index: linux-2.6.15/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.15/mm/proc_mm.c
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/proc_mm.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/* Checks if a task must be considered dumpable
++ *
++ * XXX: copied from fs/proc/base.c, removed task_lock, added rmb(): this must be
++ * called with task_lock(task) held. */
++static int task_dumpable(struct task_struct *task)
++{
++	int dumpable = 0;
++	struct mm_struct *mm;
++
++	mm = task->mm;
++	if (mm) {
++		rmb();
++		dumpable = mm->dumpable;
++	}
++	return dumpable;
++}
++
++/*
++ * This is to be used in PTRACE_SWITCH_MM handling. We are going to set
++ * child->mm to new, and we must first correctly set new->dumpable.
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++void lock_fix_dumpable_setting(struct task_struct* child, struct mm_struct* new)
++	__acquires(child->alloc_lock)
++{
++	int dumpable = 1;
++
++	/* We must be safe.
++	 * If the child is ptraced from a non-dumpable process,
++	 * let's not be dumpable. If the child is non-dumpable itself,
++	 * copy this property across mm's.
++	 *
++	 * Don't try to be smart for the opposite case and turn
++	 * child->mm->dumpable to 1: I've not made sure it is safe.
++	 */
++
++	task_lock(current);
++	if (unlikely(!task_dumpable(current))) {
++		dumpable = 0;
++	}
++	task_unlock(current);
++
++	task_lock(child);
++	if (likely(dumpable) && unlikely(!task_dumpable(child))) {
++		dumpable = 0;
++	}
++
++	if (!dumpable) {
++		new->dumpable = 0;
++		wmb();
++	}
++}
++#endif
++
++/* Naming conventions are a mess, so I note them down.
++ *
++ * Things ending in _mm can be for everything. It's only for
++ * {open,release}_proc_mm.
++ *
++ * For the rest:
++ *
++ * _mm means /proc/mm, _mm64 means /proc/mm64. This is for the infrastructure
++ * only (for instance proc_mm_get_mm checks whether the file is /proc/mm or
++ * /proc/mm64; for instance the /proc handling).
++ *
++ * While for what is conversion dependant, we use the suffix _native and _emul.
++ * In some cases, there is a mapping between these ones (defined by
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++	mm->dumpable = current->mm->dumpable;
++	wmb();
++#endif
++
++	file->private_data = mm;
++
++	return 0;
++
++out_mem:
++	return ret;
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return 0;
++}
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++static ssize_t write_proc_mm_native(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_native(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
++/*These three are all for /proc/mm.*/
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++/*Macro-ify it to avoid the duplication.*/
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm);
++
++/*XXX: change the option.*/
++#ifdef CONFIG_64BIT
++static struct file_operations proc_mm64_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm64,
++};
++
++static int make_proc_mm64(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm64", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm64\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm64_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm64);
++
++struct mm_struct *proc_mm_get_mm64(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	/*This is the only change.*/
++	if(file->f_op != &proc_mm64_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.6.15/mm/proc_mm-mod.c
+===================================================================
+--- /dev/null
++++ linux-2.6.15/mm/proc_mm-mod.c
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#ifdef CONFIG_64BIT
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "32->" #member " \t: %ld\n", (long) offsetof(struct type ## 32, member))
++#else
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "->" #member " \t: %ld\n", (long) offsetof(struct type, member))
++#endif
++
++static int debug_printoffsets(void)
++{
++	printk(KERN_DEBUG "Skas core structures layout BEGIN:\n");
++	PRINT_OFFSET(mm_mmap, addr);
++	PRINT_OFFSET(mm_mmap, len);
++	PRINT_OFFSET(mm_mmap, prot);
++	PRINT_OFFSET(mm_mmap, flags);
++	PRINT_OFFSET(mm_mmap, fd);
++	PRINT_OFFSET(mm_mmap, offset);
++
++	PRINT_OFFSET(mm_munmap, addr);
++	PRINT_OFFSET(mm_munmap, len);
++
++	PRINT_OFFSET(mm_mprotect, addr);
++	PRINT_OFFSET(mm_mprotect, len);
++	PRINT_OFFSET(mm_mprotect, prot);
++
++	PRINT_OFFSET(proc_mm_op, op);
++	PRINT_OFFSET(proc_mm_op, u);
++	PRINT_OFFSET(proc_mm_op, u.mmap);
++	PRINT_OFFSET(proc_mm_op, u.munmap);
++	PRINT_OFFSET(proc_mm_op, u.mprotect);
++	PRINT_OFFSET(proc_mm_op, u.copy_segments);
++
++	PRINT_OFFSET(ptrace_faultinfo, is_write);
++	PRINT_OFFSET(ptrace_faultinfo, addr);
++
++	PRINT_OFFSET(ptrace_ldt, func);
++	PRINT_OFFSET(ptrace_ldt, ptr);
++	PRINT_OFFSET(ptrace_ldt, bytecount);
++	printk(KERN_DEBUG "Skas core structures layout END.\n");
++
++	return 0;
++}
++#undef PRINT_OFFSET
++
++module_init(debug_printoffsets);

Added: trunk/src/kernel-patch-skas/skas-2.6.16-v9-pre9.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.16-v9-pre9.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.16-v9-pre9.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1846 @@
+Index: linux-2.6.16/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.16.orig/arch/i386/Kconfig
++++ linux-2.6.16/arch/i386/Kconfig
+@@ -496,6 +496,26 @@ config X86_PAE
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+Index: linux-2.6.16/arch/i386/kernel/ldt.c
+===================================================================
+--- linux-2.6.16.orig/arch/i386/kernel/ldt.c
++++ linux-2.6.16/arch/i386/kernel/ldt.c
+@@ -28,11 +28,12 @@ static void flush_ldt(void *null)
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	int oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= pc->size)
+ 		return 0;
+@@ -59,13 +60,15 @@ static int alloc_ldt(mm_context_t *pc, i
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -77,12 +80,12 @@ static int alloc_ldt(mm_context_t *pc, i
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -90,22 +93,24 @@ static inline int copy_ldt(mm_context_t 
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -122,11 +127,11 @@ void destroy_context(struct mm_struct *m
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -175,9 +180,8 @@ static int read_default_ldt(void __user 
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -201,7 +205,7 @@ static int write_ldt(void __user * ptr, 
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -231,23 +235,33 @@ out:
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	int ret = __modify_ldt(current->mm, func, ptr, bytecount);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+Index: linux-2.6.16/arch/i386/kernel/ptrace.c
+===================================================================
+--- linux-2.6.16.orig/arch/i386/kernel/ptrace.c
++++ linux-2.6.16/arch/i386/kernel/ptrace.c
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -625,6 +626,66 @@ long arch_ptrace(struct task_struct *chi
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+Index: linux-2.6.16/arch/i386/kernel/sys_i386.c
+===================================================================
+--- linux-2.6.16.orig/arch/i386/kernel/sys_i386.c
++++ linux-2.6.16/arch/i386/kernel/sys_i386.c
+@@ -41,7 +41,7 @@ asmlinkage int sys_pipe(unsigned long __
+ }
+ 
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
++long do_mmap2(struct mm_struct *mm,
+ 	unsigned long addr, unsigned long len,
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+@@ -56,9 +56,9 @@ static inline long do_mmap2(
+ 			goto out;
+ 	}
+ 
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -70,7 +70,12 @@ asmlinkage long sys_mmap2(unsigned long 
+ 	unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
++	long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
+ }
+ 
+ /*
+@@ -101,7 +106,10 @@ asmlinkage int old_mmap(struct mmap_arg_
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(err);
+ out:
+ 	return err;
+ }
+Index: linux-2.6.16/arch/um/include/skas_ptrace.h
+===================================================================
+--- linux-2.6.16.orig/arch/um/include/skas_ptrace.h
++++ linux-2.6.16/arch/um/include/skas_ptrace.h
+@@ -6,6 +6,8 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
++
+ #define PTRACE_FAULTINFO 52
+ #define PTRACE_SWITCH_MM 55
+ 
+@@ -13,6 +15,8 @@
+ 
+ #endif
+ 
++#endif
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+Index: linux-2.6.16/arch/x86_64/ia32/ptrace32.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/ia32/ptrace32.c
++++ linux-2.6.16/arch/x86_64/ia32/ptrace32.c
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+ 
+ /*
+  * Determines which flags the user has access to [1 = access, 0 = no access].
+@@ -224,6 +227,12 @@ asmlinkage long sys32_ptrace(long reques
+ 	case PTRACE_SETFPXREGS:
+ 	case PTRACE_GETFPXREGS:
+ 	case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO:
++	case PTRACE_FAULTINFO:
++	case PTRACE_LDT:
++	case PTRACE_SWITCH_MM:
++#endif
+ 		break;
+ 	} 
+ 
+@@ -343,6 +352,65 @@ asmlinkage long sys32_ptrace(long reques
+ 		ret = 0; 
+ 		break;
+ 	}
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo32 fault;
++
++		fault = ((struct ptrace_ex_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2,
++			  .trap_no	= (compat_int_t) child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo32 fault;
++
++		fault = ((struct ptrace_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt32 ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) datap,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, compat_ptr(ldt.ptr), ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
+ 
+ 	case PTRACE_GETEVENTMSG:
+ 		ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+Index: linux-2.6.16/arch/x86_64/ia32/sys_ia32.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/ia32/sys_ia32.c
++++ linux-2.6.16/arch/x86_64/ia32/sys_ia32.c
+@@ -855,11 +855,10 @@ sys32_adjtimex(struct timex32 __user *ut
+ 	return ret;
+ }
+ 
+-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
++long do32_mmap2(struct mm_struct *mm, unsigned long addr,
++	unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	struct mm_struct *mm = current->mm;
+ 	unsigned long error;
+ 	struct file * file = NULL;
+ 
+@@ -871,7 +870,7 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	}
+ 
+ 	down_write(&mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
+ 	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+@@ -879,6 +878,15 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	return error;
+ }
+ 
++/* XXX: this wrapper can be probably removed, we can simply use the 64-bit
++ * version.*/
++asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
++	unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long pgoff)
++{
++	return do32_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++}
++
+ asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
+ {
+ 	int error;
+Index: linux-2.6.16/arch/x86_64/Kconfig
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/Kconfig
++++ linux-2.6.16/arch/x86_64/Kconfig
+@@ -378,6 +378,26 @@ config SWIOTLB
+ 	default y
+ 	depends on GART_IOMMU
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ config X86_MCE
+ 	bool "Machine check support" if EMBEDDED
+ 	default y
+Index: linux-2.6.16/arch/x86_64/kernel/ldt.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/kernel/ldt.c
++++ linux-2.6.16/arch/x86_64/kernel/ldt.c
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@ static void flush_ldt(void *null)
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, unsigned mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	unsigned oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= (unsigned)pc->size)
+ 		return 0;
+@@ -64,12 +66,14 @@ static int alloc_ldt(mm_context_t *pc, u
+ 
+ 		preempt_disable();
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		load_LDT(pc);
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -81,12 +85,12 @@ static int alloc_ldt(mm_context_t *pc, u
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -94,22 +98,24 @@ static inline int copy_ldt(mm_context_t 
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * 
+  * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@ void destroy_context(struct mm_struct *m
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -170,10 +175,8 @@ static int read_default_ldt(void __user 
+ 	return bytecount; 
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct task_struct *me = current;
+-	struct mm_struct * mm = me->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -198,7 +201,7 @@ static int write_ldt(void __user * ptr, 
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= (unsigned)mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -231,23 +234,29 @@ out:
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return __modify_ldt(current->mm, func, ptr, bytecount);
++}
+Index: linux-2.6.16/arch/x86_64/kernel/ptrace.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/kernel/ptrace.c
++++ linux-2.6.16/arch/x86_64/kernel/ptrace.c
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -564,6 +565,75 @@ long arch_ptrace(struct task_struct *chi
+ 		break;
+ 	}
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	/*Don't extend this broken interface to x86-64*/
++#if 0
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++#endif
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm64(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+Index: linux-2.6.16/arch/x86_64/kernel/sys_x86_64.c
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/kernel/sys_x86_64.c
++++ linux-2.6.16/arch/x86_64/kernel/sys_x86_64.c
+@@ -19,6 +19,7 @@
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+ 
+ /*
+  * sys_pipe() is the normal C calling standard for creating
+@@ -37,7 +38,7 @@ asmlinkage long sys_pipe(int __user *fil
+ 	return error;
+ }
+ 
+-asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long off)
+ {
+ 	long error;
+@@ -55,9 +56,9 @@ asmlinkage long sys_mmap(unsigned long a
+ 		if (!file)
+ 			goto out;
+ 	}
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, off >> PAGE_SHIFT);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -65,6 +66,12 @@ out:
+ 	return error;
+ }
+ 
++asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off)
++{
++	return do64_mmap(current->mm, addr, len, prot, flags, fd, off);
++}
++
+ static void find_start_end(unsigned long flags, unsigned long *begin,
+ 			   unsigned long *end)
+ {
+Index: linux-2.6.16/arch/x86_64/mm/Makefile
+===================================================================
+--- linux-2.6.16.orig/arch/x86_64/mm/Makefile
++++ linux-2.6.16/arch/x86_64/mm/Makefile
+@@ -7,5 +7,6 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag
+ obj-$(CONFIG_NUMA) += numa.o
+ obj-$(CONFIG_K8_NUMA) += k8topology.o
+ obj-$(CONFIG_ACPI_NUMA) += srat.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+ 
+ hugetlbpage-y = ../../i386/mm/hugetlbpage.o
+Index: linux-2.6.16/arch/x86_64/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.16/arch/x86_64/mm/proc_mm.c
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op32 req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap32 *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap32 *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect32 *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_emul(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
+Index: linux-2.6.16/include/asm-i386/desc.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-i386/desc.h
++++ linux-2.6.16/include/asm-i386/desc.h
+@@ -162,6 +162,9 @@ static inline unsigned long get_desc_bas
+ 	return base;
+ }
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+Index: linux-2.6.16/include/asm-i386/mmu_context.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-i386/mmu_context.h
++++ linux-2.6.16/include/asm-i386/mmu_context.h
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@ static inline void switch_mm(struct mm_s
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+Index: linux-2.6.16/include/asm-i386/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.16/include/asm-i386/proc_mm.h
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		unsigned long len, unsigned long prot, unsigned long flags,
++		unsigned long fd, unsigned long pgoff);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	return do_mmap2(mm, addr, len, prot, flags, fd, off >> PAGE_SHIFT);
++}
++
++#endif /* __ASM_PROC_MM */
+Index: linux-2.6.16/include/asm-i386/ptrace.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-i386/ptrace.h
++++ linux-2.6.16/include/asm-i386/ptrace.h
+@@ -87,4 +87,33 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif /* __KERNEL__ */
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++#define PTRACE_EX_FAULTINFO	  56
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+Index: linux-2.6.16/include/asm-x86_64/desc.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-x86_64/desc.h
++++ linux-2.6.16/include/asm-x86_64/desc.h
+@@ -233,6 +233,9 @@ static inline void load_LDT(mm_context_t
+ 
+ extern struct desc_ptr idt_descr;
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+Index: linux-2.6.16/include/asm-x86_64/mmu_context.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-x86_64/mmu_context.h
++++ linux-2.6.16/include/asm-x86_64/mmu_context.h
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+  * possibly do the LDT unload here?
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
++
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+ #ifdef CONFIG_SMP
+@@ -32,6 +47,9 @@ static inline void switch_mm(struct mm_s
+ 			     struct task_struct *tsk)
+ {
+ 	unsigned cpu = smp_processor_id();
++#ifdef CONFIG_SMP
++	prev = read_pda(active_mm);
++#endif
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		clear_bit(cpu, &prev->cpu_vm_mask);
+@@ -48,8 +66,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		write_pda(mmu_state, TLBSTATE_OK);
+-		if (read_pda(active_mm) != next)
+-			out_of_line_bug();
+ 		if(!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+ 			 * tlb flush IPI delivery. We must reload CR3
+Index: linux-2.6.16/include/asm-x86_64/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.16/include/asm-x86_64/proc_mm.h
+@@ -0,0 +1,58 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++struct mm_mmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++	compat_ulong_t prot;
++	compat_ulong_t flags;
++	compat_ulong_t fd;
++	compat_ulong_t offset;
++};
++
++struct mm_munmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++};
++
++struct mm_mprotect32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++        compat_uint_t prot;
++};
++
++struct proc_mm_op32 {
++	compat_int_t op;
++	union {
++		struct mm_mmap32 mmap;
++		struct mm_munmap32 munmap;
++	        struct mm_mprotect32 mprotect;
++		compat_int_t copy_segments;
++	} u;
++};
++
++extern ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos);
++
++extern struct mm_struct *proc_mm_get_mm64(int fd);
++
++extern long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	/* The latter one is stricter, since will actually check that off is page
++	 * aligned. The first one skipped the check. */
++
++	/* return do32_mmap2(mm, addr, len, prot, flags, fd, off >>
++	 * PAGE_SHIFT);*/
++	return do64_mmap(mm, addr, len, prot, flags, fd, off);
++}
++
++#endif /* __ASM_PROC_MM */
+Index: linux-2.6.16/include/asm-x86_64/ptrace.h
+===================================================================
+--- linux-2.6.16.orig/include/asm-x86_64/ptrace.h
++++ linux-2.6.16/include/asm-x86_64/ptrace.h
+@@ -64,6 +64,59 @@ struct pt_regs {
+ /* top of stack page */ 
+ };
+ 
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#define		compat_int_t	s32
++#define		compat_long_t	s32
++#define		compat_uint_t	u32
++#define		compat_ulong_t	u32
++#define		compat_uptr_t	u32
++
++struct ptrace_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++};
++
++struct ptrace_ex_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++	compat_int_t trap_no;
++};
++
++struct ptrace_ldt32 {
++	compat_int_t func;
++	compat_uptr_t ptr; /*Actually a void pointer on i386, but must be converted.*/
++	compat_ulong_t bytecount;
++};
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#undef	compat_int_t
++#undef	compat_long_t
++#undef	compat_uint_t
++#undef	compat_ulong_t
++#undef	compat_uptr_t
++
+ #endif
+ 
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@ struct pt_regs {
+ #define PTRACE_GETFPXREGS         18
+ #define PTRACE_SETFPXREGS         19
+ 
++#define PTRACE_FAULTINFO 52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++#define PTRACE_EX_FAULTINFO	  56
++
+ /* only useful for access 32bit programs */
+ #define PTRACE_GET_THREAD_AREA    25
+ #define PTRACE_SET_THREAD_AREA    26
+Index: linux-2.6.16/include/linux/mm.h
+===================================================================
+--- linux-2.6.16.orig/include/linux/mm.h
++++ linux-2.6.16/include/linux/mm.h
+@@ -918,9 +918,15 @@ extern int may_expand_vm(struct mm_struc
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+@@ -937,6 +943,9 @@ out:
+ 
+ extern int do_munmap(struct mm_struct *, unsigned long, size_t);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ extern unsigned long do_brk(unsigned long, unsigned long);
+ 
+ /* filemap.c */
+Index: linux-2.6.16/include/linux/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.16/include/linux/proc_mm.h
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* The differences between this one and do_mmap are that:
++ * - we must perform controls for userspace-supplied params (which are
++ *   arch-specific currently). And also fget(fd) if needed and so on...
++ * - we must accept the struct mm_struct on which to act as first param, and the
++ *   offset in byte rather than page units as last param.
++ */
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off);
++
++/* This header can be used only on archs defining CONFIG_PROC_MM in their
++ * configs, so asm/proc_mm.h can still exist only for the needed archs.
++ * Including it only in the x86-64 case does not make sense.*/
++#include <asm/proc_mm.h>
++
++/*XXX: this is defined on x86_64, but not on every 64-bit arch (not on sh64).*/
++#ifdef CONFIG_64BIT
++
++#define write_proc_mm write_proc_mm_emul
++#define write_proc_mm64 write_proc_mm_native
++
++/* It would make more sense to do this mapping the reverse direction, to map the
++ * called name to the defined one and not the reverse. Like the 2nd example
++ */
++/*#define proc_mm_get_mm proc_mm_get_mm_emul
++#define proc_mm_get_mm64 proc_mm_get_mm_native*/
++
++#define proc_mm_get_mm_emul proc_mm_get_mm
++#define proc_mm_get_mm_native proc_mm_get_mm64
++
++#else
++
++#define write_proc_mm write_proc_mm_native
++#undef write_proc_mm64
++
++/*#define proc_mm_get_mm proc_mm_get_mm_native
++#undef proc_mm_get_mm64*/
++
++#define proc_mm_get_mm_native proc_mm_get_mm
++#undef proc_mm_get_mm_emul
++
++#endif
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++/* Cope with older kernels */
++#ifndef __acquires
++#define __acquires(x)
++#endif
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/*
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++extern void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock);
++#else
++static inline void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock)
++{
++	task_lock(child);
++}
++#endif
++
++#endif
+Index: linux-2.6.16/localversion-skas
+===================================================================
+--- /dev/null
++++ linux-2.6.16/localversion-skas
+@@ -0,0 +1 @@
++-skas3-v9-pre9
+Index: linux-2.6.16/mm/Makefile
+===================================================================
+--- linux-2.6.16.orig/mm/Makefile
++++ linux-2.6.16/mm/Makefile
+@@ -22,3 +22,9 @@ obj-$(CONFIG_SLOB) += slob.o
+ obj-$(CONFIG_SLAB) += slab.o
+ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
++
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m			+= proc_mm-mod.o
++endif
+Index: linux-2.6.16/mm/mmap.c
+===================================================================
+--- linux-2.6.16.orig/mm/mmap.c
++++ linux-2.6.16/mm/mmap.c
+@@ -868,11 +868,11 @@ void vm_stat_account(struct mm_struct *m
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1147,7 +1147,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+Index: linux-2.6.16/mm/mprotect.c
+===================================================================
+--- linux-2.6.16.orig/mm/mprotect.c
++++ linux-2.6.16/mm/mprotect.c
+@@ -176,8 +176,9 @@ fail:
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp, reqprot;
+ 	struct vm_area_struct *vma, *prev;
+@@ -208,9 +209,9 @@ sys_mprotect(unsigned long start, size_t
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -277,6 +278,15 @@ sys_mprotect(unsigned long start, size_t
+ 		}
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	long ret = do_mprotect(current->mm, start, len, prot);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+Index: linux-2.6.16/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.16/mm/proc_mm.c
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/proc_mm.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/* Checks if a task must be considered dumpable
++ *
++ * XXX: copied from fs/proc/base.c, removed task_lock, added rmb(): this must be
++ * called with task_lock(task) held. */
++static int task_dumpable(struct task_struct *task)
++{
++	int dumpable = 0;
++	struct mm_struct *mm;
++
++	mm = task->mm;
++	if (mm) {
++		rmb();
++		dumpable = mm->dumpable;
++	}
++	return dumpable;
++}
++
++/*
++ * This is to be used in PTRACE_SWITCH_MM handling. We are going to set
++ * child->mm to new, and we must first correctly set new->dumpable.
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++void lock_fix_dumpable_setting(struct task_struct* child, struct mm_struct* new)
++	__acquires(child->alloc_lock)
++{
++	int dumpable = 1;
++
++	/* We must be safe.
++	 * If the child is ptraced from a non-dumpable process,
++	 * let's not be dumpable. If the child is non-dumpable itself,
++	 * copy this property across mm's.
++	 *
++	 * Don't try to be smart for the opposite case and turn
++	 * child->mm->dumpable to 1: I've not made sure it is safe.
++	 */
++
++	task_lock(current);
++	if (unlikely(!task_dumpable(current))) {
++		dumpable = 0;
++	}
++	task_unlock(current);
++
++	task_lock(child);
++	if (likely(dumpable) && unlikely(!task_dumpable(child))) {
++		dumpable = 0;
++	}
++
++	if (!dumpable) {
++		new->dumpable = 0;
++		wmb();
++	}
++}
++#endif
++
++/* Naming conventions are a mess, so I note them down.
++ *
++ * Things ending in _mm can be for everything. It's only for
++ * {open,release}_proc_mm.
++ *
++ * For the rest:
++ *
++ * _mm means /proc/mm, _mm64 means /proc/mm64. This is for the infrastructure
++ * only (for instance proc_mm_get_mm checks whether the file is /proc/mm or
++ * /proc/mm64; for instance the /proc handling).
++ *
++ * While for what is conversion dependant, we use the suffix _native and _emul.
++ * In some cases, there is a mapping between these ones (defined by
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++	mm->dumpable = current->mm->dumpable;
++	wmb();
++#endif
++
++	file->private_data = mm;
++
++	return 0;
++
++out_mem:
++	return ret;
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return 0;
++}
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++static ssize_t write_proc_mm_native(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_native(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
++/*These three are all for /proc/mm.*/
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++/*Macro-ify it to avoid the duplication.*/
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm);
++
++/*XXX: change the option.*/
++#ifdef CONFIG_64BIT
++static struct file_operations proc_mm64_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm64,
++};
++
++static int make_proc_mm64(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm64", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm64\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm64_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm64);
++
++struct mm_struct *proc_mm_get_mm64(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	/*This is the only change.*/
++	if(file->f_op != &proc_mm64_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+Index: linux-2.6.16/mm/proc_mm-mod.c
+===================================================================
+--- /dev/null
++++ linux-2.6.16/mm/proc_mm-mod.c
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#ifdef CONFIG_64BIT
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "32->" #member " \t: %ld\n", (long) offsetof(struct type ## 32, member))
++#else
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "->" #member " \t: %ld\n", (long) offsetof(struct type, member))
++#endif
++
++static int debug_printoffsets(void)
++{
++	printk(KERN_DEBUG "Skas core structures layout BEGIN:\n");
++	PRINT_OFFSET(mm_mmap, addr);
++	PRINT_OFFSET(mm_mmap, len);
++	PRINT_OFFSET(mm_mmap, prot);
++	PRINT_OFFSET(mm_mmap, flags);
++	PRINT_OFFSET(mm_mmap, fd);
++	PRINT_OFFSET(mm_mmap, offset);
++
++	PRINT_OFFSET(mm_munmap, addr);
++	PRINT_OFFSET(mm_munmap, len);
++
++	PRINT_OFFSET(mm_mprotect, addr);
++	PRINT_OFFSET(mm_mprotect, len);
++	PRINT_OFFSET(mm_mprotect, prot);
++
++	PRINT_OFFSET(proc_mm_op, op);
++	PRINT_OFFSET(proc_mm_op, u);
++	PRINT_OFFSET(proc_mm_op, u.mmap);
++	PRINT_OFFSET(proc_mm_op, u.munmap);
++	PRINT_OFFSET(proc_mm_op, u.mprotect);
++	PRINT_OFFSET(proc_mm_op, u.copy_segments);
++
++	PRINT_OFFSET(ptrace_faultinfo, is_write);
++	PRINT_OFFSET(ptrace_faultinfo, addr);
++
++	PRINT_OFFSET(ptrace_ldt, func);
++	PRINT_OFFSET(ptrace_ldt, ptr);
++	PRINT_OFFSET(ptrace_ldt, bytecount);
++	printk(KERN_DEBUG "Skas core structures layout END.\n");
++
++	return 0;
++}
++#undef PRINT_OFFSET
++
++module_init(debug_printoffsets);

Added: trunk/src/kernel-patch-skas/skas-2.6.17-rc5-v9-pre9.patch
===================================================================
--- trunk/src/kernel-patch-skas/skas-2.6.17-rc5-v9-pre9.patch	2006-08-24 19:09:05 UTC (rev 159)
+++ trunk/src/kernel-patch-skas/skas-2.6.17-rc5-v9-pre9.patch	2006-08-26 11:25:57 UTC (rev 160)
@@ -0,0 +1,1863 @@
+Index: linux-2.6.git/arch/i386/Kconfig
+===================================================================
+--- linux-2.6.git.orig/arch/i386/Kconfig
++++ linux-2.6.git/arch/i386/Kconfig
+@@ -512,6 +512,26 @@ config X86_PAE
+ 	depends on HIGHMEM64G
+ 	default y
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ # Common NUMA Features
+ config NUMA
+ 	bool "Numa Memory Allocation and Scheduler Support"
+Index: linux-2.6.git/arch/i386/kernel/ldt.c
+===================================================================
+--- linux-2.6.git.orig/arch/i386/kernel/ldt.c
++++ linux-2.6.git/arch/i386/kernel/ldt.c
+@@ -28,11 +28,12 @@ static void flush_ldt(void *null)
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, int mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	int oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= pc->size)
+ 		return 0;
+@@ -59,13 +60,15 @@ static int alloc_ldt(mm_context_t *pc, i
+ #ifdef CONFIG_SMP
+ 		cpumask_t mask;
+ 		preempt_disable();
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -77,12 +80,12 @@ static int alloc_ldt(mm_context_t *pc, i
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -90,22 +93,24 @@ static inline int copy_ldt(mm_context_t 
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * No need to lock the MM as we are the last user
+  */
+@@ -122,11 +127,11 @@ void destroy_context(struct mm_struct *m
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr,
++		    unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -175,9 +180,8 @@ static int read_default_ldt(void __user 
+ 	return err;
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	__u32 entry_1, entry_2;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -201,7 +205,7 @@ static int write_ldt(void __user * ptr, 
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -231,23 +235,33 @@ out:
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++	       unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	int ret = __modify_ldt(current->mm, func, ptr, bytecount);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+Index: linux-2.6.git/arch/i386/kernel/ptrace.c
+===================================================================
+--- linux-2.6.git.orig/arch/i386/kernel/ptrace.c
++++ linux-2.6.git/arch/i386/kernel/ptrace.c
+@@ -17,6 +17,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -625,6 +626,66 @@ long arch_ptrace(struct task_struct *chi
+ 					(struct user_desc __user *) data);
+ 		break;
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+Index: linux-2.6.git/arch/i386/kernel/sys_i386.c
+===================================================================
+--- linux-2.6.git.orig/arch/i386/kernel/sys_i386.c
++++ linux-2.6.git/arch/i386/kernel/sys_i386.c
+@@ -22,6 +22,7 @@
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ipc.h>
++#include <asm/proc_mm.h>
+ 
+ /*
+  * sys_pipe() is the normal C calling standard for creating
+@@ -40,13 +41,12 @@ asmlinkage int sys_pipe(unsigned long __
+ 	return error;
+ }
+ 
+-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+-			  unsigned long prot, unsigned long flags,
+-			  unsigned long fd, unsigned long pgoff)
++long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len,
++		unsigned long prot, unsigned long flags, unsigned long fd,
++		unsigned long pgoff)
+ {
+ 	int error = -EBADF;
+ 	struct file *file = NULL;
+-	struct mm_struct *mm = current->mm;
+ 
+ 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ 	if (!(flags & MAP_ANONYMOUS)) {
+@@ -56,7 +56,7 @@ asmlinkage long sys_mmap2(unsigned long 
+ 	}
+ 
+ 	down_write(&mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
+ 	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+@@ -65,6 +65,18 @@ out:
+ 	return error;
+ }
+ 
++asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
++       unsigned long prot, unsigned long flags,
++       unsigned long fd, unsigned long pgoff)
++{
++	long ret = do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
++
+ /*
+  * Perform the select(nd, in, out, ex, tv) and mmap() system
+  * calls. Linux/i386 didn't use to be able to handle more than
+@@ -93,8 +105,11 @@ asmlinkage int old_mmap(struct mmap_arg_
+ 	if (a.offset & ~PAGE_MASK)
+ 		goto out;
+ 
+-	err = sys_mmap2(a.addr, a.len, a.prot, a.flags,
++	err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags,
+ 			a.fd, a.offset >> PAGE_SHIFT);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(err);
+ out:
+ 	return err;
+ }
+Index: linux-2.6.git/arch/um/include/skas_ptrace.h
+===================================================================
+--- linux-2.6.git.orig/arch/um/include/skas_ptrace.h
++++ linux-2.6.git/arch/um/include/skas_ptrace.h
+@@ -6,6 +6,8 @@
+ #ifndef __SKAS_PTRACE_H
+ #define __SKAS_PTRACE_H
+ 
++#ifndef PTRACE_FAULTINFO
++
+ #define PTRACE_FAULTINFO 52
+ #define PTRACE_SWITCH_MM 55
+ 
+@@ -13,6 +15,8 @@
+ 
+ #endif
+ 
++#endif
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+Index: linux-2.6.git/arch/x86_64/Kconfig
+===================================================================
+--- linux-2.6.git.orig/arch/x86_64/Kconfig
++++ linux-2.6.git/arch/x86_64/Kconfig
+@@ -407,6 +407,26 @@ config SWIOTLB
+ 	default y
+ 	depends on GART_IOMMU
+ 
++config PROC_MM
++	bool "/proc/mm support"
++	default y
++
++config PROC_MM_DUMPABLE
++	bool "Make UML childs /proc/<pid> completely browsable"
++	default n
++	help
++	  If in doubt, say N.
++
++	  This fiddles with some settings to make sure /proc/<pid> is completely
++	  browsable by who started UML, at the expense of some additional
++	  locking (maybe this could slow down the runned UMLs of a few percents,
++	  I've not tested this).
++
++	  Also, if there is a bug in this feature, there is some little
++	  possibility to do privilege escalation if you have UML installed
++	  setuid (which you shouldn't have done) or if UML changes uid on
++	  startup (which will be a good thing, when enabled) ...
++
+ config X86_MCE
+ 	bool "Machine check support" if EMBEDDED
+ 	default y
+Index: linux-2.6.git/arch/x86_64/ia32/ptrace32.c
+===================================================================
+--- linux-2.6.git.orig/arch/x86_64/ia32/ptrace32.c
++++ linux-2.6.git/arch/x86_64/ia32/ptrace32.c
+@@ -18,6 +18,8 @@
+ #include <linux/unistd.h>
+ #include <linux/mm.h>
+ #include <linux/ptrace.h>
++#include <linux/types.h>
++#include <linux/proc_mm.h>
+ #include <asm/ptrace.h>
+ #include <asm/compat.h>
+ #include <asm/uaccess.h>
+@@ -27,6 +29,7 @@
+ #include <asm/debugreg.h>
+ #include <asm/i387.h>
+ #include <asm/fpu32.h>
++#include <asm/desc.h>
+ 
+ /*
+  * Determines which flags the user has access to [1 = access, 0 = no access].
+@@ -224,6 +227,12 @@ asmlinkage long sys32_ptrace(long reques
+ 	case PTRACE_SETFPXREGS:
+ 	case PTRACE_GETFPXREGS:
+ 	case PTRACE_GETEVENTMSG:
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO:
++	case PTRACE_FAULTINFO:
++	case PTRACE_LDT:
++	case PTRACE_SWITCH_MM:
++#endif
+ 		break;
+ 	} 
+ 
+@@ -343,6 +352,65 @@ asmlinkage long sys32_ptrace(long reques
+ 		ret = 0; 
+ 		break;
+ 	}
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo32 fault;
++
++		fault = ((struct ptrace_ex_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2,
++			  .trap_no	= (compat_int_t) child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo32 fault;
++
++		fault = ((struct ptrace_faultinfo32)
++			{ .is_write	= (compat_int_t) child->thread.error_code,
++			  .addr		= (compat_uptr_t) child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) datap, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt32 ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) datap,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, compat_ptr(ldt.ptr), ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
+ 
+ 	case PTRACE_GETEVENTMSG:
+ 		ret = put_user(child->ptrace_message,(unsigned int __user *)compat_ptr(data));
+Index: linux-2.6.git/arch/x86_64/ia32/sys_ia32.c
+===================================================================
+--- linux-2.6.git.orig/arch/x86_64/ia32/sys_ia32.c
++++ linux-2.6.git/arch/x86_64/ia32/sys_ia32.c
+@@ -766,11 +766,10 @@ sys32_sendfile(int out_fd, int in_fd, co
+ 	return ret;
+ }
+ 
+-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
+-	unsigned long prot, unsigned long flags,
++long do32_mmap2(struct mm_struct *mm, unsigned long addr,
++	unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long pgoff)
+ {
+-	struct mm_struct *mm = current->mm;
+ 	unsigned long error;
+ 	struct file * file = NULL;
+ 
+@@ -782,7 +781,7 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	}
+ 
+ 	down_write(&mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
+ 	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+@@ -790,6 +789,15 @@ asmlinkage long sys32_mmap2(unsigned lon
+ 	return error;
+ }
+ 
++/* XXX: this wrapper can be probably removed, we can simply use the 64-bit
++ * version.*/
++asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len,
++	unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long pgoff)
++{
++	return do32_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
++}
++
+ asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
+ {
+ 	int error;
+Index: linux-2.6.git/arch/x86_64/kernel/ldt.c
+===================================================================
+--- linux-2.6.git.orig/arch/x86_64/kernel/ldt.c
++++ linux-2.6.git/arch/x86_64/kernel/ldt.c
+@@ -22,6 +22,7 @@
+ #include <asm/ldt.h>
+ #include <asm/desc.h>
+ #include <asm/proto.h>
++#include <asm/mmu_context.h>
+ 
+ #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+ static void flush_ldt(void *null)
+@@ -31,11 +32,12 @@ static void flush_ldt(void *null)
+ }
+ #endif
+ 
+-static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload)
++static int alloc_ldt(struct mm_struct *mm, unsigned mincount, int reload)
+ {
+ 	void *oldldt;
+ 	void *newldt;
+ 	unsigned oldsize;
++	mm_context_t * pc = &mm->context;
+ 
+ 	if (mincount <= (unsigned)pc->size)
+ 		return 0;
+@@ -64,12 +66,14 @@ static int alloc_ldt(mm_context_t *pc, u
+ 
+ 		preempt_disable();
+ 		mask = cpumask_of_cpu(smp_processor_id());
+-		load_LDT(pc);
+-		if (!cpus_equal(current->mm->cpu_vm_mask, mask))
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
++		if (!cpus_equal(mm->cpu_vm_mask, mask))
+ 			smp_call_function(flush_ldt, NULL, 1, 1);
+ 		preempt_enable();
+ #else
+-		load_LDT(pc);
++		if (&current->active_mm->context == pc)
++			load_LDT(pc);
+ #endif
+ 	}
+ 	if (oldsize) {
+@@ -81,12 +85,12 @@ static int alloc_ldt(mm_context_t *pc, u
+ 	return 0;
+ }
+ 
+-static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
++static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old)
+ {
+-	int err = alloc_ldt(new, old->size, 0);
++	int err = alloc_ldt(new, old->context.size, 0);
+ 	if (err < 0)
+ 		return err;
+-	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
++	memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE);
+ 	return 0;
+ }
+ 
+@@ -94,22 +98,24 @@ static inline int copy_ldt(mm_context_t 
+  * we do not have to muck with descriptors here, that is
+  * done in switch_mm() as needed.
+  */
+-int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm)
+ {
+-	struct mm_struct * old_mm;
+ 	int retval = 0;
+ 
+-	init_MUTEX(&mm->context.sem);
+-	mm->context.size = 0;
+-	old_mm = current->mm;
+ 	if (old_mm && old_mm->context.size > 0) {
+ 		down(&old_mm->context.sem);
+-		retval = copy_ldt(&mm->context, &old_mm->context);
++		retval = copy_ldt(mm, old_mm);
+ 		up(&old_mm->context.sem);
+ 	}
+ 	return retval;
+ }
+ 
++int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
++{
++	init_new_empty_context(mm);
++	return copy_context(mm, current->mm);
++}
++
+ /*
+  * 
+  * Don't touch the LDT register - we're already in the next thread.
+@@ -125,11 +131,10 @@ void destroy_context(struct mm_struct *m
+ 	}
+ }
+ 
+-static int read_ldt(void __user * ptr, unsigned long bytecount)
++static int read_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount)
+ {
+ 	int err;
+ 	unsigned long size;
+-	struct mm_struct * mm = current->mm;
+ 
+ 	if (!mm->context.size)
+ 		return 0;
+@@ -170,10 +175,8 @@ static int read_default_ldt(void __user 
+ 	return bytecount; 
+ }
+ 
+-static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
++static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode)
+ {
+-	struct task_struct *me = current;
+-	struct mm_struct * mm = me->mm;
+ 	__u32 entry_1, entry_2, *lp;
+ 	int error;
+ 	struct user_desc ldt_info;
+@@ -198,7 +201,7 @@ static int write_ldt(void __user * ptr, 
+ 
+ 	down(&mm->context.sem);
+ 	if (ldt_info.entry_number >= (unsigned)mm->context.size) {
+-		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
++		error = alloc_ldt(mm, ldt_info.entry_number+1, 1);
+ 		if (error < 0)
+ 			goto out_unlock;
+ 	}
+@@ -231,23 +234,29 @@ out:
+ 	return error;
+ }
+ 
+-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount)
+ {
+ 	int ret = -ENOSYS;
+ 
+ 	switch (func) {
+ 	case 0:
+-		ret = read_ldt(ptr, bytecount);
++		ret = read_ldt(mm, ptr, bytecount);
+ 		break;
+ 	case 1:
+-		ret = write_ldt(ptr, bytecount, 1);
++		ret = write_ldt(mm, ptr, bytecount, 1);
+ 		break;
+ 	case 2:
+ 		ret = read_default_ldt(ptr, bytecount);
+ 		break;
+ 	case 0x11:
+-		ret = write_ldt(ptr, bytecount, 0);
++		ret = write_ldt(mm, ptr, bytecount, 0);
+ 		break;
+ 	}
+ 	return ret;
+ }
++
++asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
++{
++	return __modify_ldt(current->mm, func, ptr, bytecount);
++}
+Index: linux-2.6.git/arch/x86_64/kernel/ptrace.c
+===================================================================
+--- linux-2.6.git.orig/arch/x86_64/kernel/ptrace.c
++++ linux-2.6.git/arch/x86_64/kernel/ptrace.c
+@@ -19,6 +19,7 @@
+ #include <linux/audit.h>
+ #include <linux/seccomp.h>
+ #include <linux/signal.h>
++#include <linux/proc_mm.h>
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -559,6 +560,75 @@ long arch_ptrace(struct task_struct *chi
+ 		break;
+ 	}
+ 
++#ifdef CONFIG_PROC_MM
++	case PTRACE_EX_FAULTINFO: {
++		struct ptrace_ex_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_ex_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2,
++			  .trap_no	= child->thread.trap_no });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++
++	/*Don't extend this broken interface to x86-64*/
++#if 0
++	case PTRACE_FAULTINFO: {
++		struct ptrace_faultinfo fault;
++
++		/* I checked in thread_struct comments that error_code and cr2
++		 * are still part of the "fault info" section, so I guess that
++		 * things are unchanged for now. Still to check manuals. BB*/
++		fault = ((struct ptrace_faultinfo)
++			{ .is_write	= child->thread.error_code,
++			  .addr		= child->thread.cr2 });
++		ret = copy_to_user((unsigned long *) data, &fault,
++				   sizeof(fault));
++		break;
++	}
++#endif
++
++	case PTRACE_LDT: {
++		struct ptrace_ldt ldt;
++
++		if(copy_from_user(&ldt, (unsigned long *) data,
++				  sizeof(ldt))){
++			ret = -EIO;
++			break;
++		}
++		ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount);
++		break;
++	}
++
++	case PTRACE_SWITCH_MM: {
++		struct mm_struct *old = child->mm;
++		struct mm_struct *new = proc_mm_get_mm64(data);
++
++		if(IS_ERR(new)){
++			ret = PTR_ERR(new);
++			break;
++		}
++
++		atomic_inc(&new->mm_users);
++
++		lock_fix_dumpable_setting(child, new);
++
++		child->mm = new;
++		child->active_mm = new;
++
++		task_unlock(child);
++
++		mmput(old);
++		ret = 0;
++		break;
++	}
++#endif
++
+ 	default:
+ 		ret = ptrace_request(child, request, addr, data);
+ 		break;
+Index: linux-2.6.git/arch/x86_64/kernel/sys_x86_64.c
+===================================================================
+--- linux-2.6.git.orig/arch/x86_64/kernel/sys_x86_64.c
++++ linux-2.6.git/arch/x86_64/kernel/sys_x86_64.c
+@@ -19,6 +19,7 @@
+ 
+ #include <asm/uaccess.h>
+ #include <asm/ia32.h>
++#include <asm/proc_mm.h>
+ 
+ /*
+  * sys_pipe() is the normal C calling standard for creating
+@@ -37,7 +38,7 @@ asmlinkage long sys_pipe(int __user *fil
+ 	return error;
+ }
+ 
+-asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
+ 	unsigned long fd, unsigned long off)
+ {
+ 	long error;
+@@ -55,9 +56,9 @@ asmlinkage long sys_mmap(unsigned long a
+ 		if (!file)
+ 			goto out;
+ 	}
+-	down_write(&current->mm->mmap_sem);
+-	error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT);
+-	up_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
++	error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, off >> PAGE_SHIFT);
++	up_write(&mm->mmap_sem);
+ 
+ 	if (file)
+ 		fput(file);
+@@ -65,6 +66,12 @@ out:
+ 	return error;
+ }
+ 
++asmlinkage long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off)
++{
++	return do64_mmap(current->mm, addr, len, prot, flags, fd, off);
++}
++
+ static void find_start_end(unsigned long flags, unsigned long *begin,
+ 			   unsigned long *end)
+ {
+Index: linux-2.6.git/arch/x86_64/mm/Makefile
+===================================================================
+--- linux-2.6.git.orig/arch/x86_64/mm/Makefile
++++ linux-2.6.git/arch/x86_64/mm/Makefile
+@@ -7,5 +7,6 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpag
+ obj-$(CONFIG_NUMA) += numa.o
+ obj-$(CONFIG_K8_NUMA) += k8topology.o
+ obj-$(CONFIG_ACPI_NUMA) += srat.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
+ 
+ hugetlbpage-y = ../../i386/mm/hugetlbpage.o
+Index: linux-2.6.git/arch/x86_64/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.git/arch/x86_64/mm/proc_mm.c
+@@ -0,0 +1,85 @@
++#include <linux/proc_mm.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op32 req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap32 *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap32 *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect32 *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_emul(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
+Index: linux-2.6.git/include/asm-i386/desc.h
+===================================================================
+--- linux-2.6.git.orig/include/asm-i386/desc.h
++++ linux-2.6.git/include/asm-i386/desc.h
+@@ -162,6 +162,9 @@ static inline unsigned long get_desc_bas
+ 	return base;
+ }
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		      unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+Index: linux-2.6.git/include/asm-i386/mmu_context.h
+===================================================================
+--- linux-2.6.git.orig/include/asm-i386/mmu_context.h
++++ linux-2.6.git/include/asm-i386/mmu_context.h
+@@ -6,13 +6,25 @@
+ #include <asm/atomic.h>
+ #include <asm/pgalloc.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+- * Used for LDT copy/destruction.
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
+ 
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+@@ -29,6 +41,10 @@ static inline void switch_mm(struct mm_s
+ {
+ 	int cpu = smp_processor_id();
+ 
++#ifdef CONFIG_SMP
++	prev = per_cpu(cpu_tlbstate, cpu).active_mm;
++#endif
++
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -50,7 +66,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK;
+-		BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next);
+ 
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+Index: linux-2.6.git/include/asm-i386/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.git/include/asm-i386/proc_mm.h
+@@ -0,0 +1,18 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++
++#include <asm/page.h>
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr,
++		unsigned long len, unsigned long prot, unsigned long flags,
++		unsigned long fd, unsigned long pgoff);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	return do_mmap2(mm, addr, len, prot, flags, fd, off >> PAGE_SHIFT);
++}
++
++#endif /* __ASM_PROC_MM */
+Index: linux-2.6.git/include/asm-i386/ptrace.h
+===================================================================
+--- linux-2.6.git.orig/include/asm-i386/ptrace.h
++++ linux-2.6.git/include/asm-i386/ptrace.h
+@@ -87,4 +87,33 @@ extern unsigned long profile_pc(struct p
+ #endif
+ #endif /* __KERNEL__ */
+ 
++/*For SKAS3 support.*/
++#ifndef _LINUX_PTRACE_STRUCT_DEF
++#define _LINUX_PTRACE_STRUCT_DEF
++
++#define PTRACE_FAULTINFO	  52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT		  54
++#define PTRACE_SWITCH_MM 	  55
++#define PTRACE_EX_FAULTINFO	  56
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#endif /*ifndef _LINUX_PTRACE_STRUCT_DEF*/
++
+ #endif
+Index: linux-2.6.git/include/asm-x86_64/desc.h
+===================================================================
+--- linux-2.6.git.orig/include/asm-x86_64/desc.h
++++ linux-2.6.git/include/asm-x86_64/desc.h
+@@ -233,6 +233,9 @@ static inline void load_LDT(mm_context_t
+ 
+ extern struct desc_ptr idt_descr;
+ 
++extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr,
++		unsigned long bytecount);
++
+ #endif /* !__ASSEMBLY__ */
+ 
+ #endif
+Index: linux-2.6.git/include/asm-x86_64/mmu_context.h
+===================================================================
+--- linux-2.6.git.orig/include/asm-x86_64/mmu_context.h
++++ linux-2.6.git/include/asm-x86_64/mmu_context.h
+@@ -8,13 +8,28 @@
+ #include <asm/pda.h>
+ #include <asm/pgtable.h>
+ #include <asm/tlbflush.h>
++#include <asm/semaphore.h>
+ 
+ /*
+  * possibly do the LDT unload here?
++ * Used for LDT initialization/destruction. You cannot copy an LDT with
++ * init_new_context, since it thinks you are passing it a new LDT and won't
++ * deallocate its old content.
+  */
++
+ int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+ void destroy_context(struct mm_struct *mm);
+ 
++/* LDT initialization for a clean environment - needed for SKAS.*/
++static inline void init_new_empty_context(struct mm_struct *mm)
++{
++	init_MUTEX(&mm->context.sem);
++	mm->context.size = 0;
++}
++
++/* LDT copy for SKAS - for the above problem.*/
++int copy_context(struct mm_struct *mm, struct mm_struct *old_mm);
++
+ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+ {
+ #ifdef CONFIG_SMP
+@@ -32,6 +47,9 @@ static inline void switch_mm(struct mm_s
+ 			     struct task_struct *tsk)
+ {
+ 	unsigned cpu = smp_processor_id();
++#ifdef CONFIG_SMP
++	prev = read_pda(active_mm);
++#endif
+ 	if (likely(prev != next)) {
+ 		/* stop flush ipis for the previous mm */
+ 		cpu_clear(cpu, prev->cpu_vm_mask);
+@@ -48,8 +66,6 @@ static inline void switch_mm(struct mm_s
+ #ifdef CONFIG_SMP
+ 	else {
+ 		write_pda(mmu_state, TLBSTATE_OK);
+-		if (read_pda(active_mm) != next)
+-			out_of_line_bug();
+ 		if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) {
+ 			/* We were in lazy tlb mode and leave_mm disabled 
+ 			 * tlb flush IPI delivery. We must reload CR3
+Index: linux-2.6.git/include/asm-x86_64/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.git/include/asm-x86_64/proc_mm.h
+@@ -0,0 +1,58 @@
++#ifndef __ASM_PROC_MM
++#define __ASM_PROC_MM
++#include <linux/types.h>
++
++#include <asm/compat.h>
++
++struct mm_mmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++	compat_ulong_t prot;
++	compat_ulong_t flags;
++	compat_ulong_t fd;
++	compat_ulong_t offset;
++};
++
++struct mm_munmap32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++};
++
++struct mm_mprotect32 {
++	compat_ulong_t addr;
++	compat_ulong_t len;
++        compat_uint_t prot;
++};
++
++struct proc_mm_op32 {
++	compat_int_t op;
++	union {
++		struct mm_mmap32 mmap;
++		struct mm_munmap32 munmap;
++	        struct mm_mprotect32 mprotect;
++		compat_int_t copy_segments;
++	} u;
++};
++
++extern ssize_t write_proc_mm_emul(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos);
++
++extern struct mm_struct *proc_mm_get_mm64(int fd);
++
++extern long do64_mmap(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags,
++	unsigned long fd, unsigned long off);
++
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off)
++{
++	/* The latter one is stricter, since will actually check that off is page
++	 * aligned. The first one skipped the check. */
++
++	/* return do32_mmap2(mm, addr, len, prot, flags, fd, off >>
++	 * PAGE_SHIFT);*/
++	return do64_mmap(mm, addr, len, prot, flags, fd, off);
++}
++
++#endif /* __ASM_PROC_MM */
+Index: linux-2.6.git/include/asm-x86_64/ptrace.h
+===================================================================
+--- linux-2.6.git.orig/include/asm-x86_64/ptrace.h
++++ linux-2.6.git/include/asm-x86_64/ptrace.h
+@@ -64,6 +64,59 @@ struct pt_regs {
+ /* top of stack page */ 
+ };
+ 
++/* Stolen from
++#include <linux/compat.h>; we can't include it because
++there is a nasty ciclic include chain.
++*/
++
++#include <asm/types.h>
++
++#define		compat_int_t	s32
++#define		compat_long_t	s32
++#define		compat_uint_t	u32
++#define		compat_ulong_t	u32
++#define		compat_uptr_t	u32
++
++struct ptrace_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++};
++
++struct ptrace_ex_faultinfo32 {
++	compat_int_t is_write;
++	compat_ulong_t addr;
++	compat_int_t trap_no;
++};
++
++struct ptrace_ldt32 {
++	compat_int_t func;
++	compat_uptr_t ptr; /*Actually a void pointer on i386, but must be converted.*/
++	compat_ulong_t bytecount;
++};
++
++struct ptrace_faultinfo {
++	int is_write;
++	unsigned long addr;
++};
++
++struct ptrace_ex_faultinfo {
++	int is_write;
++	unsigned long addr;
++	int trap_no;
++};
++
++struct ptrace_ldt {
++	int func;
++  	void *ptr;
++	unsigned long bytecount;
++};
++
++#undef	compat_int_t
++#undef	compat_long_t
++#undef	compat_uint_t
++#undef	compat_ulong_t
++#undef	compat_uptr_t
++
+ #endif
+ 
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+@@ -74,6 +127,12 @@ struct pt_regs {
+ #define PTRACE_GETFPXREGS         18
+ #define PTRACE_SETFPXREGS         19
+ 
++#define PTRACE_FAULTINFO 52
++/* 53 was used for PTRACE_SIGPENDING, don't reuse it. */
++#define PTRACE_LDT 54
++#define PTRACE_SWITCH_MM 55
++#define PTRACE_EX_FAULTINFO	  56
++
+ /* only useful for access 32bit programs */
+ #define PTRACE_GET_THREAD_AREA    25
+ #define PTRACE_SET_THREAD_AREA    26
+Index: linux-2.6.git/include/linux/mm.h
+===================================================================
+--- linux-2.6.git.orig/include/linux/mm.h
++++ linux-2.6.git/include/linux/mm.h
+@@ -919,9 +919,15 @@ extern int may_expand_vm(struct mm_struc
+ 
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+ 
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
++extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file,
++				   unsigned long addr, unsigned long len,
++				   unsigned long prot, unsigned long flag,
++				   unsigned long pgoff);
++static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+-	unsigned long flag, unsigned long pgoff);
++	unsigned long flag, unsigned long pgoff) {
++	return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff);
++}
+ 
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+ 	unsigned long len, unsigned long prot,
+@@ -938,6 +944,9 @@ out:
+ 
+ extern int do_munmap(struct mm_struct *, unsigned long, size_t);
+ 
++extern long do_mprotect(struct mm_struct *mm, unsigned long start,
++			size_t len, unsigned long prot);
++
+ extern unsigned long do_brk(unsigned long, unsigned long);
+ 
+ /* filemap.c */
+Index: linux-2.6.git/include/linux/proc_mm.h
+===================================================================
+--- /dev/null
++++ linux-2.6.git/include/linux/proc_mm.h
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/compiler.h>
++
++/* The differences between this one and do_mmap are that:
++ * - we must perform controls for userspace-supplied params (which are
++ *   arch-specific currently). And also fget(fd) if needed and so on...
++ * - we must accept the struct mm_struct on which to act as first param, and the
++ *   offset in byte rather than page units as last param.
++ */
++static inline long __do_mmap(struct mm_struct *mm, unsigned long addr,
++		     unsigned long len, unsigned long prot,
++		     unsigned long flags, unsigned long fd,
++		     unsigned long off);
++
++/* This header can be used only on archs defining CONFIG_PROC_MM in their
++ * configs, so asm/proc_mm.h can still exist only for the needed archs.
++ * Including it only in the x86-64 case does not make sense.*/
++#include <asm/proc_mm.h>
++
++/*XXX: this is defined on x86_64, but not on every 64-bit arch (not on sh64).*/
++#ifdef CONFIG_64BIT
++
++#define write_proc_mm write_proc_mm_emul
++#define write_proc_mm64 write_proc_mm_native
++
++/* It would make more sense to do this mapping the reverse direction, to map the
++ * called name to the defined one and not the reverse. Like the 2nd example
++ */
++/*#define proc_mm_get_mm proc_mm_get_mm_emul
++#define proc_mm_get_mm64 proc_mm_get_mm_native*/
++
++#define proc_mm_get_mm_emul proc_mm_get_mm
++#define proc_mm_get_mm_native proc_mm_get_mm64
++
++#else
++
++#define write_proc_mm write_proc_mm_native
++#undef write_proc_mm64
++
++/*#define proc_mm_get_mm proc_mm_get_mm_native
++#undef proc_mm_get_mm64*/
++
++#define proc_mm_get_mm_native proc_mm_get_mm
++#undef proc_mm_get_mm_emul
++
++#endif
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++	unsigned long addr;
++	unsigned long len;
++	unsigned long prot;
++	unsigned long flags;
++	unsigned long fd;
++	unsigned long offset;
++};
++
++struct mm_munmap {
++	unsigned long addr;
++	unsigned long len;
++};
++
++struct mm_mprotect {
++	unsigned long addr;
++	unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++	int op;
++	union {
++		struct mm_mmap mmap;
++		struct mm_munmap munmap;
++	        struct mm_mprotect mprotect;
++		int copy_segments;
++	} u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++/* Cope with older kernels */
++#ifndef __acquires
++#define __acquires(x)
++#endif
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/*
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++extern void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock);
++#else
++static inline void lock_fix_dumpable_setting(struct task_struct * child,
++		struct mm_struct* new) __acquires(child->alloc_lock)
++{
++	task_lock(child);
++}
++#endif
++
++#endif
+Index: linux-2.6.git/localversion-skas
+===================================================================
+--- /dev/null
++++ linux-2.6.git/localversion-skas
+@@ -0,0 +1 @@
++-skas3-v9-pre9
+Index: linux-2.6.git/mm/Makefile
+===================================================================
+--- linux-2.6.git.orig/mm/Makefile
++++ linux-2.6.git/mm/Makefile
+@@ -24,3 +24,8 @@ obj-$(CONFIG_MEMORY_HOTPLUG) += memory_h
+ obj-$(CONFIG_FS_XIP) += filemap_xip.o
+ obj-$(CONFIG_MIGRATION) += migrate.o
+ 
++obj-$(CONFIG_PROC_MM)	+= proc_mm.o
++
++ifeq ($(CONFIG_PROC_MM),y)
++obj-m			+= proc_mm-mod.o
++endif
+Index: linux-2.6.git/mm/mmap.c
+===================================================================
+--- linux-2.6.git.orig/mm/mmap.c
++++ linux-2.6.git/mm/mmap.c
+@@ -875,11 +875,11 @@ void vm_stat_account(struct mm_struct *m
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+ 
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-			unsigned long len, unsigned long prot,
+-			unsigned long flags, unsigned long pgoff)
++unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file,
++			    unsigned long addr, unsigned long len,
++			    unsigned long prot, unsigned long flags,
++			    unsigned long pgoff)
+ {
+-	struct mm_struct * mm = current->mm;
+ 	struct vm_area_struct * vma, * prev;
+ 	struct inode *inode;
+ 	unsigned int vm_flags;
+@@ -1153,7 +1153,7 @@ unacct_error:
+ 	return error;
+ }
+ 
+-EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(__do_mmap_pgoff);
+ 
+ /* Get an address range which is currently unmapped.
+  * For shmat() with addr=0.
+Index: linux-2.6.git/mm/mprotect.c
+===================================================================
+--- linux-2.6.git.orig/mm/mprotect.c
++++ linux-2.6.git/mm/mprotect.c
+@@ -179,8 +179,9 @@ fail:
+ 	return error;
+ }
+ 
+-asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++long
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len,
++	     unsigned long prot)
+ {
+ 	unsigned long vm_flags, nstart, end, tmp, reqprot;
+ 	struct vm_area_struct *vma, *prev;
+@@ -211,9 +212,9 @@ sys_mprotect(unsigned long start, size_t
+ 
+ 	vm_flags = calc_vm_prot_bits(prot);
+ 
+-	down_write(&current->mm->mmap_sem);
++	down_write(&mm->mmap_sem);
+ 
+-	vma = find_vma_prev(current->mm, start, &prev);
++	vma = find_vma_prev(mm, start, &prev);
+ 	error = -ENOMEM;
+ 	if (!vma)
+ 		goto out;
+@@ -275,6 +276,15 @@ sys_mprotect(unsigned long start, size_t
+ 		}
+ 	}
+ out:
+-	up_write(&current->mm->mmap_sem);
++	up_write(&mm->mmap_sem);
+ 	return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++	long ret = do_mprotect(current->mm, start, len, prot);
++	/* A tail call would reorder parameters on the stack and they would then
++	 * be restored at the wrong places. */
++	prevent_tail_call(ret);
++	return ret;
++}
+Index: linux-2.6.git/mm/proc_mm-mod.c
+===================================================================
+--- /dev/null
++++ linux-2.6.git/mm/proc_mm-mod.c
+@@ -0,0 +1,51 @@
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/proc_mm.h>
++#include <linux/ptrace.h>
++#include <linux/module.h>
++
++#ifdef CONFIG_64BIT
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "32->" #member " \t: %ld\n", (long) offsetof(struct type ## 32, member))
++#else
++#define PRINT_OFFSET(type, member) \
++	printk(KERN_DEBUG "struct " #type "->" #member " \t: %ld\n", (long) offsetof(struct type, member))
++#endif
++
++static int debug_printoffsets(void)
++{
++	printk(KERN_DEBUG "Skas core structures layout BEGIN:\n");
++	PRINT_OFFSET(mm_mmap, addr);
++	PRINT_OFFSET(mm_mmap, len);
++	PRINT_OFFSET(mm_mmap, prot);
++	PRINT_OFFSET(mm_mmap, flags);
++	PRINT_OFFSET(mm_mmap, fd);
++	PRINT_OFFSET(mm_mmap, offset);
++
++	PRINT_OFFSET(mm_munmap, addr);
++	PRINT_OFFSET(mm_munmap, len);
++
++	PRINT_OFFSET(mm_mprotect, addr);
++	PRINT_OFFSET(mm_mprotect, len);
++	PRINT_OFFSET(mm_mprotect, prot);
++
++	PRINT_OFFSET(proc_mm_op, op);
++	PRINT_OFFSET(proc_mm_op, u);
++	PRINT_OFFSET(proc_mm_op, u.mmap);
++	PRINT_OFFSET(proc_mm_op, u.munmap);
++	PRINT_OFFSET(proc_mm_op, u.mprotect);
++	PRINT_OFFSET(proc_mm_op, u.copy_segments);
++
++	PRINT_OFFSET(ptrace_faultinfo, is_write);
++	PRINT_OFFSET(ptrace_faultinfo, addr);
++
++	PRINT_OFFSET(ptrace_ldt, func);
++	PRINT_OFFSET(ptrace_ldt, ptr);
++	PRINT_OFFSET(ptrace_ldt, bytecount);
++	printk(KERN_DEBUG "Skas core structures layout END.\n");
++
++	return 0;
++}
++#undef PRINT_OFFSET
++
++module_init(debug_printoffsets);
+Index: linux-2.6.git/mm/proc_mm.c
+===================================================================
+--- /dev/null
++++ linux-2.6.git/mm/proc_mm.c
+@@ -0,0 +1,300 @@
++/*
++ * Copyright (C) 2002 Jeff Dike (jdike at karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/config.h>
++#include <linux/compiler.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/proc_mm.h>
++#include <linux/file.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/mmu_context.h>
++
++#ifdef CONFIG_PROC_MM_DUMPABLE
++/* Checks if a task must be considered dumpable
++ *
++ * XXX: copied from fs/proc/base.c, removed task_lock, added rmb(): this must be
++ * called with task_lock(task) held. */
++static int task_dumpable(struct task_struct *task)
++{
++	int dumpable = 0;
++	struct mm_struct *mm;
++
++	mm = task->mm;
++	if (mm) {
++		rmb();
++		dumpable = mm->dumpable;
++	}
++	return dumpable;
++}
++
++/*
++ * This is to be used in PTRACE_SWITCH_MM handling. We are going to set
++ * child->mm to new, and we must first correctly set new->dumpable.
++ * Since we take task_lock of child and it's needed also by the caller, we
++ * return with it locked.
++ */
++void lock_fix_dumpable_setting(struct task_struct* child, struct mm_struct* new)
++	__acquires(child->alloc_lock)
++{
++	int dumpable = 1;
++
++	/* We must be safe.
++	 * If the child is ptraced from a non-dumpable process,
++	 * let's not be dumpable. If the child is non-dumpable itself,
++	 * copy this property across mm's.
++	 *
++	 * Don't try to be smart for the opposite case and turn
++	 * child->mm->dumpable to 1: I've not made sure it is safe.
++	 */
++
++	task_lock(current);
++	if (unlikely(!task_dumpable(current))) {
++		dumpable = 0;
++	}
++	task_unlock(current);
++
++	task_lock(child);
++	if (likely(dumpable) && unlikely(!task_dumpable(child))) {
++		dumpable = 0;
++	}
++
++	if (!dumpable) {
++		new->dumpable = 0;
++		wmb();
++	}
++}
++#endif
++
++/* Naming conventions are a mess, so I note them down.
++ *
++ * Things ending in _mm can be for everything. It's only for
++ * {open,release}_proc_mm.
++ *
++ * For the rest:
++ *
++ * _mm means /proc/mm, _mm64 means /proc/mm64. This is for the infrastructure
++ * only (for instance proc_mm_get_mm checks whether the file is /proc/mm or
++ * /proc/mm64; for instance the /proc handling).
++ *
++ * While for what is conversion dependant, we use the suffix _native and _emul.
++ * In some cases, there is a mapping between these ones (defined by
++ * <asm/proc_mm.h>).
++ */
++
++/*These two are common to everything.*/
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = mm_alloc();
++	int ret;
++
++	ret = -ENOMEM;
++	if(mm == NULL)
++		goto out_mem;
++
++	init_new_empty_context(mm);
++	arch_pick_mmap_layout(mm);
++#ifdef CONFIG_PROC_MM_DUMPABLE
++	mm->dumpable = current->mm->dumpable;
++	wmb();
++#endif
++
++	file->private_data = mm;
++
++	return 0;
++
++out_mem:
++	return ret;
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++	struct mm_struct *mm = file->private_data;
++
++	mmput(mm);
++	return 0;
++}
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm_native(int fd);
++
++static ssize_t write_proc_mm_native(struct file *file, const char *buffer,
++			     size_t count, loff_t *ppos)
++{
++	struct mm_struct *mm = file->private_data;
++	struct proc_mm_op req;
++	int n, ret;
++
++	if(count > sizeof(req))
++		return(-EINVAL);
++
++	n = copy_from_user(&req, buffer, count);
++	if(n != 0)
++		return(-EFAULT);
++
++	ret = count;
++	switch(req.op){
++	case MM_MMAP: {
++		struct mm_mmap *map = &req.u.mmap;
++
++		/* Nobody ever noticed it, but do_mmap_pgoff() calls
++		 * get_unmapped_area() which checks current->mm, if
++		 * MAP_FIXED is not set, so mmap() could replace
++		 * an old mapping.
++		 */
++		if (! (map->flags & MAP_FIXED))
++			return(-EINVAL);
++
++		ret = __do_mmap(mm, map->addr, map->len, map->prot,
++			       map->flags, map->fd, map->offset);
++		if((ret & ~PAGE_MASK) == 0)
++			ret = count;
++
++		break;
++	}
++	case MM_MUNMAP: {
++		struct mm_munmap *unmap = &req.u.munmap;
++
++		down_write(&mm->mmap_sem);
++		ret = do_munmap(mm, unmap->addr, unmap->len);
++		up_write(&mm->mmap_sem);
++
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	case MM_MPROTECT: {
++		struct mm_mprotect *protect = &req.u.mprotect;
++
++		ret = do_mprotect(mm, protect->addr, protect->len,
++				  protect->prot);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++
++	case MM_COPY_SEGMENTS: {
++		struct mm_struct *from = proc_mm_get_mm_native(req.u.copy_segments);
++
++		if(IS_ERR(from)){
++			ret = PTR_ERR(from);
++			break;
++		}
++
++		ret = copy_context(mm, from);
++		if(ret == 0)
++			ret = count;
++		break;
++	}
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
++/*These three are all for /proc/mm.*/
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	if(file->f_op != &proc_mm_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++
++static struct file_operations proc_mm_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm,
++};
++
++/*Macro-ify it to avoid the duplication.*/
++static int make_proc_mm(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm);
++
++/*XXX: change the option.*/
++#ifdef CONFIG_64BIT
++static struct file_operations proc_mm64_fops = {
++	.open		= open_proc_mm,
++	.release	= release_proc_mm,
++	.write		= write_proc_mm64,
++};
++
++static int make_proc_mm64(void)
++{
++	struct proc_dir_entry *ent;
++
++	ent = create_proc_entry("mm64", 0222, &proc_root);
++	if(ent == NULL){
++		printk("make_proc_mm : Failed to register /proc/mm64\n");
++		return(0);
++	}
++	ent->proc_fops = &proc_mm64_fops;
++
++	return 0;
++}
++
++__initcall(make_proc_mm64);
++
++struct mm_struct *proc_mm_get_mm64(int fd)
++{
++	struct mm_struct *ret = ERR_PTR(-EBADF);
++	struct file *file;
++
++	file = fget(fd);
++	if (!file)
++		goto out;
++
++	ret = ERR_PTR(-EINVAL);
++	/*This is the only change.*/
++	if(file->f_op != &proc_mm64_fops)
++		goto out_fput;
++
++	ret = file->private_data;
++out_fput:
++	fput(file);
++out:
++	return(ret);
++}
++#endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */




More information about the Pkg-uml-commit mailing list