date and time created 92/07/13 00:44:42 by torek
authorChris Torek <torek@ucbvax.Berkeley.EDU>
Mon, 13 Jul 1992 15:44:42 +0000 (07:44 -0800)
committerChris Torek <torek@ucbvax.Berkeley.EDU>
Mon, 13 Jul 1992 15:44:42 +0000 (07:44 -0800)
SCCS-vsn: sys/sparc/sparc/sys_machdep.c 7.1
SCCS-vsn: sys/sparc/sparc/sys_process.c 7.1
SCCS-vsn: sys/sparc/sparc/timerreg.h 7.1

usr/src/sys/sparc/sparc/sys_machdep.c [new file with mode: 0644]
usr/src/sys/sparc/sparc/sys_process.c [new file with mode: 0644]
usr/src/sys/sparc/sparc/timerreg.h [new file with mode: 0644]

diff --git a/usr/src/sys/sparc/sparc/sys_machdep.c b/usr/src/sys/sparc/sparc/sys_machdep.c
new file mode 100644 (file)
index 0000000..082a8d3
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)sys_machdep.c       7.1 (Berkeley) %G%
+ *
+ * from: $Header: sys_machdep.c,v 1.5 92/07/10 00:29:56 torek Exp $ (LBL)
+ */
+
+#ifdef TRACE
+#include "sys/param.h"
+#include "sys/systm.h"
+#include "sys/ioctl.h"
+#include "sys/file.h"
+#include "sys/time.h"
+#include "sys/proc.h"
+#include "sys/uio.h"
+#include "sys/kernel.h"
+#include "sys/mtio.h"
+#include "sys/buf.h"
+#include "sys/trace.h"
+
+int    nvualarm;
+
+struct vtrace_args {
+       int     request;
+       int     value;
+};
+vtrace(p, uap, retval)
+       struct proc *p;
+       register struct vtrace_args *uap;
+       int *retval;
+{
+       int vdoualarm();
+
+       switch (uap->request) {
+
+       case VTR_DISABLE:               /* disable a trace point */
+       case VTR_ENABLE:                /* enable a trace point */
+               if (uap->value < 0 || uap->value >= TR_NFLAGS)
+                       return (EINVAL);
+               *retval = traceflags[uap->value];
+               traceflags[uap->value] = uap->request;
+               break;
+
+       case VTR_VALUE:         /* return a trace point setting */
+               if (uap->value < 0 || uap->value >= TR_NFLAGS)
+                       return (EINVAL);
+               *retval = traceflags[uap->value];
+               break;
+
+       case VTR_UALARM:        /* set a real-time ualarm, less than 1 min */
+               if (uap->value <= 0 || uap->value > 60 * hz || nvualarm > 5)
+                       return (EINVAL);
+               nvualarm++;
+               timeout(vdoualarm, (caddr_t)p->p_pid, uap->value);
+               break;
+
+       case VTR_STAMP:
+               trace(TR_STAMP, uap->value, p->p_pid);
+               break;
+       }
+       return (0);
+}
+
+vdoualarm(arg)
+       int arg;
+{
+       register struct proc *p = pfind(arg);
+
+       if (p != NULL)
+               psignal(p, 16);
+       nvualarm--;
+}
+#endif
diff --git a/usr/src/sys/sparc/sparc/sys_process.c b/usr/src/sys/sparc/sparc/sys_process.c
new file mode 100644 (file)
index 0000000..e6fe594
--- /dev/null
@@ -0,0 +1,358 @@
+/*-
+ * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * %sccs.include.proprietary.c%
+ *
+ *     @(#)sys_process.c       7.1 (Berkeley) %G%
+ */
+
+#include "sys/param.h"
+#include "sys/proc.h"
+#include "sys/vnode.h"
+#include "sys/buf.h"
+#include "sys/malloc.h"
+#include "sys/ptrace.h"
+#include "sys/user.h"
+
+#include "vm/vm.h"
+#include "vm/vm_page.h"
+
+#include "machine/psl.h"
+#include "machine/reg.h"
+
+/*
+ * Priority for tracing
+ */
+#define        IPCPRI  PZERO
+
+/*
+ * Tracing variables.
+ * Used to pass trace command from
+ * parent to child being traced.
+ * This data base cannot be
+ * shared and is locked
+ * per user.
+ */
+struct {
+       int     ip_lock;
+       int     ip_req;
+       int     ip_error;
+       union {
+               char    un_any[4];
+               struct {
+                       int     wd_data;
+                       caddr_t wd_addr;
+               } un_wd;
+               struct  trapframe un_tf;
+               struct  fpstate un_f;
+       } ip_un;
+} ipc;
+#define        ip_any  ip_un.un_any
+#define        ip_data ip_un.un_wd.wd_data
+#define        ip_addr ip_un.un_wd.wd_addr
+#define        ip_tf   ip_un.un_tf
+#define        ip_f    ip_un.un_f
+
+/*
+ * Process debugging system call.
+ */
+struct ptrace_args {
+       int     req;
+       int     pid;
+       caddr_t addr;
+       int     data;
+};
+ptrace(curp, uap, retval)
+       struct proc *curp;
+       register struct ptrace_args *uap;
+       int *retval;
+{
+       register struct proc *p;
+       register enum { t_oneword, t_regin, t_regout } type;
+       register size_t size;
+       register int error;
+
+       if (uap->req == PT_TRACE_ME) {
+               curp->p_flag |= STRC;
+               curp->p_oppid = 0;      /* XXX put in the zeroed section */
+               return (0);
+       }
+       if ((p = pfind(uap->pid)) == NULL)
+               return (ESRCH);
+       switch (uap->req) {
+
+       case PT_READ_I:
+       case PT_READ_D:
+       case PT_WRITE_I:
+       case PT_WRITE_D:
+       case PT_CONTINUE:
+       case PT_KILL:
+       case PT_DETACH:
+               type = t_oneword;
+               size = 0;
+               break;
+
+       case PT_ATTACH:
+               /*
+                * Must be root if the process has used set user or
+                * group privileges or does not belong to the real
+                * user. Must not be already traced.
+                */
+               if ((p->p_flag & SUGID ||
+                   p->p_cred->p_ruid != curp->p_cred->p_ruid) &&
+                   (error = suser(p->p_ucred, &p->p_acflag)) != 0)
+                       return (error);
+               if (p->p_flag & STRC)
+                       return (EALREADY);      /* ??? */
+               /*
+                * It would be nice if the tracing relationship was separate
+                * from the parent relationship but that would require
+                * another set of links in the proc struct or for "wait"
+                * to scan the entire proc table.  To make life easier,
+                * we just re-parent the process we're trying to trace.
+                * The old parent is remembered so we can put things back
+                * on a "detach".
+                */
+               p->p_flag |= STRC;
+               p->p_oppid = p->p_pptr->p_pid;
+               proc_reparent(p, curp);
+               psignal(p, SIGSTOP);
+               return (0);
+
+       case PT_GETREGS:
+               type = t_regout;
+               size = sizeof(struct trapframe);
+               break;
+
+       case PT_SETREGS:
+               type = t_regin;
+               size = sizeof(struct trapframe);
+               break;
+
+       case PT_GETFPREGS:
+               type = t_regout;
+               size = sizeof(struct fpstate);
+               break;
+
+       case PT_SETFPREGS:
+               type = t_regin;
+               size = sizeof(struct fpstate);
+               break;
+
+       default:
+               return (EINVAL);
+       }
+       if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & STRC))
+               return (ESRCH);
+       while (ipc.ip_lock)
+               sleep((caddr_t)&ipc, IPCPRI);
+       ipc.ip_lock = p->p_pid;
+       ipc.ip_req = uap->req;
+       ipc.ip_error = 0;
+       switch (type) {
+
+       case t_oneword:
+               ipc.ip_addr = uap->addr;
+               ipc.ip_data = uap->data;
+               break;
+
+       case t_regin:
+               if ((error = copyin(uap->addr, ipc.ip_any, size)) != 0)
+                       return (error);
+               break;
+
+       case t_regout:
+               break;
+
+       default:
+               panic("ptrace");
+       }
+       p->p_flag &= ~SWTED;
+       do {
+               if (p->p_stat == SSTOP)
+                       setrun(p);
+               sleep((caddr_t)&ipc, IPCPRI);
+       } while (ipc.ip_req > 0);
+       if ((error = ipc.ip_error) == 0) {
+               if (type == t_oneword)
+                       *retval = ipc.ip_data;
+               else if (type == t_regout)
+                       error = copyout(ipc.ip_any, uap->addr, size);
+       }
+       ipc.ip_lock = 0;
+       wakeup((caddr_t)&ipc);
+       return (error);
+}
+
+/*
+ * Write text space by unprotecting, writing, and reprotecting.
+ */
+static int
+writetext(p, addr, data, len)
+       struct proc *p;
+       caddr_t addr, data;
+       int len;
+{
+       vm_offset_t sa, ea;
+       vm_map_t map;
+       int error;
+
+       map = &p->p_vmspace->vm_map;
+       sa = trunc_page((vm_offset_t)addr);
+       ea = round_page((vm_offset_t)addr + len - 1);
+       if (vm_map_protect(map, sa, ea, VM_PROT_DEFAULT, 0) != KERN_SUCCESS)
+               return (-1);
+       error = copyout(data, addr, len);
+       (void) vm_map_protect(map, sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, 0);
+       return (error);
+}
+
+/*
+ * Transmit a tracing request from the parent to the child process
+ * being debugged.  This code runs in the context of the child process
+ * to fulfill the command requested by the parent.
+ */
+procxmt(p)
+       register struct proc *p;
+{
+       register int req, error, sig, pc, psr;
+       register caddr_t addr;
+       register struct trapframe *tf, *utf;
+       register struct fpstate *fs, *oldfs;
+       extern struct fpstate initfpstate;
+
+       if (ipc.ip_lock != p->p_pid)
+               return (0);
+       p->p_slptime = 0;
+       req = ipc.ip_req;
+       ipc.ip_req = 0;
+       error = 0;
+       switch (req) {
+
+       case PT_READ_I:                 /* read the child's text space */
+       case PT_READ_D:                 /* read the child's data space */
+               write_user_windows();
+               (void) rwindow_save(p); /* ignore unwritable windows */
+               error = copyin(ipc.ip_addr, ipc.ip_any, sizeof(int));
+               break;
+
+       case PT_WRITE_I:                /* write the child's text space */
+       case PT_WRITE_D:                /* write the child's data space */
+               addr = ipc.ip_addr;
+               write_user_windows();
+               (void) rwindow_save(p);
+               error = copyout(ipc.ip_any, addr, sizeof(int));
+               if (error && req == PT_WRITE_I)
+                       error = writetext(p, addr, ipc.ip_any, sizeof(int));
+               break;
+
+       case PT_CONTINUE:               /* continue the child */
+               sig = ipc.ip_data;
+               if ((unsigned)sig >= NSIG) {
+                       error = EINVAL;
+                       break;
+               }
+               pc = (int)ipc.ip_addr;
+               if (pc & 3) {
+                       if (pc != 1) {
+                               error = EINVAL;
+                               break;
+                       }
+               } else {
+                       tf = p->p_md.md_tf;
+                       tf->tf_pc = pc;
+                       tf->tf_npc = pc + 4;
+               }
+               p->p_xstat = sig;       /* see issig */
+               wakeup((caddr_t)&ipc);
+               return (1);
+
+       case PT_KILL:                   /* kill the child process */
+               wakeup((caddr_t)&ipc);
+               exit(p, (int)p->p_xstat);
+
+       case PT_DETACH:                 /* stop tracing the child */
+               sig = ipc.ip_data;
+               if ((unsigned)sig >= NSIG) {
+                       error = EINVAL;
+                       break;
+               }
+               pc = (int)ipc.ip_addr;
+               if (pc & 3) {
+                       if (pc != 1) {
+                               error = EINVAL;
+                               break;
+                       }
+               } else {
+                       tf = p->p_md.md_tf;
+                       tf->tf_pc = pc;
+                       tf->tf_npc = pc + 4;
+               }
+               p->p_xstat = sig;       /* see issig */
+               p->p_flag &= ~STRC;
+               if (p->p_oppid != p->p_pptr->p_pid) {
+                        register struct proc *pp = pfind(p->p_oppid);
+
+                        if (pp)
+                                proc_reparent(p, pp);
+               }
+               p->p_oppid = 0;
+               wakeup((caddr_t)&ipc);
+               return (1);
+
+       case PT_GETREGS:
+               copywords((caddr_t)p->p_md.md_tf, (caddr_t)&ipc.ip_tf,
+                         sizeof(struct trapframe));
+               ipc.ip_tf.tf_global[0] = 0; /* XXX */
+               break;
+
+       case PT_SETREGS:
+               tf = p->p_md.md_tf;
+               utf = &ipc.ip_tf;
+               if ((utf->tf_pc | utf->tf_npc) & 3) {
+                       error = EINVAL;
+                       break;
+               }
+               psr = (tf->tf_psr & ~PSR_ICC) | (utf->tf_psr & PSR_ICC);
+               copywords((caddr_t)utf, (caddr_t)tf, sizeof(*tf));
+               tf->tf_psr = psr;
+               break;
+
+       case PT_GETFPREGS:
+               if ((fs = p->p_md.md_fpstate) == NULL)
+                       fs = &initfpstate;
+               else if (p == fpproc)
+                       savefpstate(fs);
+               copywords((caddr_t)fs, (caddr_t)&ipc.ip_f, sizeof *fs);
+               break;
+
+       case PT_SETFPREGS:
+               fs = &ipc.ip_f;
+               if ((fs->fs_fsr & FSR_MBZ) != 0 || fs->fs_qsize) {
+                       error = EINVAL;
+                       break;
+               }
+               oldfs = p->p_md.md_fpstate;
+               if (oldfs == NULL)
+                       p->p_md.md_fpstate = oldfs = malloc(sizeof *oldfs,
+                           M_SUBPROC, M_WAITOK);
+               else if (p == fpproc) {
+                       savefpstate(oldfs);
+                       fpproc = NULL;
+                       p->p_md.md_tf->tf_psr &= ~PSR_EF;
+               }
+               copywords((caddr_t)fs, (caddr_t)oldfs, sizeof *oldfs);
+               break;
+
+       default:
+               panic("procxmt");
+       }
+       ipc.ip_error = error;
+       wakeup((caddr_t)&ipc);
+       return (0);
+}
diff --git a/usr/src/sys/sparc/sparc/timerreg.h b/usr/src/sys/sparc/sparc/timerreg.h
new file mode 100644 (file)
index 0000000..1463e5d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * %sccs.include.redist.c%
+ *
+ *     @(#)timerreg.h  7.1 (Berkeley) %G%
+ *
+ * from: $Header: timerreg.h,v 1.6 92/07/07 04:56:09 leres Exp $ (LBL)
+ */
+
+/*
+ * Sun-4c counter/timer registers.  The timers are implemented within
+ * the cache chip (!).  The counter and limit fields below could be
+ * defined as:
+ *
+ *     struct {
+ *             u_int   t_limit:1,      // limit reached
+ *                     t_usec:21,      // counter value in microseconds
+ *                     t_mbz:10;       // always zero
+ *     };
+ *
+ * but this is more trouble than it is worth.
+ *
+ * These timers work in a rather peculiar fashion.  Most clock counters
+ * run to 0 (as, e.g., on the VAX, where the ICR counts up to 0 from a
+ * large unsigned number).  On the Sun-4c, it counts up to a limit.  But
+ * for some reason, when it reaches the limit, it resets to 1, not 0.
+ * Thus, if the limit is set to 4, the counter counts like this:
+ *
+ *     1, 2, 3, 1, 2, 3, ...
+ *
+ * and if we want to divide by N we must set the limit register to N+1.
+ */
+#ifndef LOCORE
+struct timer {
+       int     t_counter;              /* counter reg */
+       int     t_limit;                /* limit reg */
+};
+
+struct timerreg {
+       struct  timer t_c10;            /* counter that interrupts at ipl 10 */
+       struct  timer t_c14;            /* counter that interrupts at ipl 14 */
+};
+#endif
+
+#define        TMR_LIMIT       0x80000000      /* counter reached its limit */
+#define        TMR_SHIFT       10              /* shift to obtain microseconds */
+#define        TMR_MASK        0x1fffff        /* 21 bits */
+
+/* Compute a limit that causes the timer to fire every n microseconds. */
+#define        tmr_ustolim(n)  (((n) + 1) << TMR_SHIFT)
+
+#include "vaddrs.h"
+#define        TIMERREG        ((volatile struct timerreg *)TIMERREG_VA)