X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fsparc64%2Fkernel%2Fprocess.c;h=649131b6df7831f1aa0dec4f462b53a77a8ee3b0;hb=refs%2Fheads%2Fvserver;hp=f6d3364624c3bbb6bbd72e8d959a27efcd4d1af1;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index f6d336462..649131b6d 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -25,9 +25,9 @@ #include #include #include -#include #include #include +#include #include #include @@ -42,75 +42,61 @@ #include #include #include +#include #include +#include /* #define VERBOSE_SHOWREGS */ -/* - * Nothing special yet... - */ -void default_idle(void) +static void sparc64_yield(void) { -} - -#ifndef CONFIG_SMP - -/* - * the idle loop on a Sparc... ;) - */ -int cpu_idle(void) -{ - if (current->pid != 0) - return -EPERM; - - /* endless idle loop with no priority at all */ - for (;;) { - /* If current->work.need_resched is zero we should really - * setup for a system wakup event and execute a shutdown - * instruction. - * - * But this requires writing back the contents of the - * L2 cache etc. so implement this later. -DaveM - */ - while (!need_resched()) - barrier(); + if (tlb_type != hypervisor) + return; - schedule(); - check_pgt_cache(); + clear_thread_flag(TIF_POLLING_NRFLAG); + smp_mb__after_clear_bit(); + + while (!need_resched()) { + unsigned long pstate; + + /* Disable interrupts. */ + __asm__ __volatile__( + "rdpr %%pstate, %0\n\t" + "andn %0, %1, %0\n\t" + "wrpr %0, %%g0, %%pstate" + : "=&r" (pstate) + : "i" (PSTATE_IE)); + + if (!need_resched()) + sun4v_cpu_yield(); + + /* Re-enable interrupts. */ + __asm__ __volatile__( + "rdpr %%pstate, %0\n\t" + "or %0, %1, %0\n\t" + "wrpr %0, %%g0, %%pstate" + : "=&r" (pstate) + : "i" (PSTATE_IE)); } - return 0; -} -#else + set_thread_flag(TIF_POLLING_NRFLAG); +} -/* - * the idle loop on a UltraMultiPenguin... - */ -#define idle_me_harder() (cpu_data(smp_processor_id()).idle_volume += 1) -#define unidle_me() (cpu_data(smp_processor_id()).idle_volume = 0) -int cpu_idle(void) +/* The idle loop on sparc64. */ +void cpu_idle(void) { set_thread_flag(TIF_POLLING_NRFLAG); + while(1) { if (need_resched()) { - unidle_me(); - clear_thread_flag(TIF_POLLING_NRFLAG); + preempt_enable_no_resched(); schedule(); - set_thread_flag(TIF_POLLING_NRFLAG); - check_pgt_cache(); + preempt_disable(); } - idle_me_harder(); - - /* The store ordering is so that IRQ handlers on - * other cpus see our increasing idleness for the buddy - * redistribution algorithm. -DaveM - */ - membar("#StoreStore | #StoreLoad"); + sparc64_yield(); } } -#endif - extern char reboot_command []; extern void (*prom_palette)(int); @@ -126,8 +112,6 @@ void machine_halt(void) panic("Halt failed!"); } -EXPORT_SYMBOL(machine_halt); - void machine_alt_power_off(void) { if (!serial_console && prom_palette) @@ -156,43 +140,49 @@ void machine_restart(char * cmd) panic("Reboot failed!"); } -EXPORT_SYMBOL(machine_restart); - +#ifdef CONFIG_COMPAT static void show_regwindow32(struct pt_regs *regs) { - struct reg_window32 *rw; + struct reg_window32 __user *rw; struct reg_window32 r_w; mm_segment_t old_fs; __asm__ __volatile__ ("flushw"); - rw = (struct reg_window32 *)((long)(unsigned)regs->u_regs[14]); + rw = compat_ptr((unsigned)regs->u_regs[14]); old_fs = get_fs(); set_fs (USER_DS); if (copy_from_user (&r_w, rw, sizeof(r_w))) { set_fs (old_fs); return; } - rw = &r_w; + set_fs (old_fs); printk("l0: %08x l1: %08x l2: %08x l3: %08x " "l4: %08x l5: %08x l6: %08x l7: %08x\n", - rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3], - rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); + r_w.locals[0], r_w.locals[1], r_w.locals[2], r_w.locals[3], + r_w.locals[4], r_w.locals[5], r_w.locals[6], r_w.locals[7]); printk("i0: %08x i1: %08x i2: %08x i3: %08x " "i4: %08x i5: %08x i6: %08x i7: %08x\n", - rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], - rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); + r_w.ins[0], r_w.ins[1], r_w.ins[2], r_w.ins[3], + r_w.ins[4], r_w.ins[5], r_w.ins[6], r_w.ins[7]); } +#else +#define show_regwindow32(regs) do { } while (0) +#endif static void show_regwindow(struct pt_regs *regs) { - struct reg_window *rw; + struct reg_window __user *rw; + struct reg_window *rwk; struct reg_window r_w; mm_segment_t old_fs; if ((regs->tstate & TSTATE_PRIV) || !(test_thread_flag(TIF_32BIT))) { __asm__ __volatile__ ("flushw"); - rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS); + rw = (struct reg_window __user *) + (regs->u_regs[14] + STACK_BIAS); + rwk = (struct reg_window *) + (regs->u_regs[14] + STACK_BIAS); if (!(regs->tstate & TSTATE_PRIV)) { old_fs = get_fs(); set_fs (USER_DS); @@ -200,7 +190,7 @@ static void show_regwindow(struct pt_regs *regs) set_fs (old_fs); return; } - rw = &r_w; + rwk = &r_w; set_fs (old_fs); } } else { @@ -208,15 +198,15 @@ static void show_regwindow(struct pt_regs *regs) return; } printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n", - rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3]); + rwk->locals[0], rwk->locals[1], rwk->locals[2], rwk->locals[3]); printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n", - rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]); + rwk->locals[4], rwk->locals[5], rwk->locals[6], rwk->locals[7]); printk("i0: %016lx i1: %016lx i2: %016lx i3: %016lx\n", - rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3]); + rwk->ins[0], rwk->ins[1], rwk->ins[2], rwk->ins[3]); printk("i4: %016lx i5: %016lx i6: %016lx i7: %016lx\n", - rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); + rwk->ins[4], rwk->ins[5], rwk->ins[6], rwk->ins[7]); if (regs->tstate & TSTATE_PRIV) - print_symbol("I7: <%s>\n", rw->ins[7]); + print_symbol("I7: <%s>\n", rwk->ins[7]); } void show_stackframe(struct sparc_stackf *sf) @@ -276,7 +266,7 @@ void show_stackframe32(struct sparc_stackf32 *sf) } #ifdef CONFIG_SMP -static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(regdump_lock); #endif void __show_regs(struct pt_regs * regs) @@ -340,6 +330,7 @@ void show_regs(struct pt_regs *regs) extern long etrap, etraptl1; #endif __show_regs(regs); +#if 0 #ifdef CONFIG_SMP { extern void smp_report_regs(void); @@ -347,6 +338,7 @@ void show_regs(struct pt_regs *regs) smp_report_regs(); } #endif +#endif #ifdef VERBOSE_SHOWREGS if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && @@ -380,7 +372,7 @@ void show_regs32(struct pt_regs32 *regs) unsigned long thread_saved_pc(struct task_struct *tsk) { - struct thread_info *ti = tsk->thread_info; + struct thread_info *ti = task_thread_info(tsk); unsigned long ret = 0xdeadbeefUL; if (ti && ti->ksp) { @@ -419,31 +411,15 @@ void exit_thread(void) void flush_thread(void) { struct thread_info *t = current_thread_info(); + struct mm_struct *mm; if (t->flags & _TIF_ABI_PENDING) t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT); - if (t->task->mm) { - unsigned long pgd_cache = 0UL; - if (test_thread_flag(TIF_32BIT)) { - struct mm_struct *mm = t->task->mm; - pgd_t *pgd0 = &mm->pgd[0]; - - if (pgd_none(*pgd0)) { - pmd_t *page = pmd_alloc_one_fast(NULL, 0); - if (!page) - page = pmd_alloc_one(NULL, 0); - pgd_set(pgd0, page); - } - pgd_cache = ((unsigned long) pgd_val(*pgd0)) << 11UL; - } - __asm__ __volatile__("stxa %0, [%1] %2\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (pgd_cache), - "r" (TSB_REG), - "i" (ASI_DMMU)); - } + mm = t->task->mm; + if (mm) + tsb_context_switch(mm); + set_thread_wsaved(0); /* Turn off performance counters if on. */ @@ -471,10 +447,10 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) if (!(test_thread_flag(TIF_32BIT))) { csp += STACK_BIAS; psp += STACK_BIAS; - __get_user(fp, &(((struct reg_window *)psp)->ins[6])); + __get_user(fp, &(((struct reg_window __user *)psp)->ins[6])); fp += STACK_BIAS; } else - __get_user(fp, &(((struct reg_window32 *)psp)->ins[6])); + __get_user(fp, &(((struct reg_window32 __user *)psp)->ins[6])); /* Now 8-byte align the stack as this is mandatory in the * Sparc ABI due to how register windows work. This hides @@ -487,11 +463,12 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) if (copy_in_user((void __user *) rval, (void __user *) psp, distance)) rval = 0; else if (test_thread_flag(TIF_32BIT)) { - if (put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6]))) + if (put_user(((u32)csp), + &(((struct reg_window32 __user *)rval)->ins[6]))) rval = 0; } else { if (put_user(((u64)csp - STACK_BIAS), - &(((struct reg_window *)rval)->ins[6]))) + &(((struct reg_window __user *)rval)->ins[6]))) rval = 0; else rval = rval - STACK_BIAS; @@ -533,7 +510,7 @@ void synchronize_user_stack(void) unsigned long sp = (t->rwbuf_stkptrs[window] + bias); struct reg_window *rwin = &t->reg_window[window]; - if (!copy_to_user((char *)sp, rwin, winsize)) { + if (!copy_to_user((char __user *)sp, rwin, winsize)) { shift_window_buffer(window, get_thread_wsaved() - 1, t); set_thread_wsaved(get_thread_wsaved() - 1); } @@ -541,6 +518,18 @@ void synchronize_user_stack(void) } } +static void stack_unaligned(unsigned long sp) +{ + siginfo_t info; + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRALN; + info.si_addr = (void __user *) sp; + info.si_trapno = 0; + force_sig_info(SIGBUS, &info, current); +} + void fault_in_user_windows(void) { struct thread_info *t = current_thread_info(); @@ -556,13 +545,17 @@ void fault_in_user_windows(void) flush_user_windows(); window = get_thread_wsaved(); - if (window != 0) { + if (likely(window != 0)) { window -= 1; do { unsigned long sp = (t->rwbuf_stkptrs[window] + bias); struct reg_window *rwin = &t->reg_window[window]; - if (copy_to_user((char *)sp, rwin, winsize)) + if (unlikely(sp & 0x7UL)) + stack_unaligned(sp); + + if (unlikely(copy_to_user((char __user *)sp, + rwin, winsize))) goto barf; } while (window--); } @@ -574,26 +567,27 @@ barf: do_exit(SIGILL); } -asmlinkage int sparc_do_fork(unsigned long clone_flags, - unsigned long stack_start, - struct pt_regs *regs, - unsigned long stack_size) +asmlinkage long sparc_do_fork(unsigned long clone_flags, + unsigned long stack_start, + struct pt_regs *regs, + unsigned long stack_size) { - unsigned long parent_tid_ptr, child_tid_ptr; - - clone_flags &= ~CLONE_IDLETASK; + int __user *parent_tid_ptr, *child_tid_ptr; - parent_tid_ptr = regs->u_regs[UREG_I2]; - child_tid_ptr = regs->u_regs[UREG_I4]; +#ifdef CONFIG_COMPAT if (test_thread_flag(TIF_32BIT)) { - parent_tid_ptr &= 0xffffffff; - child_tid_ptr &= 0xffffffff; + parent_tid_ptr = compat_ptr(regs->u_regs[UREG_I2]); + child_tid_ptr = compat_ptr(regs->u_regs[UREG_I4]); + } else +#endif + { + parent_tid_ptr = (int __user *) regs->u_regs[UREG_I2]; + child_tid_ptr = (int __user *) regs->u_regs[UREG_I4]; } return do_fork(clone_flags, stack_start, regs, stack_size, - (int *) parent_tid_ptr, - (int *) child_tid_ptr); + parent_tid_ptr, child_tid_ptr); } /* Copy a Sparc thread. The fork() return value conventions @@ -605,23 +599,16 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { - struct thread_info *t = p->thread_info; + struct thread_info *t = task_thread_info(p); char *child_trap_frame; -#ifdef CONFIG_DEBUG_SPINLOCK - p->thread.smp_lock_count = 0; - p->thread.smp_lock_pc = 0; -#endif - - p->set_child_tid = p->clear_child_tid = NULL; - /* Calculate offset to stack_frame & pt_regs */ - child_trap_frame = ((char *)t) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ)); + child_trap_frame = task_stack_page(p) + (THREAD_SIZE - (TRACEREG_SZ+STACKFRAME_SZ)); memcpy(child_trap_frame, (((struct sparc_stackf *)regs)-1), (TRACEREG_SZ+STACKFRAME_SZ)); t->flags = (t->flags & ~((0xffUL << TI_FLAG_CWP_SHIFT) | (0xffUL << TI_FLAG_CURRENT_DS_SHIFT))) | - _TIF_NEWCHILD | (((regs->tstate + 1) & TSTATE_CWP) << TI_FLAG_CWP_SHIFT); + t->new_child = 1; t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct sparc_stackf)); t->fpsaved[0] = 0; @@ -694,24 +681,25 @@ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) * So we stash 'fn' and 'arg' into global registers which * will not be modified by the parent. */ - __asm__ __volatile("mov %4, %%g2\n\t" /* Save FN into global */ - "mov %5, %%g3\n\t" /* Save ARG into global */ - "mov %1, %%g1\n\t" /* Clone syscall nr. */ - "mov %2, %%o0\n\t" /* Clone flags. */ - "mov 0, %%o1\n\t" /* usp arg == 0 */ - "t 0x6d\n\t" /* Linux/Sparc clone(). */ - "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */ - " mov %%o0, %0\n\t" - "jmpl %%g2, %%o7\n\t" /* Call the function. */ - " mov %%g3, %%o0\n\t" /* Set arg in delay. */ - "mov %3, %%g1\n\t" - "t 0x6d\n\t" /* Linux/Sparc exit(). */ - /* Notreached by child. */ - "1:" : - "=r" (retval) : - "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), - "i" (__NR_exit), "r" (fn), "r" (arg) : - "g1", "g2", "g3", "o0", "o1", "memory", "cc"); + __asm__ __volatile__("mov %4, %%g2\n\t" /* Save FN into global */ + "mov %5, %%g3\n\t" /* Save ARG into global */ + "mov %1, %%g1\n\t" /* Clone syscall nr. */ + "mov %2, %%o0\n\t" /* Clone flags. */ + "mov 0, %%o1\n\t" /* usp arg == 0 */ + "t 0x6d\n\t" /* Linux/Sparc clone(). */ + "brz,a,pn %%o1, 1f\n\t" /* Parent, just return. */ + " mov %%o0, %0\n\t" + "jmpl %%g2, %%o7\n\t" /* Call the function. */ + " mov %%g3, %%o0\n\t" /* Set arg in delay. */ + "mov %3, %%g1\n\t" + "t 0x6d\n\t" /* Linux/Sparc exit(). */ + /* Notreached by child. */ + "1:" : + "=r" (retval) : + "i" (__NR_clone), "r" (flags | + CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD), + "i" (__NR_exit), "r" (fn), "r" (arg) : + "g1", "g2", "g3", "o0", "o1", "memory", "cc"); return retval; } @@ -806,19 +794,21 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if (regs->u_regs[UREG_G1] == 0) base = 1; - filename = getname((char *)regs->u_regs[base + UREG_I0]); + filename = getname((char __user *)regs->u_regs[base + UREG_I0]); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; - error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1], - (char **) regs->u_regs[base + UREG_I2], regs); + error = do_execve(filename, + (char __user * __user *) + regs->u_regs[base + UREG_I1], + (char __user * __user *) + regs->u_regs[base + UREG_I2], regs); putname(filename); if (!error) { fprs_write(0); current_thread_info()->xfsr[0] = 0; current_thread_info()->fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; - current->ptrace &= ~PT_DTRACE; } out: return error; @@ -836,9 +826,9 @@ unsigned long get_wchan(struct task_struct *task) task->state == TASK_RUNNING) goto out; - thread_info_base = (unsigned long) task->thread_info; + thread_info_base = (unsigned long) task_stack_page(task); bias = STACK_BIAS; - fp = task->thread_info->ksp + bias; + fp = task_thread_info(task)->ksp + bias; do { /* Bogus frame pointer? */ @@ -847,8 +837,7 @@ unsigned long get_wchan(struct task_struct *task) break; rw = (struct reg_window *) fp; pc = rw->ins[7]; - if (pc < ((unsigned long) scheduling_functions_start_here) || - pc >= ((unsigned long) scheduling_functions_end_here)) { + if (!in_sched_functions(pc)) { ret = pc; goto out; }