patch-1.3.44 linux/arch/sparc/kernel/process.c

Next file: linux/arch/sparc/kernel/promops.c
Previous file: linux/arch/sparc/kernel/probe.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.43/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 $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -20,43 +20,63 @@
 #include <linux/user.h>
 #include <linux/a.out.h>
 
+#include <asm/auxio.h>
 #include <asm/oplib.h>
 #include <asm/segment.h>
 #include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/processor.h>
+#include <asm/psr.h>
+
+int current_user_segment = USER_DS; /* the return value from get_fs */
 
 /*
- * The idle loop on a sparc... ;)
+ * the idle loop on a Sparc... ;)
  */
 asmlinkage int sys_idle(void)
 {
-
 	if (current->pid != 0)
 		return -EPERM;
 
-	printk("in sys_idle...\n");
-	/* Map out the low memory: it's no longer needed */
-	/* Sparc version RSN */
-
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;) {
-	  printk("calling schedule() aieee!\n");
-	  schedule();
-	  printk("schedule() returned, halting...\n");
-	  halt();
+		schedule();
 	}
 }
 
 void hard_reset_now(void)
 {
-	prom_reboot("boot vmlinux");
+	prom_halt();
+}
+
+void show_regwindow(struct reg_window *rw)
+{
+	printk("l0:%08lx l1:%08lx l2:%08lx l3:%08lx l4:%08lx l5:%08lx l6:%08lx l7:%08lx\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:%08lx i1:%08lx i2:%08lx i3:%08lx i4:%08lx i5:%08lx i6:%08lx i7:%08lx\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_regs(struct pt_regs * regs)
 {
-        printk("\nFP: %08lx PC: %08lx NPC: %08lx\n", regs->u_regs[14],
-	       regs->pc, regs->npc);
+        printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx\n", regs->psr,
+	       regs->pc, regs->npc, regs->y);
+	printk("%%g0: %08lx %%g1: %08lx %%g2: %08lx %%g3: %08lx\n",
+	       regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
+	       regs->u_regs[3]);
+	printk("%%g4: %08lx %%g5: %08lx %%g6: %08lx %%g7: %08lx\n",
+	       regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
+	       regs->u_regs[7]);
+	printk("%%o0: %08lx %%o1: %08lx %%o2: %08lx %%o3: %08lx\n",
+	       regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
+	       regs->u_regs[11]);
+	printk("%%o4: %08lx %%o5: %08lx %%sp: %08lx %%ret_pc: %08lx\n",
+	       regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
+	       regs->u_regs[15]);
 }
 
 /*
@@ -64,74 +84,92 @@
  */
 void exit_thread(void)
 {
-  halt();
+	if(last_task_used_math == current)
+		last_task_used_math = NULL;
+	mmu_exit_hook(current);
 }
 
-void flush_thread(void)
+/*
+ * Free old dead task when we know it can never be on the cpu again.
+ */
+void release_thread(struct task_struct *dead_task)
 {
-  halt();
+	mmu_release_hook(dead_task);
 }
 
-void release_thread(struct task_struct *dead_task)
+void flush_thread(void)
 {
-  halt();
+	/* 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;
+
+	memset(&current->tss.reg_window[0], 0,
+	       (sizeof(struct reg_window) * NSWINS));
+	memset(&current->tss.rwbuf_stkptrs[0], 0,
+	       (sizeof(unsigned long) * NSWINS));
 }
 
-extern void ret_sys_call(void);
-
 /*
- * Copy a Sparc thread.  The context of a process on the Sparc is
- * composed of the following:
- *  1) status registers  %psr (for condition codes + CWP) and %wim
- *  2) current register window (in's and global registers)
- *  3) the current live stack frame, it contains the register
- *     windows the child may 'restore' into, this is important
- *  4) kernel stack pointer, user stack pointer (which is %i6)
- *  5) The pc and npc the child returns to during a switch
+ * Copy a Sparc thread.  The fork() return value conventions
+ * under SunOS are nothing short of bletcherous:
+ * Parent -->  %o0 == childs  pid, %o1 == 0
+ * Child  -->  %o0 == parents pid, %o1 == 1
+ *
+ * I'm feeling sick...
  */
+extern void ret_sys_call(void);
 
 void copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
-		 struct task_struct * p, struct pt_regs * regs)
+		 struct task_struct *p, struct pt_regs *regs)
 {
 	struct pt_regs *childregs;
-	unsigned char *old_stack;
-	unsigned char *new_stack;
-	int i;
+	struct sparc_stackf *old_stack, *new_stack;
+	unsigned long stack_offset, kthread_usp = 0;
 
-	/* This process has no context yet. */
+	mmu_task_cacheflush(current);
 	p->tss.context = -1;
 
-	/* Grrr, Sparc stack alignment restrictions make things difficult. */
-	childregs = ((struct pt_regs *) 
-		     ((p->kernel_stack_page + PAGE_SIZE - 80)&(~7)));
-
+	/* Calculate offset to stack_frame & pt_regs */
+	stack_offset = (PAGE_SIZE - TRACEREG_SZ);
+	childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset));
 	*childregs = *regs;
-
-	p->tss.usp = sp;    /* both processes have the same user stack */
-	/* See entry.S */
-
-	/* Allocate new processes kernel stack right under pt_regs.
-	 * Hopefully this should align things the right way.
+	new_stack = (((struct sparc_stackf *) childregs) - 1);
+	old_stack = (((struct sparc_stackf *) regs) - 1);
+	*new_stack = *old_stack;
+	p->tss.ksp = (unsigned long) new_stack;
+	p->tss.kpc = (((unsigned long) ret_sys_call) - 0x8);
+
+	/* 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.
 	 */
-	p->tss.ksp = (unsigned long) ((p->kernel_stack_page + PAGE_SIZE - 80 - 96)&(~7));
-	new_stack = (unsigned char *) (p->tss.ksp);
-	old_stack = (unsigned char *) (((unsigned long) regs) - 96);
-
-	/* Copy c-stack. */
-	for(i=0; i<96; i++) *new_stack++ = *old_stack++;
-
-	/* These pc values are only used when we switch to the child for
-	 * the first time, it jumps the child to ret_sys_call in entry.S
-	 * so that the child returns from the sys_call just like parent.
-	 */
-	p->tss.pc = (((unsigned long) ret_sys_call) - 8);
-	p->tss.npc = p->tss.pc+4;
+	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;
+	}
 
-	/* Set the return values for both the parent and the child */
-	regs->u_regs[8] = p->pid;
-	childregs->u_regs[8] = 0;
+	/* Set the return value for the child. */
+	childregs->u_regs[UREG_I0] = current->pid;
+	childregs->u_regs[UREG_I1] = 1;
 
-	return;
+	/* Set the return value for the parent. */
+	regs->u_regs[UREG_I1] = 0;
+
+	mmu_fork_hook(p, kthread_usp);
 }
 
 /*
@@ -139,21 +177,57 @@
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-  return; /* solaris does this enough */
 }
 
-asmlinkage int sys_fork(struct pt_regs *regs)
+/*
+ * fill in the fpu structure for a core dump.
+ */
+int dump_fpu (void *fpu_structure)
 {
-  return do_fork(SIGCHLD, regs->u_regs[14], regs);
+	/* Currently we report that we couldn't dump the fpu structure */
+	return 0;
 }
 
 /*
- * sys_execve() executes a new program.
+ * sparc_execve() executes a new program after the asm stub has set
+ * things up for us.  This should basically do what I want it to.
  */
-asmlinkage int sys_execve(struct pt_regs regs)
+asmlinkage int sparc_execve(struct pt_regs *regs)
 {
-  printk("sys_execve()... halting\n");
-  halt();
-  return 0;
+	int error;
+	char *filename;
+
+	flush_user_windows();
+	mmu_task_cacheflush(current);
+	error = getname((char *) regs->u_regs[UREG_I0], &filename);
+	if(error)
+		return error;
+	error = do_execve(filename, (char **) regs->u_regs[UREG_I1],
+			  (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