diff options
Diffstat (limited to 'arch/um/kernel/process.c')
-rw-r--r-- | arch/um/kernel/process.c | 226 |
1 files changed, 137 insertions, 89 deletions
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index bfa52f206bb..0eae00b3e58 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -1,53 +1,30 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Copyright 2003 PathScale, Inc. * Licensed under the GPL */ -#include "linux/kernel.h" -#include "linux/sched.h" -#include "linux/interrupt.h" -#include "linux/string.h" +#include "linux/stddef.h" +#include "linux/err.h" +#include "linux/hardirq.h" #include "linux/mm.h" -#include "linux/slab.h" -#include "linux/utsname.h" -#include "linux/fs.h" -#include "linux/utime.h" -#include "linux/smp_lock.h" -#include "linux/module.h" -#include "linux/init.h" -#include "linux/capability.h" -#include "linux/vmalloc.h" -#include "linux/spinlock.h" +#include "linux/personality.h" #include "linux/proc_fs.h" #include "linux/ptrace.h" #include "linux/random.h" -#include "linux/personality.h" -#include "asm/unistd.h" -#include "asm/mman.h" -#include "asm/segment.h" -#include "asm/stat.h" +#include "linux/sched.h" +#include "linux/tick.h" +#include "linux/threads.h" #include "asm/pgtable.h" -#include "asm/processor.h" -#include "asm/tlbflush.h" #include "asm/uaccess.h" -#include "asm/user.h" -#include "kern_util.h" #include "as-layout.h" -#include "kern.h" -#include "signal_kern.h" -#include "init.h" -#include "irq_user.h" -#include "mem_user.h" -#include "tlb.h" -#include "frame_kern.h" -#include "sigcontext.h" +#include "kern_util.h" #include "os.h" -#include "mode.h" -#include "mode_kern.h" -#include "choose-mode.h" +#include "skas.h" +#include "tlb.h" -/* This is a per-cpu array. A processor only modifies its entry and it only +/* + * This is a per-cpu array. A processor only modifies its entry and it only * cares about its entry, so it's OK if another processor is modifying its * entry. */ @@ -55,15 +32,16 @@ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; static inline int external_pid(struct task_struct *task) { - return CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task); + /* FIXME: Need to look up userspace_pid by cpu */ + return userspace_pid[0]; } int pid_to_processor_id(int pid) { int i; - for(i = 0; i < ncpus; i++){ - if(cpu_tasks[i].pid == pid) + for(i = 0; i < ncpus; i++) { + if (cpu_tasks[i].pid == pid) return i; } return -1; @@ -82,9 +60,9 @@ unsigned long alloc_stack(int order, int atomic) if (atomic) flags = GFP_ATOMIC; page = __get_free_pages(flags, order); - if(page == 0) + if (page == 0) return 0; - stack_protections(page); + return page; } @@ -105,6 +83,8 @@ static inline void set_current(struct task_struct *task) { external_pid(task), task }); } +extern void arch_switch_to(struct task_struct *from, struct task_struct *to); + void *_switch_to(void *prev, void *next, void *last) { struct task_struct *from = prev; @@ -114,9 +94,14 @@ void *_switch_to(void *prev, void *next, void *last) set_current(to); do { - current->thread.saved_task = NULL ; - CHOOSE_MODE_PROC(switch_to_tt, switch_to_skas, prev, next); - if(current->thread.saved_task) + current->thread.saved_task = NULL; + + switch_threads(&from->thread.switch_buf, + &to->thread.switch_buf); + + arch_switch_to(current->thread.prev_sched, current); + + if (current->thread.saved_task) show_regs(&(current->thread.regs)); next= current->thread.saved_task; prev= current; @@ -128,20 +113,14 @@ void *_switch_to(void *prev, void *next, void *last) void interrupt_end(void) { - if(need_resched()) + if (need_resched()) schedule(); - if(test_tsk_thread_flag(current, TIF_SIGPENDING)) + if (test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal(); } -void release_thread(struct task_struct *task) -{ - CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); -} - void exit_thread(void) { - unprotect_stack((unsigned long) current_thread); } void *get_current(void) @@ -149,28 +128,99 @@ 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. + */ +void new_thread_handler(void) +{ + int (*fn)(void *), n; + void *arg; + + if (current->thread.prev_sched != NULL) + schedule_tail(current->thread.prev_sched); + current->thread.prev_sched = NULL; + + fn = current->thread.request.u.thread.proc; + arg = current->thread.request.u.thread.arg; + + /* + * The return value is 1 if the kernel thread execs a process, + * 0 if it just exits + */ + n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); + if (n == 1) { + /* Handle any immediate reschedules or signals */ + interrupt_end(); + userspace(¤t->thread.regs.regs); + } + else do_exit(0); +} + +/* Called magically, see new_thread_handler above */ +void fork_handler(void) +{ + force_flush_all(); + if (current->thread.prev_sched == NULL) + panic("blech"); + + schedule_tail(current->thread.prev_sched); + + /* + * XXX: if interrupt_end() calls schedule, this call to + * arch_switch_to isn't needed. We could want to apply this to + * improve performance. -bb + */ + arch_switch_to(current->thread.prev_sched, current); + + current->thread.prev_sched = NULL; + + /* Handle any immediate reschedules or signals */ + interrupt_end(); + + userspace(¤t->thread.regs.regs); +} + int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { - int ret; + void (*handler)(void); + int ret = 0; p->thread = (struct thread_struct) INIT_THREAD; - ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, - clone_flags, sp, stack_top, p, regs); - if (ret || !current->thread.forking) - goto out; + if (current->thread.forking) { + memcpy(&p->thread.regs.regs, ®s->regs, + sizeof(p->thread.regs.regs)); + REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.gp, 0); + if (sp != 0) + REGS_SP(p->thread.regs.regs.gp) = sp; - clear_flushed_tls(p); + handler = fork_handler; - /* - * Set a new TLS for the child thread? - */ - if (clone_flags & CLONE_SETTLS) - ret = arch_copy_tls(p); + arch_copy_thread(¤t->thread.arch, &p->thread.arch); + } + else { + init_thread_registers(&p->thread.regs.regs); + p->thread.request.u.thread = current->thread.request.u.thread; + handler = new_thread_handler; + } + + new_thread(task_stack_page(p), &p->thread.switch_buf, handler); + + if (current->thread.forking) { + clear_flushed_tls(p); + + /* + * Set a new TLS for the child thread? + */ + if (clone_flags & CLONE_SETTLS) + ret = arch_copy_tls(p); + } -out: return ret; } @@ -179,39 +229,35 @@ void initial_thread_cb(void (*proc)(void *), void *arg) int save_kmalloc_ok = kmalloc_ok; kmalloc_ok = 0; - CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, - arg); + initial_thread_cb_skas(proc, arg); kmalloc_ok = save_kmalloc_ok; } -#ifdef CONFIG_MODE_TT -unsigned long stack_sp(unsigned long page) -{ - return page + PAGE_SIZE - sizeof(void *); -} -#endif - void default_idle(void) { - CHOOSE_MODE(uml_idle_timer(), (void) 0); + unsigned long long nsecs; - while(1){ + while(1) { /* endless idle loop with no priority at all */ /* * although we are an idle CPU, we do not want to * get into the scheduler unnecessarily. */ - if(need_resched()) + if (need_resched()) schedule(); - idle_sleep(10); + tick_nohz_stop_sched_tick(); + nsecs = disable_timer(); + idle_sleep(nsecs); + tick_nohz_restart_sched_tick(); } } void cpu_idle(void) { - CHOOSE_MODE(init_idle_tt(), init_idle_skas()); + cpu_tasks[current_thread->cpu].pid = os_getpid(); + default_idle(); } void *um_virt_to_phys(struct task_struct *task, unsigned long addr, @@ -223,26 +269,26 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte; pte_t ptent; - if(task->mm == NULL) + if (task->mm == NULL) return ERR_PTR(-EINVAL); pgd = pgd_offset(task->mm, addr); - if(!pgd_present(*pgd)) + if (!pgd_present(*pgd)) return ERR_PTR(-EINVAL); pud = pud_offset(pgd, addr); - if(!pud_present(*pud)) + if (!pud_present(*pud)) return ERR_PTR(-EINVAL); pmd = pmd_offset(pud, addr); - if(!pmd_present(*pmd)) + if (!pmd_present(*pmd)) return ERR_PTR(-EINVAL); pte = pte_offset_kernel(pmd, addr); ptent = *pte; - if(!pte_present(ptent)) + if (!pte_present(ptent)) return ERR_PTR(-EINVAL); - if(pte_out != NULL) + if (pte_out != NULL) *pte_out = ptent; return (void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK); } @@ -315,7 +361,7 @@ int smp_sigio_handler(void) #ifdef CONFIG_SMP int cpu = current_thread->cpu; IPI_handler(cpu); - if(cpu != 0) + if (cpu != 0) return 1; #endif return 0; @@ -343,7 +389,8 @@ int get_using_sysemu(void) static int proc_read_sysemu(char *buf, char **start, off_t offset, int size,int *eof, void *data) { - if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) /*No overflow*/ + if (snprintf(buf, size, "%d\n", get_using_sysemu()) < size) + /* No overflow */ *eof = 1; return strlen(buf); @@ -358,7 +405,8 @@ static int proc_write_sysemu(struct file *file,const char __user *buf, unsigned if (tmp[0] >= '0' && tmp[0] <= '2') set_using_sysemu(tmp[0] - '0'); - return count; /*We use the first char, but pretend to write everything*/ + /* We use the first char, but pretend to write everything */ + return count; } int __init make_proc_sysemu(void) @@ -388,10 +436,10 @@ int singlestepping(void * t) struct task_struct *task = t ? t : current; if ( ! (task->ptrace & PT_DTRACE) ) - return(0); + return 0; if (task->thread.singlestep_syscall) - return(1); + return 1; return 2; } |