summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/process.c')
-rw-r--r--arch/sparc64/kernel/process.c354
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 *)&current->tss.float_regs[0],
- &current->tss.fsr);
- else
- fpsave((unsigned long *)&current->tss.float_regs[0],
- &current->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 *)&current->tss.float_regs[0],
- &current->tss.fsr);
- else
- fpsave((unsigned long *)&current->tss.float_regs[0],
- &current->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 = &current->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;
}