patch-1.3.71 linux/arch/sparc/kernel/process.c
Next file: linux/arch/sparc/kernel/rtrap.S
Previous file: linux/arch/sparc/kernel/probe.c
Back to the patch index
Back to the overall index
- Lines: 245
- Date:
Mon Mar 4 08:49:55 1996
- Orig file:
v1.3.70/linux/arch/sparc/kernel/process.c
- Orig date:
Sat Nov 25 19:04:36 1995
diff -u --recursive --new-file v1.3.70/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.29 1995/11/25 00:58:17 davem Exp $
+/* $Id: process.c,v 1.42 1996/02/20 07:45:08 davem Exp $
* linux/arch/sparc/kernel/process.c
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -26,10 +26,13 @@
#include <asm/system.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/delay.h>
#include <asm/processor.h>
#include <asm/psr.h>
-int current_user_segment = USER_DS; /* the return value from get_fs */
+extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *);
+
+int active_ds = USER_DS;
/*
* the idle loop on a Sparc... ;)
@@ -46,9 +49,15 @@
}
}
+extern char saved_command_line[];
+
void hard_reset_now(void)
{
- prom_halt();
+ sti();
+ udelay(8000);
+ cli();
+ prom_feval("reset");
+ panic("Reboot failed!");
}
void show_regwindow(struct reg_window *rw)
@@ -84,9 +93,15 @@
*/
void exit_thread(void)
{
- if(last_task_used_math == current)
+ flush_user_windows();
+ if(last_task_used_math == current) {
+ /* Keep process from leaving FPU in a bogon state. */
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr,
+ ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth);
last_task_used_math = NULL;
- mmu_exit_hook(current);
+ }
+ mmu_exit_hook();
}
/*
@@ -94,29 +109,33 @@
*/
void release_thread(struct task_struct *dead_task)
{
- mmu_release_hook(dead_task);
}
void flush_thread(void)
{
/* Make sure old user windows don't get in the way. */
- mmu_flush_hook(current);
flush_user_windows();
- current->signal &= ~(1<<(SIGILL-1));
current->tss.w_saved = 0;
current->tss.uwinmask = 0;
-
current->tss.sig_address = 0;
current->tss.sig_desc = 0;
-
- /* Signal stack state does not inherit. XXX Really? XXX */
current->tss.sstk_info.cur_status = 0;
current->tss.sstk_info.the_stack = 0;
+ if(last_task_used_math == current) {
+ /* Clean the fpu. */
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr,
+ ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth);
+ }
+
memset(¤t->tss.reg_window[0], 0,
(sizeof(struct reg_window) * NSWINS));
memset(¤t->tss.rwbuf_stkptrs[0], 0,
(sizeof(unsigned long) * NSWINS));
+ mmu_flush_hook();
+ /* Now, this task is no longer a kernel thread. */
+ current->tss.flags &= ~SPARC_FLAG_KTHREAD;
}
/*
@@ -125,7 +144,12 @@
* Parent --> %o0 == childs pid, %o1 == 0
* Child --> %o0 == parents pid, %o1 == 1
*
- * I'm feeling sick...
+ * NOTE: We have a seperate fork kpsr/kwim because
+ * the parent could change these values between
+ * sys_fork invocation and when we reach here
+ * if the parent should sleep while trying to
+ * allocate the task_struct and kernel stack in
+ * do_fork().
*/
extern void ret_sys_call(void);
@@ -133,34 +157,37 @@
struct task_struct *p, struct pt_regs *regs)
{
struct pt_regs *childregs;
- struct sparc_stackf *old_stack, *new_stack;
- unsigned long stack_offset, kthread_usp = 0;
+ struct reg_window *old_stack, *new_stack;
+ unsigned long stack_offset;
- mmu_task_cacheflush(current);
- p->tss.context = -1;
+ if(last_task_used_math == current) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(&p->tss.float_regs[0], &p->tss.fsr,
+ &p->tss.fpqueue[0], &p->tss.fpqdepth);
+ }
/* Calculate offset to stack_frame & pt_regs */
- stack_offset = (PAGE_SIZE - TRACEREG_SZ);
+ stack_offset = ((PAGE_SIZE*2) - TRACEREG_SZ);
+ if(regs->psr & PSR_PS)
+ stack_offset -= REGWIN_SZ;
childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
*childregs = *regs;
- new_stack = (((struct sparc_stackf *) childregs) - 1);
- old_stack = (((struct sparc_stackf *) regs) - 1);
+ 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;
+ p->tss.ksp = p->saved_kernel_stack = (unsigned long) new_stack;
p->tss.kpc = (((unsigned long) ret_sys_call) - 0x8);
+ p->tss.kpsr = current->tss.fork_kpsr;
+ p->tss.kwim = current->tss.fork_kwim;
+ p->tss.kregs = childregs;
+ childregs->u_regs[UREG_FP] = sp;
- /* As a special case, if this is a kernel fork we need
- * to give the child a new fresh stack for when it returns
- * from the syscall. (ie. the "user" stack) This happens
- * only once and we count on the page acquisition happening
- * successfully.
- */
if(regs->psr & PSR_PS) {
- unsigned long n_stack = get_free_page(GFP_KERNEL);
- childregs->u_regs[UREG_FP] = (n_stack | (sp & 0xfff));
- memcpy((char *)n_stack,(char *)(sp & PAGE_MASK),PAGE_SIZE);
- kthread_usp = n_stack;
- }
+ stack_offset += TRACEREG_SZ;
+ childregs->u_regs[UREG_FP] = p->kernel_stack_page + stack_offset;
+ p->tss.flags |= SPARC_FLAG_KTHREAD;
+ } else
+ p->tss.flags &= ~SPARC_FLAG_KTHREAD;
/* Set the return value for the child. */
childregs->u_regs[UREG_I0] = current->pid;
@@ -168,8 +195,6 @@
/* Set the return value for the parent. */
regs->u_regs[UREG_I1] = 0;
-
- mmu_fork_hook(p, kthread_usp);
}
/*
@@ -177,6 +202,31 @@
*/
void dump_thread(struct pt_regs * regs, struct user * dump)
{
+ unsigned long first_stack_page;
+
+ dump->magic = SUNOS_CORE_MAGIC;
+ dump->len = sizeof(struct user);
+ dump->regs.psr = regs->psr;
+ dump->regs.pc = regs->pc;
+ dump->regs.npc = regs->npc;
+ dump->regs.y = regs->y;
+ /* fuck me plenty */
+ memcpy(&dump->regs.regs[0], ®s->u_regs[1], (sizeof(unsigned long) * 15));
+ dump->uexec = current->tss.core_exec;
+ dump->u_tsize = (((unsigned long) current->mm->end_code) -
+ ((unsigned long) current->mm->start_code)) & ~(PAGE_SIZE - 1);
+ dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1)));
+ dump->u_dsize -= dump->u_tsize;
+ dump->u_dsize &= ~(PAGE_SIZE - 1);
+ first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1));
+ dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1);
+ memcpy(&dump->fpu.fpstatus.fregs.regs[0], ¤t->tss.float_regs[0], (sizeof(unsigned long) * 32));
+ dump->fpu.fpstatus.fsr = current->tss.fsr;
+ dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0;
+ dump->fpu.fpstatus.fpq_count = current->tss.fpqdepth;
+ memcpy(&dump->fpu.fpstatus.fpq[0], ¤t->tss.fpqueue[0],
+ ((sizeof(unsigned long) * 2) * 16));
+ dump->sigcode = current->tss.sig_desc;
}
/*
@@ -198,7 +248,6 @@
char *filename;
flush_user_windows();
- mmu_task_cacheflush(current);
error = getname((char *) regs->u_regs[UREG_I0], &filename);
if(error)
return error;
@@ -206,28 +255,4 @@
(char **) regs->u_regs[UREG_I2], regs);
putname(filename);
return error;
-}
-
-void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
-{
- unsigned long saved_psr = (regs->psr & (PSR_CWP)) | PSR_S;
-
- memset(regs, 0, sizeof(struct pt_regs));
- regs->pc = ((pc & (~3)) - 4); /* whee borken a.out header fields... */
- regs->npc = regs->pc + 4;
- regs->psr = saved_psr;
- regs->u_regs[UREG_G1] = sp; /* Base of arg/env stack area */
-
- /* XXX More mysterious netbsd garbage... XXX */
- regs->u_regs[UREG_G2] = regs->u_regs[UREG_G7] = regs->npc;
-
- /* Allocate one reg window because the first jump into
- * user mode will restore one register window by definition
- * of the 'rett' instruction. Also, SunOS crt.o code
- * depends upon the arg/envp area being _exactly_ one
- * register window above %sp when the process begins
- * execution.
- */
- sp -= REGWIN_SZ;
- regs->u_regs[UREG_FP] = sp;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this