patch-2.1.16 linux/arch/ppc/kernel/process.c
Next file: linux/arch/ppc/kernel/ptrace.c
Previous file: linux/arch/ppc/kernel/ppc_defs.h
Back to the patch index
Back to the overall index
- Lines: 392
- Date:
Wed Dec 18 10:49:52 1996
- Orig file:
v2.1.15/linux/arch/ppc/kernel/process.c
- Orig date:
Mon Jul 8 11:27:43 1996
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1995 Linus Torvalds
* Adapted for PowerPC by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
*/
/*
@@ -17,69 +18,140 @@
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
-#include <linux/ldt.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/ppc_machine.h>
+int dump_fpu(void);
+void hard_reset_now(void);
+void switch_to(struct task_struct *, struct task_struct *);
+void copy_thread(int,unsigned long,unsigned long,struct task_struct *,
+ struct pt_regs *);
+void print_backtrace(unsigned long *);
int
-dump_fpu()
+dump_fpu(void)
{
- return (1);
+ return (1);
}
+
+/* check to make sure the kernel stack is healthy */
+int check_stack(struct task_struct *tsk)
+{
+ extern unsigned long init_kernel_stack[PAGE_SIZE/sizeof(long)];
+ int ret = 0;
+ int i;
+
+ /* skip check in init_kernel_task -- swapper */
+ if ( tsk->kernel_stack_page == (unsigned long)&init_kernel_stack )
+ return;
+ /* check bounds on stack -- above/below kstack page */
+ if ( (tsk->tss.ksp-1 & KERNEL_STACK_MASK) != tsk->kernel_stack_page )
+ {
+ printk("check_stack(): not in bounds %s/%d ksp %x/%x\n",
+ tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page);
+ ret |= 1;
+ }
+
+ /* check for magic on kstack */
+ if ( *(unsigned long *)(tsk->kernel_stack_page) != STACK_MAGIC)
+ {
+ printk("check_stack(): no magic %s/%d ksp %x/%x magic %x\n",
+ tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
+ *(unsigned long *)(tsk->kernel_stack_page));
+ ret |= 2;
+ }
+
+#ifdef KERNEL_STACK_BUFFER
+ /* check extra padding page under kernel stack */
+ for ( i = PAGE_SIZE/sizeof(long) ; i >= 1; i--)
+ {
+ struct pt_regs *regs;
+
+ if ( *((unsigned long *)(tsk->kernel_stack_page)-1) )
+ {
+ printk("check_stack(): padding touched %s/%d ksp %x/%x value %x/%d\n",
+ tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
+ *(unsigned long *)(tsk->kernel_stack_page-i),i*sizeof(long));
+ regs = (struct pt_regs *)(tsk->kernel_stack_page-(i*sizeof(long)));
+ printk("marker %x trap %x\n", regs->marker,regs->trap);
+ print_backtrace((unsigned long *)(tsk->tss.ksp));
+
+ ret |= 4;
+ break;
+ }
+ }
+#endif
+
+#if 0
+ if (ret)
+ panic("bad stack");
+#endif
+ return(ret);
+}
+
+
void
switch_to(struct task_struct *prev, struct task_struct *new)
{
struct pt_regs *regs;
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
- regs = new->tss.ksp;
+ regs = (struct pt_regs *)(new->tss.ksp);
+#if 1
+ check_stack(prev);
+ check_stack(new);
+#endif
+ /* if a process has used fp 15 times, then turn
+ on the fpu for good otherwise turn it on with the fp
+ exception handler as needed.
+ skip this for kernel tasks.
+ -- Cort */
+ if ( (regs->msr & MSR_FP)&&(regs->msr & MSR_PR)&&(new->tss.fp_used < 15) )
+ {
#if 0
- printk("Task %x(%d) -> %x(%d)", current, current->pid, new, new->pid);
- printk(" - IP: %x, SR: %x, SP: %x\n", regs->nip, regs->msr, regs);
+ printk("turning off fpu: %s/%d fp_used %d\n",
+ new->comm,new->pid,new->tss.fp_used);
+#endif
+ regs->msr = regs->msr & ~MSR_FP;
+ }
+#if 0
+ printk("%s/%d -> %s/%d\n",prev->comm,prev->pid,new->comm,new->pid);
#endif
new_tss = &new->tss;
old_tss = ¤t->tss;
- current_set[0] = new; /* FIX ME! */
+ current_set[0] = new;
_switch(old_tss, new_tss);
-#if 0
- printk("Back in task %x(%d)\n", current, current->pid);
-#endif
_enable_interrupts(s);
}
-asmlinkage int sys_idle(void)
+asmlinkage int sys_debug(unsigned long r3)
{
- if (current->pid != 0)
- return -EPERM;
-
- /* endless idle loop with no priority at all */
- current->counter = -100;
- for (;;) {
- schedule();
- }
+ if ( !strcmp(current->comm,"crashme"))
+ printk("sys_debug(): r3 (syscall) %d\n", r3);
}
-void hard_reset_now(void)
+asmlinkage int sys_idle(void)
{
- halt();
+ if (current->pid != 0)
+ return -EPERM;
+ /* endless idle loop with no priority at all */
+ current->counter = -100;
+ for (;;) {
+ schedule();
+ }
}
void show_regs(struct pt_regs * regs)
{
- _panic("show_regs");
}
-/*
- * Free current thread data structures etc..
- */
void exit_thread(void)
{
}
@@ -102,24 +174,28 @@
int i;
SEGREG *segs;
struct pt_regs * childregs;
-#if 0
-printk("copy thread - NR: %d, Flags: %x, USP: %x, Task: %x, Regs: %x\n", nr, clone_flags, usp, p, regs);
-#endif
+
/* Construct segment registers */
- segs = p->tss.segs;
+ segs = (SEGREG *)(p->tss.segs);
for (i = 0; i < 8; i++)
{
segs[i].ks = 0;
segs[i].kp = 1;
+#if 0
segs[i].vsid = i | (nr << 4);
+#else
+ segs[i].vsid = i | ((nr * 10000) << 4);
+#endif
}
if ((p->mm->context == 0) || (p->mm->count == 1))
{
- p->mm->context = (nr<<4);
-#if 0
-printk("Setting MM[%x] Context = %x Task = %x Current = %x/%x\n", p->mm, p->mm->context, p, current, current->mm);
+#if 0
+ p->mm->context = ((nr)<<4);
+#else
+ p->mm->context = ((nr*10000)<<4);
#endif
}
+
/* Last 8 are shared with kernel & everybody else... */
for (i = 8; i < 16; i++)
{
@@ -127,22 +203,21 @@
segs[i].kp = 1;
segs[i].vsid = i;
}
+
/* Copy registers */
-#ifdef STACK_HAS_TWO_PAGES
- childregs = ((struct pt_regs *) (p->kernel_stack_page + 2*PAGE_SIZE)) - 2;
-#else
- childregs = ((struct pt_regs *) (p->kernel_stack_page + 1*PAGE_SIZE)) - 2;
-#endif
+ childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 2;
+
*childregs = *regs; /* STRUCT COPY */
childregs->gpr[3] = 0; /* Result from fork() */
- p->tss.ksp = childregs;
+ p->tss.ksp = (unsigned long)(childregs);
if (usp >= (unsigned long)regs)
{ /* Stack is in kernel space - must adjust */
- childregs->gpr[1] = childregs+1;
+ childregs->gpr[1] = (long)(childregs+1);
} else
{ /* Provided stack is in user space */
childregs->gpr[1] = usp;
}
+ p->tss.fp_used = 0;
}
/*
@@ -152,43 +227,12 @@
{
}
-#if 0
-/*
- * Do necessary setup to start up a newly executed thread.
- */
-void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
-{
- regs->nip = eip;
- regs->gpr[1] = esp;
- regs->msr = MSR_USER;
-#if 0
-{
- int len;
- len = (unsigned long)0x80000000 - esp;
- if (len > 128) len = 128;
- printk("Start thread [%x] at PC: %x, SR: %x, SP: %x\n", regs, eip, regs->msr, esp);
- dump_buf(esp, len);
- dump_buf(eip, 0x80);
-}
-#endif
-}
-#endif
asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
{
- return do_fork(SIGCHLD, regs->gpr[1], regs);
+ return do_fork(SIGCHLD, regs->gpr[1], regs);
}
-/*
- * sys_execve() executes a new program.
- *
- * This works due to the PowerPC calling sequence: the first 6 args
- * are gotten from registers, while the rest is on the stack, so
- * we get a0-a5 for free, and then magically find "struct pt_regs"
- * on the stack for us..
- *
- * Don't do this at home.
- */
asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs *regs)
@@ -196,11 +240,31 @@
int error;
char * filename;
+ /* getname does it's own verification of the address
+ when it calls get_max_filename() but
+ it will assume it's valid if get_fs() == KERNEL_DS
+ which is always true on the ppc so we check
+ it here
+
+ this doesn't completely check any of these data structures,
+ it just makes sure that the 1st long is in a good area
+ and from there we assume that it's safe then
+ -- Cort
+ */
+ /* works now since get_fs/set_fs work properly */
+#if 0
+ if ( verify_area(VERIFY_READ,(void *)a0,1)
+ && verify_area(VERIFY_READ,(void *)a1,1)
+ && verify_area(VERIFY_READ,(void *)a2,1)
+ )
+ {
+ return -EFAULT;
+ }
+#endif
error = getname((char *) a0, &filename);
if (error)
{
-printk("Error getting EXEC name: %d\n", error);
- return error;
+ return error;
}
flush_instruction_cache();
error = do_execve(filename, (char **) a1, (char **) a2, regs);
@@ -214,10 +278,6 @@
return error;
}
-/*
- * This doesn't actually work correctly like this: we need to do the
- * same stack setups that fork() does first.
- */
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;
@@ -229,12 +289,13 @@
void
print_backtrace(unsigned long *sp)
{
+#if 0
int cnt = 0;
printk("... Call backtrace:\n");
- while (*sp)
+ while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
{
printk("%08X ", sp[1]);
- sp = *sp;
+ sp = (unsigned long *)*sp;
if (++cnt == 8)
{
printk("\n");
@@ -242,17 +303,19 @@
if (cnt > 32) break;
}
printk("\n");
+#endif
}
void
print_user_backtrace(unsigned long *sp)
{
+#if 0
int cnt = 0;
printk("... [User] Call backtrace:\n");
- while (valid_addr(sp) && *sp)
+ while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
{
printk("%08X ", sp[1]);
- sp = *sp;
+ sp = (unsigned long *)*sp;
if (++cnt == 8)
{
printk("\n");
@@ -260,11 +323,23 @@
if (cnt > 16) break;
}
printk("\n");
+#endif
}
void
print_kernel_backtrace(void)
{
+#if 0
unsigned long *_get_SP(void);
print_backtrace(_get_SP());
+#endif
}
+inline void start_thread(struct pt_regs * regs,
+ unsigned long eip, unsigned long esp)
+{
+ regs->nip = eip;
+ regs->gpr[1] = esp;
+ regs->msr = MSR_USER;
+ set_fs(USER_DS);
+}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov