diff options
Diffstat (limited to 'arch/sparc64/kernel/process.c')
-rw-r--r-- | arch/sparc64/kernel/process.c | 354 |
1 files changed, 128 insertions, 226 deletions
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index cc8183618..89f63f78f 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.17 1997/06/02 06:33:32 davem Exp $ +/* $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -17,6 +17,8 @@ #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> @@ -137,7 +139,7 @@ void machine_restart(char * cmd) prom_reboot(cmd); if (*reboot_command) prom_reboot(reboot_command); - prom_feval ("reset"); + prom_reboot(""); panic("Reboot failed!"); } @@ -146,8 +148,55 @@ void machine_power_off(void) machine_halt(); } -void show_regwindow(struct reg_window *rw) +static void show_regwindow32(struct pt_regs *regs) { + struct reg_window32 *rw; + struct reg_window32 r_w; + unsigned long old_fs; + + __asm__ __volatile__ ("flushw"); + rw = (struct reg_window32 *)((long)(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: %016x l1: %016x l2: %016x l3: %016x\n" + "l4: %016x l5: %016x l6: %016x l7: %016x\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]); + printk("i0: %016x i1: %016x i2: %016x i3: %016x\n" + "i4: %016x i5: %016x i6: %016x i7: %016x\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]); +} + +static void show_regwindow(struct pt_regs *regs) +{ + struct reg_window *rw; + struct reg_window r_w; + unsigned long old_fs; + + if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) { + __asm__ __volatile__ ("flushw"); + rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS); + if (!(regs->tstate & TSTATE_PRIV)) { + 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); + } + } else { + show_regwindow32(regs); + return; + } printk("l0: %016lx l1: %016lx l2: %016lx l3: %016lx\n", rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3]); printk("l4: %016lx l5: %016lx l6: %016lx l7: %016lx\n", @@ -158,18 +207,6 @@ void show_regwindow(struct reg_window *rw) rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]); } -void show_regwindow32(struct reg_window32 *rw) -{ - printk("l0: %08x l1: %08x l2: %08x l3: %08x\n" - "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]); - printk("i0: %08x i1: %08x i2: %08x i3: %08x\n" - "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]); -} - void show_stackframe(struct sparc_stackf *sf) { unsigned long size; @@ -228,10 +265,7 @@ void show_stackframe32(struct sparc_stackf32 *sf) void show_regs(struct pt_regs * regs) { -#if __MPP__ - printk("CID: %d\n",mpp_cid()); -#endif - printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %016lx\n", regs->tstate, + printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate, regs->tpc, regs->tnpc, regs->y); printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n", regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], @@ -245,16 +279,11 @@ void show_regs(struct pt_regs * regs) printk("o4: %016lx o5: %016lx sp: %016lx ret_pc: %016lx\n", regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], regs->u_regs[15]); -#if 0 - show_regwindow((struct reg_window *)(regs->u_regs[14] + STACK_BIAS)); -#endif + show_regwindow(regs); } void show_regs32(struct pt_regs32 *regs) { -#if __MPP__ - printk("CID: %d\n",mpp_cid()); -#endif printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr, regs->pc, regs->npc, regs->y); printk("g0: %08x g1: %08x g2: %08x g3: %08x\n", @@ -269,7 +298,6 @@ void show_regs32(struct pt_regs32 *regs) printk("o4: %08x o5: %08x sp: %08x ret_pc: %08x\n", regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], regs->u_regs[15]); - show_regwindow32((struct reg_window32 *)((unsigned long)regs->u_regs[14])); } void show_thread(struct thread_struct *tss) @@ -290,46 +318,22 @@ void show_thread(struct thread_struct *tss) continue; printk("reg_window[%d]:\n", i); printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]); - show_regwindow(&tss->reg_window[i]); } printk("w_saved: 0x%08lx\n", tss->w_saved); - /* XXX missing: float_regs */ - printk("fsr: 0x%016lx\n", tss->fsr); - printk("sstk_info.stack: 0x%016lx\n", (unsigned long)tss->sstk_info.the_stack); printk("sstk_info.status: 0x%016lx\n", (unsigned long)tss->sstk_info.cur_status); - printk("flags: 0x%016lx\n", tss->flags); - printk("current_ds: 0x%016x\n", tss->current_ds); + printk("flags: 0x%08x\n", tss->flags); + printk("current_ds: 0x%016lx\n", tss->current_ds); /* XXX missing: core_exec */ } -/* - * Free current thread data structures etc.. - */ +/* Free current thread data structures etc.. */ void exit_thread(void) { -#ifndef __SMP__ - if(last_task_used_math == current) { -#else - if(current->flags & PF_USEDFPU) { -#endif - fprs_write(FPRS_FEF); - if(current->tss.flags & SPARC_FLAG_32BIT) - fpsave32((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); - else - fpsave((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); -#ifndef __SMP__ - last_task_used_math = NULL; -#else - current->flags &= ~PF_USEDFPU; -#endif - } } void flush_thread(void) @@ -338,28 +342,12 @@ void flush_thread(void) current->tss.sstk_info.cur_status = 0; current->tss.sstk_info.the_stack = 0; - /* No new signal delivery by default */ + /* No new signal delivery by default. */ current->tss.new_signal = 0; -#ifndef __SMP__ - if(last_task_used_math == current) { -#else - if(current->flags & PF_USEDFPU) { -#endif - fprs_write(FPRS_FEF); - if(current->tss.flags & SPARC_FLAG_32BIT) - fpsave32((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); - else - fpsave((unsigned long *)¤t->tss.float_regs[0], - ¤t->tss.fsr); -#ifndef __SMP__ - last_task_used_math = NULL; -#else - current->flags &= ~PF_USEDFPU; -#endif - } + current->flags &= ~PF_USEDFPU; /* Now, this task is no longer a kernel thread. */ + current->tss.current_ds = USER_DS; if(current->tss.flags & SPARC_FLAG_KTHREAD) { current->tss.flags &= ~SPARC_FLAG_KTHREAD; @@ -368,78 +356,38 @@ void flush_thread(void) */ get_mmu_context(current); } - current->tss.current_ds = USER_DS; - spitfire_set_secondary_context (current->mm->context); + current->tss.ctx = current->mm->context & 0x1fff; + spitfire_set_secondary_context (current->tss.ctx); + __asm__ __volatile__("flush %g6"); } -static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src) +/* It's a bit more tricky when 64-bit tasks are involved... */ +static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) { - __asm__ __volatile__("ldd\t[%1 + 0x00], %%g2\n\t" - "ldd\t[%1 + 0x08], %%g4\n\t" - "ldd\t[%1 + 0x10], %%o4\n\t" - "std\t%%g2, [%0 + 0x00]\n\t" - "std\t%%g4, [%0 + 0x08]\n\t" - "std\t%%o4, [%0 + 0x10]\n\t" - "ldd\t[%1 + 0x18], %%g2\n\t" - "ldd\t[%1 + 0x20], %%g4\n\t" - "ldd\t[%1 + 0x28], %%o4\n\t" - "std\t%%g2, [%0 + 0x18]\n\t" - "std\t%%g4, [%0 + 0x20]\n\t" - "std\t%%o4, [%0 + 0x28]\n\t" - "ldd\t[%1 + 0x30], %%g2\n\t" - "ldd\t[%1 + 0x38], %%g4\n\t" - "ldd\t[%1 + 0x40], %%o4\n\t" - "std\t%%g2, [%0 + 0x30]\n\t" - "std\t%%g4, [%0 + 0x38]\n\t" - "ldd\t[%1 + 0x48], %%g2\n\t" - "std\t%%o4, [%0 + 0x40]\n\t" - "std\t%%g2, [%0 + 0x48]\n\t" : : - "r" (dst), "r" (src) : - "g2", "g3", "g4", "g5", "o4", "o5"); -} - -static __inline__ void copy_regwin(struct reg_window *dst, struct reg_window *src) -{ - __asm__ __volatile__("ldd\t[%1 + 0x00], %%g2\n\t" - "ldd\t[%1 + 0x08], %%g4\n\t" - "ldd\t[%1 + 0x10], %%o4\n\t" - "std\t%%g2, [%0 + 0x00]\n\t" - "std\t%%g4, [%0 + 0x08]\n\t" - "std\t%%o4, [%0 + 0x10]\n\t" - "ldd\t[%1 + 0x18], %%g2\n\t" - "ldd\t[%1 + 0x20], %%g4\n\t" - "ldd\t[%1 + 0x28], %%o4\n\t" - "std\t%%g2, [%0 + 0x18]\n\t" - "std\t%%g4, [%0 + 0x20]\n\t" - "std\t%%o4, [%0 + 0x28]\n\t" - "ldd\t[%1 + 0x30], %%g2\n\t" - "ldd\t[%1 + 0x38], %%g4\n\t" - "std\t%%g2, [%0 + 0x30]\n\t" - "std\t%%g4, [%0 + 0x38]\n\t" : : - "r" (dst), "r" (src) : - "g2", "g3", "g4", "g5", "o4", "o5"); -} - -static __inline__ struct sparc_stackf * -clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src) -{ - struct sparc_stackf *sp; - -#if 0 - unsigned long size; - size = ((unsigned long)src->fp) - ((unsigned long)src); - sp = (struct sparc_stackf *)(((unsigned long)dst) - size); - - if (copy_to_user(sp, src, size)) - return 0; - if (put_user(dst, &sp->fp)) + unsigned long fp, distance, rval; + + if(!(current->tss.flags & SPARC_FLAG_32BIT)) { + csp += STACK_BIAS; + psp += STACK_BIAS; + __get_user(fp, &(((struct reg_window *)psp)->ins[6])); + } else + __get_user(fp, &(((struct reg_window32 *)psp)->ins[6])); + distance = fp - psp; + rval = (csp - distance); + if(copy_in_user(rval, psp, distance)) return 0; -#endif - return sp; + if(current->tss.flags & SPARC_FLAG_32BIT) { + if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6]))) + return 0; + return rval; + } else { + if(put_user(((u64)csp - STACK_BIAS), + &(((struct reg_window *)rval)->ins[6]))) + return 0; + return rval - STACK_BIAS; + } } -/* #define DEBUG_WINFIXUPS */ - /* Standard stuff. */ static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp) @@ -461,16 +409,16 @@ void synchronize_user_stack(void) flush_user_windows(); if((window = tp->w_saved) != 0) { int winsize = REGWIN_SZ; + int bias = 0; -#ifdef DEBUG_WINFIXUPS - printk("sus(%d", (int)window); -#endif if(tp->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; + else + bias = STACK_BIAS; window -= 1; do { - unsigned long sp = tp->rwbuf_stkptrs[window]; + unsigned long sp = (tp->rwbuf_stkptrs[window] + bias); struct reg_window *rwin = &tp->reg_window[window]; if(!copy_to_user((char *)sp, rwin, winsize)) { @@ -478,9 +426,6 @@ void synchronize_user_stack(void) tp->w_saved--; } } while(window--); -#ifdef DEBUG_WINFIXUPS - printk(")"); -#endif } } @@ -489,18 +434,18 @@ void fault_in_user_windows(struct pt_regs *regs) struct thread_struct *tp = ¤t->tss; unsigned long window; int winsize = REGWIN_SZ; + int bias = 0; if(tp->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; + else + bias = STACK_BIAS; flush_user_windows(); window = tp->w_saved; -#ifdef DEBUG_WINFIXUPS - printk("fiuw(%d", (int)window); -#endif if(window != 0) { window -= 1; do { - unsigned long sp = tp->rwbuf_stkptrs[window]; + unsigned long sp = (tp->rwbuf_stkptrs[window] + bias); struct reg_window *rwin = &tp->reg_window[window]; if(copy_to_user((char *)sp, rwin, winsize)) @@ -508,9 +453,6 @@ void fault_in_user_windows(struct pt_regs *regs) } while(window--); } current->tss.w_saved = 0; -#ifdef DEBUG_WINFIXUPS - printk(")"); -#endif } /* Copy a Sparc thread. The fork() return value conventions @@ -530,97 +472,49 @@ extern void ret_from_syscall(void); int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct task_struct *p, struct pt_regs *regs) { - struct pt_regs *childregs; - struct reg_window *new_stack, *old_stack; unsigned long stack_offset; - -#ifndef __SMP__ - if(last_task_used_math == current) { -#else - if(current->flags & PF_USEDFPU) { -#endif - fprs_write(FPRS_FEF); - fpsave((unsigned long *)&p->tss.float_regs[0], &p->tss.fsr); -#ifdef __SMP__ - current->flags &= ~PF_USEDFPU; -#endif - } + char *child_trap_frame; + int tframe_size; /* Calculate offset to stack_frame & pt_regs */ - stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ); - - if(regs->tstate & TSTATE_PRIV) - stack_offset -= REGWIN_SZ; - - childregs = ((struct pt_regs *) (((unsigned long)p) + stack_offset)); - *childregs = *regs; - new_stack = (((struct reg_window *) childregs) - 1); - old_stack = (((struct reg_window *) regs) - 1); - *new_stack = *old_stack; - - p->tss.ksp = ((unsigned long) new_stack) - STACK_BIAS; + stack_offset = (((PAGE_SIZE << 1) - + ((sizeof(unsigned int)*64) + (2*sizeof(unsigned long)))) & + ~(64 - 1)) - (TRACEREG_SZ+REGWIN_SZ); + tframe_size = (TRACEREG_SZ + REGWIN_SZ) + + (sizeof(unsigned int) * 64) + (2 * sizeof(unsigned long)); + child_trap_frame = ((char *)p) + stack_offset; + memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size); + p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8; - p->tss.kregs = childregs; - - /* Don't look... */ + p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); p->tss.cwp = regs->u_regs[UREG_G0]; - - /* tss.wstate was copied by do_fork() */ - if(regs->tstate & TSTATE_PRIV) { - childregs->u_regs[UREG_FP] = p->tss.ksp; + p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp; p->tss.flags |= SPARC_FLAG_KTHREAD; p->tss.current_ds = KERNEL_DS; - childregs->u_regs[UREG_G6] = (unsigned long) p; + p->tss.ctx = 0; + p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p; } else { - childregs->u_regs[UREG_FP] = sp; + p->tss.kregs->u_regs[UREG_FP] = sp; p->tss.flags &= ~SPARC_FLAG_KTHREAD; p->tss.current_ds = USER_DS; - -#if 0 + p->tss.ctx = (p->mm->context & 0x1fff); if (sp != regs->u_regs[UREG_FP]) { - struct sparc_stackf *childstack; - struct sparc_stackf *parentstack; - - /* - * This is a clone() call with supplied user stack. - * Set some valid stack frames to give to the child. - */ - childstack = (struct sparc_stackf *)sp; - parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP]; + unsigned long csp; -#if 0 - printk("clone: parent stack:\n"); - show_stackframe(parentstack); -#endif - - childstack = clone_stackframe(childstack, parentstack); - if (!childstack) + csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); + if(!csp) return -EFAULT; - -#if 0 - printk("clone: child stack:\n"); - show_stackframe(childstack); -#endif - - childregs->u_regs[UREG_FP] = (unsigned long)childstack; + p->tss.kregs->u_regs[UREG_FP] = csp; } -#endif } /* Set the return value for the child. */ - childregs->u_regs[UREG_I0] = current->pid; - childregs->u_regs[UREG_I1] = 1; + p->tss.kregs->u_regs[UREG_I0] = current->pid; + p->tss.kregs->u_regs[UREG_I1] = 1; - /* Set the return value for the parent. */ + /* Set the second return value for the parent. */ regs->u_regs[UREG_I1] = 0; -#if 0 - printk("CHILD register dump\n"); - show_regs(childregs); - show_regwindow(new_stack); - while(1) - barrier(); -#endif return 0; } @@ -676,11 +570,19 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if(regs->u_regs[UREG_G1] == 0) base = 1; - error = getname((char *) regs->u_regs[base + UREG_I0], &filename); - if(error) - return error; + lock_kernel(); + filename = getname((char *)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); putname(filename); + if(!error) { + fprs_write(0); + regs->fprs = 0; + } +out: + unlock_kernel(); return error; } |