um: Save FPU registers between task switches
[linux-2.6.git] / arch / um / kernel / process.c
index 62a4e0e..21c1ae7 100644 (file)
@@ -4,19 +4,23 @@
  * Licensed under the GPL
  */
 
-#include "linux/stddef.h"
-#include "linux/err.h"
-#include "linux/hardirq.h"
-#include "linux/mm.h"
-#include "linux/personality.h"
-#include "linux/proc_fs.h"
-#include "linux/ptrace.h"
-#include "linux/random.h"
-#include "linux/sched.h"
-#include "linux/tick.h"
-#include "linux/threads.h"
-#include "asm/pgtable.h"
-#include "asm/uaccess.h"
+#include <linux/stddef.h>
+#include <linux/err.h>
+#include <linux/hardirq.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/personality.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/tick.h>
+#include <linux/threads.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
 #include "as-layout.h"
 #include "kern_util.h"
 #include "os.h"
@@ -30,7 +34,7 @@
  */
 struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
 
-static inline int external_pid(struct task_struct *task)
+static inline int external_pid(void)
 {
        /* FIXME: Need to look up userspace_pid by cpu */
        return userspace_pid[0];
@@ -40,7 +44,7 @@ int pid_to_processor_id(int pid)
 {
        int i;
 
-       for(i = 0; i < ncpus; i++) {
+       for (i = 0; i < ncpus; i++) {
                if (cpu_tasks[i].pid == pid)
                        return i;
        }
@@ -78,7 +82,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 static inline void set_current(struct task_struct *task)
 {
        cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
-               { external_pid(task), task });
+               { external_pid(), task });
 }
 
 extern void arch_switch_to(struct task_struct *to);
@@ -94,14 +98,15 @@ void *_switch_to(void *prev, void *next, void *last)
        do {
                current->thread.saved_task = NULL;
 
-               switch_threads(&from->thread.switch_buf, &to->thread.switch_buf);
+               switch_threads(&from->thread.switch_buf,
+                              &to->thread.switch_buf);
 
                arch_switch_to(current);
 
                if (current->thread.saved_task)
                        show_regs(&(current->thread.regs));
-               next = current->thread.saved_task;
-               prev = current;
+               to = current->thread.saved_task;
+               from = current;
        } while (current->thread.saved_task);
 
        return current->thread.prev_sched;
@@ -125,8 +130,6 @@ void *get_current(void)
        return current;
 }
 
-extern void schedule_tail(struct task_struct *prev);
-
 /*
  * This is called magically, by its address being stuffed in a jmp_buf
  * and being longjmp-d to.
@@ -178,7 +181,7 @@ void fork_handler(void)
        userspace(&current->thread.regs.regs);
 }
 
-int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+int copy_thread(unsigned long clone_flags, unsigned long sp,
                unsigned long stack_top, struct task_struct * p,
                struct pt_regs *regs)
 {
@@ -199,7 +202,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
                arch_copy_thread(&current->thread.arch, &p->thread.arch);
        }
        else {
-               init_thread_registers(&p->thread.regs.regs);
+               get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp);
                p->thread.request.u.thread = current->thread.request.u.thread;
                handler = new_thread_handler;
        }
@@ -232,7 +235,7 @@ void default_idle(void)
 {
        unsigned long long nsecs;
 
-       while(1) {
+       while (1) {
                /* endless idle loop with no priority at all */
 
                /*
@@ -242,7 +245,7 @@ void default_idle(void)
                if (need_resched())
                        schedule();
 
-               tick_nohz_stop_sched_tick();
+               tick_nohz_stop_sched_tick(1);
                nsecs = disable_timer();
                idle_sleep(nsecs);
                tick_nohz_restart_sched_tick();
@@ -251,57 +254,10 @@ void default_idle(void)
 
 void cpu_idle(void)
 {
-       cpu_tasks[current_thread->cpu].pid = os_getpid();
+       cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
        default_idle();
 }
 
-void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
-                     pte_t *pte_out)
-{
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-       pte_t ptent;
-
-       if (task->mm == NULL)
-               return ERR_PTR(-EINVAL);
-       pgd = pgd_offset(task->mm, addr);
-       if (!pgd_present(*pgd))
-               return ERR_PTR(-EINVAL);
-
-       pud = pud_offset(pgd, addr);
-       if (!pud_present(*pud))
-               return ERR_PTR(-EINVAL);
-
-       pmd = pmd_offset(pud, addr);
-       if (!pmd_present(*pmd))
-               return ERR_PTR(-EINVAL);
-
-       pte = pte_offset_kernel(pmd, addr);
-       ptent = *pte;
-       if (!pte_present(ptent))
-               return ERR_PTR(-EINVAL);
-
-       if (pte_out != NULL)
-               *pte_out = ptent;
-       return (void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK);
-}
-
-char *current_cmd(void)
-{
-#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
-       return "(Unknown)";
-#else
-       void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
-       return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
-#endif
-}
-
-void dump_thread(struct pt_regs *regs, struct user *u)
-{
-}
-
 int __cant_sleep(void) {
        return in_atomic() || irqs_disabled() || in_interrupt();
        /* Is in_interrupt() really needed? */
@@ -312,7 +268,7 @@ int user_context(unsigned long sp)
        unsigned long stack;
 
        stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
-       return stack != (unsigned long) current_thread;
+       return stack != (unsigned long) current_thread_info();
 }
 
 extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
@@ -354,7 +310,7 @@ int strlen_user_proc(char __user *str)
 int smp_sigio_handler(void)
 {
 #ifdef CONFIG_SMP
-       int cpu = current_thread->cpu;
+       int cpu = current_thread_info()->cpu;
        IPI_handler(cpu);
        if (cpu != 0)
                return 1;
@@ -364,7 +320,7 @@ int smp_sigio_handler(void)
 
 int cpu(void)
 {
-       return current_thread->cpu;
+       return current_thread_info()->cpu;
 }
 
 static atomic_t using_sysemu = ATOMIC_INIT(0);
@@ -382,16 +338,19 @@ int get_using_sysemu(void)
        return atomic_read(&using_sysemu);
 }
 
-static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data)
+static int sysemu_proc_show(struct seq_file *m, void *v)
 {
-       if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size)
-               /* No overflow */
-               *eof = 1;
+       seq_printf(m, "%d\n", get_using_sysemu());
+       return 0;
+}
 
-       return strlen(buf);
+static int sysemu_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, sysemu_proc_show, NULL);
 }
 
-static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned long count,void *data)
+static ssize_t sysemu_proc_write(struct file *file, const char __user *buf,
+                                size_t count, loff_t *pos)
 {
        char tmp[2];
 
@@ -404,13 +363,22 @@ static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned
        return count;
 }
 
+static const struct file_operations sysemu_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = sysemu_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = sysemu_proc_write,
+};
+
 int __init make_proc_sysemu(void)
 {
        struct proc_dir_entry *ent;
        if (!sysemu_supported)
                return 0;
 
-       ent = create_proc_entry("sysemu", 0600, &proc_root);
+       ent = proc_create("sysemu", 0600, NULL, &sysemu_proc_fops);
 
        if (ent == NULL)
        {
@@ -418,9 +386,6 @@ int __init make_proc_sysemu(void)
                return 0;
        }
 
-       ent->read_proc  = proc_read_sysemu;
-       ent->write_proc = proc_write_sysemu;
-
        return 0;
 }
 
@@ -430,7 +395,7 @@ int singlestepping(void * t)
 {
        struct task_struct *task = t ? t : current;
 
-       if ( ! (task->ptrace & PT_DTRACE) )
+       if (!(task->ptrace & PT_DTRACE))
                return 0;
 
        if (task->thread.singlestep_syscall)
@@ -489,3 +454,11 @@ unsigned long get_wchan(struct task_struct *p)
 
        return 0;
 }
+
+int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+{
+       int cpu = current_thread_info()->cpu;
+
+       return save_fp_registers(userspace_pid[cpu], (unsigned long *) fpu);
+}
+