Pull sony into release branch
[pandora-kernel.git] / arch / sh / kernel / process.c
index a52b13a..9d6a438 100644 (file)
@@ -1,42 +1,30 @@
-/* $Id: process.c,v 1.28 2004/05/05 16:54:23 lethal Exp $
+/*
+ * arch/sh/kernel/process.c
  *
- *  linux/arch/sh/kernel/process.c
+ * This file handles the architecture-dependent parts of process handling..
  *
  *  Copyright (C) 1995  Linus Torvalds
  *
  *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
  *                  Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
+ *                  Copyright (C) 2002 - 2006  Paul Mundt
  */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
 #include <linux/module.h>
-#include <linux/unistd.h>
 #include <linux/mm.h>
 #include <linux/elfcore.h>
-#include <linux/a.out.h>
-#include <linux/slab.h>
 #include <linux/pm.h>
-#include <linux/ptrace.h>
 #include <linux/kallsyms.h>
 #include <linux/kexec.h>
-
-#include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
-#include <asm/elf.h>
 #include <asm/ubc.h>
 
-static int hlt_counter=0;
-
+static int hlt_counter;
 int ubc_usercnt = 0;
 
 #define HARD_IDLE_TIMEOUT (HZ / 3)
 
 void (*pm_idle)(void);
-
 void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
@@ -44,14 +32,12 @@ void disable_hlt(void)
 {
        hlt_counter++;
 }
-
 EXPORT_SYMBOL(disable_hlt);
 
 void enable_hlt(void)
 {
        hlt_counter--;
 }
-
 EXPORT_SYMBOL(enable_hlt);
 
 void default_idle(void)
@@ -152,19 +138,21 @@ __asm__(".align 5\n"
        ".align 2\n\t"
        "1:.long do_exit");
 
+/* Don't use this in BL=1(cli).  Or else, CPU resets! */
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{      /* Don't use this in BL=1(cli).  Or else, CPU resets! */
+{
        struct pt_regs regs;
 
        memset(&regs, 0, sizeof(regs));
-       regs.regs[4] = (unsigned long) arg;
-       regs.regs[5] = (unsigned long) fn;
+       regs.regs[4] = (unsigned long)arg;
+       regs.regs[5] = (unsigned long)fn;
 
-       regs.pc = (unsigned long) kernel_thread_helper;
+       regs.pc = (unsigned long)kernel_thread_helper;
        regs.sr = (1 << 30);
 
        /* Ok, create the new process.. */
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+                      &regs, 0, NULL, NULL);
 }
 
 /*
@@ -211,21 +199,20 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
        return fpvalid;
 }
 
-/* 
+/*
  * Capture the user space registers if the task is not running (in user space)
  */
 int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
 {
        struct pt_regs ptregs;
-       
+
        ptregs = *task_pt_regs(tsk);
        elf_core_copy_regs(regs, &ptregs);
 
        return 1;
 }
 
-int
-dump_task_fpu (struct task_struct *tsk, elf_fpregset_t *fpu)
+int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu)
 {
        int fpvalid = 0;
 
@@ -263,12 +250,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
                childregs->regs[15] = usp;
                ti->addr_limit = USER_DS;
        } else {
-               childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+               childregs->regs[15] = (unsigned long)task_stack_page(p) +
+                                                       THREAD_SIZE;
                ti->addr_limit = KERNEL_DS;
        }
-        if (clone_flags & CLONE_SETTLS) {
+
+        if (clone_flags & CLONE_SETTLS)
                childregs->gbr = childregs->regs[0];
-       }
+
        childregs->regs[0] = 0; /* Set return value for child */
 
        p->thread.sp = (unsigned long) childregs;
@@ -280,8 +269,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 }
 
 /* Tracing by user break controller.  */
-static void
-ubc_set_tracing(int asid, unsigned long pc)
+static void ubc_set_tracing(int asid, unsigned long pc)
 {
 #if defined(CONFIG_CPU_SH4A)
        unsigned long val;
@@ -297,7 +285,7 @@ ubc_set_tracing(int asid, unsigned long pc)
        val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
        ctrl_outl(val, UBC_CRR0);
 
-       /* Read UBC register that we writed last. For chekking UBC Register changed */
+       /* Read UBC register that we wrote last, for checking update */
        val = ctrl_inl(UBC_CRR0);
 
 #else  /* CONFIG_CPU_SH4A */
@@ -305,13 +293,14 @@ ubc_set_tracing(int asid, unsigned long pc)
 
 #ifdef CONFIG_MMU
        /* We don't have any ASID settings for the SH-2! */
-       if (cpu_data->type != CPU_SH7604)
+       if (current_cpu_data.type != CPU_SH7604)
                ctrl_outb(asid, UBC_BASRA);
 #endif
 
        ctrl_outl(0, UBC_BAMRA);
 
-       if (cpu_data->type == CPU_SH7729 || cpu_data->type == CPU_SH7710) {
+       if (current_cpu_data.type == CPU_SH7729 ||
+           current_cpu_data.type == CPU_SH7710) {
                ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
                ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
        } else {
@@ -325,7 +314,8 @@ ubc_set_tracing(int asid, unsigned long pc)
  *     switch_to(x,y) should switch tasks from x to y.
  *
  */
-struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *next)
+struct task_struct *__switch_to(struct task_struct *prev,
+                               struct task_struct *next)
 {
 #if defined(CONFIG_SH_FPU)
        unlazy_fpu(prev, task_pt_regs(prev));
@@ -354,7 +344,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne
 #ifdef CONFIG_MMU
        /*
         * Restore the kernel mode register
-        *      k7 (r7_bank1)
+        *      k7 (r7_bank1)
         */
        asm volatile("ldc       %0, r7_bank"
                     : /* no output */
@@ -367,7 +357,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne
        else if (next->thread.ubc_pc && next->mm) {
                int asid = 0;
 #ifdef CONFIG_MMU
-               asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK;
+               asid |= cpu_asid(smp_processor_id(), next->mm);
 #endif
                ubc_set_tracing(asid, next->thread.ubc_pc);
        } else {
@@ -385,10 +375,11 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne
 
 asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
                        unsigned long r6, unsigned long r7,
-                       struct pt_regs regs)
+                       struct pt_regs __regs)
 {
+       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
 #ifdef CONFIG_MMU
-       return do_fork(SIGCHLD, regs.regs[15], &regs, 0, NULL, NULL);
+       return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
 #else
        /* fork almost works, enough to trick you into looking elsewhere :-( */
        return -EINVAL;
@@ -398,12 +389,14 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
                         unsigned long parent_tidptr,
                         unsigned long child_tidptr,
-                        struct pt_regs regs)
+                        struct pt_regs __regs)
 {
+       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
        if (!newsp)
-               newsp = regs.regs[15];
-       return do_fork(clone_flags, newsp, &regs, 0,
-                       (int __user *)parent_tidptr, (int __user *)child_tidptr);
+               newsp = regs->regs[15];
+       return do_fork(clone_flags, newsp, regs, 0,
+                       (int __user *)parent_tidptr,
+                       (int __user *)child_tidptr);
 }
 
 /*
@@ -418,9 +411,10 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
  */
 asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
                         unsigned long r6, unsigned long r7,
-                        struct pt_regs regs)
+                        struct pt_regs __regs)
 {
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.regs[15], &regs,
+       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs,
                       0, NULL, NULL);
 }
 
@@ -429,8 +423,9 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
  */
 asmlinkage int sys_execve(char *ufilename, char **uargv,
                          char **uenvp, unsigned long r7,
-                         struct pt_regs regs)
+                         struct pt_regs __regs)
 {
+       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
        int error;
        char *filename;
 
@@ -442,7 +437,7 @@ asmlinkage int sys_execve(char *ufilename, char **uargv,
        error = do_execve(filename,
                          (char __user * __user *)uargv,
                          (char __user * __user *)uenvp,
-                         &regs);
+                         regs);
        if (error == 0) {
                task_lock(current);
                current->ptrace &= ~PT_DTRACE;
@@ -466,15 +461,14 @@ unsigned long get_wchan(struct task_struct *p)
         */
        pc = thread_saved_pc(p);
        if (in_sched_functions(pc)) {
-               schedule_frame = ((unsigned long *)(long)p->thread.sp)[1];
-               return (unsigned long)((unsigned long *)schedule_frame)[1];
+               schedule_frame = (unsigned long)p->thread.sp;
+               return ((unsigned long *)schedule_frame)[21];
        }
+
        return pc;
 }
 
-asmlinkage void break_point_trap(unsigned long r4, unsigned long r5,
-                                unsigned long r6, unsigned long r7,
-                                struct pt_regs regs)
+asmlinkage void break_point_trap(void)
 {
        /* Clear tracing.  */
 #if defined(CONFIG_CPU_SH4A)
@@ -490,10 +484,40 @@ asmlinkage void break_point_trap(unsigned long r4, unsigned long r5,
        force_sig(SIGTRAP, current);
 }
 
-asmlinkage void break_point_trap_software(unsigned long r4, unsigned long r5,
-                                         unsigned long r6, unsigned long r7,
-                                         struct pt_regs regs)
+/*
+ * Generic trap handler.
+ */
+asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
+                                  unsigned long r6, unsigned long r7,
+                                  struct pt_regs __regs)
+{
+       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+
+       /* Rewind */
+       regs->pc -= 2;
+
+       force_sig(SIGTRAP, current);
+}
+
+/*
+ * Special handler for BUG() traps.
+ */
+asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
+                                unsigned long r6, unsigned long r7,
+                                struct pt_regs __regs)
 {
-       regs.pc -= 2;
+       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+
+       /* Rewind */
+       regs->pc -= 2;
+
+#ifdef CONFIG_BUG
+       if (__kernel_text_address(instruction_pointer(regs))) {
+               u16 insn = *(u16 *)instruction_pointer(regs);
+               if (insn == TRAPA_BUG_OPCODE)
+                       handle_BUG(regs);
+       }
+#endif
+
        force_sig(SIGTRAP, current);
 }