patch-2.1.51 linux/arch/ppc/kernel/process.c

Next file: linux/arch/ppc/kernel/prom.c
Previous file: linux/arch/ppc/kernel/prep_time.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
@@ -7,7 +7,7 @@
  *  Derived from "arch/i386/kernel/process.c"
  *    Copyright (C) 1995  Linus Torvalds
  *
- *  Modified by Cort Dougan (cort@cs.nmt.edu) and
+ *  Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
  *  Paul Mackerras (paulus@cs.anu.edu.au)
  *
  *  This program is free software; you can redistribute it and/or
@@ -28,22 +28,22 @@
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
+#include <linux/elf.h>
 #include <linux/config.h>
+#include <linux/elf.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/smp_lock.h>
+#include <asm/processor.h>
 
-int dump_fpu(void);
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
 void switch_to(struct task_struct *, struct task_struct *);
-void print_backtrace(unsigned long *);
-void show_regs(struct pt_regs * regs);
-void inline zero_paged(void);
 extern unsigned long _get_SP(void);
 
+
 #undef SHOW_TASK_SWITCHES 1
 #undef CHECK_STACK 1
 #undef IDLE_ZERO 1
@@ -59,7 +59,7 @@
 {
 	return ((unsigned long)tsk) + sizeof(struct task_struct);
 }
-	
+
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
@@ -69,9 +69,12 @@
 union task_union init_task_union = { INIT_TASK };
 
 int
-dump_fpu(void)
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
 {
-	return (1);
+	if (last_task_used_math == current)
+		giveup_fpu();
+	memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
+	return 1;
 }
 
 /* check to make sure the kernel stack is healthy */
@@ -80,7 +83,6 @@
 	unsigned long stack_top = kernel_stack_top(tsk);
 	unsigned long tsk_top = task_top(tsk);
 	int ret = 0;
-	unsigned long *i;
 
 #if 0	
 	/* check tss magic */
@@ -98,7 +100,7 @@
 	if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
 	{
 		printk("stack out of bounds: %s/%d\n"
-		       " tsk_top %08x ksp %08x stack_top %08x\n",
+		       " tsk_top %08lx ksp %08lx stack_top %08lx\n",
 		       tsk->comm,tsk->pid,
 		       tsk_top, tsk->tss.ksp, stack_top);
 		ret |= 2;
@@ -108,7 +110,7 @@
 	if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
 	{
 		printk("current stack ptr out of bounds: %s/%d\n"
-		       " tsk_top %08x sp %08x stack_top %08x\n",
+		       " tsk_top %08lx sp %08lx stack_top %08lx\n",
 		       current->comm,current->pid,
 		       tsk_top, _get_SP(), stack_top);
 		ret |= 4;
@@ -143,15 +145,12 @@
 {
 	struct thread_struct *new_tss, *old_tss;
 	int s = _disable_interrupts();
-	struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
 
 #if CHECK_STACK
 	check_stack(prev);
 	check_stack(new);
 #endif
-        /* turn off fpu for task last to run */
-	/*prev->tss.regs->msr &= ~MSR_FP;*/
-	
+
 #ifdef SHOW_TASK_SWITCHES
 	printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
 	       prev->comm,prev->pid,prev->tss.regs->nip,
@@ -160,289 +159,29 @@
 	new_tss = &new->tss;
 	old_tss = &current->tss;
 	_switch(old_tss, new_tss, new->mm->context);
-        /* turn off fpu for task last to run */	
 	_enable_interrupts(s);
 }
-	
-#include <linux/mc146818rtc.h>
-asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
-{
-#if 1
-	struct task_struct *p;
-	printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
-	printk("last %x\n", last_task_used_math);
-	printk("cur %x regs %x/%x tss %x/%x\n",
-	       current, current->tss.regs,regs,&current->tss,current->tss);
-	for_each_task(p)
-	{
-		if ((long)p < KERNELBASE)
-		{
-			printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
-			print_mm_info();
-			__cli();
-			while(1);
-		}
-	}
-	return regs->gpr[3];
-#endif
-#if 0
-	/* set the time in the cmos clock */
-	unsigned long hwtime, nowtime;
-	struct rtc_time tm;
-	
-	hwtime = get_cmos_time();
-	to_tm(hwtime, &tm);
-	printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n", 
-	       tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
-	       tm.tm_mday, tm.tm_year);
-	return;
-#endif
-}
 
-/*
- * vars for idle task zero'ing out pages
- */
-unsigned long zero_list = 0;	/* head linked list of pre-zero'd pages */
-unsigned long bytecount = 0;	/* pointer into the currently being zero'd page */
-unsigned long zerocount = 0;	/* # currently pre-zero'd pages */
-unsigned long zerototal = 0;	/* # pages zero'd over time -- for ooh's and ahhh's */
-unsigned long pageptr = 0;	/* current page being zero'd */
-unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
-
-/*
- * Returns a pre-zero'd page from the list otherwise returns
- * NULL.
- */
-unsigned long get_prezerod_page(void)
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
 {
-	unsigned long page;
-	unsigned long s;
-
-	if ( zero_list )
-	{
-		/* atomically remove this page from the list */
-		asm (	"101:lwarx  %1,0,%2\n"  /* reserve zero_list */
-			"    lwz    %0,0(%1)\n" /* get next -- new zero_list */
-			"    stwcx. %0,0,%2\n"  /* update zero_list */
-			"    bne-   101b\n"     /* if lost reservation try again */
-			: "=&r" (zero_list), "=&r" (page)
-			: "r" (&zero_list)
-			: "cc" );
-		/* we can update zerocount after the fact since it is not
-		 * used for anything but control of a loop which doesn't
-		 * matter since it won't effect anything if it zero's one
-		 * less page -- Cort
-		 */
-		atomic_inc((atomic_t *)&zeropage_hits);
-		atomic_dec((atomic_t *)&zerocount);
-		/* zero out the pointer to next in the page */
-		*(unsigned long *)page = 0;
-		return page;
-	}
 	return 0;
 }
 
-/*
- * Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages() -- Cort
- * Zero's out pages until we need to resched or
- * we've reached the limit of zero'd pages.
- */
-void inline zero_paged(void)
-{
-	extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
-	unsigned long tmp;
-	pte_t ptep;
-	pgd_t *dir;
-	pmd_t *pmd;
-	pte_t *pte;
-
-	sprintf(current->comm, "zero_paged");
-	printk("Started zero_paged\n");
-	/* want priority over idle task and powerd */
-	current->priority = -98;
-	current->counter = -98;
-	__sti();
-	
-	while ( zerocount < 128 )
-	{
-		/*
-		 * Mark a page as reserved so we can mess with it
-		 * If we're interrupted we keep this page and our place in it
-		 * since we validly hold it and it's reserved for us.
-		 */
-		pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
-		if ( !pageptr )
-		{
-			printk("!pageptr in zero_paged\n");
-			goto retry;
-		}
-		
-		if ( need_resched )
-			schedule();
-		
-		/*
-		 * Make the page no cache so we don't blow our cache with 0's
-		 */
-		dir = pgd_offset( init_task.mm, pageptr );
-		if (dir)
-		{
-			pmd = pmd_offset(dir, pageptr & PAGE_MASK);
-			if (pmd && pmd_present(*pmd))
-			{
-				pte = pte_offset(pmd, pageptr & PAGE_MASK);
-				if (pte && pte_present(*pte))
-				{			
-					pte_uncache(*pte);
-					flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-				}
-			}
-		}
-	
-		/*
-		 * Important here to not take time away from real processes.
-		 */
-		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
-		{
-			if ( need_resched )
-				schedule();
-			*(unsigned long *)(bytecount + pageptr) = 0;
-		}
-		
-		/*
-		 * If we finished zero-ing out a page add this page to
-		 * the zero_list atomically -- we can't use
-		 * down/up since we can't sleep in idle.
-		 * Disabling interrupts is also a bad idea since we would
-		 * steal time away from real processes.
-		 * We can also have several zero_paged's running
-		 * on different processors so we can't interfere with them.
-		 * So we update the list atomically without locking it.
-		 * -- Cort
-		 */
-		/* turn cache on for this page */
-		pte_cache(*pte);
-		flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-		
-		/* atomically add this page to the list */
-		asm (	"101:lwarx  %0,0,%1\n"  /* reserve zero_list */
-			"    stw    %0,0(%2)\n" /* update *pageptr */
-#ifdef __SMP__
-			"    sync\n"            /* let store settle */
-#endif			
-			"    mr     %0,%2\n"    /* update zero_list in reg */
-			"    stwcx. %2,0,%1\n"  /* update zero_list in mem */
-			"    bne-   101b\n"     /* if lost reservation try again */
-			: "=&r" (zero_list)
-			: "r" (&zero_list), "r" (pageptr)
-			: "cc" );
-		/*
-		 * This variable is used in the above loop and nowhere
-		 * else so the worst that could happen is we would
-		 * zero out one more or one less page than we want
-		 * per processor on the machine.  This is because
-		 * we could add our page to the list but not have
-		 * zerocount updated yet when another processor
-		 * reads it.  -- Cort
-		 */
-		atomic_inc((atomic_t *)&zerocount);
-		atomic_inc((atomic_t *)&zerototal);
-retry:	
-		schedule();
-	}
-}
-
-void powerd(void)
-{
-	unsigned long msr, hid0;
-
-	sprintf(current->comm, "powerd");
-	__sti();
-	while (1)
-	{
-		/* want priority over idle task 'swapper' -- Cort */
-		current->priority = -99;
-		current->counter = -99;
-		asm volatile(
-			/* clear powersaving modes and set nap mode */
-			"mfspr %3,1008 \n\t"
-			"andc  %3,%3,%4 \n\t"
-			"or    %3,%3,%5 \n\t"
-			"mtspr 1008,%3 \n\t"
-			/* enter the mode */
-			"mfmsr %0 \n\t"
-			"oris  %0,%0,%2 \n\t"
-			"sync \n\t"
-			"mtmsr %0 \n\t"
-			"isync \n\t"
-			: "=&r" (msr)
-			: "0" (msr), "i" (MSR_POW>>16),
-			"r" (hid0),
-			"r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
-			"r" (HID0_NAP));
-		if ( need_resched )
-			schedule();
-		/*
-		 * The ibm carolina spec says that the eagle memory
-		 * controller will detect the need for a snoop
-		 * and wake up the processor so we don't need to
-		 * check for cache operations that need to be
-		 * snooped.  The ppc book says the run signal
-		 * must be asserted while napping for this though.
-		 * -- Cort
-		 */
-	}
-}
-	
-asmlinkage int sys_idle(void)
-{
-	int ret = -EPERM;
-	if (current->pid != 0)
-		goto out;
-
-#ifdef IDLE_ZERO
-	/*
-	 * want one per cpu since it would be nice to have all
-	 * processors who aren't doing anything
-	 * zero-ing pages since this daemon is lock-free
-	 * -- Cort
-	 */
-	kernel_thread(zero_paged, NULL, 0);
-#endif /* IDLE_ZERO */
-
-#ifdef CONFIG_POWERSAVING
-	/* no powersaving modes on 601 - one per processor */
-	if(  (_get_PVR()>>16) != 1 )
-		kernel_thread(powerd, NULL, 0);
-#endif /* CONFIG_POWERSAVING */
-	
-	/* endless loop with no priority at all */
-	current->priority = -100;
-	current->counter = -100;
-	for (;;) 
-	{
-		schedule();
-	}
-	ret = 0;
-out:
-	return ret;
-}
-
 void show_regs(struct pt_regs * regs)
 {
 	int i;
 
-	printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+	printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
 	       regs->nip, regs->xer, regs->link, regs,regs->trap);
-	printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
 	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
 	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
 	       regs->msr&MSR_IR ? 1 : 0,
 	       regs->msr&MSR_DR ? 1 : 0);
-	printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+	printk("TASK = %p[%d] '%s' mm->pgd %p ",
 	       current, current->pid, current->comm, current->mm->pgd);
-	printk("Last syscall: %d ", current->tss.last_syscall);
-	printk("\nlast math %08X\n", last_task_used_math);
+	printk("Last syscall: %ld ", current->tss.last_syscall);
+	printk("\nlast math %p\n", last_task_used_math);
 	for (i = 0;  i < 32;  i++)
 	{
 		long r;
@@ -451,9 +190,9 @@
 			printk("GPR%02d: ", i);
 		}
 
-		if ( get_user(r, &(regs->gpr[i])) )
+		if ( __get_user(r, &(regs->gpr[i])) )
 		    goto out;
-		printk("%08X ", r);
+		printk("%08lX ", r);
 		if ((i % 8) == 7)
 		{
 			printk("\n");
@@ -480,14 +219,14 @@
 }
 
 /*
-  * Copy a thread..
-  */
+ * Copy a thread..
+ */
 int
 copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	    struct task_struct * p, struct pt_regs * regs)
 {
-	int i;
 	struct pt_regs * childregs;
+
 	/* Copy registers */
 	childregs = ((struct pt_regs *)
 		     ((unsigned long)p + sizeof(union task_union)
@@ -497,13 +236,13 @@
 	if ((childregs->msr & MSR_PR) == 0)
 		childregs->gpr[2] = (unsigned long) p;	/* `current' in new task */
 	childregs->gpr[3] = 0;  /* Result from fork() */
-	p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
-	p->tss.regs = (struct pt_regs *)(childregs);
-	if (usp >= (unsigned long)regs)
-	{ /* Stack is in kernel space - must adjust */
-		childregs->gpr[1] = (long)(childregs+1);
-	} else
-	{ /* Provided stack is in user space */
+	p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
+	p->tss.regs = childregs;
+	if (usp >= (unsigned long) regs) {
+		/* Stack is in kernel space - must adjust */
+		childregs->gpr[1] = (unsigned long)(childregs + 1);
+	} else {
+		/* Provided stack is in user space */
 		childregs->gpr[1] = usp;
 	}
 
@@ -511,24 +250,75 @@
 
 	/*
 	 * copy fpu info - assume lazy fpu switch now always
-	 * this should really be conditional on whether or
-	 * not the process has used the fpu
 	 *  -- Cort
 	 */
 	if ( last_task_used_math == current )
 		giveup_fpu();
-	
+
 	memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
 	p->tss.fpscr = current->tss.fpscr;
 	childregs->msr &= ~MSR_FP;
-	
+
 	return 0;
 }
 
+/*
+ * XXX ld.so expects the auxiliary table to start on
+ * a 16-byte boundary, so we have to find it and
+ * move it up. :-(
+ */
+static inline void shove_aux_table(unsigned long sp)
+{
+	int argc;
+	char *p;
+	unsigned long e;
+	unsigned long aux_start, offset;
+
+	if (__get_user(argc, (int *)sp))
+		return;
+	sp += sizeof(int) + (argc + 1) * sizeof(char *);
+	/* skip over the environment pointers */
+	do {
+		if (__get_user(p, (char **)sp))
+			return;
+		sp += sizeof(char *);
+	} while (p != NULL);
+	aux_start = sp;
+	/* skip to the end of the auxiliary table */
+	do {
+		if (__get_user(e, (unsigned long *)sp))
+			return;
+		sp += 2 * sizeof(unsigned long);
+	} while (e != AT_NULL);
+	offset = ((aux_start + 15) & ~15) - aux_start;
+	if (offset != 0) {
+		do {
+			sp -= sizeof(unsigned long);
+			if (__get_user(e, (unsigned long *)sp)
+			    || __put_user(e, (unsigned long *)(sp + offset)))
+				return;
+		} while (sp > aux_start);
+	}
+}
+
+/*
+ * Set up a thread for executing a new program
+ */
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
+{
+	set_fs(USER_DS);
+	regs->nip = nip;
+	regs->gpr[1] = sp;
+	regs->msr = MSR_USER;
+	shove_aux_table(sp);
+}
+
+
 asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
 			struct pt_regs *regs)
 {
 	int ret;
+
 	lock_kernel();
 	ret = do_fork(SIGCHLD, regs->gpr[1], regs);
 	unlock_kernel();
@@ -541,26 +331,26 @@
 {
 	int error;
 	char * filename;
-	filename = (int) getname((char *) a0);
+	
+	filename = getname((char *) a0);
 	error = PTR_ERR(filename);
-	if(IS_ERR(filename))
+	if (IS_ERR(filename))
 		goto out;
 	if ( last_task_used_math == current )
 		last_task_used_math = NULL;
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
-
 	putname(filename);
-
 out:
 	unlock_kernel();
 	return error;
 }
 
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
+			 struct pt_regs *regs)
 {
 	unsigned long clone_flags = p1;
 	int res;
-	
+
 	lock_kernel();
 	res = do_fork(clone_flags, regs->gpr[1], regs);
 	unlock_kernel();
@@ -571,34 +361,23 @@
 print_backtrace(unsigned long *sp)
 {
 	int cnt = 0;
-	int i;
+	unsigned long i;
+
 	printk("Call backtrace: ");
-	while ( !get_user(i, sp) && i)
-	{
-		if ( get_user( i, &sp[1] ) )
-			return;
-		printk("%08X ", i);
-		if ( get_user( (ulong)sp, sp) )
-		    return;
-		if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
-		if (++cnt == 8)
-		{
+	while (sp) {
+		if (__get_user( i, &sp[1] ))
+			break;
+		if (cnt++ % 7 == 0)
 			printk("\n");
-		}
+		printk("%08lX ", i);
 		if (cnt > 32) break;
+		if (__get_user(sp, (unsigned long **)sp))
+			break;
 	}
 	printk("\n");
 }
 
-inline void start_thread(struct pt_regs * regs,
-                         unsigned long eip, unsigned long esp)
-{
-	set_fs(USER_DS);
-	regs->nip = eip;
-	regs->gpr[1] = esp;
-	regs->msr = MSR_USER;
-}
-
+#if 0
 /*
  * Low level print for debugging - Cort
  */
@@ -651,3 +430,4 @@
 	orig_x = x;
 	orig_y = y;
 }
+#endif /* CONFIG_PREP */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov