patch-2.1.126 linux/arch/mips/kernel/ptrace.c

Next file: linux/arch/mips/kernel/r2300_fpu.S
Previous file: linux/arch/mips/kernel/process.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.125/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
@@ -1,8 +1,14 @@
-/* ptrace.c */
-/* By Ross Biro 1/23/92 */
-/* edited by Linus Torvalds */
-/* further hacked for MIPS by David S. Miller (dm@engr.sgi.com) */
-
+/* $Id: ptrace.c,v 1.11 1998/10/19 16:26:31 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1992 Ross Biro
+ * Copyright (C) Linus Torvalds
+ * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1996 David S. Miller
+ */
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -12,10 +18,12 @@
 #include <linux/smp_lock.h>
 #include <linux/user.h>
 
-#include <asm/uaccess.h>
+#include <asm/fp.h>
+#include <asm/mipsregs.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/system.h>
+#include <asm/uaccess.h>
 
 /*
  * This routine gets a long from any process space by following the page
@@ -67,6 +75,7 @@
 	 */
 	flush_cache_all();
 	retval = *(unsigned long *) page;
+	flush_cache_all();	/* VCED avoidance  */
 	return retval;
 }
 
@@ -121,10 +130,10 @@
 	}
 	/* This is a hack for non-kernel-mapped video buffers and similar */
 	if (MAP_NR(page) < MAP_NR(high_memory))
-		flush_cache_page(vma, addr);
+		flush_cache_all();
 	*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
 	if (MAP_NR(page) < MAP_NR(high_memory))
-		flush_page_to_ram(page);
+		flush_cache_all();
 	/*
 	 * We're bypassing pagetables, so we have to set the dirty bit
 	 * ourselves this should also re-instate whatever read-only mode
@@ -324,163 +333,182 @@
 	}
 
 	switch (request) {
-	/* when I and D space are separate, these will need to be fixed. */
-		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-		case PTRACE_PEEKDATA: {
-			unsigned long tmp;
+	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+	case PTRACE_PEEKDATA: {
+		unsigned long tmp;
 
-			res = read_long(child, addr, &tmp);
-			if (res < 0)
-				goto out;
-			res = put_user(tmp,(unsigned long *) data);
+		res = read_long(child, addr, &tmp);
+		if (res < 0)
 			goto out;
+		res = put_user(tmp,(unsigned long *) data);
+		goto out;
 		}
 
 	/* read the word at location addr in the USER area. */
 /* #define DEBUG_PEEKUSR */
-		case PTRACE_PEEKUSR: {
-			struct pt_regs *regs;
-			unsigned long tmp;
-
-			regs = (struct pt_regs *) ((unsigned long) child +
-			       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
-			tmp = 0;  /* Default return value. */
-			if(addr < 32 && addr >= 0) {
-				tmp = regs->regs[addr];
-			} else if(addr >= 32 && addr < 64) {
-				unsigned long long *fregs;
-
-				/* We don't want to do a FPU operation here. */
+	case PTRACE_PEEKUSR: {
+		struct pt_regs *regs;
+		unsigned long tmp;
+
+		regs = (struct pt_regs *) ((unsigned long) child +
+		       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
+		tmp = 0;  /* Default return value. */
+		if (addr < 32 && addr >= 0)
+			tmp = regs->regs[addr];
+		else if (addr >= 32 && addr < 64) {
+			unsigned long long *fregs;
+
+			if (child->used_math) {
+				if (last_task_used_math == child) {
+					enable_cp1();
+					r4xx0_save_fp(child);
+					disable_cp1();
+					last_task_used_math = NULL;
+				}
 				fregs = (unsigned long long *)
 					&child->tss.fpu.hard.fp_regs[0];
 				tmp = (unsigned long) fregs[(addr - 32)];
 			} else {
-				addr -= 64;
-				switch(addr) {
-				case 0:
-					tmp = regs->cp0_epc;
-					break;
-				case 1:
-					tmp = regs->cp0_cause;
-					break;
-				case 2:
-					tmp = regs->cp0_badvaddr;
-					break;
-				case 3:
-					tmp = regs->lo;
-					break;
-				case 4:
-					tmp = regs->hi;
-					break;
-				case 5:
-					tmp = child->tss.fpu.hard.control;
-					break;
-				case 6:	/* implementation / version register */
-					tmp = 0;
-					break;
-				default:
-					tmp = 0;
-					res = -EIO;
-					goto out;
-				};
+				tmp = -1;	/* FP not yet used  */
+			}
+		} else {
+			addr -= 64;
+			switch(addr) {
+			case 0:
+				tmp = regs->cp0_epc;
+				break;
+			case 1:
+				tmp = regs->cp0_cause;
+				break;
+			case 2:
+				tmp = regs->cp0_badvaddr;
+				break;
+			case 3:
+				tmp = regs->lo;
+				break;
+			case 4:
+				tmp = regs->hi;
+				break;
+			case 5:
+				tmp = child->tss.fpu.hard.control;
+				break;
+			case 6:	/* implementation / version register */
+				tmp = 0;	/* XXX */
+				break;
+			default:
+				tmp = 0;
+				res = -EIO;
+				goto out;
 			}
-			res = put_user(tmp, (unsigned long *) data);
-			goto out;
+		}
+		res = put_user(tmp, (unsigned long *) data);
+		goto out;
 		}
 
-      /* when I and D space are separate, this will have to be fixed. */
-		case PTRACE_POKETEXT: /* write the word at location addr. */
-		case PTRACE_POKEDATA:
-			res = write_long(child,addr,data);
-			goto out;
-
-		case PTRACE_POKEUSR: {
-			struct pt_regs *regs;
-			int res = 0;
-
-			regs = (struct pt_regs *) ((unsigned long) child +
-			       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
-			if(addr < 32 && addr >= 0) {
-				regs->regs[addr] = data;
-			} else if(addr >= 32 && addr < 64) {
-				unsigned long long *fregs;
+	case PTRACE_POKETEXT: /* write the word at location addr. */
+	case PTRACE_POKEDATA:
+		res = write_long(child,addr,data);
+		goto out;
 
-				/* We don't want to do a FPU operation here. */
-				fregs = (unsigned long long *)
-					&child->tss.fpu.hard.fp_regs[0];
-				fregs[(addr - 32)] = (unsigned long long) data;
+	case PTRACE_POKEUSR: {
+		struct pt_regs *regs;
+		int res = 0;
+
+		regs = (struct pt_regs *) ((unsigned long) child +
+		       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
+		if (addr < 32 && addr >= 0)
+			regs->regs[addr] = data;
+		else if (addr >= 32 && addr < 64) {
+			unsigned long long *fregs;
+
+			if (child->used_math) {
+				if (last_task_used_math == child) {
+					enable_cp1();
+					r4xx0_save_fp(child);
+					disable_cp1();
+					last_task_used_math = NULL;
+				}
 			} else {
-				addr -= 64;
-				switch(addr) {
-				case 0:
-					regs->cp0_epc = data;
-					break;
-				case 3:
-					regs->lo = data;
-					break;
-				case 4:
-					regs->hi = data;
-					break;
-				case 5:
-					child->tss.fpu.hard.control = data;
-					break;
-				default:
-					/* The rest are not allowed. */
-					res = -EIO;
-					break;
-				};
+				/* FP not yet used  */
+				memset(&child->tss.fpu.hard, ~0,
+				       sizeof(child->tss.fpu.hard));
+				child->tss.fpu.hard.control = 0;
 			}
-			goto out;
-		}
-
-		case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
-		case PTRACE_CONT: { /* restart after signal. */
-			if ((unsigned long) data > _NSIG) {
+			fregs = (unsigned long long *)
+				&child->tss.fpu.hard.fp_regs[0];
+			fregs[(addr - 32)] = (unsigned long long) data;
+		} else {
+			addr -= 64;
+			switch (addr) {
+			case 0:
+				regs->cp0_epc = data;
+				break;
+			case 3:
+				regs->lo = data;
+				break;
+			case 4:
+				regs->hi = data;
+				break;
+			case 5:
+				child->tss.fpu.hard.control = data;
+				break;
+			default:
+				/* The rest are not allowed. */
 				res = -EIO;
-				goto out;
-			}
-			if (request == PTRACE_SYSCALL)
-				child->flags |= PF_TRACESYS;
-			else
-				child->flags &= ~PF_TRACESYS;
-			child->exit_code = data;
-			wake_up_process(child);
-			res = data;
-			goto out;
+				break;
+			};
+		}
+		goto out;
 		}
 
-/*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
- * exit.
- */
-		case PTRACE_KILL: {
-			if (child->state != TASK_ZOMBIE) {
-				wake_up_process(child);
-				child->exit_code = SIGKILL;
-			}
-			res = 0;
+	case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+	case PTRACE_CONT: { /* restart after signal. */
+		if ((unsigned long) data > _NSIG) {
+			res = -EIO;
 			goto out;
 		}
+		if (request == PTRACE_SYSCALL)
+			child->flags |= PF_TRACESYS;
+		else
+			child->flags &= ~PF_TRACESYS;
+		child->exit_code = data;
+		wake_up_process(child);
+		res = data;
+		goto out;
+		}
 
-		case PTRACE_DETACH: { /* detach a process that was attached. */
-			if ((unsigned long) data > _NSIG) {
-				res = -EIO;
-				goto out;
-			}
-			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+	/*
+	 * make the child exit.  Best I can do is send it a sigkill. 
+	 * perhaps it should be put in the status that it wants to 
+	 * exit.
+	 */
+	case PTRACE_KILL: {
+		if (child->state != TASK_ZOMBIE) {
+			child->exit_code = SIGKILL;
 			wake_up_process(child);
-			child->exit_code = data;
-			REMOVE_LINKS(child);
-			child->p_pptr = child->p_opptr;
-			SET_LINKS(child);
-			res = 0;
-			goto out;
+		}
+		res = 0;
+		goto out;
 		}
 
-		default:
+	case PTRACE_DETACH: { /* detach a process that was attached. */
+		if ((unsigned long) data > _NSIG) {
 			res = -EIO;
 			goto out;
+		}
+		child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+		child->exit_code = data;
+		REMOVE_LINKS(child);
+		child->p_pptr = child->p_opptr;
+		SET_LINKS(child);
+		wake_up_process(child);
+		res = 0;
+		goto out;
+		}
+
+	default:
+		res = -EIO;
+		goto out;
 	}
 out:
 	unlock_kernel();

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