vserver 1.9.3
[linux-2.6.git] / arch / ppc64 / kernel / process.c
index 5acc567..8211337 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/prctl.h>
 #include <linux/ptrace.h>
 #include <linux/kallsyms.h>
+#include <linux/interrupt.h>
 #include <linux/version.h>
 
 #include <asm/pgtable.h>
@@ -47,7 +48,6 @@
 #include <asm/ppcdebug.h>
 #include <asm/machdep.h>
 #include <asm/iSeries/HvCallHpt.h>
-#include <asm/hardirq.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
 #include <asm/tlbflush.h>
@@ -147,7 +147,6 @@ EXPORT_SYMBOL(enable_kernel_altivec);
  */
 void flush_altivec_to_thread(struct task_struct *tsk)
 {
-#ifdef CONFIG_ALTIVEC
        if (tsk->thread.regs) {
                preempt_disable();
                if (tsk->thread.regs->msr & MSR_VEC) {
@@ -158,7 +157,6 @@ void flush_altivec_to_thread(struct task_struct *tsk)
                }
                preempt_enable();
        }
-#endif
 }
 
 int dump_task_altivec(struct pt_regs *regs, elf_vrregset_t *vrregs)
@@ -356,6 +354,16 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        kregs = (struct pt_regs *) sp;
        sp -= STACK_FRAME_OVERHEAD;
        p->thread.ksp = sp;
+       if (cur_cpu_spec->cpu_features & CPU_FTR_SLB) {
+               unsigned long sp_vsid = get_kernel_vsid(sp);
+
+               sp_vsid <<= SLB_VSID_SHIFT;
+               sp_vsid |= SLB_VSID_KERNEL;
+               if (cur_cpu_spec->cpu_features & CPU_FTR_16M_PAGE)
+                       sp_vsid |= SLB_VSID_L;
+
+               p->thread.ksp_vsid = sp_vsid;
+       }
 
        /*
         * The PPC64 ABI makes use of a TOC to contain function 
@@ -387,11 +395,22 @@ void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp)
        /* Check whether the e_entry function descriptor entries
         * need to be relocated before we can use them.
         */
-       if ( load_addr != 0 ) {
+       if (load_addr != 0) {
                entry += load_addr;
                toc   += load_addr;
        }
 
+       /*
+        * If we exec out of a kernel thread then thread.regs will not be
+        * set. Do it now.
+        */
+       if (!current->thread.regs) {
+               unsigned long childregs = (unsigned long)current->thread_info +
+                                               THREAD_SIZE;
+               childregs -= sizeof(struct pt_regs);
+               current->thread.regs = (struct pt_regs *)childregs;
+       }
+
        regs->nip = entry;
        regs->gpr[1] = sp;
        regs->gpr[2] = toc;
@@ -458,7 +477,7 @@ int sys_clone(unsigned long clone_flags, unsigned long p2, unsigned long p3,
                }
        }
 
-       return do_fork(clone_flags & ~CLONE_IDLETASK, p2, regs, 0,
+       return do_fork(clone_flags, p2, regs, 0,
                    (int __user *)parent_tidptr, (int __user *)child_tidptr);
 }